From 5ad4eb2105cda09c5996d51559fdea9f9bd95914 Mon Sep 17 00:00:00 2001 From: morsch Date: Wed, 7 Oct 2009 12:45:36 +0000 Subject: [PATCH] pythia8130 distributed with AliRoot --- PYTHIA8/libpythia8.pkg | 51 + PYTHIA8/pythia8130/include/Analysis.h | 343 + PYTHIA8/pythia8130/include/Basics.h | 381 + PYTHIA8/pythia8130/include/BeamParticle.h | 284 + PYTHIA8/pythia8130/include/BeamRemnants.h | 83 + PYTHIA8/pythia8130/include/BeamShape.h | 61 + PYTHIA8/pythia8130/include/BoseEinstein.h | 92 + PYTHIA8/pythia8130/include/Event.h | 542 ++ .../pythia8130/include/FragmentationFlavZpT.h | 173 + .../pythia8130/include/FragmentationSystems.h | 183 + PYTHIA8/pythia8130/include/HadronLevel.h | 112 + PYTHIA8/pythia8130/include/HepMCInterface.h | 103 + PYTHIA8/pythia8130/include/Info.h | 251 + PYTHIA8/pythia8130/include/LHAFortran.h | 105 + PYTHIA8/pythia8130/include/LHAPDFInterface.h | 75 + PYTHIA8/pythia8130/include/LesHouches.h | 295 + .../include/MiniStringFragmentation.h | 78 + .../pythia8130/include/MultipleInteractions.h | 218 + PYTHIA8/pythia8130/include/ParticleData.h | 602 ++ PYTHIA8/pythia8130/include/ParticleDecays.h | 138 + .../pythia8130/include/PartonDistributions.h | 192 + PYTHIA8/pythia8130/include/PartonLevel.h | 114 + PYTHIA8/pythia8130/include/PhaseSpace.h | 458 + PYTHIA8/pythia8130/include/ProcessContainer.h | 164 + PYTHIA8/pythia8130/include/ProcessLevel.h | 135 + PYTHIA8/pythia8130/include/Pythia.h | 263 + PYTHIA8/pythia8130/include/Pythia6Interface.h | 78 + PYTHIA8/pythia8130/include/PythiaComplex.h | 21 + PYTHIA8/pythia8130/include/PythiaStdlib.h | 82 + PYTHIA8/pythia8130/include/ResonanceDecays.h | 71 + PYTHIA8/pythia8130/include/ResonanceWidths.h | 635 ++ PYTHIA8/pythia8130/include/Settings.h | 235 + .../pythia8130/include/SigmaCompositeness.h | 184 + PYTHIA8/pythia8130/include/SigmaEW.h | 1019 +++ PYTHIA8/pythia8130/include/SigmaExtraDim.h | 226 + PYTHIA8/pythia8130/include/SigmaHiggs.h | 812 ++ .../pythia8130/include/SigmaLeftRightSym.h | 275 + PYTHIA8/pythia8130/include/SigmaLeptoquark.h | 176 + .../pythia8130/include/SigmaNewGaugeBosons.h | 185 + PYTHIA8/pythia8130/include/SigmaOnia.h | 294 + PYTHIA8/pythia8130/include/SigmaProcess.h | 537 ++ PYTHIA8/pythia8130/include/SigmaQCD.h | 446 + PYTHIA8/pythia8130/include/SigmaSUSY.h | 164 + PYTHIA8/pythia8130/include/SigmaTotal.h | 94 + PYTHIA8/pythia8130/include/SpaceShower.h | 185 + PYTHIA8/pythia8130/include/StandardModel.h | 169 + .../pythia8130/include/StringFragmentation.h | 163 + PYTHIA8/pythia8130/include/SusyLesHouches.h | 489 + PYTHIA8/pythia8130/include/TimeShower.h | 185 + PYTHIA8/pythia8130/include/UserHooks.h | 170 + PYTHIA8/pythia8130/src/Analysis.cxx | 886 ++ PYTHIA8/pythia8130/src/Basics.cxx | 1175 +++ PYTHIA8/pythia8130/src/BeamParticle.cxx | 862 ++ PYTHIA8/pythia8130/src/BeamRemnants.cxx | 809 ++ PYTHIA8/pythia8130/src/BeamShape.cxx | 148 + PYTHIA8/pythia8130/src/BoseEinstein.cxx | 280 + PYTHIA8/pythia8130/src/Event.cxx | 752 ++ .../pythia8130/src/FragmentationFlavZpT.cxx | 748 ++ .../pythia8130/src/FragmentationSystems.cxx | 471 + PYTHIA8/pythia8130/src/HadronLevel.cxx | 904 ++ PYTHIA8/pythia8130/src/Info.cxx | 186 + PYTHIA8/pythia8130/src/LesHouches.cxx | 503 ++ .../src/MiniStringFragmentation.cxx | 317 + .../pythia8130/src/MultipleInteractions.cxx | 1353 +++ PYTHIA8/pythia8130/src/ParticleData.cxx | 2027 +++++ PYTHIA8/pythia8130/src/ParticleDecays.cxx | 1220 +++ .../pythia8130/src/PartonDistributions.cxx | 579 ++ PYTHIA8/pythia8130/src/PartonLevel.cxx | 707 ++ PYTHIA8/pythia8130/src/PhaseSpace.cxx | 2842 ++++++ PYTHIA8/pythia8130/src/ProcessContainer.cxx | 1622 ++++ PYTHIA8/pythia8130/src/ProcessLevel.cxx | 1069 +++ PYTHIA8/pythia8130/src/Pythia.cxx | 1346 +++ PYTHIA8/pythia8130/src/ResonanceDecays.cxx | 798 ++ PYTHIA8/pythia8130/src/ResonanceWidths.cxx | 2084 +++++ PYTHIA8/pythia8130/src/Settings.cxx | 687 ++ PYTHIA8/pythia8130/src/SigmaCompositeness.cxx | 436 + PYTHIA8/pythia8130/src/SigmaEW.cxx | 2732 ++++++ PYTHIA8/pythia8130/src/SigmaExtraDim.cxx | 443 + PYTHIA8/pythia8130/src/SigmaHiggs.cxx | 2530 ++++++ PYTHIA8/pythia8130/src/SigmaLeftRightSym.cxx | 808 ++ PYTHIA8/pythia8130/src/SigmaLeptoquark.cxx | 310 + .../pythia8130/src/SigmaNewGaugeBosons.cxx | 757 ++ PYTHIA8/pythia8130/src/SigmaOnia.cxx | 626 ++ PYTHIA8/pythia8130/src/SigmaProcess.cxx | 947 ++ PYTHIA8/pythia8130/src/SigmaQCD.cxx | 542 ++ PYTHIA8/pythia8130/src/SigmaSUSY.cxx | 656 ++ PYTHIA8/pythia8130/src/SigmaTotal.cxx | 299 + PYTHIA8/pythia8130/src/SpaceShower.cxx | 1209 +++ PYTHIA8/pythia8130/src/StandardModel.cxx | 509 ++ .../pythia8130/src/StringFragmentation.cxx | 1209 +++ PYTHIA8/pythia8130/src/SusyLesHouches.cxx | 1094 +++ PYTHIA8/pythia8130/src/TimeShower.cxx | 2213 +++++ PYTHIA8/pythia8130/src/UserHooks.cxx | 161 + .../pythia8130/xmldoc/ASecondHardProcess.xml | 334 + .../xmldoc/AccessPYTHIA6Processes.xml | 110 + PYTHIA8/pythia8130/xmldoc/BeamParameters.xml | 253 + PYTHIA8/pythia8130/xmldoc/BeamRemnants.xml | 313 + PYTHIA8/pythia8130/xmldoc/BeamShape.xml | 56 + PYTHIA8/pythia8130/xmldoc/Bibliography.xml | 155 + .../pythia8130/xmldoc/BoseEinsteinEffects.xml | 116 + .../xmldoc/CompositenessProcesses.xml | 150 + .../pythia8130/xmldoc/CouplingsAndScales.xml | 287 + .../xmldoc/ElectroweakProcesses.xml | 225 + PYTHIA8/pythia8130/xmldoc/ErrorChecks.xml | 71 + PYTHIA8/pythia8130/xmldoc/EventAnalysis.xml | 389 + .../pythia8130/xmldoc/EventInformation.xml | 221 + PYTHIA8/pythia8130/xmldoc/EventRecord.xml | 312 + PYTHIA8/pythia8130/xmldoc/EventStatistics.xml | 116 + PYTHIA8/pythia8130/xmldoc/ExternalDecays.xml | 71 + .../xmldoc/ExtraDimensionalProcesses.xml | 73 + .../pythia8130/xmldoc/FlavourSelection.xml | 356 + PYTHIA8/pythia8130/xmldoc/FourVectors.xml | 133 + .../xmldoc/FourthGenerationProcesses.xml | 176 + PYTHIA8/pythia8130/xmldoc/Fragmentation.xml | 310 + PYTHIA8/pythia8130/xmldoc/Frontpage.xml | 102 + PYTHIA8/pythia8130/xmldoc/Glossary.xml | 92 + .../xmldoc/HadronLevelStandalone.xml | 160 + PYTHIA8/pythia8130/xmldoc/HepMCInterface.xml | 44 + PYTHIA8/pythia8130/xmldoc/HiggsProcesses.xml | 910 ++ PYTHIA8/pythia8130/xmldoc/Histograms.xml | 176 + .../pythia8130/xmldoc/ImplementNewShowers.xml | 530 ++ PYTHIA8/pythia8130/xmldoc/Index.xml | 111 + .../xmldoc/LeftRightSymmetryProcesses.xml | 183 + .../pythia8130/xmldoc/LeptoquarkProcesses.xml | 84 + .../pythia8130/xmldoc/LesHouchesAccord.xml | 437 + .../pythia8130/xmldoc/MainProgramSettings.xml | 199 + PYTHIA8/pythia8130/xmldoc/MasterSwitches.xml | 164 + .../xmldoc/MultipleInteractions.xml | 392 + .../xmldoc/NewGaugeBosonProcesses.xml | 344 + PYTHIA8/pythia8130/xmldoc/OniaProcesses.xml | 301 + PYTHIA8/pythia8130/xmldoc/PDFSelection.xml | 219 + .../xmldoc/PYTHIA6TranslationTable.xml | 100 + PYTHIA8/pythia8130/xmldoc/ParticleData.xml | 7897 +++++++++++++++++ .../pythia8130/xmldoc/ParticleDataScheme.xml | 625 ++ PYTHIA8/pythia8130/xmldoc/ParticleDecays.xml | 255 + .../pythia8130/xmldoc/ParticleProperties.xml | 485 + .../pythia8130/xmldoc/PartonDistributions.xml | 102 + PYTHIA8/pythia8130/xmldoc/PhaseSpaceCuts.xml | 120 + .../pythia8130/xmldoc/ProcessSelection.xml | 130 + PYTHIA8/pythia8130/xmldoc/ProgramFiles.xml | 329 + PYTHIA8/pythia8130/xmldoc/ProgramFlow.xml | 492 + PYTHIA8/pythia8130/xmldoc/QCDProcesses.xml | 164 + .../pythia8130/xmldoc/RandomNumberSeed.xml | 30 + PYTHIA8/pythia8130/xmldoc/RandomNumbers.xml | 72 + .../xmldoc/RandomNumbersAndChecks.xml | 30 + PYTHIA8/pythia8130/xmldoc/ResonanceDecays.xml | 316 + .../xmldoc/SUSYLesHouchesAccord.xml | 29 + PYTHIA8/pythia8130/xmldoc/SUSYProcesses.xml | 37 + .../pythia8130/xmldoc/SampleMainPrograms.xml | 167 + PYTHIA8/pythia8130/xmldoc/SaveSettings.xml | 150 + .../xmldoc/SemiInternalProcesses.xml | 405 + .../xmldoc/SemiInternalResonances.xml | 204 + PYTHIA8/pythia8130/xmldoc/SettingsScheme.xml | 266 + .../pythia8130/xmldoc/SpacelikeShowers.xml | 310 + .../xmldoc/StandardModelParameters.xml | 191 + PYTHIA8/pythia8130/xmldoc/TimelikeShowers.xml | 326 + PYTHIA8/pythia8130/xmldoc/TopProcesses.xml | 43 + .../pythia8130/xmldoc/TotalCrossSections.xml | 115 + PYTHIA8/pythia8130/xmldoc/Tunes.xml | 96 + PYTHIA8/pythia8130/xmldoc/UpdateHistory.xml | 180 + PYTHIA8/pythia8130/xmldoc/UserHooks.xml | 292 + PYTHIA8/pythia8130/xmldoc/Version.xml | 19 + PYTHIA8/pythia8130/xmldoc/Welcome.xml | 14 + 163 files changed, 76913 insertions(+) create mode 100644 PYTHIA8/libpythia8.pkg create mode 100644 PYTHIA8/pythia8130/include/Analysis.h create mode 100644 PYTHIA8/pythia8130/include/Basics.h create mode 100644 PYTHIA8/pythia8130/include/BeamParticle.h create mode 100644 PYTHIA8/pythia8130/include/BeamRemnants.h create mode 100644 PYTHIA8/pythia8130/include/BeamShape.h create mode 100644 PYTHIA8/pythia8130/include/BoseEinstein.h create mode 100644 PYTHIA8/pythia8130/include/Event.h create mode 100644 PYTHIA8/pythia8130/include/FragmentationFlavZpT.h create mode 100644 PYTHIA8/pythia8130/include/FragmentationSystems.h create mode 100644 PYTHIA8/pythia8130/include/HadronLevel.h create mode 100644 PYTHIA8/pythia8130/include/HepMCInterface.h create mode 100644 PYTHIA8/pythia8130/include/Info.h create mode 100644 PYTHIA8/pythia8130/include/LHAFortran.h create mode 100644 PYTHIA8/pythia8130/include/LHAPDFInterface.h create mode 100644 PYTHIA8/pythia8130/include/LesHouches.h create mode 100644 PYTHIA8/pythia8130/include/MiniStringFragmentation.h create mode 100644 PYTHIA8/pythia8130/include/MultipleInteractions.h create mode 100644 PYTHIA8/pythia8130/include/ParticleData.h create mode 100644 PYTHIA8/pythia8130/include/ParticleDecays.h create mode 100644 PYTHIA8/pythia8130/include/PartonDistributions.h create mode 100644 PYTHIA8/pythia8130/include/PartonLevel.h create mode 100644 PYTHIA8/pythia8130/include/PhaseSpace.h create mode 100644 PYTHIA8/pythia8130/include/ProcessContainer.h create mode 100644 PYTHIA8/pythia8130/include/ProcessLevel.h create mode 100644 PYTHIA8/pythia8130/include/Pythia.h create mode 100644 PYTHIA8/pythia8130/include/Pythia6Interface.h create mode 100644 PYTHIA8/pythia8130/include/PythiaComplex.h create mode 100644 PYTHIA8/pythia8130/include/PythiaStdlib.h create mode 100644 PYTHIA8/pythia8130/include/ResonanceDecays.h create mode 100644 PYTHIA8/pythia8130/include/ResonanceWidths.h create mode 100644 PYTHIA8/pythia8130/include/Settings.h create mode 100644 PYTHIA8/pythia8130/include/SigmaCompositeness.h create mode 100644 PYTHIA8/pythia8130/include/SigmaEW.h create mode 100644 PYTHIA8/pythia8130/include/SigmaExtraDim.h create mode 100644 PYTHIA8/pythia8130/include/SigmaHiggs.h create mode 100644 PYTHIA8/pythia8130/include/SigmaLeftRightSym.h create mode 100644 PYTHIA8/pythia8130/include/SigmaLeptoquark.h create mode 100644 PYTHIA8/pythia8130/include/SigmaNewGaugeBosons.h create mode 100644 PYTHIA8/pythia8130/include/SigmaOnia.h create mode 100644 PYTHIA8/pythia8130/include/SigmaProcess.h create mode 100644 PYTHIA8/pythia8130/include/SigmaQCD.h create mode 100644 PYTHIA8/pythia8130/include/SigmaSUSY.h create mode 100644 PYTHIA8/pythia8130/include/SigmaTotal.h create mode 100644 PYTHIA8/pythia8130/include/SpaceShower.h create mode 100644 PYTHIA8/pythia8130/include/StandardModel.h create mode 100644 PYTHIA8/pythia8130/include/StringFragmentation.h create mode 100644 PYTHIA8/pythia8130/include/SusyLesHouches.h create mode 100644 PYTHIA8/pythia8130/include/TimeShower.h create mode 100644 PYTHIA8/pythia8130/include/UserHooks.h create mode 100644 PYTHIA8/pythia8130/src/Analysis.cxx create mode 100644 PYTHIA8/pythia8130/src/Basics.cxx create mode 100644 PYTHIA8/pythia8130/src/BeamParticle.cxx create mode 100644 PYTHIA8/pythia8130/src/BeamRemnants.cxx create mode 100644 PYTHIA8/pythia8130/src/BeamShape.cxx create mode 100644 PYTHIA8/pythia8130/src/BoseEinstein.cxx create mode 100644 PYTHIA8/pythia8130/src/Event.cxx create mode 100644 PYTHIA8/pythia8130/src/FragmentationFlavZpT.cxx create mode 100644 PYTHIA8/pythia8130/src/FragmentationSystems.cxx create mode 100644 PYTHIA8/pythia8130/src/HadronLevel.cxx create mode 100644 PYTHIA8/pythia8130/src/Info.cxx create mode 100644 PYTHIA8/pythia8130/src/LesHouches.cxx create mode 100644 PYTHIA8/pythia8130/src/MiniStringFragmentation.cxx create mode 100644 PYTHIA8/pythia8130/src/MultipleInteractions.cxx create mode 100644 PYTHIA8/pythia8130/src/ParticleData.cxx create mode 100644 PYTHIA8/pythia8130/src/ParticleDecays.cxx create mode 100644 PYTHIA8/pythia8130/src/PartonDistributions.cxx create mode 100644 PYTHIA8/pythia8130/src/PartonLevel.cxx create mode 100644 PYTHIA8/pythia8130/src/PhaseSpace.cxx create mode 100644 PYTHIA8/pythia8130/src/ProcessContainer.cxx create mode 100644 PYTHIA8/pythia8130/src/ProcessLevel.cxx create mode 100644 PYTHIA8/pythia8130/src/Pythia.cxx create mode 100644 PYTHIA8/pythia8130/src/ResonanceDecays.cxx create mode 100644 PYTHIA8/pythia8130/src/ResonanceWidths.cxx create mode 100644 PYTHIA8/pythia8130/src/Settings.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaCompositeness.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaEW.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaExtraDim.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaHiggs.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaLeftRightSym.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaLeptoquark.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaNewGaugeBosons.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaOnia.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaProcess.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaQCD.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaSUSY.cxx create mode 100644 PYTHIA8/pythia8130/src/SigmaTotal.cxx create mode 100644 PYTHIA8/pythia8130/src/SpaceShower.cxx create mode 100644 PYTHIA8/pythia8130/src/StandardModel.cxx create mode 100644 PYTHIA8/pythia8130/src/StringFragmentation.cxx create mode 100644 PYTHIA8/pythia8130/src/SusyLesHouches.cxx create mode 100644 PYTHIA8/pythia8130/src/TimeShower.cxx create mode 100644 PYTHIA8/pythia8130/src/UserHooks.cxx create mode 100644 PYTHIA8/pythia8130/xmldoc/ASecondHardProcess.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/AccessPYTHIA6Processes.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/BeamParameters.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/BeamRemnants.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/BeamShape.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/Bibliography.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/BoseEinsteinEffects.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/CompositenessProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/CouplingsAndScales.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ElectroweakProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ErrorChecks.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/EventAnalysis.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/EventInformation.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/EventRecord.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/EventStatistics.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ExternalDecays.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ExtraDimensionalProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/FlavourSelection.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/FourVectors.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/FourthGenerationProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/Fragmentation.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/Frontpage.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/Glossary.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/HadronLevelStandalone.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/HepMCInterface.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/HiggsProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/Histograms.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ImplementNewShowers.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/Index.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/LeftRightSymmetryProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/LeptoquarkProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/LesHouchesAccord.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/MainProgramSettings.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/MasterSwitches.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/MultipleInteractions.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/NewGaugeBosonProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/OniaProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/PDFSelection.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/PYTHIA6TranslationTable.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ParticleData.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ParticleDataScheme.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ParticleDecays.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ParticleProperties.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/PartonDistributions.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/PhaseSpaceCuts.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ProcessSelection.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ProgramFiles.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ProgramFlow.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/QCDProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/RandomNumberSeed.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/RandomNumbers.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/RandomNumbersAndChecks.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/ResonanceDecays.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/SUSYLesHouchesAccord.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/SUSYProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/SampleMainPrograms.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/SaveSettings.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/SemiInternalProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/SemiInternalResonances.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/SettingsScheme.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/SpacelikeShowers.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/StandardModelParameters.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/TimelikeShowers.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/TopProcesses.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/TotalCrossSections.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/Tunes.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/UpdateHistory.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/UserHooks.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/Version.xml create mode 100644 PYTHIA8/pythia8130/xmldoc/Welcome.xml diff --git a/PYTHIA8/libpythia8.pkg b/PYTHIA8/libpythia8.pkg new file mode 100644 index 00000000000..aba88f2b332 --- /dev/null +++ b/PYTHIA8/libpythia8.pkg @@ -0,0 +1,51 @@ +#-*- Mode: Makefile -*- + +SRCS:= \ +pythia8130/src/Analysis.cxx \ +pythia8130/src/Basics.cxx \ +pythia8130/src/BeamParticle.cxx \ +pythia8130/src/BeamRemnants.cxx \ +pythia8130/src/BeamShape.cxx \ +pythia8130/src/BoseEinstein.cxx \ +pythia8130/src/Event.cxx \ +pythia8130/src/FragmentationFlavZpT.cxx \ +pythia8130/src/FragmentationSystems.cxx \ +pythia8130/src/HadronLevel.cxx \ +pythia8130/src/Info.cxx \ +pythia8130/src/LesHouches.cxx \ +pythia8130/src/MiniStringFragmentation.cxx \ +pythia8130/src/MultipleInteractions.cxx \ +pythia8130/src/ParticleData.cxx \ +pythia8130/src/ParticleDecays.cxx \ +pythia8130/src/PartonDistributions.cxx \ +pythia8130/src/PartonLevel.cxx \ +pythia8130/src/PhaseSpace.cxx \ +pythia8130/src/ProcessContainer.cxx \ +pythia8130/src/ProcessLevel.cxx \ +pythia8130/src/Pythia.cxx \ +pythia8130/src/ResonanceDecays.cxx \ +pythia8130/src/ResonanceWidths.cxx \ +pythia8130/src/Settings.cxx \ +pythia8130/src/SigmaCompositeness.cxx \ +pythia8130/src/SigmaEW.cxx \ +pythia8130/src/SigmaExtraDim.cxx \ +pythia8130/src/SigmaHiggs.cxx \ +pythia8130/src/SigmaLeftRightSym.cxx \ +pythia8130/src/SigmaLeptoquark.cxx \ +pythia8130/src/SigmaNewGaugeBosons.cxx \ +pythia8130/src/SigmaOnia.cxx \ +pythia8130/src/SigmaProcess.cxx \ +pythia8130/src/SigmaQCD.cxx \ +pythia8130/src/SigmaSUSY.cxx \ +pythia8130/src/SigmaTotal.cxx \ +pythia8130/src/SpaceShower.cxx \ +pythia8130/src/StandardModel.cxx \ +pythia8130/src/StringFragmentation.cxx \ +pythia8130/src/SusyLesHouches.cxx \ +pythia8130/src/TimeShower.cxx \ +pythia8130/src/UserHooks.cxx + +EINCLUDE:= PYTHIA8/pythia8130/include +ifeq (macosxicc,$(ALICE_TARGET)) +PACKFFLAGS := $(filter-out -O%,$(FFLAGS)) +endif diff --git a/PYTHIA8/pythia8130/include/Analysis.h b/PYTHIA8/pythia8130/include/Analysis.h new file mode 100644 index 00000000000..99373efda3f --- /dev/null +++ b/PYTHIA8/pythia8130/include/Analysis.h @@ -0,0 +1,343 @@ +// Analysis.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for the Sphericity, Thrust, ClusterJet and CellJet classes. +// Sphericity: sphericity analysis of the event. +// Thrust: thrust analysis of the event. +// ClusterJet: clustering jet finder. +// CellJet: calorimetric cone jet finder. + +#ifndef Pythia8_Analysis_H +#define Pythia8_Analysis_H + +#include "Basics.h" +#include "Event.h" +#include "PythiaStdlib.h" + +namespace Pythia8 { + +//************************************************************************** + +// Sphericity class. +// This class performs (optionally modified) sphericity analysis on an event. + +class Sphericity { + +public: + + // Constructor. + Sphericity(double powerIn = 2., int selectIn = 2) : power(powerIn), + select(selectIn), nFew(0), nBack(0) {powerInt = 0; + if (abs(power - 1.) < 0.01) powerInt = 1; + if (abs(power - 2.) < 0.01) powerInt = 2; + powerMod = 0.5 * power - 1.;} + + // Analyze event. + bool analyze(const Event& event, ostream& os = cout); + + // Return info on results of analysis. + double sphericity() const {return 1.5 * (eVal2 + eVal3);} + double aplanarity() const {return 1.5 * eVal3;} + double eigenValue(int i) const {return (i < 2) ? eVal1 : + ( (i < 3) ? eVal2 : eVal3 ) ;} + Vec4 eventAxis(int i) const {return (i < 2) ? eVec1 : + ( (i < 3) ? eVec2 : eVec3 ) ;} + + // Provide a listing of the info. + void list(ostream& os = cout); + + // Tell how many events could not be analyzed. + int nError() const {return nFew + nBack;} + +private: + + // Constants: could only be changed in the code itself. + static const int NSTUDYMIN, TIMESTOPRINT; + static const double P2MIN, EIGENVALUEMIN; + + // Properties of analysis. + double power; + int select, powerInt; + double powerMod; + + // Outcome of analysis. + double eVal1, eVal2, eVal3; + Vec4 eVec1, eVec2, eVec3; + + // Error statistics; + int nFew, nBack; + +}; + +//************************************************************************** + +// Thrust class. +// This class performs thrust analysis on an event. + +class Thrust { + +public: + + // Constructor. + Thrust(int selectIn = 2) : select(selectIn), nFew(0) {} + + // Analyze event. + bool analyze(const Event& event, ostream& os = cout); + + // Return info on results of analysis. + double thrust() const {return eVal1;} + double tMajor() const {return eVal2;} + double tMinor() const {return eVal3;} + double oblateness() const {return eVal2 - eVal3;} + Vec4 eventAxis(int i) const {return (i < 2) ? eVec1 : + ( (i < 3) ? eVec2 : eVec3 ) ;} + + // Provide a listing of the info. + void list(ostream& os = cout); + + // Tell how many events could not be analyzed. + int nError() const {return nFew;} + +private: + + // Constants: could only be changed in the code itself. + static const int NSTUDYMIN, TIMESTOPRINT; + static const double MAJORMIN; + + // Properties of analysis. + int select; + + // Outcome of analysis. + double eVal1, eVal2, eVal3; + Vec4 eVec1, eVec2, eVec3; + + // Error statistics; + int nFew; + +}; + +//************************************************************************** + +// SingleClusterJet class. +// Simple helper class to ClusterJet for a jet and its contents. + +class SingleClusterJet { + +public: + + // Constructors. + SingleClusterJet(Vec4 pJetIn = 0., int motherIn = 0) : + pJet(pJetIn), mother(motherIn), daughter(0), multiplicity(1), + isAssigned(false) {pAbs = max( PABSMIN, pJet.pAbs());} + SingleClusterJet& operator=(const SingleClusterJet& j) { if (this != &j) + { pJet = j.pJet; mother = j.mother; daughter = j.daughter; + multiplicity = j.multiplicity; pAbs = j.pAbs; + isAssigned = j.isAssigned;} return *this; } + + // Properties of jet. + // Note: mother, daughter and isAssigned only used for original + // particles, multiplicity and pTemp only for reconstructed jets. + Vec4 pJet; + int mother, daughter, multiplicity; + bool isAssigned; + double pAbs; + Vec4 pTemp; + + // Distance measures (Lund, JADE, Durham) with friend. + friend double dist2Fun(int measure, const SingleClusterJet& j1, + const SingleClusterJet& j2); + +private: + + // Constants: could only be changed in the code itself. + static const double PABSMIN; + +} ; + +//************************************************************************** + +// ClusterJet class. +// This class performs a jet clustering according to different +// distance measures: Lund, JADE or Durham. + +class ClusterJet { + +public: + + // Constructor. + ClusterJet(string measureIn = "Lund", int selectIn = 2, int massSetIn = 2, + bool preclusterIn = false, bool reassignIn = false) : measure(1), + select(selectIn), massSet(massSetIn), doPrecluster(preclusterIn), + doReassign(reassignIn), nFew(0) { + char firstChar = toupper(measureIn[0]); + if (firstChar == 'J') measure = 2; + if (firstChar == 'D') measure = 3; + piMass = ParticleDataTable::m0(211); + } + + // Analyze event. + bool analyze(const Event& event, double yScaleIn, double pTscaleIn, + int nJetMinIn = 1, int nJetMaxIn = 0, ostream& os = cout); + + // Return info on jets produced. + int size() const {return jets.size();} + Vec4 p(int j) const {return jets[j].pJet;} + + // Return belonging of particle to one of the jets (-1 if none). + int jetAssignment(int i) const { + for (int iP = 0; iP < int(particles.size()); ++iP) + if (particles[iP].mother == i) return particles[iP].daughter; + return -1;} + + // Provide a listing of the info. + void list(ostream& os = cout); + + // Tell how many events could not be analyzed. + int nError() const {return nFew;} + +private: + + // Constants: could only be changed in the code itself. + static const int TIMESTOPRINT; + static const double PABSMIN, PRECLUSTERFRAC, PRECLUSTERSTEP; + + // Properties of analysis. + int measure, select, massSet; + bool doPrecluster, doReassign; + double yScale, pTscale; + int nJetMin, nJetMax; + + // Temporary results. + double piMass, dist2Join, dist2BigMin, distPre, dist2Pre; + vector particles; + int nParticles; + + // Error statistics; + int nFew; + + // Member functions for some operations (for clarity). + void precluster(); + void reassign(); + + // Outcome of analysis: ET-ordered list of jets. + vector jets; + +}; + +//************************************************************************** + +// SingleCell class. +// Simple helper class to CellJet for a cell and its contents. + +class SingleCell { + +public: + + // Constructor. + SingleCell(int iCellIn = 0, double etaCellIn = 0., double phiCellIn = 0., + double eTcellIn = 0., int multiplicityIn = 0) : iCell(iCellIn), + etaCell(etaCellIn), phiCell(phiCellIn), eTcell(eTcellIn), + multiplicity(multiplicityIn), canBeSeed(true), isUsed(false), + isAssigned(false) {} + + // Properties of cell. + int iCell; + double etaCell, phiCell, eTcell; + int multiplicity; + bool canBeSeed, isUsed, isAssigned; + +} ; + +//************************************************************************** + +// SingleCellJet class. +// Simple helper class to CellJet for a jet and its contents. + +class SingleCellJet { + +public: + + // Constructor. + SingleCellJet(double eTjetIn = 0., double etaCenterIn = 0., + double phiCenterIn = 0., double etaWeightedIn = 0., + double phiWeightedIn = 0., int multiplicityIn = 0, + Vec4 pMassiveIn = 0.) : eTjet(eTjetIn), etaCenter(etaCenterIn), + phiCenter(phiCenterIn), etaWeighted(etaWeightedIn), + phiWeighted(phiWeightedIn), multiplicity(multiplicityIn), + pMassive(pMassiveIn) {} + + // Properties of jet. + double eTjet, etaCenter, phiCenter, etaWeighted, phiWeighted; + int multiplicity; + Vec4 pMassive; + +} ; + +//************************************************************************** + +// CellJet class. +// This class performs a cone jet search in (eta, phi, E_T) space. + +class CellJet { + +public: + + // Constructor. + CellJet(double etaMaxIn = 5., int nEtaIn = 50, int nPhiIn = 32, + int selectIn = 2, int smearIn = 0, double resolutionIn = 0.5, + double upperCutIn = 2., double thresholdIn = 0.) : etaMax(etaMaxIn), + nEta(nEtaIn), nPhi(nPhiIn), select(selectIn), smear(smearIn), + resolution(resolutionIn), upperCut(upperCutIn), + threshold(thresholdIn), nFew(0) { } + + // Analyze event. + bool analyze(const Event& event, double eTjetMinIn = 20., + double coneRadiusIn = 0.7, double eTseedIn = 1.5, ostream& os = cout); + + // Return info on results of analysis. + int size() const {return jets.size();} + double eT(int i) const {return jets[i].eTjet;} + double etaCenter(int i) const {return jets[i].etaCenter;} + double phiCenter(int i) const {return jets[i].phiCenter;} + double etaWeighted(int i) const {return jets[i].etaWeighted;} + double phiWeighted(int i) const {return jets[i].phiWeighted;} + double multiplicity(int i) const {return jets[i].multiplicity;} + Vec4 pMassless(int i) const {return jets[i].eTjet * Vec4( + cos(jets[i].phiWeighted), sin(jets[i].phiWeighted), + sinh(jets[i].etaWeighted), cosh(jets[i].etaWeighted) );} + Vec4 pMassive(int i) const {return jets[i].pMassive;} + double m(int i) const {return jets[i].pMassive.mCalc();} + + // Provide a listing of the info. + void list(ostream& os = cout); + + // Tell how many events could not be analyzed: so far never. + int nError() const {return nFew;} + +private: + + // Constants: could only be changed in the code itself. + static const int TIMESTOPRINT; + + // Properties of analysis. + double etaMax; + int nEta, nPhi, select, smear; + double resolution, upperCut, threshold; + double eTjetMin, coneRadius, eTseed; + + // Error statistics; + int nFew; + + // Outcome of analysis: ET-ordered list of jets. + vector jets; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // end Pythia8_Analysis_H + diff --git a/PYTHIA8/pythia8130/include/Basics.h b/PYTHIA8/pythia8130/include/Basics.h new file mode 100644 index 00000000000..fecf13c010a --- /dev/null +++ b/PYTHIA8/pythia8130/include/Basics.h @@ -0,0 +1,381 @@ +// Basics.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for basic, often-used helper classes. +// RndmEngine: base class for external random number generators. +// Rndm: random number generator (static member functions). +// Vec4: simple four-vectors. +// RotBstMatrix: matrices encoding rotations and boosts of Vec4 objects. +// Hist: simple one-dimensional histograms. + +#ifndef Pythia8_Basics_H +#define Pythia8_Basics_H + +#include "PythiaStdlib.h" + +namespace Pythia8 { + +//************************************************************************** + +// RndmEngine is the base class for external random number generators. +// There is only one pure virtual method, that should do the generation. + +class RndmEngine { + +public: + + // A pure virtual method, wherein the derived class method + // generates a random number uniformly distributed between 1 and 1. + virtual double flat() = 0; + +protected: + + // Destructor. + virtual ~RndmEngine() {} + +}; + +//************************************************************************** + +// Rndm class. +// This class handles random number generation according to the +// Marsaglia-Zaman-Tsang algorithm. + +class Rndm { + +public: + + // Constructors. + Rndm() {} + Rndm(int seedIn) { init(seedIn);} + + // Possibility to pass in pointer for external random number generation. + static bool rndmEnginePtr( RndmEngine* rndmPtrIn); + + // Initialize, normally at construction or in first call. + static void init(int seedIn = 0) ; + + // Generate next random number uniformly between 0 and 1. + static double flat() ; + + // Generate random numbers according to exp(-x). + static double exp() { return -log(flat()) ;} + + // Generate random numbers according to x * exp(-x). + static double xexp() { return -log(flat() * flat()) ;} + + // Generate random numbers according to exp(-x^2/2). + static double gauss() ; + + // Pick one option among vector of (positive) probabilities. + static int pick(const vector& prob) ; + +private: + + // State of the random number generator. + static bool initRndm, saveGauss; + static int i97, j97, defaultSeed; + static double u[97], c, cd, cm, save; + + // Pointer for external random number generation. + static bool useExternalRndm; + static RndmEngine* rndmPtr; + +}; + +//************************************************************************** + +// Forward reference to RotBstMatrix class. +class RotBstMatrix; + +//************************************************************************** + +// Vec4 class. +// This class implements four-vectors, in energy-momentum space. +// (But can equally well be used to hold space-time four-vectors.) + +class Vec4 { + +public: + + // Constructors. + Vec4(double xIn = 0., double yIn = 0., double zIn = 0., double tIn = 0.) + : xx(xIn), yy(yIn), zz(zIn), tt(tIn) { } + Vec4(const Vec4& v) : xx(v.xx), yy(v.yy), zz(v.zz), tt(v.tt) { } + Vec4& operator=(const Vec4& v) { if (this != &v) { xx = v.xx; yy = v.yy; + zz = v.zz; tt = v.tt; } return *this; } + Vec4& operator=(double value) { xx = value; yy = value; zz = value; + tt = value; return *this; } + + // Member functions for input. + void reset() {xx = 0.; yy = 0.; zz = 0.; tt = 0.;} + void p(double xIn, double yIn, double zIn, double tIn) + {xx = xIn; yy = yIn; zz = zIn; tt = tIn;} + void p(Vec4 pIn) {xx = pIn.xx; yy = pIn.yy; zz = pIn.zz; tt = pIn.tt;} + void px(double xIn) {xx = xIn;} + void py(double yIn) {yy = yIn;} + void pz(double zIn) {zz = zIn;} + void e(double tIn) {tt = tIn;} + + // Member functions for output. + double px() const {return xx;} + double py() const {return yy;} + double pz() const {return zz;} + double e() const {return tt;} + double mCalc() const {double temp = tt*tt - xx*xx - yy*yy - zz*zz; + return (temp >= 0) ? sqrt(temp) : -sqrt(-temp);} + double m2Calc() const {return tt*tt - xx*xx - yy*yy - zz*zz;} + double pT() const {return sqrt(xx*xx + yy*yy);} + double pT2() const {return xx*xx + yy*yy;} + double pAbs() const {return sqrt(xx*xx + yy*yy + zz*zz);} + double pAbs2() const {return xx*xx + yy*yy + zz*zz;} + double theta() const {return atan2(sqrt(xx*xx + yy*yy), zz);} + double phi() const {return atan2(yy,xx);} + double thetaXZ() const {return atan2(xx,zz);} + double pPlus() const {return tt + zz;} + double pMinus() const {return tt - zz;} + + // Member functions that perform operations. + void rescale3(double fac) {xx *= fac; yy *= fac; zz *= fac;} + void rescale4(double fac) {xx *= fac; yy *= fac; zz *= fac; tt *= fac;} + void flip3() {xx = -xx; yy = -yy; zz = -zz;} + void flip4() {xx = -xx; yy = -yy; zz = -zz; tt = -tt;} + void rot(double thetaIn, double phiIn); + void rotaxis(double phiIn, double nx, double ny, double nz); + void rotaxis(double phiIn, const Vec4& n); + void bst(double betaX, double betaY, double betaZ); + void bst(double betaX, double betaY, double betaZ, double gamma); + void bst(const Vec4& pIn); + void bst(const Vec4& pIn, double mIn); + void bstback(const Vec4& pIn); + void bstback(const Vec4& pIn, double mIn); + void rotbst(const RotBstMatrix& M); + + // Operator overloading with member functions + Vec4& operator-() {xx = -xx; yy = -yy; zz = -zz; tt = -tt; return *this;} + Vec4& operator+=(const Vec4& v) {xx += v.xx; yy += v.yy; zz += v.zz; + tt += v.tt; return *this;} + Vec4& operator-=(const Vec4& v) {xx -= v.xx; yy -= v.yy; zz -= v.zz; + tt -= v.tt; return *this;} + Vec4& operator*=(double f) {xx *= f; yy *= f; zz *= f; + tt *= f; return *this;} + Vec4& operator/=(double f) {xx /= f; yy /= f; zz /= f; + tt /= f; return *this;} + + // Operator overloading with friends + friend Vec4 operator+(const Vec4& v1, const Vec4& v2); + friend Vec4 operator-(const Vec4& v1, const Vec4& v2); + friend Vec4 operator*(double f, const Vec4& v1); + friend Vec4 operator*(const Vec4& v1, double f); + friend Vec4 operator/(const Vec4& v1, double f); + friend double operator*(const Vec4& v1, const Vec4& v2); + + // Invariant mass of a pair and its square. + friend double m(const Vec4& v1, const Vec4& v2); + friend double m2(const Vec4& v1, const Vec4& v2); + + // Scalar and cross product of 3-vector parts. + friend double dot3(const Vec4& v1, const Vec4& v2); + friend Vec4 cross3(const Vec4& v1, const Vec4& v2); + + // theta is polar angle between v1 and v2. + friend double theta(const Vec4& v1, const Vec4& v2); + friend double costheta(const Vec4& v1, const Vec4& v2); + + // phi is azimuthal angle between v1 and v2 around z axis. + friend double phi(const Vec4& v1, const Vec4& v2); + friend double cosphi(const Vec4& v1, const Vec4& v2); + + // phi is azimuthal angle between v1 and v2 around n axis. + friend double phi(const Vec4& v1, const Vec4& v2, const Vec4& n); + friend double cosphi(const Vec4& v1, const Vec4& v2, const Vec4& n); + + // Print a four-vector + friend ostream& operator<<(ostream&, const Vec4& v) ; + +private: + + // Constants: could only be changed in the code itself. + static const double TINY; + + // The four-vector data members. + double xx, yy, zz, tt; + +}; + +// Implementation of operator overloading with friends. + +inline Vec4 operator+(const Vec4& v1, const Vec4& v2) + {Vec4 v = v1 ; return v += v2;} + +inline Vec4 operator-(const Vec4& v1, const Vec4& v2) + {Vec4 v = v1 ; return v -= v2;} + +inline Vec4 operator*(double f, const Vec4& v1) + {Vec4 v = v1; return v *= f;} + +inline Vec4 operator*(const Vec4& v1, double f) + {Vec4 v = v1; return v *= f;} + +inline Vec4 operator/(const Vec4& v1, double f) + {Vec4 v = v1; return v /= f;} + +inline double operator*(const Vec4& v1, const Vec4& v2) + {return v1.tt*v2.tt - v1.xx*v2.xx - v1.yy*v2.yy - v1.zz*v2.zz;} + +//************************************************************************** + +// RotBstMatrix class. +// This class implements 4 * 4 matrices that encode an arbitrary combination +// of rotations and boosts, that can be applied to Vec4 four-vectors. + +class RotBstMatrix { + +public: + + // Constructors. + RotBstMatrix() {for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) + { M[i][j] = (i==j) ? 1. : 0.; } } } + RotBstMatrix(const RotBstMatrix& Min) { + for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { + M[i][j] = Min.M[i][j]; } } } + RotBstMatrix& operator=(const RotBstMatrix& Min) {if (this != &Min) { + for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { + M[i][j] = Min.M[i][j]; } } } return *this; } + + // Member functions. + void rot(double = 0., double = 0.); + void rot(const Vec4& p); + void bst(double = 0., double = 0., double = 0.); + void bst(const Vec4&); + void bstback(const Vec4&); + void bst(const Vec4&, const Vec4&); + void toCMframe(const Vec4&, const Vec4&); + void fromCMframe(const Vec4&, const Vec4&); + void rotbst(const RotBstMatrix&); + void invert(); + void reset(); + + // Crude estimate deviation from unit matrix. + double deviation() const; + + // Print a transformation matrix. + friend ostream& operator<<(ostream&, const RotBstMatrix&) ; + + // Private members to be accessible from Vec4. + friend class Vec4; + +private: + + // Constants: could only be changed in the code itself. + static const double TINY; + + // The rotation-and-boost matrix data members. + double M[4][4]; + +}; + +//************************************************************************** + +// Hist class. +// This class handles a single histogram at a time. + +class Hist{ + +public: + + // Constructors, including copy constructors. + Hist() {;} + Hist(string titleIn, int nBinIn = 100, double xMinIn = 0., + double xMaxIn = 1.) { + book(titleIn, nBinIn, xMinIn, xMaxIn);} + Hist(const Hist& h) + : title(h.title), nBin(h.nBin), nFill(h.nFill), xMin(h.xMin), + xMax(h.xMax), dx(h.dx), under(h.under), inside(h.inside), + over(h.over), res(h.res) { } + Hist(string titleIn, const Hist& h) + : title(titleIn), nBin(h.nBin), nFill(h.nFill), xMin(h.xMin), + xMax(h.xMax), dx(h.dx), under(h.under), inside(h.inside), + over(h.over), res(h.res) { } + Hist& operator=(const Hist& h) { if(this != &h) { + nBin = h.nBin; nFill = h.nFill; xMin = h.xMin; xMax = h.xMax; + dx = h.dx; under = h.under; inside = h.inside; over = h.over; + res = h.res; } return *this; } + + // Book a histogram. + void book(string titleIn = " ", int nBinIn = 100, double xMinIn = 0., + double xMaxIn = 1.) ; + + // Set title of a histogram. + void name(string titleIn = " ") {title = titleIn; } + + // Reset bin contents. + void null() ; + + // Fill bin with weight. + void fill(double x, double w = 1.) ; + + // Return content of specific bin: -1 gives underflow and nBin overflow. + double getBinContent(int iBin) ; + + // Return number of entries + double getEntries() {return nFill; } + + // Print histogram contents as a table (e.g. for Gnuplot). + void table(ostream& os = cout) const ; + + // Check whether another histogram has same size and limits. + bool sameSize(const Hist& h) const ; + + // Take logarithm (base 10 or e) of bin contents. + void takeLog(bool tenLog = true) ; + + // Operator overloading with member functions + Hist& operator+=(const Hist& h) ; + Hist& operator-=(const Hist& h) ; + Hist& operator*=(const Hist& h) ; + Hist& operator/=(const Hist& h) ; + Hist& operator+=(double f) ; + Hist& operator-=(double f) ; + Hist& operator*=(double f) ; + Hist& operator/=(double f) ; + + // Operator overloading with friends + friend Hist operator+(double f, const Hist& h1); + friend Hist operator+(const Hist& h1, double f); + friend Hist operator+(const Hist& h1, const Hist& h2); + friend Hist operator-(double f, const Hist& h1); + friend Hist operator-(const Hist& h1, double f); + friend Hist operator-(const Hist& h1, const Hist& h2); + friend Hist operator*(double f, const Hist& h1); + friend Hist operator*(const Hist& h1, double f); + friend Hist operator*(const Hist& h1, const Hist& h2); + friend Hist operator/(double f, const Hist& h1); + friend Hist operator/(const Hist& h1, double f); + friend Hist operator/(const Hist& h1, const Hist& h2); + + // Print a histogram with overloaded << operator. + friend ostream& operator<<(ostream& os, const Hist& h) ; + +private: + + // Constants: could only be changed in the code itself. + static const int NBINMAX, NLINES; + static const double TOLERANCE, TINY, SMALLFRAC, DYAC[]; + static const char NUMBER[]; + + // Properties and contents of a histogram. + string title; + int nBin, nFill; + double xMin, xMax, dx, under, inside, over; + vector res; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // end Pythia8_Basics_H diff --git a/PYTHIA8/pythia8130/include/BeamParticle.h b/PYTHIA8/pythia8130/include/BeamParticle.h new file mode 100644 index 00000000000..ec6e4a767b4 --- /dev/null +++ b/PYTHIA8/pythia8130/include/BeamParticle.h @@ -0,0 +1,284 @@ +// BeamParticle.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for information on incoming beams. +// ResolvedParton: an initiator or remnant in beam. +// BeamParticle: contains partons, parton densities, etc. + +#ifndef Pythia8_BeamParticle_H +#define Pythia8_BeamParticle_H + +#include "Basics.h" +#include "Event.h" +#include "FragmentationFlavZpT.h" +#include "Info.h" +#include "ParticleData.h" +#include "PartonDistributions.h" +#include "PythiaStdlib.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// This class holds info on a parton resolved inside the incoming beam, +// i.e. either an initiator (part of a hard or a multiple interaction) +// or a remnant (part of the beam remnant treatment). + +// The companion code is -1 from onset and for g, is -2 for an unmatched +// sea quark, is >= 0 for a matched sea quark, with the number giving the +// companion position, and is -3 for a valence quark. + +class ResolvedParton { + +public: + + // Constructor. + ResolvedParton( int iPosIn = 0, int idIn = 0, double xIn = 0., + int companionIn = -1) : iPosRes(iPosIn), idRes(idIn), xRes(xIn), + companionRes(companionIn), xqCompRes(0.), mRes(0.), colRes(0), + acolRes(0) { } + + // Set info on initiator or remnant parton. + void iPos( int iPosIn) {iPosRes = iPosIn;} + void id( int idIn) {idRes = idIn;} + void x( double xIn) {xRes = xIn;} + void update( int iPosIn, int idIn, double xIn) {iPosRes = iPosIn; + idRes = idIn; xRes = xIn;} + void companion( int companionIn) {companionRes = companionIn;} + void xqCompanion( double xqCompIn) {xqCompRes = xqCompIn;} + void p(Vec4 pIn) {pRes = pIn;} + void px(double pxIn) {pRes.px(pxIn);} + void py(double pyIn) {pRes.py(pyIn);} + void pz(double pzIn) {pRes.pz(pzIn);} + void e(double eIn) {pRes.e(eIn);} + void m(double mIn) {mRes = mIn;} + void col(int colIn) {colRes = colIn;} + void acol(int acolIn) {acolRes = acolIn;} + void cols(int colIn = 0,int acolIn = 0) + {colRes = colIn; acolRes = acolIn;} + + // Get info on initiator or remnant parton. + int iPos() const {return iPosRes;} + int id() const {return idRes;} + double x() const {return xRes;} + int companion() const {return companionRes;} + bool isValence() const {return (companionRes == -3);} + bool isUnmatched() const {return (companionRes == -2);} + bool isCompanion() const {return (companionRes >= 0);} + double xqCompanion() const {return xqCompRes;} + Vec4 p() const {return pRes;} + double px() const {return pRes.px();} + double py() const {return pRes.py();} + double pz() const {return pRes.pz();} + double e() const {return pRes.e();} + double m() const {return mRes;} + double pT() const {return pRes.pT();} + double mT2() const {return mRes*mRes + pRes.pT2();} + int col() const {return colRes;} + int acol() const {return acolRes;} + +private: + + // Properties of a resolved parton. + int iPosRes, idRes; + double xRes; + // Companion code and distribution value, if any. + int companionRes; + double xqCompRes; + // Four-momentum and mass; for remnant kinematics construction. + Vec4 pRes; + double mRes; + // Colour codes. + int colRes, acolRes; + +}; + +//************************************************************************** + +// This class holds info on a beam particle in the evolution of +// initial-state radiation and multiple interactions. + +class BeamParticle { + +public: + + // Constructor. + BeamParticle() {Q2ValFracSav = -1.;} + + // Initialize data on a beam particle and save pointers. + void init( int idIn, double pzIn, double eIn, double mIn, + Info* infoPtrIn, PDF* pdfInPtr, PDF* pdfHardInPtr, + bool isUnresolvedIn, StringFlav* flavSelPtrIn); + + // Set new pZ and E, but keep the rest the same. + void newPzE( double pzIn, double eIn) {pBeam = Vec4( 0., 0., pzIn, eIn);} + + // Member functions for output. + int id() const {return idBeam;} + Vec4 p() const {return pBeam;} + double px() const {return pBeam.px();} + double py() const {return pBeam.py();} + double pz() const {return pBeam.pz();} + double e() const {return pBeam.e();} + double m() const {return mBeam;} + bool isLepton() const {return isLeptonBeam;} + bool isUnresolved() const {return isUnresolvedBeam;} + // As hadrons here we only count those we know how to handle remnants for. + bool isHadron() const {return isHadronBeam;} + bool isMeson() const {return isMesonBeam;} + bool isBaryon() const {return isBaryonBeam;} + + // Maximum x remaining after previous MI and ISR, plus safety margin. + double xMax(int iSkip = -1); + + // Special hard-process parton distributions (can agree with standard ones). + double xfHard(int idIn, double x, double Q2) + {return pdfHardBeamPtr->xf(idIn, x, Q2);} + + // Standard parton distributions. + double xf(int idIn, double x, double Q2) + {return pdfBeamPtr->xf(idIn, x, Q2);} + + // Ditto, split into valence and sea parts (where gluon counts as sea). + double xfVal(int idIn, double x, double Q2) + {return pdfBeamPtr->xfVal(idIn, x, Q2);} + double xfSea(int idIn, double x, double Q2) + {return pdfBeamPtr->xfSea(idIn, x, Q2);} + + // Rescaled parton distributions, as needed for MI and ISR. + // For ISR also allow split valence/sea, and only return relevant part. + double xfMI(int idIn, double x, double Q2) + {return xfModified(-1, idIn, x, Q2);} + double xfISR(int indexMI, int idIn, double x, double Q2) + {return xfModified( indexMI, idIn, x, Q2);} + + // Decide whether chosen quark is valence, sea or companion. + int pickValSeaComp(); + + // Initialize kind of incoming beam particle. + void initBeamKind(); + + // Overload index operator to access a resolved parton from the list. + ResolvedParton& operator[](int i) {return resolved[i];} + + // Total number of partons extracted from beam, and initiators only. + int size() const {return resolved.size();} + int sizeInit() const {return nInit;} + + // Clear list of resolved partons. + void clear() {resolved.resize(0);} + + // Add a resolved parton to list. + int append( int iPos, int idIn, double x, int companion = -1) + {resolved.push_back( ResolvedParton( iPos, idIn, x, companion) ); + return resolved.size() - 1;} + + // Print extracted parton list; for debug mainly. + void list(ostream& os = cout); + + // How many different flavours, and how many quarks of given flavour. + int nValenceKinds() const {return nValKinds;} + int nValence(int idIn) const {for (int i = 0; i < nValKinds; ++i) + if (idIn == idVal[i]) return nVal[i]; return 0;} + + // Test whether a lepton is to be considered as unresolved. + bool isUnresolvedLepton(); + + // Add extra remnant flavours to make valence and sea come out right. + bool remnantFlavours(Event& event); + + // Correlate all initiators and remnants to make a colour singlet. + bool remnantColours(Event& event, vector& colFrom, + vector& colTo); + + // Pick unrescaled x of remnant parton (valence or sea). + double xRemnant(int i); + + // Tell whether a junction has been resolved, and its junction colours. + bool hasJunction() const {return hasJunctionBeam;} + int junctionCol(int i) const {return junCol[i];} + void junctionCol(int i, int col) {junCol[i] = col;} + + // For a diffractive system, decide whether to kick out gluon or quark. + bool pickGluon(double mDiff); + + // Pick a valence quark at random, and provide the remaining flavour. + int pickValence(); + int pickRemnant() const {return idVal2;} + + // Share lightcone momentum between two remnants in a diffractive system. + // At the same time generate a relative pT for the two. + double zShare( double mDiff, double m1, double m2); + double pxShare() const {return pxRel;} + double pyShare() const {return pyRel;} + +private: + + // Constants: could only be changed in the code itself. + static const double XMINUNRESOLVED; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pinters to PDF sets. + PDF* pdfBeamPtr; + PDF* pdfHardBeamPtr; + + // Pointer to class for flavour generation. + StringFlav* flavSelPtr; + + // Initialization data, normally only set once. + bool allowJunction; + int maxValQuark, companionPower; + double valencePowerMeson, valencePowerUinP, valencePowerDinP, + valenceDiqEnhance, pickQuarkNorm, pickQuarkPower, + diffPrimKTwidth, diffLargeMassSuppress; + + // Basic properties of a beam particle. + int idBeam, idBeamAbs; + Vec4 pBeam; + double mBeam; + // Beam kind. Valence flavour content for hadrons. + bool isLeptonBeam, isUnresolvedBeam, isHadronBeam, isMesonBeam, + isBaryonBeam; + int nValKinds, idVal[3], nVal[3]; + + // Current parton density, by valence, sea and companion. + int idSave, iSkipSave, nValLeft[3]; + double xqgTot, xqVal, xqgSea, xqCompSum; + + // The list of resolved partons. + vector resolved; + + // Status after all initiators have been accounted for. Junction content. + int nInit; + bool hasJunctionBeam; + int junCol[3]; + + // Routine to calculate pdf's given previous interactions. + double xfModified( int iSkip, int idIn, double x, double Q2); + + // Fraction of hadron momentum sitting in a valence quark distribution. + double xValFrac(int j, double Q2); + double Q2ValFracSav, uValInt, dValInt; + + // Fraction of hadron momentum sitting in a companion quark distribution. + double xCompFrac(double xs); + + // Value of companion quark PDF, also given the sea quark x. + double xCompDist(double xc, double xs); + + // Valence quark subdivision for diffractive systems. + int idVal1, idVal2, idVal3; + double zRel, pxRel, pyRel; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_BeamParticle_H diff --git a/PYTHIA8/pythia8130/include/BeamRemnants.h b/PYTHIA8/pythia8130/include/BeamRemnants.h new file mode 100644 index 00000000000..9770c98972e --- /dev/null +++ b/PYTHIA8/pythia8130/include/BeamRemnants.h @@ -0,0 +1,83 @@ +// BeamRemnants.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for beam-remnants handling. +// BeamRemnants: matches the remnants between the two beams. + +#ifndef Pythia8_BeamRemnants_H +#define Pythia8_BeamRemnants_H + +#include "Basics.h" +#include "BeamParticle.h" +#include "Event.h" +#include "FragmentationFlavZpT.h" +#include "Info.h" +#include "ParticleData.h" +#include "PartonDistributions.h" +#include "PythiaStdlib.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// This class matches the kinematics of the hard-scattering subsystems +// (with primordial kT added) to that of the two beam remnants. + +class BeamRemnants { + +public: + + // Constructor. + BeamRemnants() { } + + // Initialization. + bool init( Info* infoPtrIn, BeamParticle* beamAPtrIn, + BeamParticle* beamBPtrIn); + + // Select the flavours/kinematics/colours of the two beam remnants. + bool add( Event& event); + +private: + + // Constants: could only be changed in the code itself. + static const int NTRYCOLMATCH, NTRYKINMATCH; + + // Initialization data, read from Settings. + bool doPrimordialKT, doReconnect; + double primordialKTsoft, primordialKThard, primordialKTremnant, + halfScaleForKT, halfMassForKT, reconnectRange, + pT0Ref, ecmRef, ecmPow; + + // Information set for events. + int nSys, oldSize; + double eCM, sCM, pT0, pT20Rec; + + // Colour collapses (when one colour is mapped onto another). + vector colFrom, colTo; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointers to the two incoming beams. + BeamParticle* beamAPtr; + BeamParticle* beamBPtr; + + // Do the kinematics of the collision subsystems and two beam remnants. + bool setKinematics( Event& event); + + // Allow colour reconnections. + bool reconnectColours( Event& event); + + // Check that colours are consistent. + bool checkColours( Event& event); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_BeamRemnants_H diff --git a/PYTHIA8/pythia8130/include/BeamShape.h b/PYTHIA8/pythia8130/include/BeamShape.h new file mode 100644 index 00000000000..337f13a4fd6 --- /dev/null +++ b/PYTHIA8/pythia8130/include/BeamShape.h @@ -0,0 +1,61 @@ +// BeamShape.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header for classes to set beam momentum and interaction vertex spread. + +#ifndef Pythia8_BeamShape_H +#define Pythia8_BeamShape_H + +#include "Basics.h" +#include "PythiaStdlib.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// Base class to set beam momentum and interaction spot spread. + +class BeamShape { + +public: + + // Constructor. + BeamShape() {} + + // Destructor. + virtual ~BeamShape() {} + + // Initialize beam parameters. + virtual void init(); + + // Set the two beam momentum deviations and the beam vertex. + virtual void pick(); + + // Methods to read out the choice made with the above method. + Vec4 deltaPA() const {return Vec4( deltaPxA, deltaPyA, deltaPzA, 0);} + Vec4 deltaPB() const {return Vec4( deltaPxB, deltaPyB, deltaPzB, 0);} + Vec4 vertex() const {return Vec4( vertexX, vertexY, vertexZ, vertexT);} + +protected: + + // Values to be set. + double deltaPxA, deltaPyA, deltaPzA, deltaPxB, deltaPyB, deltaPzB, + vertexX, vertexY, vertexZ, vertexT; + + // Parameters of Gaussian parametrizations. + bool allowMomentumSpread, allowVertexSpread; + double sigmaPxA, sigmaPyA, sigmaPzA, maxDevA, sigmaPxB, sigmaPyB, + sigmaPzB, maxDevB, sigmaVertexX, sigmaVertexY, sigmaVertexZ, + maxDevVertex, sigmaTime, maxDevTime, offsetX, offsetY, + offsetZ, offsetT; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_BeamShape_H diff --git a/PYTHIA8/pythia8130/include/BoseEinstein.h b/PYTHIA8/pythia8130/include/BoseEinstein.h new file mode 100644 index 00000000000..aedd02860f7 --- /dev/null +++ b/PYTHIA8/pythia8130/include/BoseEinstein.h @@ -0,0 +1,92 @@ +// Bose-Einstein.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the classes to handle Bose-Einstein effects. +// BoseEinsteinHadron: simple working container for particle momenta. +// BoseEinstein: main class to perform the task. + +#ifndef Pythia8_BoseEinstein_H +#define Pythia8_BoseEinstein_H + +#include "Basics.h" +#include "Event.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// The BoseEinsteinHadron class is a simple container for studied hadrons. + +class BoseEinsteinHadron { + +public: + + // Constructors. + BoseEinsteinHadron() : id(0), iPos(0), p(0.), pShift(0.), pComp(0.), + m2(0.) {} + BoseEinsteinHadron(int idIn, int iPosIn, Vec4 pIn, double mIn) : + id(idIn), iPos(iPosIn), p(pIn), pShift(0.), pComp(0.) {m2 = mIn*mIn;} + + // Information on hadron - all public. + int id, iPos; + Vec4 p, pShift, pComp; + double m2; + +}; + +//************************************************************************** + +// The BoseEinstein class shifts the momenta of identical particles relative +// to each other, to simulate Bose-Einstein effects to some approximation. + +class BoseEinstein { + +public: + + // Constructor. + BoseEinstein() {} + + // Find settings. Precalculate table used to find momentum shifts. + bool init(Info* infoPtrIn); + + // Perform Bose-Einstein corrections on an event. + bool shiftEvent( Event& event); + +private: + + // Constants: could only be changed in the code itself. + static const int IDHADRON[9], ITABLE[9], NCOMPSTEP; + static const double STEPSIZE, Q2MIN, COMPRELERR, COMPFACMAX; + + // Initialization data, read from Settings. + bool doPion, doKaon, doEta; + double lambda, QRef; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Table of momentum shifts for different hadron species. + int nStep[4], nStep3[4], nStored[10]; + double QRef2, QRef3, R2Ref, R2Ref2, R2Ref3, mHadron[9], + mPair[4], m2Pair[4], deltaQ[4], deltaQ3[4], maxQ[4], maxQ3[4]; + double shift[4][200], shift3[4][200]; + + // Vector of hadrons to study. + vector hadronBE; + + // Calculate shift and (unnormalized) compensation for pair. + void shiftPair(int i1, int i2, int iHad); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_BoseEinstein_H + diff --git a/PYTHIA8/pythia8130/include/Event.h b/PYTHIA8/pythia8130/include/Event.h new file mode 100644 index 00000000000..88918fae5ce --- /dev/null +++ b/PYTHIA8/pythia8130/include/Event.h @@ -0,0 +1,542 @@ +// Event.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for the Particle and Event classes. +// Particle: information on an instance of a particle. +// Junction: information on a junction between three colours. +// Event: list of particles in the current event. + +#ifndef Pythia8_Event_H +#define Pythia8_Event_H + +#include "Basics.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// Forward references to ParticleData and ResonanceWidths classes. +class ParticleDataEntry; +class ResonanceWidths; + +//************************************************************************** + +// Particle class. +// This class holds info on a particle in general. + +class Particle { + +public: + + // Constructors. + Particle() : idSave(0), statusSave(0), mother1Save(0), mother2Save(0), + daughter1Save(0), daughter2Save(0), colSave(0), acolSave(0), + pSave(Vec4(0.,0.,0.,0.)), mSave(0.), scaleSave(0.), + hasVertexSave(false), vProdSave(Vec4(0.,0.,0.,0.)), tauSave(0.), + particlePtr(0) { } + Particle(int idIn, int statusIn = 0, int mother1In = 0, + int mother2In = 0, int daughter1In = 0, int daughter2In = 0, + int colIn = 0, int acolIn = 0, double pxIn = 0., double pyIn = 0., + double pzIn = 0., double eIn = 0., double mIn = 0., double scaleIn = 0.) + : idSave(idIn), statusSave(statusIn), mother1Save(mother1In), + mother2Save(mother2In), daughter1Save(daughter1In), + daughter2Save(daughter2In), colSave(colIn), acolSave(acolIn), + pSave(Vec4(pxIn, pyIn, pzIn, eIn)), mSave(mIn), scaleSave(scaleIn), + hasVertexSave(false), vProdSave(Vec4(0.,0.,0.,0.)), tauSave(0.) + {setParticlePtr();} + Particle(int idIn, int statusIn, int mother1In, int mother2In, + int daughter1In, int daughter2In, int colIn, int acolIn, + Vec4 pIn, double mIn = 0., double scaleIn = 0.) + : idSave(idIn), statusSave(statusIn), mother1Save(mother1In), + mother2Save(mother2In), daughter1Save(daughter1In), + daughter2Save(daughter2In), colSave(colIn), acolSave(acolIn), + pSave(pIn), mSave(mIn), scaleSave(scaleIn), hasVertexSave(false), + vProdSave(Vec4(0.,0.,0.,0.)), tauSave(0.) {setParticlePtr();} + Particle(const Particle& pt) : idSave(pt.idSave), + statusSave(pt.statusSave), mother1Save(pt.mother1Save), + mother2Save(pt.mother2Save), daughter1Save(pt.daughter1Save), + daughter2Save(pt.daughter2Save), colSave(pt.colSave), + acolSave(pt.acolSave), pSave(pt.pSave), mSave(pt.mSave), + scaleSave(pt.scaleSave), hasVertexSave(pt.hasVertexSave), + vProdSave(pt.vProdSave), tauSave(pt.tauSave), + particlePtr(pt.particlePtr) { } + Particle& operator=(const Particle& pt) {if (this != &pt) { + idSave = pt.idSave; statusSave = pt.statusSave; + mother1Save = pt.mother1Save; mother2Save = pt.mother2Save; + daughter1Save = pt.daughter1Save; daughter2Save = pt.daughter2Save; + colSave = pt.colSave; acolSave = pt.acolSave; pSave = pt.pSave; + mSave = pt.mSave; scaleSave = pt.scaleSave; + hasVertexSave = pt.hasVertexSave; vProdSave = pt.vProdSave; + tauSave = pt.tauSave; particlePtr = pt.particlePtr; } return *this; } + + // Member functions for input. + void id(int idIn) {idSave = idIn; setParticlePtr();} + void status(int statusIn) {statusSave = statusIn;} + void statusPos() {statusSave = abs(statusSave);} + void statusNeg() {statusSave = -abs(statusSave);} + void statusCode(int statusIn) {statusSave = + (statusSave > 0) ? abs(statusIn) : -abs(statusIn);} + void mother1(int mother1In) {mother1Save = mother1In;} + void mother2(int mother2In) {mother2Save = mother2In;} + void mothers(int mother1In = 0, int mother2In = 0) + {mother1Save = mother1In; mother2Save = mother2In;} + void daughter1(int daughter1In) {daughter1Save = daughter1In;} + void daughter2(int daughter2In) {daughter2Save = daughter2In;} + void daughters(int daughter1In = 0, int daughter2In = 0) + {daughter1Save = daughter1In; daughter2Save = daughter2In;} + void col(int colIn) {colSave = colIn;} + void acol(int acolIn) {acolSave = acolIn;} + void cols(int colIn = 0,int acolIn = 0) {colSave = colIn; + acolSave = acolIn;} + void p(Vec4 pIn) {pSave = pIn;} + void p(double pxIn, double pyIn, double pzIn, double eIn) + {pSave.p(pxIn, pyIn, pzIn, eIn);} + void px(double pxIn) {pSave.px(pxIn);} + void py(double pyIn) {pSave.py(pyIn);} + void pz(double pzIn) {pSave.pz(pzIn);} + void e(double eIn) {pSave.e(eIn);} + void m(double mIn) {mSave = mIn;} + void scale(double scaleIn) {scaleSave = scaleIn;} + void vProd(Vec4 vProdIn) {vProdSave = vProdIn; hasVertexSave = true;} + void vProd(double xProdIn, double yProdIn, double zProdIn, double tProdIn) + {vProdSave.p(xProdIn, yProdIn, zProdIn, tProdIn); hasVertexSave = true;} + void xProd(double xProdIn) {vProdSave.px(xProdIn); hasVertexSave = true;} + void yProd(double yProdIn) {vProdSave.py(yProdIn); hasVertexSave = true;} + void zProd(double zProdIn) {vProdSave.pz(zProdIn); hasVertexSave = true;} + void tProd(double tProdIn) {vProdSave.e(tProdIn); hasVertexSave = true;} + void tau(double tauIn) {tauSave = tauIn;} + + // Member functions for output. + int id() const {return idSave;} + int status() const {return statusSave;} + int mother1() const {return mother1Save;} + int mother2() const {return mother2Save;} + int daughter1() const {return daughter1Save;} + int daughter2() const {return daughter2Save;} + int col() const {return colSave;} + int acol() const {return acolSave;} + Vec4 p() const {return pSave;} + double px() const {return pSave.px();} + double py() const {return pSave.py();} + double pz() const {return pSave.pz();} + double e() const {return pSave.e();} + double m() const {return mSave;} + double scale() const {return scaleSave;} + bool hasVertex() const {return hasVertexSave;} + Vec4 vProd() const {return vProdSave;} + double xProd() const {return vProdSave.px();} + double yProd() const {return vProdSave.py();} + double zProd() const {return vProdSave.pz();} + double tProd() const {return vProdSave.e();} + double tau() const {return tauSave;} + + // Member functions for output; derived int and bool quantities. + int idAbs() const {return abs(idSave);} + int statusAbs() const {return abs(statusSave);} + bool isFinal() const {return (statusSave > 0);} + + // Member functions for output; derived double quantities. + double m2() const {return mSave*mSave;} + double mCalc() const {return pSave.mCalc();} + double m2Calc() const {return pSave.m2Calc();} + double eCalc() const {return sqrt(mSave*mSave + pSave.pAbs2());} + double pT() const {return pSave.pT();} + double pT2() const {return pSave.pT2();} + double mT() const {return sqrt(mSave*mSave + pSave.pT2());} + double mT2() const {return mSave*mSave + pSave.pT2();} + double pAbs() const {return pSave.pAbs();} + double pAbs2() const {return pSave.pAbs2();} + double theta() const {return pSave.theta();} + double phi() const {return pSave.phi();} + double thetaXZ() const {return pSave.thetaXZ();} + double pPlus() const {return pSave.pPlus();} + double pMinus() const {return pSave.pMinus();} + double y() const; + double eta() const; + Vec4 vDec() const {return (tauSave > 0. && mSave > 0.) + ? vProdSave + tauSave * pSave / mSave : vProdSave;} + double xDec() const {return (tauSave > 0. && mSave > 0.) + ? vProdSave.px() + tauSave * pSave.px() / mSave : vProdSave.px();} + double yDec() const {return (tauSave > 0. && mSave > 0.) + ? vProdSave.py() + tauSave * pSave.py() / mSave : vProdSave.py();} + double zDec() const {return (tauSave > 0. && mSave > 0.) + ? vProdSave.pz() + tauSave * pSave.pz() / mSave : vProdSave.pz();} + double tDec() const {return (tauSave > 0. && mSave > 0.) + ? vProdSave.e() + tauSave * pSave.e() / mSave : vProdSave.e();} + + // Further output, based on a pointer to a ParticleDataEntry object. + string name() const {return particlePtr->name(idSave);} + string nameWithStatus(int maxLen = 20) const; + int spinType() const {return particlePtr->spinType();} + int chargeType() const {return particlePtr->chargeType(idSave);} + double charge() const {return particlePtr->charge(idSave);} + bool isCharged() const {return (particlePtr->chargeType(idSave) != 0);} + bool isNeutral() const {return (particlePtr->chargeType(idSave) == 0);} + int colType() const {return particlePtr->colType(idSave);} + double m0() const {return particlePtr->m0();} + double mWidth() const {return particlePtr->mWidth();} + double mMin() const {return particlePtr->mMin();} + double mMax() const {return particlePtr->mMax();} + double mass() const {return particlePtr->mass();} + double constituentMass() const {return particlePtr->constituentMass();} + double tau0() const {return particlePtr->tau0();} + bool mayDecay() const {return particlePtr->mayDecay();} + bool canDecay() const {return particlePtr->canDecay();} + bool doExternalDecay() const {return particlePtr->doExternalDecay();} + bool isResonance() const {return particlePtr->isResonance();} + bool isVisible() const {return particlePtr->isVisible();} + bool isLepton() const {return particlePtr->isLepton();} + bool isQuark() const {return particlePtr->isQuark();} + bool isGluon() const {return particlePtr->isGluon();} + bool isHadron() const {return particlePtr->isHadron();} + ParticleDataEntry& particleData() const {return *particlePtr;} + + // Member functions that perform operations. + void rescale3(double fac) {pSave.rescale3(fac);} + void rescale4(double fac) {pSave.rescale4(fac);} + void rescale5(double fac) {pSave.rescale4(fac); mSave *= fac;} + void rot(double thetaIn, double phiIn) {pSave.rot(thetaIn, phiIn); + if (hasVertexSave) vProdSave.rot(thetaIn, phiIn);} + void bst(double betaX, double betaY, double betaZ) { + pSave.bst(betaX, betaY, betaZ); + if (hasVertexSave) vProdSave.bst(betaX, betaY, betaZ);} + void bst(double betaX, double betaY, double betaZ, double gamma) { + pSave.bst(betaX, betaY, betaZ, gamma); + if (hasVertexSave) vProdSave.bst(betaX, betaY, betaZ, gamma);} + void bst(const Vec4& pBst) {pSave.bst(pBst); + if (hasVertexSave) vProdSave.bst(pBst);} + void bst(const Vec4& pBst, double mBst) {pSave.bst(pBst, mBst); + if (hasVertexSave) vProdSave.bst(pBst, mBst);} + void bstback(const Vec4& pBst) {pSave.bstback(pBst); + if (hasVertexSave) vProdSave.bstback(pBst);} + void bstback(const Vec4& pBst, double mBst) {pSave.bstback(pBst, mBst); + if (hasVertexSave) vProdSave.bstback(pBst, mBst);} + void rotbst(const RotBstMatrix& M) {pSave.rotbst(M); + if (hasVertexSave) vProdSave.rotbst(M);} + void offsetHistory( int minMother, int addMother, int minDaughter, + int addDaughter); + void offsetCol( int addCol); + + // Member function to set the ParticleDataEntry pointer, using idSave. + void setParticlePtr(); + +private: + + // Constants: could only be changed in the code itself. + static const double TINY; + + // Properties of the current particle. + int idSave, statusSave, mother1Save, mother2Save, daughter1Save, + daughter2Save, colSave, acolSave; + Vec4 pSave; + double mSave, scaleSave; + bool hasVertexSave; + Vec4 vProdSave; + double tauSave; + + // Pointer to properties of the particle species. + // Should no be saved in a persistent copy of the event record. + // The //! below is ROOT notation that this member should not be saved. + // Event::restorePtrs() can be called to restore the missing information. + ParticleDataEntry* particlePtr; //! + +}; + +// Invariant mass of a pair and its square. +// (Not part of class proper, but tightly linked.) +double m(const Particle&, const Particle&); +double m2(const Particle&, const Particle&); + +//************************************************************************** + +// The juction class stores what kind of junction it is, the colour indices +// of the legs at the junction and as far out as legs have been traced, +// and the status codes assigned for fragmentation of each leg. + +class Junction { + +public: + + // Constructors. + Junction() : remainsSave(true), kindSave(0) { + for (int j = 0; j < 3; ++j) { + colSave[j] = 0; endColSave[j] = 0; statusSave[j] = 0; } } + Junction( int kindIn, int col0In, int col1In, int col2In) + : remainsSave(true), kindSave(kindIn) {colSave[0] = col0In; + colSave[1] = col1In; colSave[2] = col2In; + for (int j = 0; j < 3; ++j) { + endColSave[j] = colSave[j]; statusSave[j] = 0; } } + Junction(const Junction& ju) : remainsSave(ju.remainsSave), + kindSave(ju.kindSave) { for (int j = 0; j < 3; ++j) { + colSave[j] = ju.colSave[j]; endColSave[j] = ju.endColSave[j]; + statusSave[j] = ju.statusSave[j]; } } + Junction& operator=(const Junction& ju) {if (this != &ju) { + remainsSave = ju.remainsSave; kindSave = ju.kindSave; + for (int j = 0; j < 3; ++j) { colSave[j] = ju.colSave[j]; + endColSave[j] = ju.endColSave[j]; statusSave[j] = ju.statusSave[j]; } } + return *this; } + + // Set values. + void remains(bool remainsIn) {remainsSave = remainsIn;} + void col(int j, int colIn) {colSave[j] = colIn; endColSave[j] = colIn;} + void cols(int j, int colIn, int endColIn) {colSave[j] = colIn; + endColSave[j] = endColIn;} + void endCol(int j, int endColIn) {endColSave[j] = endColIn;} + void status(int j, int statusIn) {statusSave[j] = statusIn;} + + // Read out value. + bool remains() const {return remainsSave;} + int kind() const {return kindSave;} + int col(int j) const {return colSave[j];} + int endCol(int j) const {return endColSave[j];} + int status(int j) const {return statusSave[j];} + +private: + + // Kind, positions of the three ends and their status codes. + bool remainsSave; + int kindSave, colSave[3], endColSave[3], statusSave[3]; + +}; + +//************************************************************************** + +// The Event class holds all info on the generated event. + +class Event { + +public: + + // Constructors. + Event(int capacity = 100) {entry.reserve(capacity); startColTag = 100; + headerList = "----------------------------------------";} + Event& operator=(const Event& oldEvent); + + // Initialize colour and header specification for event listing. + void init( string headerIn = ""); + + // Clear event record. + void clear() {entry.resize(0); maxColTag = startColTag; + clearJunctions(); clearSystems();} + + // Clear event record, and set first particle empty. + void reset() {clear(); append(90, -11, 0, 0, 0., 0., 0., 0., 0.);} + + // Overload index operator to access element of event record. + Particle& operator[](int i) {return entry[i];} + const Particle& operator[](int i) const {return entry[i];} + + // Event record size. + int size() const {return entry.size();} + + // Put a new particle at the end of the event record; return index. + int append(Particle entryIn) { + entry.push_back(entryIn); + if (entryIn.col() > maxColTag) maxColTag = entryIn.col(); + if (entryIn.acol() > maxColTag) maxColTag = entryIn.acol(); + return entry.size() - 1; + } + int append(int id, int status, int mother1, int mother2, int daughter1, + int daughter2, int col, int acol, double px, double py, double pz, + double e, double m = 0., double scaleIn = 0.) {entry.push_back( + Particle(id, status, mother1, mother2, daughter1, daughter2, col, acol, + px, py, pz, e, m, scaleIn) ); + if (col > maxColTag) maxColTag = col; + if (acol > maxColTag) maxColTag = acol; + return entry.size() - 1; + } + int append(int id, int status, int mother1, int mother2, int daughter1, + int daughter2, int col, int acol, Vec4 p, double m = 0., + double scaleIn = 0.) {entry.push_back( Particle(id, status, mother1, + mother2, daughter1, daughter2, col, acol, p, m, scaleIn) ); + if (col > maxColTag) maxColTag = col; + if (acol > maxColTag) maxColTag = acol; + return entry.size() - 1; + } + + // Brief versions of append: no mothers and no daughters. + int append(int id, int status, int col, int acol, double px, double py, + double pz, double e, double m = 0.) {entry.push_back( Particle(id, + status, 0, 0, 0, 0, col, acol, px, py, pz, e, m, 0.) ); + if (col > maxColTag) maxColTag = col; + if (acol > maxColTag) maxColTag = acol; + return entry.size() - 1; + } + int append(int id, int status, int col, int acol, Vec4 p, double m = 0.) + {entry.push_back( Particle(id, status, 0, 0, 0, 0, col, acol, p, m, 0.) ); + if (col > maxColTag) maxColTag = col; + if (acol > maxColTag) maxColTag = acol; + return entry.size() - 1; + } + + // Add a copy of an existing particle at the end of the event record. + int copy(int iCopy, int newStatus = 0); + + // Implement reference "back" to access last element. + Particle& back() {return entry.back();} + + // List the particles in an event. + void list(ostream& os = cout) {list(false, false, os);} + void list(bool showScaleAndVertex, bool showMothersAndDaughters = false, + ostream& os = cout); + + // Remove last n entries. + void popBack(int nRemove = 1) { if (nRemove ==1) entry.pop_back(); + else {int newSize = max( 0, size() - nRemove); + entry.resize(newSize);} } + + // Restore all ParticleDataEntry* pointers in the Particle vector. + // Useful when a persistent copy of the event record is read back in. + void restorePtrs() { + for (int i = 0; i < size(); ++i) entry[i].setParticlePtr(); } + + // Save or restore the size of the event record (throwing at the end). + void saveSize() {savedSize = entry.size();} + void restoreSize() {entry.resize(savedSize);} + + // Initialize and access colour tag information. + void initColTag(int colTag = 0) {maxColTag = max( colTag,startColTag);} + int lastColTag() const {return maxColTag;} + int nextColTag() {return ++maxColTag;} + + // Access scale for which event as a whole is defined. + void scale( double scaleIn) {scaleSave = scaleIn;} + double scale() const {return scaleSave;} + + // Need a second scale if two hard interactions in event. + void scaleSecond( double scaleSecondIn) {scaleSecondSave = scaleSecondIn;} + double scaleSecond() const {return scaleSecondSave;} + + // Find complete list of daughters and mothers. + vector motherList(int i) const; + vector daughterList(int i) const; + + // Trace the first and last copy of one and the same particle. + int iTopCopy(int i) const; + int iBotCopy(int i) const; + + // Trace the first and last copy of a particle, using flavour match. + int iTopCopyId(int i) const; + int iBotCopyId(int i) const; + + // Find list of sisters, also tracking up and down identical copies. + vector sisterList(int i) const; + vector sisterListTopBot(int i, bool widenSearch = true) const; + + // Check whether two particles have a direct mother-daughter relation. + bool isAncestor(int i, int iAncestor) const; + + // Member functions for rotations and boosts of an event. + void rot(double theta, double phi) + {for (int i = 0; i < size(); ++i) entry[i].rot(theta, phi);} + void bst(double betaX, double betaY, double betaZ) + {for (int i = 0; i < size(); ++i) entry[i].bst(betaX, betaY, betaZ);} + void bst(double betaX, double betaY, double betaZ, double gamma) + {for (int i = 0; i < size(); ++i) entry[i].bst(betaX, betaY, betaZ, + gamma);} + void bst(const Vec4& vec) + {for (int i = 0; i < size(); ++i) entry[i].bst(vec);} + void rotbst(const RotBstMatrix& M) + {for (int i = 0; i < size(); ++i) entry[i].rotbst(M);} + + // Clear the list of junctions. + void clearJunctions() {junction.resize(0);} + + // Add a junction to the list, study it or extra input. + void appendJunction( int kind, int col0, int col1, int col2) + { junction.push_back( Junction( kind, col0, col1, col2) );} + void appendJunction(Junction junctionIn) {junction.push_back(junctionIn);} + int sizeJunction() const {return junction.size();} + bool remainsJunction(int i) const {return junction[i].remains();} + void remainsJunction(int i, bool remainsIn) {junction[i].remains(remainsIn);} + int kindJunction(int i) const {return junction[i].kind();} + int colJunction( int i, int j) const {return junction[i].col(j);} + void colJunction( int i, int j, int colIn) {junction[i].col(j, colIn);} + int endColJunction( int i, int j) const {return junction[i].endCol(j);} + void endColJunction( int i, int j, int endColIn) + {junction[i].endCol(j, endColIn);} + int statusJunction( int i, int j) const {return junction[i].status(j);} + void statusJunction( int i, int j, int statusIn) + {junction[i].status(j, statusIn);} + Junction& getJunction(int i) {return junction[i];} + const Junction& getJunction(int i) const {return junction[i];} + void eraseJunction(int i); + + // Save or restore the size of the junction list (throwing at the end). + void saveJunctionSize() {savedJunctionSize = junction.size();} + void restoreJunctionSize() {junction.resize(savedJunctionSize);} + + // List any junctions in the event; for debug mainly. + void listJunctions(ostream& os = cout) const; + + // Operations with grouped systems of partons for internal use only. + // (Used by combined MI, ISR, FSR and BR machinery in PartonLevel.) + + // Reset all systems and system number to empty. + void clearSystems() {beginSys.resize(0); sizeSys.resize(0); + memberSys.resize(0);} + + // Get number of systems or number of members in a system. + int sizeSystems() const {return beginSys.size();} + int sizeSystem(int iSys) const {return sizeSys[iSys];} + + // New system or new parton in system. + int newSystem() {beginSys.push_back(memberSys.size()); + sizeSys.push_back(0); return (beginSys.size() - 1);} + void addToSystem(int iSys, int iPos); + + // Get or set value of given member in given system. Replace value by new. + int getInSystem(int iSys, int iMem) const { + return memberSys[beginSys[iSys] + iMem];} + void setInSystem(int iSys, int iMem, int iPos) { + memberSys[beginSys[iSys] + iMem] = iPos;} + void replaceInSystem(int iSys, int iPosOld, int iPosNew); + + // List members in systems; for debug mainly. + void listSystems(ostream& os = cout) const; + + // Operator overloading allows to append one event to an existing one. + // Warning: particles should be OK, but some other information unreliable. + Event& operator+=(const Event& addEvent); + +private: + + // Constants: could only be changed in the code itself. + static const int IPERLINE; + + // Initialization data, normally only set once. + int startColTag; + + // The event: a vector containing all particles (entries). + vector entry; + + // The list of junctions. + vector junction; + + // The maximum colour tag of the event so far. + int maxColTag; + + // Saved entry and junction list sizes, for simple restoration. + int savedSize, savedJunctionSize; + + // The scale of the event; linear quantity in GeV. + double scaleSave, scaleSecondSave; + + // Header specification in event listing (at most 40 characters wide). + string headerList; + + // Offsets, sizes and values of systems. + vector beginSys, sizeSys, memberSys; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // end Pythia8_Event_H diff --git a/PYTHIA8/pythia8130/include/FragmentationFlavZpT.h b/PYTHIA8/pythia8130/include/FragmentationFlavZpT.h new file mode 100644 index 00000000000..bc7f0204d49 --- /dev/null +++ b/PYTHIA8/pythia8130/include/FragmentationFlavZpT.h @@ -0,0 +1,173 @@ +// FragmentationFlavZpT.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains helper classes for fragmentation. +// StringFlav is used to select quark and hadron flavours. +// StringPT is used to select transverse momenta. +// StringZ is used to sample the fragmentation function f(z). + +#ifndef Pythia8_FragmentationFlavZpT_H +#define Pythia8_FragmentationFlavZpT_H + +#include "Basics.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" + +namespace Pythia8 { + + +//************************************************************************** + +// The FlavContainer class is a simple container for flavour, +// including the extra properties needed for popcorn baryon handling. +// id = current flavour. +// rank = current rank; 0 for endpoint flavour and then increase by 1. +// nPop = number of popcorn mesons yet to be produced (1 or 0). +// idPop = (absolute sign of) popcorn quark, shared between B and Bbar. +// idVtx = (absolute sign of) vertex (= non-shared) quark in diquark. + +class FlavContainer { + +public: + + // Constructor. + FlavContainer(int idIn = 0, int rankIn = 0, int nPopIn = 0, + int idPopIn = 0, int idVtxIn = 0) : id(idIn), rank(rankIn), + nPop(nPopIn), idPop(idPopIn), idVtx(idVtxIn) {} + + // Overloaded equal operator. + FlavContainer& operator=(const FlavContainer& flav) { if (this != &flav) { + id = flav.id; rank = flav.rank; nPop = flav.nPop; idPop = flav.idPop; + idVtx = flav.idVtx; } return *this; } + + // Invert flavour. + FlavContainer& anti() {id = -id; return *this;} + + // Read in a container into another, without/with id sign flip. + FlavContainer& copy(const FlavContainer& flav) { if (this != &flav) { + id = flav.id; rank = flav.rank; nPop = flav.nPop; idPop = flav.idPop; + idVtx = flav.idVtx; } return *this; } + FlavContainer& anti(const FlavContainer& flav) { if (this != &flav) { + id = -flav.id; rank = flav.rank; nPop = flav.nPop; idPop = flav.idPop; + idVtx = flav.idVtx; } return *this; } + + // Stored properties. + int id, rank, nPop, idPop, idVtx; + +}; + +//************************************************************************** + +// The StringFlav class is used to select quark and hadron flavours. + +class StringFlav { + +public: + + // Constructor. + StringFlav() {} + + // Initialize data members. + void init(); + + // Pick a light d, u or s quark according to fixed ratios. + int pickLightQ() { double rndmFlav = probQandS * Rndm::flat(); + if (rndmFlav < 1.) return 1; if (rndmFlav < 2.) return 2; return 3; } + + // Pick a new flavour (including diquarks) given an incoming one. + FlavContainer pick(FlavContainer& flavOld); + + // Combine two flavours (including diquarks) to produce a hadron. + int combine(FlavContainer& flav1, FlavContainer& flav2); + + // Assign popcorn quark inside an original (= rank 0) diquark. + void assignPopQ(FlavContainer& flav); + + // Combine two quarks to produce a diquark. + int makeDiquark(int id1, int id2, int idHad = 0); + +private: + + // Constants: could only be changed in the code itself. + static const int mesonMultipletCode[6]; + static const double baryonCGOct[6], baryonCGDec[6]; + + // Initialization data, to be read from Settings. + bool suppressLeadingB; + double probQQtoQ, probStoUD, probSQtoQQ, probQQ1toQQ0, probQandQQ, + probQandS, probQandSinQQ, probQQ1corr, probQQ1corrInv, probQQ1norm, + mesonRate[4][6], mesonRateSum[4], mesonMix1[2][6], mesonMix2[2][6], + etaSup, etaPrimeSup, decupletSup, baryonCGSum[6], baryonCGMax[6], + popcornRate, popcornSpair, popcornSmeson, scbBM[3], popFrac, + popS[3], dWT[3][7], lightLeadingBSup, heavyLeadingBSup; +}; + +//************************************************************************** + +// The StringZ class is used to sample the fragmentation function f(z). + +class StringZ { + +public: + + // Constructor. + StringZ() {} + + // Initialize data members. + void init(); + + // Fragmentation function: top-level to determine parameters. + double zFrag( int idOld, int idNew = 0, double mT2 = 1.); + +private: + + // Constants: could only be changed in the code itself. + static const double CFROMUNITY, AFROMZERO, AFROMC, EXPMAX; + + // Initialization data, to be read from Settings. + bool usePetersonC, usePetersonB, usePetersonH; + double mc2, mb2, aLund, bLund, aExtraDiquark, rFactC, rFactB, rFactH, + epsilonC, epsilonB, epsilonH; + + // Fragmentation function: select z according to provided parameters. + double zLund( double a, double b, double c = 1.); + double zPeterson( double epsilon); + +}; + +//************************************************************************** + +// The StringPT class is used to select select transverse momenta. + +class StringPT { + +public: + + // Constructor. + StringPT() {} + + // Initialize data members. + void init(); + + // Return px and py separately, but really same routine. + double px() {return pxy();} + double py() {return pxy();} + +private: + + // Initialization data, to be read from Settings. + double sigmaQ, enhancedFraction, enhancedWidth; + + // pT fragmentation spectrum. + double pxy(); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_FragmentationFlavZpT_H diff --git a/PYTHIA8/pythia8130/include/FragmentationSystems.h b/PYTHIA8/pythia8130/include/FragmentationSystems.h new file mode 100644 index 00000000000..7399ee637bd --- /dev/null +++ b/PYTHIA8/pythia8130/include/FragmentationSystems.h @@ -0,0 +1,183 @@ +// FragmentationSystems.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains auxiliary classes in the fragmentation process. +// ColSinglet contains info on an individual singlet. +// ColConfig describes the colour configuration of the whole event. +// StringRegion keeps track on string momenta and directions. +// StringSystem contains all the StringRegions of the colour singlet. + +#ifndef Pythia8_FragmentationSystems_H +#define Pythia8_FragmentationSystems_H + +#include "Basics.h" +#include "Event.h" +#include "FragmentationFlavZpT.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// The ColSinglet class contains info on an individual singlet. +// Only to be used inside ColConfig, so no private members. + +class ColSinglet { + +public: + + // Constructors. + ColSinglet() : pSum(0., 0., 0., 0.), mass(0.), massExcess(0.), + hasJunction(false), isClosed(false), isCollected(false) {} + ColSinglet(vector& iPartonIn, Vec4 pSumIn, double massIn, + double massExcessIn, bool hasJunctionIn = false, + bool isClosedIn = false, bool isCollectedIn = false) + : iParton(iPartonIn), pSum(pSumIn), mass(massIn), + massExcess(massExcessIn), hasJunction(hasJunctionIn), + isClosed(isClosedIn), isCollected(isCollectedIn) {} + + // Size of iParton array. + int size() const { return iParton.size();} + + // Stored quantities. + vector iParton; + Vec4 pSum; + double mass, massExcess; + bool hasJunction, isClosed, isCollected; + +}; + +//************************************************************************** + +// The ColConfig class describes the colour configuration of the whole event. + +class ColConfig { + +public: + + // Constructor. + ColConfig() {} + + // Initialize and save pointers. + void init(StringFlav* flavSelPtrIn); + + // Number of colour singlets. + int size() const {return singlets.size();} + + // Overload index operator to access separate colour singlets. + ColSinglet& operator[](int iSub) {return singlets[iSub];} + + // Clear contents. + void clear() {singlets.resize(0);} + + // Insert a new colour singlet system in ascending mass order. + // Calculate its properties. Join nearby partons. + void insert( vector& iPartonIn, Event& event); + + // Collect all partons of singlet to be consecutively ordered. + void collect(int iSub, Event& event); + + // List all currently identified singlets. + void list(ostream& os = cout); + +private: + + // Pointer to class for flavour generation. + StringFlav* flavSelPtr; + + // Initialization data, to be read from Settings. + double mJoin, mJoinJunction, mStringMin; + + // List of all separate colour singlets. + vector singlets; + + // Join two legs of junction to a diquark for small invariant masses. + bool joinJunction( vector& iPartonIn, Event& event, + double massExcessIn); + +}; + +//************************************************************************** + +// The StringRegion class contains the information related to +// one string section in the evolution of a multiparton system. +// Only to be used inside StringFragmentation and MiniStringFragmentation, +// so no private members. + +class StringRegion { + +public: + + // Constructor. + StringRegion() : isSetUp(false), isEmpty(true) {} + + // Constants: could only be changed in the code itself. + static const double MJOIN, TINY; + + // Data members. + bool isSetUp, isEmpty; + Vec4 pPos, pNeg, eX, eY; + double w2, xPosProj, xNegProj, pxProj, pyProj; + + // Set up four-vectors for longitudinal and transverse directions. + void setUp(Vec4 p1, Vec4 p2, bool isMassless = false); + + // Construct a four-momentum from (x+, x-, px, py). + Vec4 pHad( double xPosIn, double xNegIn, double pxIn, double pyIn) + { return xPosIn * pPos + xNegIn * pNeg + pxIn * eX + pyIn * eY; } + + // Project a four-momentum onto (x+, x-, px, py). Read out projection. + void project(Vec4 pIn); + void project( double pxIn, double pyIn, double pzIn, double eIn) + { project( Vec4( pxIn, pyIn, pzIn, eIn) ); } + double xPos() const {return xPosProj;} + double xNeg() const {return xNegProj;} + double px() const {return pxProj;} + double py() const {return pyProj;} + +}; + +//************************************************************************** + +// The StringSystem class contains the complete set of all string regions. +// Only to be used inside StringFragmentation, so no private members. + +class StringSystem { + +public: + + // Constructor. + StringSystem() {} + + // Set up system from parton list. + void setUp(vector& iSys, Event& event); + + // Calculate string region from (iPos, iNeg) pair. + int iReg( int iPos, int iNeg) const + {return (iPos * (indxReg - iPos)) / 2 + iNeg;} + + // Reference to string region specified by (iPos, iNeg) pair. + StringRegion& region(int iPos, int iNeg) {return system[iReg(iPos, iNeg)];} + + // Reference to low string region specified either by iPos or iNeg. + StringRegion& regionLowPos(int iPos) {return system[iReg(iPos, iMax - iPos)];} + StringRegion& regionLowNeg(int iNeg) {return system[iReg(iMax - iNeg, iNeg)];} + + // Main content: a vector with all the string regions of the system. + vector system; + + // Other data members. + int sizePartons, sizeStrings, sizeRegions, indxReg, iMax; + double mJoin, m2Join; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_FragmentationSystems_H diff --git a/PYTHIA8/pythia8130/include/HadronLevel.h b/PYTHIA8/pythia8130/include/HadronLevel.h new file mode 100644 index 00000000000..de8b64125ff --- /dev/null +++ b/PYTHIA8/pythia8130/include/HadronLevel.h @@ -0,0 +1,112 @@ +// HadronLevel.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the main class for hadron-level generation. +// HadronLevel: handles administration of fragmentation and decay. + +#ifndef Pythia8_HadronLevel_H +#define Pythia8_HadronLevel_H + +#include "Basics.h" +#include "BoseEinstein.h" +#include "Event.h" +#include "FragmentationFlavZpT.h" +#include "FragmentationSystems.h" +#include "Info.h" +#include "MiniStringFragmentation.h" +#include "ParticleData.h" +#include "ParticleDecays.h" +#include "PythiaStdlib.h" +#include "Settings.h" +#include "StringFragmentation.h" +#include "TimeShower.h" + +namespace Pythia8 { + +//************************************************************************** + +// The HadronLevel class contains the top-level routines to generate +// the transition from the partonic to the hadronic stage of an event. + +class HadronLevel { + +public: + + // Constructor. + HadronLevel() {} + + // Initialize HadronLevel classes as required. + bool init(Info* infoPtrIn, TimeShower* timesDecPtr, + DecayHandler* decayHandlePtr, vector handledParticles); + + // Get pointer to StringFlav instance (needed by BeamParticle). + StringFlav* getStringFlavPtr() {return &flavSel;} + + // Generate the next event. + bool next(Event& event); + + // Special routine to allow more decays if on/off switches changed. + bool moreDecays(Event& event); + +private: + + // Constants: could only be changed in the code itself. + static const int NTRYJNREST; + static const double JJSTRINGM2MAX, JJSTRINGM2FRAC, CONVJNREST, MTHAD; + + // Initialization data, read from Settings. + bool doHadronize, doDecay, doBoseEinstein; + double mStringMin, eNormJunction, widthSepBE; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Configuration of colour-singlet systems. + ColConfig colConfig; + + // Colour information. + vector iColEnd, iAcolEnd, iColAndAcol, iParton, iPartonJun, + iPartonAntiJun, iJunLegA, iJunLegB, iJunLegC, + iAntiLegA, iAntiLegB, iAntiLegC, iGluLeg; + vector m2Pair; + + // The generator class for normal string fragmentation. + StringFragmentation stringFrag; + + // The generator class for special low-mass string fragmentation. + MiniStringFragmentation ministringFrag; + + // The generator class for normal decays. + ParticleDecays decays; + + // The generator class for Bose-Einstein effects. + BoseEinstein boseEinstein; + + // Classes for flavour, pT and z generation. + StringFlav flavSel; + StringPT pTSel; + StringZ zSel; + + // Special case: colour-octet onium decays, to be done initially. + bool decayOctetOnia(Event& event); + + // Trace colour flow in the event to form colour singlet subsystems. + bool findSinglets(Event& event); + + // Trace a colour line, from a colour, from an anticolour, or in loop. + bool traceFromCol(int indxCol, Event& event, int iJun = -1, int iCol = -1); + bool traceFromAcol(int indxCol, Event& event, int iJun = -1, int iCol = -1); + bool traceInLoop(int indxCol, int indxAcol, Event& event); + + // Split junction-antijunction system into two, or simplify other way. + bool splitJunctionPair(Event& event); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_HadronLevel_H diff --git a/PYTHIA8/pythia8130/include/HepMCInterface.h b/PYTHIA8/pythia8130/include/HepMCInterface.h new file mode 100644 index 00000000000..97b7ab810b1 --- /dev/null +++ b/PYTHIA8/pythia8130/include/HepMCInterface.h @@ -0,0 +1,103 @@ +// HepMCInterface.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Mikhail Kirsanov, Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +//-------------------------------------------------------------------------- +#ifndef Pythia8_HepMCInterface_H +#define Pythia8_HepMCInterface_H + +////////////////////////////////////////////////////////////////////////// +// Mikhail.Kirsanov@Cern.CH +// Pythia8 I class +////////////////////////////////////////////////////////////////////////// +// + +#include +#include +#include "HepMC/IO_BaseClass.h" +#include "Pythia.h" + +namespace HepMC { + + class GenEvent; + class GenVertex; + class GenParticle; + class ParticleDataTable; + + class I_Pythia8 : public IO_BaseClass { + public: + I_Pythia8(); + virtual ~I_Pythia8(); + bool fill_next_event( Pythia8::Event& pyev, GenEvent* evt, + int ievnum = -1 ); + bool fill_next_event( Pythia8::Pythia& pythia, GenEvent* evt, + int ievnum = -1, + bool convertGluonTo0 = false ); + void put_pdf_info( GenEvent* evt, Pythia8::Pythia& pythia, + bool convertGluonTo0 = false ); + + // see comments below for these switches. + bool trust_both_mothers_and_daughters() const; + bool trust_mothers_before_daughters() const; + bool print_inconsistency_errors() const; + void set_trust_mothers_before_daughters( bool b = 1 ); + void set_trust_both_mothers_and_daughters( bool b = 0 ); + void set_print_inconsistency_errors( bool b = 1 ); + void set_crash_on_problem( bool b = 1 ); + void set_convert_to_mev( bool b = 1 ); + + private: // following are not (yet?) implemented for this class + virtual bool fill_next_event( GenEvent* ) { return 0; } + virtual void write_event( const GenEvent* ) {;} + virtual void write_particle_data_table( const ParticleDataTable* ){} + virtual bool fill_particle_data_table( ParticleDataTable* ) + { return 0; } + + private: // use of copy constructor is not allowed + I_Pythia8( const I_Pythia8& ) : IO_BaseClass() {} + + private: // data members + + bool m_trust_mothers_before_daughters; + bool m_trust_both_mothers_and_daughters; + bool m_print_inconsistency_errors; + int m_internal_event_number; + bool m_crash_on_problem; + bool m_convert_to_mev; + float m_mom_scale_factor; + + }; + + //////////////////////////// + // INLINES access methods // + //////////////////////////// + inline bool I_Pythia8::trust_both_mothers_and_daughters() const + { return m_trust_both_mothers_and_daughters; } + + inline bool I_Pythia8::trust_mothers_before_daughters() const + { return m_trust_mothers_before_daughters; } + + inline bool I_Pythia8::print_inconsistency_errors() const + { return m_print_inconsistency_errors; } + + inline void I_Pythia8::set_trust_both_mothers_and_daughters( bool b ) + { m_trust_both_mothers_and_daughters = b; } + + inline void I_Pythia8::set_trust_mothers_before_daughters( bool b ) + { m_trust_mothers_before_daughters = b; } + + inline void I_Pythia8::set_print_inconsistency_errors( bool b ) + { m_print_inconsistency_errors = b; } + + inline void I_Pythia8::set_crash_on_problem( bool b ) + { m_crash_on_problem = b; } + + inline void I_Pythia8::set_convert_to_mev( bool b ) + { m_convert_to_mev = b; m_mom_scale_factor = 1000.; } + +} // HepMC + +#endif // Pythia8_HepMCInterface_H + +//-------------------------------------------------------------------------- diff --git a/PYTHIA8/pythia8130/include/Info.h b/PYTHIA8/pythia8130/include/Info.h new file mode 100644 index 00000000000..87a6cbf179e --- /dev/null +++ b/PYTHIA8/pythia8130/include/Info.h @@ -0,0 +1,251 @@ +// Info.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains a class that keep track of generic event info. +// Info: contains information on the generation process and errors. + +#ifndef Pythia8_Info_H +#define Pythia8_Info_H + +#include "PythiaStdlib.h" + +namespace Pythia8 { + +//************************************************************************** + +// The Info class contains a mixed bag of information on the event +// generation activity, especially on the current subprocess properties, +// and on the number of errors encountered. This is used by the +// generation machinery, but can also be read by the user. + +class Info { + +public: + + // Constructor. + Info() {} + + // Listing of most available information on current event. + void list(ostream& os = cout); + + // Beam particles (in rest frame). CM energy of event. + int idA() const {return idASave;} + int idB() const {return idBSave;} + double pzA() const {return pzASave;} + double pzB() const {return pzBSave;} + double eA() const {return eASave;} + double eB() const {return eBSave;} + double mA() const {return mASave;} + double mB() const {return mBSave;} + double eCM() const {return eCMSave;} + double s() const {return sSave;} + + // Process name and code, and the number of final-state particles. + string name() const {return nameSave;} + int code() const {return codeSave;} + int nFinal() const {return nFinalSave;} + + // Are beam particles resolved, with pdf's? Are they diffractive? + bool isResolved() const {return isRes;} + bool isDiffractiveA() const {return isDiffA;} + bool isDiffractiveB() const {return isDiffB;} + bool isMinBias() const {return isMB;} + + // Information for Les Houches Accord and reading files. + bool isLHA() const {return isLH;} + bool atEndOfFile() const {return atEOF;} + + // For minbias and Les Houches Accord identify hardest subprocess. + bool hasSub() const {return hasSubSave;} + string nameSub() const {return nameSubSave;} + int codeSub() const {return codeSubSave;} + int nFinalSub() const {return nFinalSubSave;} + + // Incoming parton flavours and x values. + int id1() const {return id1Save;} + int id2() const {return id2Save;} + double x1() const {return x1Save;} + double x2() const {return x2Save;} + double y() const {return 0.5 * log( x1Save / x2Save );} + double tau() const {return x1Save * x2Save;} + + // Incoming parton densities, hard process couplings, Q2 scales. + double pdf1() const {return pdf1Save;} + double pdf2() const {return pdf2Save;} + double QFac() const {return sqrtpos(Q2FacSave);} + double Q2Fac() const {return Q2FacSave;} + bool isValence1() const {return isVal1;} + bool isValence2() const {return isVal2;} + double alphaS() const {return alphaSSave;} + double alphaEM() const {return alphaEMSave;} + double QRen() const {return sqrtpos(Q2RenSave);} + double Q2Ren() const {return Q2RenSave;} + + // Mandelstam variables (notation as if subcollision). + double mHat() const {return sqrt(sH);} + double sHat() const {return sH;} + double tHat() const {return tH;} + double uHat() const {return uH;} + double pTHat() const {return pTH;} + double pT2Hat() const {return pTH*pTH;} + double m3Hat() const {return m3H;} + double m4Hat() const {return m4H;} + double thetaHat() const {return thetaH;} + double phiHat() const {return phiH;} + + // Weight of current event; normally 1, but used for Les Houches events. + double weight() const {return weightSave;} + + // Cross section estimate. + long nTried() const {return nTry;} + long nSelected() const {return nSel;} + long nAccepted() const {return nAcc;} + double sigmaGen() const {return sigGen;} + double sigmaErr() const {return sigErr;} + + // Impact parameter picture. + double bMI() const {return (bIsSet) ? bMISave : 1.;} + double enhanceMI() const {return (bIsSet) ? enhanceMISave : 1.;} + + // Maximum pT scales for MI, ISR and FSR (in hard process). + double pTmaxMI() const {return pTmaxMISave;} + double pTmaxISR() const {return pTmaxISRSave;} + double pTmaxFSR() const {return pTmaxFSRSave;} + + // Number of multiple interactions, with code and pT for them. + int nMI() const {return nMISave;} + int codeMI(int i) const {return codeMISave[i];} + double pTMI(int i) const {return pTMISave[i];} + + // Number of times other steps have been carried out. + int nISR() const {return nISRSave;} + int nFSRinProc() const {return nFSRinProcSave;} + int nFSRinRes() const {return nFSRinResSave;} + + // Reset to empty map of error messages. + void errorReset() {messages.clear();} + + // Print a message the first few times. Insert in database. + void errorMsg(string messageIn, string extraIn = " ", + ostream& os = cout); + + // Provide total number of errors/aborts/warnings experienced to date. + int errorTotalNumber(); + + // Print statistics on errors/aborts/warnings. + void errorStatistics(ostream& os = cout); + +private: + + // Store common beam quantities. + int idASave, idBSave; + double pzASave, eASave,mASave, pzBSave, eBSave, mBSave, eCMSave, sSave; + + // Store common integrated cross section quantities. + long nTry, nSel, nAcc; + double sigGen, sigErr; + + // Store current-event quantities. + bool isRes, isDiffA, isDiffB, isMB, isLH, hasSubSave, bIsSet, evolIsSet, + atEOF, isVal1, isVal2; + int codeSave, codeSubSave, nFinalSave, nFinalSubSave, nTotal, + id1Save, id2Save, nMISave, nISRSave, nFSRinProcSave, nFSRinResSave; + double x1Save, x2Save, pdf1Save, pdf2Save, Q2FacSave, alphaEMSave, + alphaSSave, Q2RenSave, sH, tH, uH, pTH, m3H, m4H, thetaH, phiH, + weightSave, bMISave, enhanceMISave, pTmaxMISave, pTmaxISRSave, + pTmaxFSRSave; + string nameSave, nameSubSave; + vector codeMISave; + vector pTMISave; + + // Friend classes allowed to set info. + friend class Pythia; + friend class ProcessLevel; + friend class ProcessContainer; + friend class PartonLevel; + friend class MultipleInteractions; + + // Set info on the two incoming beams: only from Pythia class. + void setBeamA( int idAin, double pzAin, double eAin, double mAin) { + idASave = idAin; pzASave = pzAin; eASave = eAin; mASave = mAin;} + void setBeamB( int idBin, double pzBin, double eBin, double mBin) { + idBSave = idBin; pzBSave = pzBin; eBSave = eBin; mBSave = mBin;} + void setECM( double eCMin) {eCMSave = eCMin; sSave = eCMSave * eCMSave;} + + // Reset info for current event: only from Pythia class. + void clear() { isRes = isDiffA = isDiffB = isMB = isLH = atEOF = bIsSet + = isVal1 =isVal2 = false; codeSave = nFinalSave = nTotal = id1Save + = id2Save = nMISave = nISRSave = nFSRinProcSave = nFSRinResSave = 0; + x1Save = x2Save = pdf1Save = pdf2Save = Q2FacSave = alphaEMSave + = alphaSSave = Q2RenSave = sH = tH = uH = pTH = m3H = m4H = thetaH + = phiH = 0.; nameSave = " "; weightSave = bMISave = enhanceMISave = 1.; + codeMISave.resize(0); pTMISave.resize(0);} + + // Set info on the (sub)process: from ProcessLevel, ProcessContainer or + // MultipleInteractions classes. + void setType( string nameIn, int codeIn, int nFinalIn, + bool isMinBiasIn = false, bool isResolvedIn = true, + bool isDiffractiveAin = false, bool isDiffractiveBin = false, + bool isLHAin = false) {nameSave = nameIn; codeSave = codeIn; + nFinalSave = nFinalIn; isMB = isMinBiasIn; isRes = isResolvedIn; + isDiffA = isDiffractiveAin; isDiffB = isDiffractiveBin; isLH = isLHAin; + nTotal = 2 + nFinalSave; bIsSet = false; hasSubSave = false; + nameSubSave = " "; codeSubSave = 0; nFinalSubSave = 0; evolIsSet = false;} + void setSubType( string nameSubIn, int codeSubIn, int nFinalSubIn) { + hasSubSave = true; nameSubSave = nameSubIn; codeSubSave = codeSubIn; + nFinalSubSave = nFinalSubIn;} + void setPDFalpha( int id1In, int id2In, double pdf1In, double pdf2In, + double Q2FacIn, double alphaEMIn, double alphaSIn, double Q2RenIn) + {id1Save = id1In; id2Save = id2In; pdf1Save = pdf1In; pdf2Save = pdf2In; + Q2FacSave = Q2FacIn; alphaEMSave = alphaEMIn; alphaSSave = alphaSIn; + Q2RenSave = Q2RenIn;} + void setKin( double x1In, double x2In, double sHatIn, double tHatIn, + double uHatIn, double pTHatIn, double m3HatIn, double m4HatIn, + double thetaHatIn, double phiHatIn) {x1Save = x1In; x2Save = x2In; + sH = sHatIn; tH = tHatIn; uH = uHatIn; pTH = pTHatIn; m3H = m3HatIn; + m4H = m4HatIn; thetaH = thetaHatIn; phiH = phiHatIn;} + void setTypeMI( int codeMIIn, double pTMIIn) { + codeMISave.push_back(codeMIIn); pTMISave.push_back(pTMIIn);} + + // Set info on cross section: from ProcessLevel. + void setSigma( long nTryIn, long nSelIn, long nAccIn, double sigGenIn, + double sigErrIn) { nTry = nTryIn; nSel = nSelIn; nAcc = nAccIn; + sigGen = sigGenIn; sigErr = sigErrIn;} + + // Set info on valence character of hard collision partons: from PartonLevel. + void setValence( bool isVal1In, bool isVal2In) {isVal1 = isVal1In; + isVal2 = isVal2In;} + + // Set info on impact parameter: from PartonLevel. + void setImpact( double bMIIn, double enhanceMIIn) {bMISave = bMIIn; + enhanceMISave = enhanceMIIn, bIsSet = true;} + + // Set info on pTmax scales and number of evolution steps: from PartonLevel. + void setEvolution( double pTmaxMIIn, double pTmaxISRIn, double pTmaxFSRIn, + int nMIIn, int nISRIn, int nFSRinProcIn, int nFSRinResIn) { + pTmaxMISave = pTmaxMIIn; pTmaxISRSave = pTmaxISRIn; + pTmaxFSRSave = pTmaxFSRIn; nMISave = nMIIn; nISRSave = nISRIn; + nFSRinProcSave = nFSRinProcIn; nFSRinResSave = nFSRinResIn; + evolIsSet = true;} + + // Set info whether reading of Les Houches Accord file at end. + void setEndOfFile( bool atEOFin) {atEOF = atEOFin;} + + // Set event weight; currently only for Les Houches description. + void setWeight( double weightIn) {weightSave = weightIn;} + + // Number of times the same error message is repeated. + static const int TIMESTOPRINT; + + // Map for all error messages. + map messages; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_Info_H diff --git a/PYTHIA8/pythia8130/include/LHAFortran.h b/PYTHIA8/pythia8130/include/LHAFortran.h new file mode 100644 index 00000000000..2a1e6675cdb --- /dev/null +++ b/PYTHIA8/pythia8130/include/LHAFortran.h @@ -0,0 +1,105 @@ +// LHAFortran.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for Fortran Les Houches Accord user process information. +// LHAupFortran: derived class with the HEPRUP and HEPEUP Fortran info. +// You are expected to supply the fillHepRup and fillHepEup methods. + +#ifndef Pythia8_LHAFortran_H +#define Pythia8_LHAFortran_H + +#include "PythiaStdlib.h" + +namespace Pythia8 { + +//************************************************************************** + +// Give access to the HEPRUP and HEPEUP Fortran commonblocks. + +extern "C" { + + extern struct { + int idbmup[2]; + double ebmup[2]; + int pdfgup[2], pdfsup[2], idwtup, nprup; + double xsecup[100], xerrup[100], xmaxup[100]; + int lprup[100]; + } heprup_; + + extern struct { + int nup, idprup; + double xwgtup, scalup, aqedup, aqcdup; + int idup[500], istup[500], mothup[500][2], icolup[500][2]; + double pup[500][5], vtimup[500],spinup[500]; + } hepeup_; + +} + +//********* + +// A derived class with initialization information from the HEPRUP +// Fortran commonblock and event information from the HEPEUP one. + +class LHAupFortran : public LHAup { + +public: + + // Constructor. + LHAupFortran() {} + + // Routine for doing the job of setting initialization info. + bool setInit() { + // Call the routine that does the job. + if (!fillHepRup()) return false; + // Store beam and strategy info. + setBeamA(heprup_.idbmup[0], heprup_.ebmup[0], heprup_.pdfgup[0], + heprup_.pdfsup[0]); + setBeamB(heprup_.idbmup[1], heprup_.ebmup[1], heprup_.pdfgup[1], + heprup_.pdfsup[1]); + setStrategy(heprup_.idwtup); + // Store process info. Protect against vanishing cross section. + for (int ip = 0; ip < heprup_.nprup; ++ip) { + double xsec = max( 1e-10, heprup_.xsecup[ip]); + addProcess( heprup_.lprup[ip], xsec, heprup_.xerrup[ip], + heprup_.xmaxup[ip] ); + } + // Done. + return true; + } + + // Routine for doing the job of setting info on next event. + bool setEvent(int idProcIn = 0) { + // In some strategies the type of the next event has been set. + hepeup_.idprup = idProcIn; + // Call the routine that does the job. + if (!fillHepEup()) return false; + // Store process info. + setProcess(hepeup_.idprup, hepeup_.xwgtup, hepeup_.scalup, + hepeup_.aqedup, hepeup_.aqcdup); + // Store particle info. + for (int ip = 0; ip < hepeup_.nup; ++ip) addParticle(hepeup_.idup[ip], + hepeup_.istup[ip], hepeup_.mothup[ip][0], hepeup_.mothup[ip][1], + hepeup_.icolup[ip][0], hepeup_.icolup[ip][1], hepeup_.pup[ip][0], + hepeup_.pup[ip][1], hepeup_.pup[ip][2], hepeup_.pup[ip][3], + hepeup_.pup[ip][4], hepeup_.vtimup[ip], hepeup_.spinup[ip]) ; + // Done. + return true; + } + +private: + + // User-written routine that does the intialization and fills heprup. + bool fillHepRup(); + + // User-written routine that does the event generation and fills hepeup. + bool fillHepEup(); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_LHAFortran_H diff --git a/PYTHIA8/pythia8130/include/LHAPDFInterface.h b/PYTHIA8/pythia8130/include/LHAPDFInterface.h new file mode 100644 index 00000000000..52cdaefd960 --- /dev/null +++ b/PYTHIA8/pythia8130/include/LHAPDFInterface.h @@ -0,0 +1,75 @@ +// LHAPDFInterface.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for the LHAPDF f77 external linkage to C++. +// All required code is contained here, i.e. there is no matching .cc file. + +#ifndef Pythia8_LHAPDFInterface_H +#define Pythia8_LHAPDFInterface_H + +namespace Pythia8 { + +//************************************************************************** + +// Declare the LHAPDF f77 subroutines that are needed. + +extern "C" { + + extern void initpdfsetm_(int&, const char*, int); + + extern void initpdfsetbynamem_(int&, const char*, int); + + extern void initpdfm_(int&, int&); + + extern void evolvepdfm_(int&, double&, double&, double*); + + extern void setlhaparm_(const char*, int); + +} + +//************************************************************************** + +// Interfaces to the above routines, to make the C++ calls similar to f77. + +class LHAPDFInterface { + +public: + + // Initialize set with full pathname, allowing multiple sets. + static void initPDFsetM( int nSet, string name) { + const char* cName = name.c_str(); int lenName = name.length(); + initpdfsetm_( nSet, cName, lenName); + } + + // Initialize set with simple name, allowing multiple sets. + static void initPDFsetByNameM( int nSet, string name) { + const char* cName = name.c_str(); int lenName = name.length(); + initpdfsetbynamem_( nSet, cName, lenName); + } + + // Initialize member of set. + static void initPDFM(int nSet, int member) { + initpdfm_(nSet, member); + } + + // Evaluate x f_i(x, Q). + static void evolvePDFM( int nSet, double x, double Q, double* xfArray) { + evolvepdfm_( nSet, x, Q, xfArray); + } + + // Extrapolate PDF set beyond boundaries, or freeze them there. + static void setPDFparm(string name) { + const char* cName = name.c_str(); int lenName = name.length(); + setlhaparm_( cName, lenName); + } + + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_LHAPDFInterface_H diff --git a/PYTHIA8/pythia8130/include/LesHouches.h b/PYTHIA8/pythia8130/include/LesHouches.h new file mode 100644 index 00000000000..dcb2e487640 --- /dev/null +++ b/PYTHIA8/pythia8130/include/LesHouches.h @@ -0,0 +1,295 @@ +// LesHouches.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for Les Houches Accord user process information. +// LHAup: base class for initialization and event information. +// LHAupLHEF: derived class for reading from an Les Houches Event File. +// Code for interfacing with Fortran commonblocks is found in LHAFortran.h. + +#ifndef Pythia8_LesHouches_H +#define Pythia8_LesHouches_H + +#include "Event.h" +#include "Info.h" +#include "PythiaStdlib.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// LHAup is base class for initialization and event information +// from an external parton-level generator. + +class LHAup { + +public: + + // Destructor. + virtual ~LHAup() {} + + // Set info pointer. + void setPtr(Info* infoPtrIn) {infoPtr = infoPtrIn;} + + // A pure virtual method setInit, wherein all initialization information + // is supposed to be set in the derived class. Can do this by reading a + // file or some other way, as desired. Returns false if it did not work. + virtual bool setInit() = 0; + + // Give back info on beams. + int idBeamA() const {return idBeamASave;} + int idBeamB() const {return idBeamBSave;} + double eBeamA() const {return eBeamASave;} + double eBeamB() const {return eBeamBSave;} + int pdfGroupBeamA() const {return pdfGroupBeamASave;} + int pdfGroupBeamB() const {return pdfGroupBeamBSave;} + int pdfSetBeamA() const {return pdfSetBeamASave;} + int pdfSetBeamB() const {return pdfSetBeamBSave;} + + // Give back weight strategy. + int strategy() const {return strategySave;} + + // Give back info on processes. + int sizeProc() const {return processes.size();} + int idProcess(int proc) const {return processes[proc].idProc;} + double xSec(int proc) const {return processes[proc].xSecProc;} + double xErr(int proc) const {return processes[proc].xErrProc;} + double xMax(int proc) const {return processes[proc].xMaxProc;} + + // Print the initialization info; useful to check that setting it worked. + void listInit(ostream& os = cout); + + // A pure virtual method setEvent, wherein information on the next event + // is supposed to be set in the derived class. + // Strategies +-1 and +-2: idProcIn is the process type, selected by PYTHIA. + // Strategies +-3 and +-4: idProcIn is dummy; process choice is made locally. + // The method can find the next event by a runtime interface to another + // program, or by reading a file, as desired. + // The method should return false if it did not work. + virtual bool setEvent(int idProcIn = 0) = 0; + + // Give back process number, weight, scale, alpha_em, alpha_s. + int idProcess() const {return idProc;} + double weight() const {return weightProc;} + double scale() const {return scaleProc;} + double alphaQED() const {return alphaQEDProc;} + double alphaQCD() const {return alphaQCDProc;} + + // Give back info on separate particle. + int sizePart() const {return particles.size();} + int id(int part) const {return particles[part].idPart;} + int status(int part) const {return particles[part].statusPart;} + int mother1(int part) const {return particles[part].mother1Part;} + int mother2(int part) const {return particles[part].mother2Part;} + int col1(int part) const {return particles[part].col1Part;} + int col2(int part) const {return particles[part].col2Part;} + double px(int part) const {return particles[part].pxPart;} + double py(int part) const {return particles[part].pyPart;} + double pz(int part) const {return particles[part].pzPart;} + double e(int part) const {return particles[part].ePart;} + double m(int part) const {return particles[part].mPart;} + double tau(int part) const {return particles[part].tauPart;} + double spin(int part) const {return particles[part].spinPart;} + + // Optional: give back info on parton density values of event. + bool pdfIsSet() const {return pdfIsSetSave;} + int id1() const {return id1Save;} + int id2() const {return id2Save;} + double x1() const {return x1Save;} + double x2() const {return x2Save;} + double scalePDF() const {return scalePDFSave;} + double xpdf1() const {return xpdf1Save;} + double xpdf2() const {return xpdf2Save;} + + // Print the info; useful to check that reading an event worked. + void listEvent(ostream& os = cout); + + // Four routines to write a Les Houches Event file in steps. + bool openLHEF(string fileNameIn); + bool initLHEF(); + bool eventLHEF(); + bool closeLHEF(bool updateInit = false); + +protected: + + // Constructor. Sets default to be that events come with unit weight. + LHAup(int strategyIn = 3) : strategySave(strategyIn) + { processes.reserve(10); particles.reserve(20); } + + // Allow conversion from mb to pb. + static const double CONVERTMB2PB; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Input beam info. + void setBeamA(int idIn, double eIn, int pdfGroupIn = 0, int pdfSetIn = 0) + { idBeamASave = idIn; eBeamASave = eIn; pdfGroupBeamASave = pdfGroupIn; + pdfSetBeamASave = pdfSetIn;} + void setBeamB(int idIn, double eIn, int pdfGroupIn = 0, int pdfSetIn = 0) + { idBeamBSave = idIn; eBeamBSave = eIn; pdfGroupBeamBSave = pdfGroupIn; + pdfSetBeamBSave = pdfSetIn;} + + // Input process weight strategy. + void setStrategy(int strategyIn) {strategySave = strategyIn;} + + // Input process info. + void addProcess(int idProcIn, double xSecIn = 1., double xErrIn = 0., + double xMaxIn = 1.) { processes.push_back( LHAProcess( idProcIn, + xSecIn, xErrIn, xMaxIn)); } + + // Possibility to update some cross section info at end of run. + void setXSec(int iP, double xSecIn) {processes[iP].xSecProc = xSecIn;} + void setXErr(int iP, double xErrIn) {processes[iP].xErrProc = xErrIn;} + void setXMax(int iP, double xMaxIn) {processes[iP].xMaxProc = xMaxIn;} + + // Input info on the selected process. + void setProcess(int idProcIn = 0, double weightIn = 1., double + scaleIn = 0., double alphaQEDIn = 0.0073, double alphaQCDIn = 0.12) { + idProc = idProcIn; weightProc = weightIn; scaleProc = scaleIn; + alphaQEDProc = alphaQEDIn; alphaQCDProc = alphaQCDIn; + // Clear particle list. Add empty zeroth particle for correct indices. + particles.clear(); addParticle(0); pdfIsSetSave = false;} + + // Input particle info, one particle at the time. + void addParticle(int idIn, int statusIn = 0, int mother1In = 0, + int mother2In = 0, int col1In = 0, int col2In = 0, double pxIn = 0., + double pyIn = 0., double pzIn = 0., double eIn = 0., double mIn = 0., + double tauIn = 0., double spinIn = 9.) { + particles.push_back( LHAParticle( idIn, statusIn, mother1In, mother2In, + col1In, col2In, pxIn, pyIn, pzIn, eIn, mIn, tauIn, spinIn)); } + + // Optionally input info on parton density values of event. + void setPdf(int id1In, int id2In, double x1In, double x2In, + double scalePDFIn, double xpdf1In, double xpdf2In) + { id1Save = id1In; id2Save = id2In; x1Save = x1In; x2Save = x2In; + scalePDFSave = scalePDFIn; xpdf1Save = xpdf1In; xpdf2Save = xpdf2In; + pdfIsSetSave = true;} + +private: + + // Event weighting and mixing strategy. + int strategySave; + + // Beam particle properties. + int idBeamASave, idBeamBSave; + double eBeamASave, eBeamBSave; + int pdfGroupBeamASave, pdfGroupBeamBSave, pdfSetBeamASave, pdfSetBeamBSave; + + // A nested class for processes... + class LHAProcess { + public: + LHAProcess() : idProc(0), xSecProc(0.), xErrProc(0.), xMaxProc(0.) { } + LHAProcess(int idProcIn, double xSecIn, double xErrIn, double xMaxIn) : + idProc(idProcIn), xSecProc(xSecIn), xErrProc(xErrIn), + xMaxProc(xMaxIn) { } + int idProc; + double xSecProc, xErrProc, xMaxProc; + } ; + + // ...so that the process list can be kept as a vector. + vector processes; + + // Store info on the selected process. + int idProc; + double weightProc, scaleProc, alphaQEDProc, alphaQCDProc; + + // A nested class for particles... + class LHAParticle { + public: + LHAParticle() : idPart(0), statusPart(0), mother1Part(0), + mother2Part(0), col1Part(0), col2Part(0), pxPart(0.), pyPart(0.), + pzPart(0.), ePart(0.), mPart(0.), tauPart(0.), spinPart(9.) { } + LHAParticle(int idIn, int statusIn, int mother1In, int mother2In, + int col1In, int col2In, double pxIn, double pyIn, double pzIn, + double eIn, double mIn, double tauIn, double spinIn) : + idPart(idIn), statusPart(statusIn), mother1Part(mother1In), + mother2Part(mother2In), col1Part(col1In), col2Part(col2In), + pxPart(pxIn), pyPart(pyIn), pzPart(pzIn), ePart(eIn), mPart(mIn), + tauPart(tauIn), spinPart(spinIn) { } + int idPart, statusPart, mother1Part, mother2Part, col1Part, col2Part; + double pxPart, pyPart, pzPart, ePart, mPart, tauPart, spinPart; + } ; + + // ...so that the particle list can be kept as a vector. + vector particles; + + // Optional info on parton density values of event. + bool pdfIsSetSave; + int id1Save, id2Save; + double x1Save, x2Save, scalePDFSave, xpdf1Save, xpdf2Save; + + // File to which to write Les Houches Event File information. + string fileName; + fstream osLHEF; + char dateNow[12]; + char timeNow[9]; + +}; + +//************************************************************************** + +// A derived class with information read from a Les Houches Event File. + +class LHAupLHEF : public LHAup { + +public: + + // Constructor. + LHAupLHEF(const char* fileIn) : is(fileIn) {} + + // Destructor. + ~LHAupLHEF() {} + + // Routine for doing the job of reading and setting initialization info. + bool setInit(); + + // Routine for doing the job of reading and setting info on next event. + bool setEvent(int = 0); + +private: + + // File from which to read. + ifstream is; + +}; + +//************************************************************************** + +// A derived class with information read from PYTHIA 8 itself, for output. + +class LHAupFromPYTHIA8 : public LHAup { + +public: + + // Constructor. + LHAupFromPYTHIA8(Event* processPtrIn, Info* infoPtrIn) { + processPtr = processPtrIn; infoPtr = infoPtrIn;} + + // Destructor. + ~LHAupFromPYTHIA8() {} + + // Routine for doing the job of reading and setting initialization info. + bool setInit(); + + // Routine for doing the job of reading and setting info on next event. + bool setEvent(int = 0); + + // Update cross-section information at the end of the run. + bool updateSigma(); + +private: + + // Pointers to process event record and further information. + Event* processPtr; + Info* infoPtr; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_LesHouches_H diff --git a/PYTHIA8/pythia8130/include/MiniStringFragmentation.h b/PYTHIA8/pythia8130/include/MiniStringFragmentation.h new file mode 100644 index 00000000000..dd43e5f5ebc --- /dev/null +++ b/PYTHIA8/pythia8130/include/MiniStringFragmentation.h @@ -0,0 +1,78 @@ +// MiniStringFragmentation.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the class for "cluster" fragmentation. +// MiniStringFragmentation: handle the fragmentation of low-mass systems. + +#ifndef Pythia8_MiniStringFragmentation_H +#define Pythia8_MiniStringFragmentation_H + +#include "Basics.h" +#include "Event.h" +#include "FragmentationFlavZpT.h" +#include "FragmentationSystems.h" +#include "Info.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// The MiniStringFragmentation class contains the routines to fragment +// occasional low-mass colour singlet partonic systems, where the string +// approach is not directly applicable (for technical reasons). + +class MiniStringFragmentation { + +public: + + // Constructor. + MiniStringFragmentation() {} + + // Initialize and save pointers. + void init(Info* infoPtrIn, StringFlav* flavSelPtrIn); + + // Do the fragmentation: driver routine. + bool fragment( int iSub, ColConfig& colConfig, Event& event, + bool isDiff = false); + +private: + + // Constants: could only be changed in the code itself. + static const int NTRYDIFFRACTIVE, NTRYLASTRESORT, NTRYFLAV; + static const double SIGMAMIN; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointer to class for flavour generation. + StringFlav* flavSelPtr; + + // Initialization data, read from Settings. + int nTryMass; + double sigma, sigma2Had, bLund; + + // Data members. + bool isClosed; + double mSum, m2Sum; + Vec4 pSum; + vector iParton; + FlavContainer flav1, flav2; + + // Attempt to produce two particles from a cluster. + bool ministring2two( int nTry, Event& event); + + // Attempt to produce one particle from a cluster. + bool ministring2one( int iSub, ColConfig& colConfig, Event& event); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_MiniStringFragmentation_H diff --git a/PYTHIA8/pythia8130/include/MultipleInteractions.h b/PYTHIA8/pythia8130/include/MultipleInteractions.h new file mode 100644 index 00000000000..fd746d2ffc2 --- /dev/null +++ b/PYTHIA8/pythia8130/include/MultipleInteractions.h @@ -0,0 +1,218 @@ +// MultipleInteractions.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the main classes for multiple interactions physics. +// SigmaMultiple stores allowed processes by in-flavour combination. +// MultipleInteractions: generates multiple parton-parton interactions. + +#ifndef Pythia8_MultipleInteractions_H +#define Pythia8_MultipleInteractions_H + +#include "Basics.h" +#include "BeamParticle.h" +#include "Event.h" +#include "Info.h" +#include "PythiaStdlib.h" +#include "Settings.h" +#include "SigmaTotal.h" +#include "SigmaProcess.h" +#include "StandardModel.h" + +namespace Pythia8 { + +//************************************************************************** + +// SigmaMultiple is a helper class to MultipleInteractions. +// It packs pointers to the allowed processes for different +// flavour combinations and levels of ambition. + +class SigmaMultiple { + +public: + + // Constructor. + SigmaMultiple() {} + + // Destructor. + ~SigmaMultiple() { + for (int i = 0; i < int(sigmaT.size()); ++i) delete sigmaT[i]; + for (int i = 0; i < int(sigmaU.size()); ++i) delete sigmaU[i];} + + // Initialize list of processes. + bool init(int inState, int processLevel); + + // Calculate cross section summed over possibilities. + double sigma( int id1, int id2, double x1, double x2, double sHat, + double tHat, double uHat, double alpS, double alpEM); + + // Return one subprocess, picked according to relative cross sections. + SigmaProcess* sigmaSel(); + bool swapTU() {return pickedU;} + + // Return code or name of a specified process, for statistics table. + int nProc() const {return nChan;} + int codeProc(int iProc) const {return sigmaT[iProc]->code();} + string nameProc(int iProc) const {return sigmaT[iProc]->name();} + +private: + + // Constants: could only be changed in the code itself. + static const double MASSMARGIN, OTHERFRAC; + + // Number of processes. Some use massive matrix elements. + int nChan; + vector needMasses; + vector m3Fix, m4Fix, sHatMin; + + // Vector of process list, one for t-channel and one for u-channel. + vector sigmaT, sigmaU; + + // Values of cross sections in process list above. + vector sigmaTval, sigmaUval; + double sigmaTsum, sigmaUsum; + bool pickedU; + +}; + +//************************************************************************** + +// The MultipleInteractions class contains the main methods for the +// generation of multiple parton-parton interactions in hadronic collisions. + +class MultipleInteractions { + +public: + + // Constructor. + MultipleInteractions() {sudExpPT.resize(NBINS+1);} + + // Initialize the generation process for given beams. + bool init( bool doMIinit, Info* infoPtrIn, BeamParticle* beamAPtrIn, + BeamParticle* beamBPtrIn, SigmaTotal* sigmaTotPtrIn, + ostream& os = cout); + + // Reset impact parameter choice and update the CM energy. + void clear() {bIsSet = false; bSetInFirst = false; + eCM = infoPtr->eCM(); sCM = eCM * eCM;} + + // Select first = hardest pT in minbias process. + void pTfirst(); + + // Set up kinematics for first = hardest pT in minbias process. + void setupFirstSys( Event& process); + + // Find whether to limit maximum scale of emissions. + bool limitPTmax( Event& event); + + // Prepare system for evolution. + void prepare(double pTscale = 1000.) { + if (!bSetInFirst) overlapNext(pTscale);} + + // Select next pT in downwards evolution. + double pTnext( double pTbegAll, double pTendAll); + + // Set up kinematics of acceptable interaction. + void scatter( Event& event); + + // Get some information on current interaction. + double Q2Ren() const {return pT2Ren;} + double alphaSH() const {return alpS;} + double alphaEMH() const {return alpEM;} + double x1H() const {return x1;} + double x2H() const {return x2;} + double Q2Fac() const {return pT2Fac;} + double pdf1() const {return xPDF1now;} + double pdf2() const {return xPDF2now;} + double bMI() const {return (bIsSet) ? bNow / bAvg : 0.;} + double enhanceMI() const {return (bIsSet) ? enhanceB / zeroIntCorr : 1.;} + + // Update and print statistics on number of processes. + void accumulate() { int iBeg = (infoPtr->isMinBias()) ? 0 : 1; + for (int i = iBeg; i < infoPtr->nMI(); ++i) ++nGen[ infoPtr->codeMI(i) ];} + void statistics(bool reset = false, ostream& os = cout); + +private: + + // Constants: could only be changed in the code itself. + static const bool SHIFTFACSCALE; + static const int NBINS; + static const double SIGMAFUDGE, RPT20, PT0STEP, SIGMASTEP, EXPPOWMIN, + PROBATLOWB, BSTEP, BMAX, EXPMAX, KCONVERGE, + CONVERT2MB; + + // Initialization data, read from Settings. + int pTmaxMatch, alphaSorder, alphaEMorder, bProfile, + processLevel, nQuarkIn, nSample; + double alphaSvalue, Kfactor, pT0Ref, ecmRef, ecmPow, + pTmin, coreRadius, coreFraction, expPow; + + // Other initialization data. + bool hasLowPow; + double eCM, sCM, pT0, pT20, pT2min, pTmax, pT2max, pT20R, pT20minR, + pT20maxR, pT20min0maxR, pT2maxmin, sigmaND, pT4dSigmaMax, + pT4dProbMax, dSigmaApprox, sigmaInt, zeroIntCorr, normOverlap, + nAvg, kNow, normPi, bAvg, bDiv, probLowB, radius2B, radius2C, + fracA, fracB, fracC, fracAhigh, fracBhigh, fracChigh, fracABChigh, + expRev, cDiv, cMax; + vector sudExpPT; + + // Properties specific to current system. + int id1, id2; + double bNow, enhanceB, pT2, pT2shift, pT2Ren, pT2Fac, x1, x2, xT, xT2, + tau, y, sHat, tHat, uHat, alpS, alpEM, xPDF1now, xPDF2now; + bool bIsSet, bSetInFirst, isAtLowB; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointers to the two incoming beams. + BeamParticle* beamAPtr; + BeamParticle* beamBPtr; + + // Pointer to total cross section parametrization. + SigmaTotal* sigmaTotPtr; + + // Collections of parton-level 2 -> 2 cross sections. Selected one. + SigmaMultiple sigma2gg, sigma2qg, sigma2qqbarSame, sigma2qq; + SigmaProcess* dSigmaDtSel; + + // Statistics on generated 2 -> 2 processes. + map nGen; + + // alphaStrong and alphaEM calculations. + AlphaStrong alphaS; + AlphaEM alphaEM; + + // Determine constant in d(Prob)/d(pT2) < const / (pT2 + r * pT20)^2. + void upperEnvelope(); + + // Integrate the parton-parton interaction cross section. + void jetCrossSection(); + + // Evaluate "Sudakov form factor" for not having a harder interaction. + double sudakov(double pT2sud, double enhance = 1.); + + // Do a quick evolution towards the next smaller pT. + double fastPT2( double pT2beg); + + // Calculate the actual cross section, either for the first interaction + // (including at initialization) or for any subsequent in the sequence. + double sigmaPT2(bool isFirst = false); + + // Calculate factor relating matter overlap and interaction rate. + void overlapInit(); + + // Pick impact parameter and interaction rate enhancement, + // either before the first interaction (for minbias) or after it. + void overlapFirst(); + void overlapNext(double pTscale); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_MultipleInteractions_H diff --git a/PYTHIA8/pythia8130/include/ParticleData.h b/PYTHIA8/pythia8130/include/ParticleData.h new file mode 100644 index 00000000000..e443d02bc5b --- /dev/null +++ b/PYTHIA8/pythia8130/include/ParticleData.h @@ -0,0 +1,602 @@ +// ParticleData.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for the classes containing particle data. +// DecayChannel contains info on a single decay channel. +// DecayTable contains all decay channels of a particle. +// ParticleDataEntry contains info on a single particle species. +// ParticleDataTable collects info on all particles as a map. + +#ifndef Pythia8_ParticleData_H +#define Pythia8_ParticleData_H + +#include "Basics.h" +#include "Info.h" +#include "PythiaStdlib.h" +#include "ResonanceWidths.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// Forward reference to the ResonanceWidths class. +class ResonanceWidths; + +//************************************************************************** + +// This class holds info on a single decay channel. + +class DecayChannel { + +public: + // Constructor. + DecayChannel(int onModeIn = 0, double bRatioIn = 0., int meModeIn = 0, + int prod0 = 0, int prod1 = 0, int prod2 = 0, int prod3 = 0, + int prod4 = 0, int prod5 = 0, int prod6 = 0, int prod7 = 0) + : onModeSave(onModeIn), bRatioSave(bRatioIn), currentBRSave(0.), + meModeSave(meModeIn), nProd(0), hasChangedSave(true) { + prod[0] = prod0; prod[1] = prod1; prod[2] = prod2; prod[3] = prod3; + prod[4] = prod4; prod[5] = prod5; prod[6] = prod6; prod[7] = prod7; + for (int j = 0; j < 8; ++j) if (prod[j] != 0 && j == nProd) ++nProd; } + + // Member functions for input. + void onMode(int onModeIn) {onModeSave = onModeIn; hasChangedSave = true;} + void bRatio(double bRatioIn, bool countAsChanged = true) { + bRatioSave = bRatioIn; if (countAsChanged) hasChangedSave = true;} + void rescaleBR(double fac) {bRatioSave *= fac; hasChangedSave = true;} + void meMode(int meModeIn) {meModeSave = meModeIn; hasChangedSave = true;} + void multiplicity(int multIn) {nProd = multIn; hasChangedSave = true;} + void product(int i, int prodIn) {prod[i] = prodIn; nProd = 0; + for (int j = 0; j < 8; ++j) if (prod[j] != 0 && j == nProd) ++nProd; + hasChangedSave = true;} + void setHasChanged(bool hasChangedIn) {hasChangedSave = hasChangedIn;} + + // Member functions for output. + int onMode() const {return onModeSave;} + double bRatio() const {return bRatioSave;} + int meMode() const {return meModeSave;} + int multiplicity() const {return nProd;} + int product(int i) const {return (i >= 0 && i < nProd) ? prod[i] : 0;} + bool hasChanged() const { return hasChangedSave;} + + // Check for presence of particles anywhere in decay list. + bool contains(int id1) const; + bool contains(int id1, int id2) const; + bool contains(int id1, int id2, int id3) const; + + // Input/output for current selection of decay modes. + // Takes into account on/off switches and dynamic width for resonances. + void currentBR(double currentBRIn) {currentBRSave = currentBRIn;} + double currentBR() const {return currentBRSave;} + + // Input/output for nominal partial width; used by resonances. + void onShellWidth(double onShellWidthIn) { + onShellWidthSave = onShellWidthIn;} + double onShellWidth() const {return onShellWidthSave;} + void onShellWidthFactor(double factor) {onShellWidthSave *= factor;} + + // Input/output for fraction of secondary open widths; used by resonances. + void openSec(int idSgn, double openSecIn) { + if (idSgn > 0) openSecPos = openSecIn; else openSecNeg = openSecIn;} + double openSec(int idSgn) const { + return (idSgn > 0) ? openSecPos : openSecNeg;} + +private: + + // Decay channel info. + int onModeSave; + double bRatioSave, currentBRSave, onShellWidthSave, openSecPos, + openSecNeg; + int meModeSave, nProd, prod[8]; + bool hasChangedSave; + +}; + +//************************************************************************** + +// This class holds info on all decay channels of a particle. + +class DecayTable { + +public: + + // Constructor. + DecayTable() {} + + // Overload index operator to access a channel in the decay table. + DecayChannel& operator[](int i){return channel[i];} + const DecayChannel& operator[](int i) const {return channel[i];} + + // Add a decay channel to the decay table. + void addChannel(int onMode = 0, double bRatio = 0., int meMode = 0, + int prod0 = 0, int prod1 = 0, int prod2 = 0, int prod3 = 0, + int prod4 = 0, int prod5 = 0, int prod6 = 0, int prod7 = 0) { + channel.push_back( DecayChannel( onMode, bRatio, meMode, prod0, + prod1, prod2, prod3, prod4, prod5, prod6, prod7) ); } + + // Decay table size. + int size() const {return channel.size();} + + // Reset to empty decay table.. + void clear() {channel.resize(0);} + + // Rescale sum of branching ratios to unity. + void rescaleBR(double newSumBR = 1.); + +private: + + // A vector containing all the decay channels of the particle. + vector channel; + +}; + +//************************************************************************** + +// This class holds info on a single particle species. + +class ParticleDataEntry { + +public: + + // Constructors: for antiparticle exists or not. + ParticleDataEntry(int idIn = 0, string nameIn = " ", + int spinTypeIn = 0, int chargeTypeIn = 0, int colTypeIn = 0, + double m0In = 0., double mWidthIn = 0., double mMinIn = 0., + double mMaxIn = 0., double tau0In = 0.) : idSave(abs(idIn)), + nameSave(nameIn), antiNameSave("void"), spinTypeSave(spinTypeIn), + chargeTypeSave(chargeTypeIn), colTypeSave(colTypeIn), m0Save(m0In), + mWidthSave (mWidthIn), mMinSave(mMinIn), mMaxSave(mMaxIn), + tau0Save(tau0In), hasAntiSave(false), hasChangedSave(true), + resonancePtr(0) {setDefaults();} + ParticleDataEntry(int idIn, string nameIn, string antiNameIn, + int spinTypeIn = 0, int chargeTypeIn = 0, int colTypeIn = 0, + double m0In = 0., double mWidthIn = 0., double mMinIn = 0., + double mMaxIn = 0., double tau0In = 0.) : idSave(abs(idIn)), + nameSave(nameIn), antiNameSave(antiNameIn), spinTypeSave(spinTypeIn), + chargeTypeSave(chargeTypeIn), colTypeSave(colTypeIn), m0Save(m0In), + mWidthSave (mWidthIn), mMinSave(mMinIn), mMaxSave(mMaxIn), + tau0Save(tau0In), hasAntiSave(true), hasChangedSave(true), + resonancePtr(0) {setDefaults(); + if (toLower(antiNameIn) == "void") hasAntiSave = false;} + + // Destructor: delete any ResonanceWidths object. + ~ParticleDataEntry(); + + // Initialize static pointer to Info for error messages. + static void initPtr(Info* infoPtrIn) {infoPtr = infoPtrIn;} + + // Initialize static data members. + static void initStatic(); + + // Initialization of some particle flags. + void setDefaults(); + + // Prepare for and pick mass according to Breit-Wigner. + void initBWmass(); + double mass(); + + // Calculate running mass - for quarks only! (Else normal mass.) + double mRun(double mH); + + // Random choice of decay channel according to branching ratios. + bool preparePick(int idSgn, double mHat = 0., int idInFlav = 0); + DecayChannel& pickChannel(); + + // Change current values one at a time (or set if not set before). + // (Must use set here since else name+signature clash with get methods.) + void setName(string nameIn) {nameSave = nameIn; hasChangedSave = true;} + void setAntiName(string antiNameIn) {antiNameSave = antiNameIn; + hasChangedSave = true;} + void setSpinType(int spinTypeIn) {spinTypeSave = spinTypeIn; + hasChangedSave = true;} + void setChargeType(int chargeTypeIn) {chargeTypeSave = chargeTypeIn; + hasChangedSave = true;} + void setColType(int colTypeIn) {colTypeSave = colTypeIn; + hasChangedSave = true;} + void setM0(double m0In) {m0Save = m0In; setConstituentMass(); + hasChangedSave = true;} + void setMWidth(double mWidthIn, bool countAsChanged = true) { + mWidthSave = mWidthIn; if (countAsChanged) hasChangedSave = true;} + void setMMin(double mMinIn) {mMinSave = mMinIn; hasChangedSave = true;} + void setMMax(double mMaxIn) {mMaxSave = mMaxIn; hasChangedSave = true;} + void setTau0(double tau0In) {tau0Save = tau0In; hasChangedSave = true;} + void setIsResonance(bool isResonanceIn) {isResonanceSave = isResonanceIn; + hasChangedSave = true;} + void setMayDecay(bool mayDecayIn, bool countAsChanged = true) { + mayDecaySave = mayDecayIn; if (countAsChanged) hasChangedSave = true;} + void setDoExternalDecay(bool doExternalDecayIn) + {doExternalDecaySave = doExternalDecayIn; hasChangedSave = true;} + void setIsVisible(bool isVisibleIn) {isVisibleSave = isVisibleIn; + hasChangedSave = true;} + void setDoForceWidth(bool doForceWidthIn) {doForceWidthSave = doForceWidthIn; + hasChangedSave = true;} + + // Change several values at the same time (or set if not set before). + void setNames(string nameIn, string antiNameIn) {nameSave = nameIn; + antiNameSave = antiNameIn; hasAntiSave = true; if (toLower(antiNameIn) + == "void") hasAntiSave = false; hasChangedSave = true;} + void setAll(string nameIn, string antiNameIn, int spinTypeIn = 0, + int chargeTypeIn = 0, int colTypeIn = 0, double m0In = 0., + double mWidthIn = 0., double mMinIn = 0., double mMaxIn = 0., + double tau0In = 0.) + {nameSave = nameIn; antiNameSave = antiNameIn; hasAntiSave = true; + if (toLower(antiNameIn) == "void") hasAntiSave = false; + spinTypeSave = spinTypeIn; chargeTypeSave = chargeTypeIn; + colTypeSave = colTypeIn; m0Save = m0In; mWidthSave = mWidthIn; + mMinSave = mMinIn; mMaxSave = mMaxIn; tau0Save = tau0In; + setDefaults(); hasChangedSave = true;} + void setHasChanged(bool hasChangedIn) {hasChangedSave = hasChangedIn; + for (int i = 0; i < decay.size(); ++i) + decay[i].setHasChanged(hasChangedIn);} + void rescaleBR(double newSumBR = 1.) {decay.rescaleBR(newSumBR);} + + // Give back current values. + int id() const { return idSave; } + bool hasAnti() const { return hasAntiSave; } + string name(int idIn = 1) const { + return (idIn > 0) ? nameSave : antiNameSave; } + int spinType() const {return spinTypeSave; } + int chargeType(int idIn = 1) const { + return (idIn > 0) ? chargeTypeSave : -chargeTypeSave; } + double charge(int idIn = 1) const { + return (idIn > 0) ? chargeTypeSave / 3. : -chargeTypeSave / 3.; } + int colType(int idIn = 1) const { + if (colTypeSave == 2) return colTypeSave; + return (idIn > 0) ? colTypeSave : -colTypeSave; } + double m0() const { return m0Save; } + double constituentMass() const { return constituentMassSave; } + double mWidth() const { return mWidthSave; } + double mMin() const { return mMinSave; } + double mMax() const { return mMaxSave; } + double m0Min() const { + return (modeBWnow == 0) ? m0Save : mMinSave; } + double m0Max() const { + return (modeBWnow == 0) ? m0Save : mMaxSave; } + double tau0() const { return tau0Save; } + bool isResonance() const { return isResonanceSave; } + bool mayDecay() const { return mayDecaySave; } + bool doExternalDecay() const { return doExternalDecaySave; } + bool isVisible() const { return isVisibleSave; } + bool doForceWidth() const { return doForceWidthSave; } + + // Give back other quantities. + bool hasChanged() const { if (hasChangedSave) return true; + for (int i = 0; i < decay.size(); ++i) + if (decay[i].hasChanged()) return true; return false;} + bool useBreitWigner() const { return (modeBWnow > 0); } + bool canDecay() const { return (decay.size() > 0);} + bool isLepton() const { return (idSave > 10 && idSave < 19);} + bool isQuark() const { return (idSave != 0 && idSave < 9);} + bool isGluon() const { return (idSave == 21);} + bool isDiquark() const { return (idSave > 1000 && idSave < 10000 + && (idSave/10)%10 == 0);} + bool isHadron() const; + bool isMeson() const; + bool isBaryon() const; + + // Intermediate octet ccbar or bbar states in colour-octet model. + bool isOctetHadron() const {return (idSave == 9900441 + || idSave == 9900443 || idSave == 9900551 || idSave == 9900553 + || idSave == 9910441 || idSave == 9910551); } + int heaviestQuark(int idIn = 1) const; + int baryonNumberType(int idIn = 1) const; + + // The decay table. + DecayTable decay; + + // Access methods stored in ResonanceWidths. + void setResonancePtr(ResonanceWidths* resonancePtrIn); + ResonanceWidths* getResonancePtr() const {return resonancePtr;} + void resInit(); + double resWidth(int idSgn, double mHat, int idIn = 0, + bool openOnly = false, bool setBR = false); + double resWidthOpen(int idSgn, double mHat, int idIn = 0); + double resWidthStore(int idSgn, double mHat, int idIn = 0); + double resOpenFrac(int idSgn); + double resWidthRescaleFactor(); + double resWidthChan(double mHat, int idAbs1 = 0, int idAbs2 = 0); + +private: + + // Static initialization data, normally only set once. + static int modeBreitWigner; + static double maxEnhanceBW, mQRun[7], Lambda5Run; + + // Constants: could only be changed in the code itself. + static const int INVISIBLENUMBER, INVISIBLETABLE[29]; + static const double MAXTAU0FORDECAY,MINMASSRESONANCE, NARROWMASS, + CONSTITUENTMASSTABLE[6]; + + // Pointer to various information on the generation. + static Info* infoPtr; + + // Particle data. + int idSave; + string nameSave, antiNameSave; + int spinTypeSave, chargeTypeSave, colTypeSave; + double m0Save, mWidthSave, mMinSave, mMaxSave, tau0Save, + constituentMassSave; + bool hasAntiSave, isResonanceSave, mayDecaySave, doExternalDecaySave, + isVisibleSave, doForceWidthSave, hasChangedSave; + + // Extra data for mass selection according to a Breit-Wigner. + int modeBWnow; + double atanLow, atanDif, mThr; + + // Summed branching ratio of currently open channels. + double currentBRSum; + + // Pointer to ResonanceWidths object; only used for some particles. + ResonanceWidths* resonancePtr; + + // Set constituent mass. + void setConstituentMass(); + + // Useful functions for string handling. + static string toLower(const string& name); + +}; + +//************************************************************************** + +// This class holds a map of all ParticleDataEntries. + +class ParticleDataTable { + +public: + + // Constructor. + ParticleDataTable() {} + + // Initialize static pointer. + static void initPtr(Info* infoPtrIn) {infoPtr = infoPtrIn;} + + // Read in database from specific file. + static bool init(string startFile = "../xmldoc/ParticleData.xml") { + return readXML(startFile);} + + // Overwrite existing database by reading from specific file. + static bool reInit(string startFile, bool xmlFormat = true) { + return (xmlFormat) ? readXML(startFile) : readFF(startFile);} + + // Initialize the handling of Breit-Wigner mass selection. + static void initBWmass() { + for (map::iterator pdtEntry = pdt.begin(); + pdtEntry != pdt.end(); ++pdtEntry) pdtEntry->second.initBWmass(); } + + // Initialize the special handling of resonances in ResonanceWidths. + static void initResonances(vector resonancePtrs, + bool reInit = false); + + // Calculate a mass, picked according to Breit-Wigner. + static double mass(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].mass() : 0. ; } + + // Calculate running mass - for quarks only! (Else normal mass.) + static double mRun(int idIn, double mH) { + return isParticle(idIn) ? pdt[abs(idIn)].mRun(mH) : 0. ; } + + // Read or list whole (or part of) database from/to an XML file. + static bool readXML(string inFile, bool reset = true) ; + static void listXML(string outFile) ; + + // Read or list whole (or part of) database from/to a free format file. + static bool readFF(string inFile, bool reset = true) ; + static void listFF(string outFile) ; + + // Read in one update from a single line. + static bool readString(string lineIn, bool warn = true, + ostream& os = cout) ; + + // Print out table of whole database, or of only part of it. + static void listAll(ostream& os = cout) {list(false, true, os);} + static void listChanged(ostream& os = cout) {list(true, false, os);} + static void listChanged(bool changedRes, ostream& os = cout) + {list(true, changedRes, os);} + static void list(bool changedOnly = false, bool changedRes = true, + ostream& os = cout) ; + static void list(int idList, ostream& os = cout) { + vector idListTemp; idListTemp.push_back(idList); + list( idListTemp, os);} + static void list(vector idList, ostream& os = cout) ; + + // Check that table makes sense, especially for decays. + static void checkTable(ostream& os = cout) {checkTable(1, os);}; + static void checkTable(int verbosity, ostream& os = cout) ; + + // Add new entry. + static void addParticle(int idIn, string nameIn = " ", + int spinTypeIn = 0, int chargeTypeIn = 0, int colTypeIn = 0, + double m0In = 0., double mWidthIn = 0., double mMinIn = 0., + double mMaxIn = 0., double tau0In = 0.) + { pdt[abs(idIn)] = ParticleDataEntry(idIn, nameIn, spinTypeIn, + chargeTypeIn, colTypeIn, m0In, mWidthIn, mMinIn, mMaxIn, tau0In); } + static void addParticle(int idIn, string nameIn, string antiNameIn, + int spinTypeIn = 0, int chargeTypeIn = 0, int colTypeIn = 0, + double m0In = 0., double mWidthIn = 0., double mMinIn = 0., + double mMaxIn = 0., double tau0In = 0.) + { pdt[abs(idIn)] = ParticleDataEntry(idIn, nameIn, antiNameIn, + spinTypeIn, chargeTypeIn, colTypeIn, m0In, mWidthIn, mMinIn, + mMaxIn, tau0In); } + + // Query existence of an entry. + static bool isParticle(int idIn) { + if (pdt.find(abs(idIn)) == pdt.end()) return false; + if (idIn > 0 || pdt[abs(idIn)].hasAnti()) return true; + return false; } + + // Return pointer to entry. + static ParticleDataEntry* particleDataPtr(int idIn) { + return (isParticle(idIn)) ? &pdt[abs(idIn)] : &pdt[0]; } + + // Return the id of the sequentially next particle stored in table. + static int nextId(int idIn) ; + + // Change current values one at a time (or set if not set before). + static void name(int idIn, string nameIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setName(nameIn); } + static void antiName(int idIn, string antiNameIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setAntiName(antiNameIn); } + static void spinType(int idIn, int spinTypeIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setSpinType(spinTypeIn); } + static void chargeType(int idIn, int chargeTypeIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setChargeType(chargeTypeIn); } + static void colType(int idIn, int colTypeIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setColType(colTypeIn); } + static void m0(int idIn, double m0In) { + if (isParticle(idIn)) pdt[abs(idIn)].setM0(m0In); } + static void mWidth(int idIn, double mWidthIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setMWidth(mWidthIn); } + static void mMin(int idIn, double mMinIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setMMin(mMinIn); } + static void mMax(int idIn, double mMaxIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setMMax(mMaxIn); } + static void tau0(int idIn, double tau0In) { + if (isParticle(idIn)) pdt[abs(idIn)].setTau0(tau0In); } + static void isResonance(int idIn, bool isResonanceIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setIsResonance(isResonanceIn); } + static void mayDecay(int idIn, bool mayDecayIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setMayDecay(mayDecayIn); } + static void doExternalDecay(int idIn, bool doExternalDecayIn) { + if (isParticle(idIn)) + pdt[abs(idIn)].setDoExternalDecay(doExternalDecayIn); } + static void isVisible(int idIn, bool isVisibleIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setIsVisible(isVisibleIn); } + static void doForceWidth(int idIn, bool doForceWidthIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setDoForceWidth(doForceWidthIn); } + + // Change several values at the same time (or set if not set before). + static void names(int idIn, string nameIn, string antiNameIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setNames(nameIn, antiNameIn); } + static void setAll(int idIn, string nameIn, string antiNameIn, + int spinTypeIn = 0, int chargeTypeIn = 0, int colTypeIn = 0, + double m0In = 0., double mWidthIn = 0., double mMinIn = 0., + double mMaxIn = 0.,double tau0In = 0.) + { if (isParticle(idIn)) pdt[abs(idIn)].setAll( nameIn, antiNameIn, + spinTypeIn, chargeTypeIn, colTypeIn, m0In, mWidthIn, mMinIn, mMaxIn, + tau0In); } + static void hasChanged(int idIn, bool hasChangedIn) { + if (isParticle(idIn)) pdt[abs(idIn)].setHasChanged(hasChangedIn); } + static void rescaleBR(int idIn, double newSumBR = 1.) { + if (isParticle(idIn)) pdt[abs(idIn)].rescaleBR(newSumBR); } + + // Give back current values. + static bool hasAnti(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].hasAnti() : false ; } + static string name(int idIn) { + return (isParticle(abs(idIn))) ? pdt[abs(idIn)].name(idIn) : " "; } + static int spinType(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].spinType() : 0 ; } + static int chargeType(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].chargeType(idIn) : 0 ; } + static double charge(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].charge(idIn) : 0 ; } + static int colType(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].colType(idIn) : 0 ; } + static double m0(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].m0() : 0. ; } + static double constituentMass(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].constituentMass() : 0. ; } + static double mWidth(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].mWidth() : 0. ; } + static double mMin(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].mMin() : 0. ; } + static double m0Min(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].m0Min() : 0. ; } + static double mMax(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].mMax() : 0. ; } + static double m0Max(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].m0Max() : 0. ; } + static double tau0(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].tau0() : 0. ; } + static bool isResonance(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].isResonance() : false ; } + static bool mayDecay(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].mayDecay() : false ; } + static bool doExternalDecay(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].doExternalDecay() : false ; } + static bool isVisible(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].isVisible() : false ; } + static bool doForceWidth(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].doForceWidth() : false ; } + + // Give back other quantities. + static bool hasChanged(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].hasChanged() : false ; } + static bool useBreitWigner(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].useBreitWigner() : false ; } + static bool canDecay(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].canDecay() : false ; } + static bool isLepton(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].isLepton() : false ; } + static bool isQuark(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].isQuark() : false ; } + static bool isGluon(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].isGluon() : false ; } + static bool isDiquark(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].isDiquark() : false ; } + static bool isHadron(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].isHadron() : false ; } + static bool isMeson(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].isMeson() : false ; } + static bool isBaryon(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].isBaryon() : false ; } + static bool isOctetHadron(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].isOctetHadron() : false ; } + static int heaviestQuark(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].heaviestQuark(idIn) : 0 ; } + static int baryonNumberType(int idIn) { + return isParticle(idIn) ? pdt[abs(idIn)].baryonNumberType(idIn) : 0 ; } + + // Access methods stored in ResonanceWidths. + static void resInit(int idIn) { + if (isParticle(idIn)) pdt[abs(idIn)].resInit();} + static double resWidth(int idIn, double mHat, int idInFlav = 0, + bool openOnly = false, bool setBR = false) { + return isParticle(idIn) ? pdt[abs(idIn)].resWidth(idIn, mHat, + idInFlav, openOnly, setBR) : 0.;} + static double resWidthOpen(int idIn, double mHat, int idInFlav = 0) { + return isParticle(idIn) ? pdt[abs(idIn)].resWidthOpen(idIn, mHat, + idInFlav) : 0.;} + static double resWidthStore(int idIn, double mHat, int idInFlav = 0) { + return isParticle(idIn) ? pdt[abs(idIn)].resWidthStore(idIn, mHat, + idInFlav) : 0.;} + static double resOpenFrac(int id1In, int id2In = 0, int id3In = 0); + static double resWidthRescaleFactor(int idIn) { return isParticle(idIn) + ? pdt[abs(idIn)].resWidthRescaleFactor() : 0.;} + static double resWidthChan(int idIn, double mHat, int idAbs1 = 0, + int idAbs2 = 0) { return isParticle(idIn) + ? pdt[abs(idIn)].resWidthChan( mHat, idAbs1, idAbs2) : 0.;} + +private: + + // Pointer to various information on the generation. + static Info* infoPtr; + + // All particle data stored in a map. + static map pdt; + + // Pointer to current particle (e.g. when reading decay channels). + static ParticleDataEntry* particlePtr; + + // Flag that initialization has been performed. + static bool isInit; + + // Useful functions for string handling. + static string toLower(const string& name); + static bool boolString(string tag); + static string attributeValue(string line, string attribute); + static bool boolAttributeValue(string line, string attribute); + static int intAttributeValue(string line, string attribute); + static double doubleAttributeValue(string line, string attribute); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_ParticleData_H diff --git a/PYTHIA8/pythia8130/include/ParticleDecays.h b/PYTHIA8/pythia8130/include/ParticleDecays.h new file mode 100644 index 00000000000..0530094f0bb --- /dev/null +++ b/PYTHIA8/pythia8130/include/ParticleDecays.h @@ -0,0 +1,138 @@ +// ParticleDecays.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the classes to perform a particle decay. +// DecayHandler: base class for external handling of decays. +// ParticleDecays: decay a particle. + +#ifndef Pythia8_ParticleDecays_H +#define Pythia8_ParticleDecays_H + +#include "Basics.h" +#include "Event.h" +#include "FragmentationFlavZpT.h" +#include "Info.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" +#include "TimeShower.h" + +namespace Pythia8 { + +//************************************************************************** + +// DecayHandler is base class for the external handling of decays. +// There is only one pure virtual method, that should do the decay. + +class DecayHandler { + +public: + + // A pure virtual method, wherein the derived class method does a decay. + virtual bool decay(vector& idProd, vector& mProd, + vector& pProd, int iDec, const Event& event) = 0; + +protected: + + // Destructor. + virtual ~DecayHandler() {} + +}; + +//************************************************************************** + +// The ParticleDecays class contains the routines to decay a particle. + +class ParticleDecays { + +public: + + // Constructor. + ParticleDecays() {} + + // Initialize: store pointers and find settings + void init(Info* infoPtrIn, TimeShower* timesDecPtrIn, + StringFlav* flavSelPtrIn, DecayHandler* decayHandlePtrIn, + vector handledParticles); + + // Perform a decay of a single particle. + bool decay(int iDec, Event& event); + + // Did decay result in new partons to hadronize? + bool moreToDo() const {return hasPartons && keepPartons;} + +private: + + // Constants: could only be changed in the code itself. + static const int NTRYDECAY, NTRYPICK; + static const double MSAFEDALITZ, WTCORRECTION[11]; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointers to timelike showers, for decays to partons (e.g. Upsilon). + TimeShower* timesDecPtr; + + // Pointer to class for flavour generation; needed when to pick hadrons. + StringFlav* flavSelPtr; + + // Pointer to a handler of external decays. + DecayHandler* decayHandlePtr; + + // Initialization data, read from Settings.. + bool limitTau0, limitTau, limitRadius, limitCylinder, limitDecay, + mixB, doFSRinDecays; + double mSafety, tau0Max, tauMax, rMax, xyMax, zMax, xBdMix, xBsMix, + sigmaSoft, multIncrease, multRefMass, multGoffset, colRearrange, + stopMass, sRhoDal, wRhoDal; + + // Multiplicity. Decay products positions and masses. + bool hasPartons, keepPartons; + int idDec, meMode, mult; + vector iProd, idProd, cols, acols, idPartons; + vector mProd, mInv, rndmOrd; + vector pInv, pProd; + vector flavEnds; + + // Pointer to particle data for currently decaying particle + ParticleDataEntry* decDataPtr; + + // Check whether a decay is allowed, given the upcoming decay vertex. + bool checkVertex(Particle& decayer); + + // Check for oscillations B0 <-> B0bar or B_s0 <-> B_s0bar. + bool oscillateB(Particle& decayer); + + // Do a one-body decay. + bool oneBody(Event& event); + + // Do a two-body decay; + bool twoBody(Event& event); + + // Do a three-body decay; + bool threeBody(Event& event); + + // Do a multibody decay using the M-generator algorithm. + bool mGenerator(Event& event); + + // Select mass of lepton pair in a Dalitz decay. + bool dalitzMass(); + + // Do kinematics of gamma* -> l- l+ in Dalitz decay. + bool dalitzKinematics(Event& event); + + // Translate a partonic content into a set of actual hadrons. + bool pickHadrons(); + + // Set colour flow and scale in a decay explicitly to partons. + bool setColours(Event& event); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_ParticleDecays_H diff --git a/PYTHIA8/pythia8130/include/PartonDistributions.h b/PYTHIA8/pythia8130/include/PartonDistributions.h new file mode 100644 index 00000000000..4d7872efd02 --- /dev/null +++ b/PYTHIA8/pythia8130/include/PartonDistributions.h @@ -0,0 +1,192 @@ +// PartonDistributions.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for parton densities. +// PDF: base class. +// GRV94L: derived class for the GRV 94L parton densities. +// CTEQ5L: derived class for the CTEQ 5L parton densities. +// LHAPDFinterface: derived class for interface to the LHAPDF library. +// Lepton: derived class for parton densities inside a lepton. +// LeptonPoint: derived class for unresolved lepton (mainly dummy). + +#ifndef Pythia8_PartonDistributions_H +#define Pythia8_PartonDistributions_H + +#include "Basics.h" +#include "Info.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" + +namespace Pythia8 { + +//************************************************************************** + +// Base class for parton distribution functions. + +class PDF { + +public: + + // Constructor. + PDF(int idBeamIn = 2212) {idBeam = idBeamIn; idSav = 9; xSav = -1.; + Q2Sav = -1.; isSet = true; isInit = false;} + + // Destructor. + virtual ~PDF() {} + + // Confirm that PDF has been set up (important for LHAPDF). + bool isSetup() {return isSet;} + + // Allow extrapolation beyond boundaries. This is optional. + virtual void setExtrapolate(bool) {} + + // Read out parton density + double xf(int id, double x, double Q2); + + // Read out valence and sea part of parton densities. + double xfVal(int id, double x, double Q2); + double xfSea(int id, double x, double Q2); + +protected: + + // Store relevant quantities. + int idBeam, idSav; + double xSav, Q2Sav; + double xu, xd, xubar, xdbar, xs, xc, xb, xg, xlepton, xgamma, + xuVal, xuSea, xdVal, xdSea; + bool isSet, isInit, hasLimits; + + // Update parton densities. + virtual void xfUpdate(int id, double x, double Q2) = 0; + +}; + +//************************************************************************** + +// Gives the GRV 94 L (leading order) parton distribution function set +// in parametrized form. Authors: M. Glueck, E. Reya and A. Vogt. + +class GRV94L : public PDF { + +public: + + // Constructor. + GRV94L(int idBeamIn = 2212) : PDF(idBeamIn) {} + +private: + + // Update PDF values. + void xfUpdate(int id, double x, double Q2); + + // Auxiliary routines used during the updating. + double grvv (double x, double n, double ak, double bk, double a, + double b, double c, double d); + double grvw (double x, double s, double al, double be, double ak, + double bk, double a, double b, double c, double d, double e, double es); + double grvs (double x, double s, double sth, double al, double be, + double ak, double ag, double b, double d, double e, double es); + +}; + +//************************************************************************** + +// Gives the GRV 94 L (leading order) parton distribution function set +// in parametrized form. Authors: M. Glueck, E. Reya and A. Vogt. + +class CTEQ5L : public PDF { + +public: + + // Constructor. + CTEQ5L(int idBeamIn = 2212) : PDF(idBeamIn) {} + +private: + + // Update PDF values. + void xfUpdate(int id, double x, double Q2); + +}; + +//************************************************************************** + +// Provide interface to the LHAPDF library of parton densities. + +class LHAPDF : public PDF { + +public: + + // Constructor. + LHAPDF(int idBeamIn, string setName, int member, int nSetIn = 1, + Info* infoPtr = 0) : PDF(idBeamIn), nSet(nSetIn) + {init( setName, member, infoPtr);} + + // Allow extrapolation beyond boundaries. This is optional. + void setExtrapolate(bool extrapol); + +private: + + // Initialization of PDF set. + void init(string setName, int member, Info* infoPtr); + + // Update all PDF values. + void xfUpdate(int , double x, double Q2); + + // Current set and pdf values. + int nSet; + double xfArray[13]; + + // Keep track of latest initialized PDF, so does not have to repeat. + static string latestSetName; + static int latestMember, latestNSet; + +}; + +//************************************************************************** + +// Gives electron (or muon, or tau) parton distribution. + +class Lepton : public PDF { + +public: + + // Constructor. + Lepton(int idBeamIn = 11) : PDF(idBeamIn) {} + +private: + + // Constants: could only be changed in the code itself. + static const double ALPHAEM; + + // Update PDF values. + void xfUpdate(int id, double x, double Q2); + + // The lepton mass, set at initialization. + double m2Lep; + +}; + +//************************************************************************** + +// Gives electron (or other lepton) parton distribution when unresolved. + +class LeptonPoint : public PDF { + +public: + + // Constructor. + LeptonPoint(int idBeamIn = 11) : PDF(idBeamIn) {} + +private: + + // Update PDF values in trivial way. + void xfUpdate(int , double , double ) {xlepton = 1; xgamma = 0.;} + +}; + +} // end namespace Pythia8 + +//************************************************************************** + +#endif // Pythia8_PartonDistributions_H diff --git a/PYTHIA8/pythia8130/include/PartonLevel.h b/PYTHIA8/pythia8130/include/PartonLevel.h new file mode 100644 index 00000000000..42d05fe5932 --- /dev/null +++ b/PYTHIA8/pythia8130/include/PartonLevel.h @@ -0,0 +1,114 @@ +// PartonLevel.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the main class for parton-level event generation +// PartonLevel: administrates showers, multiple interactions and remnants. + +#ifndef Pythia8_PartonLevel_H +#define Pythia8_PartonLevel_H + +#include "Basics.h" +#include "BeamParticle.h" +#include "BeamRemnants.h" +#include "Event.h" +#include "Info.h" +#include "MultipleInteractions.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" +#include "SigmaTotal.h" +#include "SpaceShower.h" +#include "TimeShower.h" +#include "UserHooks.h" + +namespace Pythia8 { + +//************************************************************************** + +// The PartonLevel class contains the top-level routines to generate +// the partonic activity of an event. + +class PartonLevel { + +public: + + // Constructor. + PartonLevel() : userHooksPtr(0) {} + + // Initialization of all classes at the parton level. + bool init( Info* infoPtrIn, BeamParticle* beamAPtrIn, + BeamParticle* beamBPtrIn, SigmaTotal* sigmaTotPtr, + TimeShower* timesDecPtrIn, TimeShower* timesPtrIn, + SpaceShower* spacePtrIn, UserHooks* userHooksPtrIn); + + // Generate the next parton-level process. + bool next( Event& process, Event& event); + + // Tell whether failure was due to vetoing. + bool hasVetoed() const {return doVeto;} + + // Accumulate and print statistics. + void accumulate() {multi.accumulate();} + void statistics(bool reset = false) {if (doMI) multi.statistics(reset);} + +private: + + // Constants: could only be changed in the code itself. + static const int NTRY; + + // Initialization data, mainly read from Settings. + bool doMI, doISR, doFSRduringProcess, doFSRafterProcess, + doFSRinResonances, doRemnants, doSecondHard, doMIinit, + hasLeptonBeams, hasPointLeptons, canVetoPT, canVetoStep; + + // Event generation strategy. Number of steps. Maximum pT scales. + bool doVeto; + int nMI, nISR, nFSRinProc, nFSRinRes, nISRhard, nFSRhard, + typeLatest, nVetoStep, typeVetoStep, iSysNow; + double pTsaveMI, pTsaveISR, pTsaveFSR, pTvetoPT; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointers to the two incoming beams. + BeamParticle* beamAPtr; + BeamParticle* beamBPtr; + + // Pointer to userHooks object for user interaction with program. + UserHooks* userHooksPtr; + + // Pointers to timelike showers for resonance decays and the rest. + TimeShower* timesDecPtr; + TimeShower* timesPtr; + + // Pointer to spacelike showers. + SpaceShower* spacePtr; + + // The generator class for multiple interactions. + MultipleInteractions multi; + + // The generator class to construct beam-remnant kinematics. + BeamRemnants remnants; + + // Set up the hard process, excluding subsequent resonance decays. + void setupHardSys( Event& process, Event& event); + // Keep track of how much of hard process has been handled. + int nHardDone; + + // Set up an unresolved process, i.e. elastic or diffractive. + bool setupUnresolvedSys( Event& process, Event& event); + + // Perform showers in resonance decay chains. + int resonanceShowers( Event& process, Event& event); + // Position in main event record of hard partons before showers. + vector iPosBefShow; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_PartonLevel_H diff --git a/PYTHIA8/pythia8130/include/PhaseSpace.h b/PYTHIA8/pythia8130/include/PhaseSpace.h new file mode 100644 index 00000000000..7fc394240c6 --- /dev/null +++ b/PYTHIA8/pythia8130/include/PhaseSpace.h @@ -0,0 +1,458 @@ +// PhaseSpace.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for phase space generators in kinematics selection. +// PhaseSpace: base class for phase space generators. +// Base class for derived classes> 2 ->1 , 2 -> 2, 2 -> 2 elastic/diffractive, +// 2 -> 2 minbias, 2 -> 3, Les Houches. + +#ifndef Pythia8_PhaseSpace_H +#define Pythia8_PhaseSpace_H + +#include "Basics.h" +#include "BeamParticle.h" +#include "Info.h" +#include "LesHouches.h" +#include "MultipleInteractions.h" +#include "ParticleData.h" +#include "PartonDistributions.h" +#include "PythiaStdlib.h" +#include "SigmaProcess.h" +#include "SigmaTotal.h" +#include "Settings.h" +#include "UserHooks.h" + +namespace Pythia8 { + +//************************************************************************** + +// Forward reference to the UserHooks class. +class UserHooks; + +//************************************************************************** + +// PhaseSpace is a base class for phase space generators +// used in the selection of hard-process kinematics. + +class PhaseSpace { + +public: + + // Destructor. + virtual ~PhaseSpace() {} + + // Perform simple initialization and store pointers. + void init(SigmaProcess* sigmaProcessPtrIn, Info* infoPtrIn, + BeamParticle* beamAPtrIn, BeamParticle* beamBPtrIn, + SigmaTotal* sigmaTotPtrIn, UserHooks* userHooksPtrIn); + + // Update the CM energy of the event. + void newECM(double eCMin) {eCM = eCMin; s = eCM * eCM;} + + // Store or replace Les Houches pointer. + void setLHAPtr(LHAup* lhaUpPtrIn) {lhaUpPtr = lhaUpPtrIn;} + + // A pure virtual method, wherein an optimization procedure + // is used to determine how phase space should be sampled. + virtual bool setupSampling() = 0; + + // A pure virtual method, wherein a trial event kinematics + // is to be selected in the derived class + virtual bool trialKin(bool inEvent = true, bool repeatSame = false) = 0; + + // A pure virtual method, wherein the accepted event kinematics + // is to be constructed in the derived class + virtual bool finalKin() = 0; + + // Allow for nonisotropic decays when ME's available. + void decayKinematics( Event& process); + + // Give back current or maximum cross section, or set latter. + double sigmaNow() const {return sigmaNw;} + double sigmaMax() const {return sigmaMx;} + bool newSigmaMax() const {return newSigmaMx;} + void setSigmaMax(double sigmaMaxIn) {sigmaMx = sigmaMaxIn;} + + // For Les Houches with negative event weight needs + virtual double sigmaSumSigned() const {return sigmaMx;} + + // Give back constructed four-vectors and known masses. + Vec4 p(int i) const {return pH[i];} + double m(int i) const {return mH[i];} + + // Give back other event properties. + double ecm() const {return eCM;} + double x1() const {return x1H;} + double x2() const {return x2H;} + double sHat() const {return sH;} + double tHat() const {return tH;} + double uHat() const {return uH;} + double pTHat() const {return pTH;} + double thetaHat() const {return theta;} + double phiHat() const {return phi;} + double runBW3() const {return runBW3H;} + double runBW4() const {return runBW4H;} + double runBW5() const {return runBW5H;} + + // Inform whether beam particles are resolved in partons or scatter directly. + virtual bool isResolved() const {return true;} + +protected: + + // Constructor. + PhaseSpace() {} + + // Constants: could only be changed in the code itself. + static const int NMAXTRY, NTRY3BODY; + static const double SAFETYMARGIN, TINY, EVENFRAC, SAMESIGMA, WIDTHMARGIN, + SAMEMASS, MASSMARGIN, EXTRABWWTMAX, THRESHOLDSIZE, + THRESHOLDSTEP, YRANGEMARGIN, LEPTONXMIN, LEPTONXMAX, + LEPTONXLOGMIN, LEPTONXLOGMAX, LEPTONTAUMIN, + SHATMINZ, PT2RATMINZ, WTCORRECTION[11]; + + // Pointer to cross section. + SigmaProcess* sigmaProcessPtr; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointers to incoming beams. + BeamParticle* beamAPtr; + BeamParticle* beamBPtr; + + // Pointer to the total/elastic/diffractive cross section object. + SigmaTotal* sigmaTotPtr; + + // Pointer to userHooks object for user interaction with program. + UserHooks* userHooksPtr; + + // Pointer to LHAup for generating external events. + LHAup* lhaUpPtr; + + // Initialization data, normally only set once. + bool useBreitWigners, doEnergySpread, showSearch, showViolation; + int gmZmodeGlobal; + double mHatGlobalMin, mHatGlobalMax, pTHatGlobalMin, pTHatGlobalMax, + pTHatMinDiverge, minWidthBreitWigners; + + // Information on incoming beams. + int idA, idB; + double mA, mB, eCM, s; + bool hasLeptonBeams, hasPointLeptons; + // Cross section information. + bool newSigmaMx, canModifySigma; + int gmZmode; + double wtBW, sigmaNw, sigmaMx, sigmaNeg; + + // Process-specific kinematics properties, almost always available. + double mHatMin, mHatMax, sHatMin, sHatMax, pTHatMin, pTHatMax, + pT2HatMin, pT2HatMax; + + // Event-specific kinematics properties, almost always available. + double x1H, x2H, m3, m4, m5, s3, s4, s5, mHat, sH, tH, uH, pAbs, p2Abs, + pTH, theta, phi, betaZ; + Vec4 pH[6]; + double mH[6]; + + // Reselect decay products momenta isotropically in phase space. + void decayKinematicsStep( Event& process, int iRes); + + // Much common code for normal 2 -> 1, 2 -> 2 and 2 -> 3 cases: + + // Determine how phase space should be sampled. + void setup3Body(); + bool setupSampling123(bool is2, bool is3, ostream& os = cout); + + // Select a trial kinematics phase space point. + bool trialKin123(bool is2, bool is3, bool inEvent = true, ostream& os = cout); + + // Presence and properties of any s-channel resonances. + int idResA, idResB; + double mResA, mResB, GammaResA, GammaResB, tauResA, tauResB, widResA, + widResB; + bool sameResMass; + + // Kinematics properties specific to 2 -> 1/2/3. + bool useMirrorWeight; + double tau, y, z, tauMin, tauMax, yMax, zMin, zMax, ratio34, unity34, + zNeg, zPos, wtTau, wtY, wtZ, wt3Body, runBW3H, runBW4H, runBW5H, + intTau0, intTau1, intTau2, intTau3, intTau4, intTau5, intTau6, + intY01, intY2, intY34, mTchan1, sTchan1, mTchan2, sTchan2, + frac3Flat, frac3Pow1, frac3Pow2; + Vec4 p3cm, p4cm, p5cm; + + // Coefficients for optimized selection in 2 -> 1/2/3. + int nTau, nY, nZ; + double tauCoef[8], yCoef[8], zCoef[8], tauCoefSum[8], yCoefSum[8], + zCoefSum[8]; + + // Calculate kinematical limits for 2 -> 1/2/3. + bool limitTau(bool is2, bool is3); + bool limitY(); + bool limitZ(); + + // Select kinematical variable between defined limits for 2 -> 1/2/3. + void selectTau(int iTau, double tauVal, bool is2); + void selectY(int iY, double yVal); + void selectZ(int iZ, double zVal); + bool select3Body(); + + // Solve equation system for better phase space coefficients in 2 -> 1/2/3. + void solveSys( int n, int bin[8], double vec[8], double mat[8][8], + double coef[8], ostream& os = cout); + + // Properties specific to resonance mass selection in 2 -> 2 and 2 -> 3. + bool useBW[6]; + int idMass[6]; + double mPeak[6], sPeak[6], mWidth[6], mMin[6], mMax[6], mw[6], wmRat[6], + mLower[6], mUpper[6], sLower[6], sUpper[6], fracFlat[6], fracInv[6], + fracInv2[6], atanLower[6], atanUpper[6], intBW[6], intFlat[6], + intInv[6], intInv2[6]; + + // Setup mass selection for one resonance at a time. Split in two parts. + void setupMass1(int iM); + void setupMass2(int iM, double distToThresh); + + // Do mass selection and find the associated weight. + void trialMass(int iM); + double weightMass(int iM); + +}; + +//************************************************************************** + +// A derived class with 2 -> 1 kinematics set up in tau, y. + +class PhaseSpace2to1tauy : public PhaseSpace { + +public: + + // Constructor. + PhaseSpace2to1tauy() {} + + // Optimize subsequent kinematics selection. + virtual bool setupSampling() {if (!setupMass()) return false; + return setupSampling123(false, false);} + + // Construct the trial kinematics. + virtual bool trialKin(bool inEvent = true, bool = false) {wtBW = 1.; + return trialKin123(false, false, inEvent);} + + // Construct the final event kinematics. + virtual bool finalKin(); + +private: + + // Set up allowed mass range. + bool setupMass(); + +}; + +//************************************************************************** + +// A derived class with 2 -> 2 kinematics set up in tau, y, z = cos(theta). + +class PhaseSpace2to2tauyz : public PhaseSpace { + +public: + + // Constructor. + PhaseSpace2to2tauyz() {} + + // Optimize subsequent kinematics selection. + virtual bool setupSampling() {if (!setupMasses()) return false; + return setupSampling123(true, false);} + + // Construct the trial kinematics. + virtual bool trialKin(bool inEvent = true, bool = false) { + if (!trialMasses()) return false; + return trialKin123(true, false, inEvent);} + + // Construct the final event kinematics. + virtual bool finalKin(); + +private: + + // Set up for fixed or Breit-Wigner mass selection. + bool setupMasses(); + + // Select fixed or Breit-Wigner-distributed masses. + bool trialMasses(); + + // Pick off-shell initialization masses when on-shell not allowed. + bool constrainedM3M4(); + bool constrainedM3(); + bool constrainedM4(); + +}; + +//************************************************************************** + +// A derived class with 2 -> 2 kinematics set up for elastic scattering. + +class PhaseSpace2to2elastic : public PhaseSpace { + +public: + + // Constructor. + PhaseSpace2to2elastic() {} + + // Construct the trial or final event kinematics. + virtual bool setupSampling(); + virtual bool trialKin(bool inEvent = true, bool = false); + virtual bool finalKin(); + + // Are beam particles resolved in partons or scatter directly? + virtual bool isResolved() const {return false;} + +private: + + // Constants: could only be changed in the code itself. + static const double EXPMAX, CONVERTEL; + + // Kinematics properties specific to 2 -> 2 elastic. + bool useCoulomb; + double s1, s2, bSlope, lambda12S, tLow, tUpp, tAux, sigmaTot, rho, + lambda, tAbsMin, phaseCst, alphaEM0, sigmaNuc, sigmaCou, signCou; + + // Calculation of alphaElectromagnetic. + AlphaEM alphaEM; + +}; + +//************************************************************************** + +// A derived class with 2 -> 2 kinematics set up for diffractive scattering. + +class PhaseSpace2to2diffractive : public PhaseSpace { + +public: + + // Constructor. + PhaseSpace2to2diffractive(bool isDiffAin = false, bool isDiffBin = false) + : isDiffA(isDiffAin), isDiffB(isDiffBin) {} + + // Construct the trial or final event kinematics. + virtual bool setupSampling(); + virtual bool trialKin(bool inEvent = true, bool = false); + virtual bool finalKin(); + + // Are beam particles resolved in partons or scatter directly? + virtual bool isResolved() const {return false;} + +private: + + // Constants: could only be changed in the code itself. + static const int NTRY; + static const double EXPMAX, DIFFMASSMAX; + + // Kinematics properties specific to 2 -> 2 diffractive. + bool isDiffA, isDiffB; + double m3ElDiff, m4ElDiff, cRes, sResXB, sResAX, sProton, + s1, s2, bMin, lambda12, lambda34, tLow, tUpp, tAux; + +}; + +//************************************************************************** + +// A derived class for minumum bias events. Hardly does anything, since +// the real action is taken care of by the MultipleInteractions class. + +class PhaseSpace2to2minbias : public PhaseSpace { + +public: + + // Constructor. + PhaseSpace2to2minbias() {} + + // Construct the trial or final event kinematics. + virtual bool setupSampling() {sigmaNw = sigmaProcessPtr->sigmaHat(); + sigmaMx = sigmaNw; return true;} + virtual bool trialKin( bool , bool = false) {return true;} + virtual bool finalKin() {return true;} + +private: + +}; + +//************************************************************************** + +// A derived class with 2 -> 3 kinematics 1 + 2 -> 3 + 4 + 5 set up in +// tau, y, pT2_4, pT2_5, phi_4, phi_5 and y_3 (partial cylindrical symmetry). + +class PhaseSpace2to3tauycyl : public PhaseSpace { + +public: + + // Constructor. + PhaseSpace2to3tauycyl() {} + + // Optimize subsequent kinematics selection. + virtual bool setupSampling() {if (!setupMasses()) return false; + setup3Body(); return setupSampling123(false, true);} + + // Construct the trial kinematics. + virtual bool trialKin(bool inEvent = true, bool = false) { + if (!trialMasses()) return false; + return trialKin123(false, true, inEvent);} + + // Construct the final event kinematics. + virtual bool finalKin(); + +private: + + // Constants: could only be changed in the code itself. + static const int NITERNR; + + // Set up for fixed or Breit-Wigner mass selection. + bool setupMasses(); + + // Select fixed or Breit-Wigner-distributed masses. + bool trialMasses(); + +}; + +//************************************************************************** + +// A derived class for Les Houches events. + +class PhaseSpaceLHA : public PhaseSpace { + +public: + + // Constructor. + PhaseSpaceLHA() {idProcSave = 0;} + + // Find maximal cross section for comparison with internal processes. + virtual bool setupSampling(); + + // Construct the next process, by interface to Les Houches class. + virtual bool trialKin( bool , bool repeatSame = false); + + // Dummy, since kinematics available in Les Houches object. + virtual bool finalKin() {return true;} + + // For Les Houches with negative event weight needs + virtual double sigmaSumSigned() const {return sigmaSgn;} + +private: + + // Constants. + static const double CONVERTPB2MB; + + // Local properties. + int strategy, stratAbs, nProc, idProcSave; + double xMaxAbsSum, xSecSgnSum, sigmaSgn; + vector idProc; + vector xMaxAbsProc; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_PhaseSpace_H + diff --git a/PYTHIA8/pythia8130/include/ProcessContainer.h b/PYTHIA8/pythia8130/include/ProcessContainer.h new file mode 100644 index 00000000000..eb4f38b9a23 --- /dev/null +++ b/PYTHIA8/pythia8130/include/ProcessContainer.h @@ -0,0 +1,164 @@ +// ProcessContainer.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the collected machinery of a process. +// ProcessContainer: contains information on a particular process. +// SetupContainers: administrates the selection/creation of processes. + +#ifndef Pythia8_ProcessContainer_H +#define Pythia8_ProcessContainer_H + +#include "Basics.h" +#include "BeamParticle.h" +#include "Event.h" +#include "Info.h" +#include "ParticleData.h" +#include "PartonDistributions.h" +#include "PhaseSpace.h" +#include "PythiaStdlib.h" +#include "ResonanceDecays.h" +#include "Settings.h" +#include "SigmaProcess.h" +#include "SigmaTotal.h" +#include "SusyLesHouches.h" +#include "UserHooks.h" + +namespace Pythia8 { + +//************************************************************************** + +// The ProcessContainer class combines pointers to matrix element and +// phase space generator with general generation info. + +class ProcessContainer { + +public: + + // Constructor. + ProcessContainer(SigmaProcess* sigmaProcessPtrIn = 0) + : sigmaProcessPtr(sigmaProcessPtrIn), phaseSpacePtr(0) {} + + // Destructor. + ~ProcessContainer() {delete phaseSpacePtr; delete sigmaProcessPtr;} + + // Initialize phase space and counters. + bool init(Info* infoPtrIn, BeamParticle* beamAPtr, BeamParticle* beamBPtr, + AlphaStrong* alphaSPtr, AlphaEM* alphaEMPtr, SigmaTotal* sigmaTotPtr, + ResonanceDecays* resDecaysPtrIn, SusyLesHouches* slhaPtr, + UserHooks* userHooksPtr); + + // Store or replace Les Houches pointer. + void setLHAPtr( LHAup* lhaUpPtrIn) {lhaUpPtr = lhaUpPtrIn; + if (sigmaProcessPtr > 0) sigmaProcessPtr->setLHAPtr(lhaUpPtr); + if (phaseSpacePtr > 0) phaseSpacePtr->setLHAPtr(lhaUpPtr);} + + // Update the CM energy of the event. + void newECM(double eCM) {phaseSpacePtr->newECM(eCM);} + + // Generate a trial event; accepted or not. + bool trialProcess(); + + // Give the hard subprocess (with option for a second hard subprocess). + bool constructProcess( Event& process, bool isHardest = true); + + // Do resonance decays. + bool decayResonances( Event& process); + + // Accumulate statistics after user veto. + void accumulate() {++nAcc;} + + // Reset statistics on events generated so far. + void reset(); + + // Process name and code, and the number of final-state particles. + string name() const {return sigmaProcessPtr->name();} + int code() const {return sigmaProcessPtr->code();} + int nFinal() const {return sigmaProcessPtr->nFinal();} + + // Member functions for info on generation process. + bool newSigmaMax() const {return newSigmaMx;} + double sigmaMax() const {return sigmaMx;} + long nTried() const {return nTry;} + long nSelected() const {return nSel;} + long nAccepted() const {return nAcc;} + double sigmaSelMC() {if (nTry > nTryStat) sigmaDelta(); return sigmaAvg;} + double sigmaMC() {if (nTry > nTryStat) sigmaDelta(); return sigmaFin;} + double deltaMC() {if (nTry > nTryStat) sigmaDelta(); return deltaFin;} + + // Some kinematics quantities. + int id1() const {return sigmaProcessPtr->id(1);} + int id2() const {return sigmaProcessPtr->id(2);} + double x1() const {return phaseSpacePtr->x1();} + double x2() const {return phaseSpacePtr->x2();} + double Q2Fac() const {return sigmaProcessPtr->Q2Fac();} + + // Tell whether container is for Les Houches events. + bool isLHAContainer() const {return isLHA;} + + // When two hard processes set or get info whether process is matched. + void isSame( bool isSameIn) { isSameSave = isSameIn;} + bool isSame() const {return isSameSave;} + +private: + + // Constants: could only be changed in the code itself. + static const int N12SAMPLE, N3SAMPLE; + + // Pointer to the subprocess matrix element. + SigmaProcess* sigmaProcessPtr; + + // Pointer to the phase space generator. + PhaseSpace* phaseSpacePtr; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointer to ResonanceDecays object for sequential resonance decays. + ResonanceDecays* resDecaysPtr; + + // Pointer to LHAup for generating external events. + LHAup* lhaUpPtr; + + // Info on process. + bool isMinBias, isResolved, isDiffA, isDiffB, isLHA, allowNegSig, + hasOctetOnium, isSameSave; + int lhaStrat, lhaStratAbs; + + // Statistics on generation process. (Long integers just in case.) + int newSigmaMx; + long nTry, nSel, nAcc, nTryStat; + double sigmaMx, sigmaSgn, sigmaSum, sigma2Sum, sigmaNeg, sigmaAvg, + sigmaFin, deltaFin; + + // Estimate integrated cross section and its uncertainty. + void sigmaDelta(); + +}; + +//************************************************************************** + +// The SetupContainers class turns the list of user-requested processes +// into a vector of ProcessContainer objects, each with a process. + +class SetupContainers { + +public: + + // Constructor. + SetupContainers() {} + + // Initialization assuming all necessary data already read. + bool init(vector& containerPtrs); + + // Initialization of a second hard process. + bool init2(vector& container2Ptrs); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_ProcessContainer_H diff --git a/PYTHIA8/pythia8130/include/ProcessLevel.h b/PYTHIA8/pythia8130/include/ProcessLevel.h new file mode 100644 index 00000000000..d351287f324 --- /dev/null +++ b/PYTHIA8/pythia8130/include/ProcessLevel.h @@ -0,0 +1,135 @@ +// ProcessLevel.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the main class for process-level event generation. +// ProcessLevel: administrates the selection of "hard" process. + +#ifndef Pythia8_ProcessLevel_H +#define Pythia8_ProcessLevel_H + +#include "Basics.h" +#include "BeamParticle.h" +#include "Event.h" +#include "Info.h" +#include "ParticleData.h" +#include "PartonDistributions.h" +#include "ProcessContainer.h" +#include "PythiaStdlib.h" +#include "ResonanceDecays.h" +#include "Settings.h" +#include "SigmaTotal.h" +#include "SusyLesHouches.h" +#include "UserHooks.h" + +namespace Pythia8 { + +//************************************************************************** + +// The ProcessLevel class contains the top-level routines to generate +// the characteristic "hard" process of an event. + +class ProcessLevel { + +public: + + // Constructor. + ProcessLevel() : iLHACont(-1) {} + + // Destructor to delete processes in containers. + ~ProcessLevel(); + + // Initialization. + bool init( Info* infoPtrIn, BeamParticle* beamAPtrIn, + BeamParticle* beamBPtrIn, SigmaTotal* sigmaTotPtrIn, bool doLHAin, + SusyLesHouches* slhaPtrIn, UserHooks* userHooksPtrIn, + vector& sigmaPtrs, ostream& os = cout); + + // Store or replace Les Houches pointer. + void setLHAPtr( LHAup* lhaUpPtrIn) {lhaUpPtr = lhaUpPtrIn; + if (iLHACont >= 0) containerPtrs[iLHACont]->setLHAPtr(lhaUpPtr);} + + // Generate the next "hard" process. + bool next( Event& process); + + // Accumulate and update statistics (after possible user veto). + void accumulate(); + + // Print statistics on cross sections and number of events. + void statistics(bool reset = false, ostream& os = cout); + + // Add any junctions to the process event record list. + void findJunctions( Event& junEvent); + +private: + + // Generic info for process generation. + bool doSecondHard, allHardSame, noneHardSame, someHardSame, doResDecays; + int nImpact, startColTag2; + double sigmaND, sumImpactFac, sum2ImpactFac; + + // Vector of containers of internally-generated processes. + vector containerPtrs; + int iContainer, iLHACont; + double sigmaMaxSum; + + // Ditto for optional choice of a second hard process. + vector container2Ptrs; + int i2Container; + double sigma2MaxSum; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointers to the two incoming beams. + BeamParticle* beamAPtr; + BeamParticle* beamBPtr; + + // Pointer to SigmaTotal object needed to handle soft QCD processes. + SigmaTotal* sigmaTotPtr; + + // Pointer to SusyLesHouches object for interface to SUSY spectra. + SusyLesHouches* slhaPtr; + + // Pointer to userHooks object for user interaction with program. + UserHooks* userHooksPtr; + + // Pointer to LHAup for generating external events. + LHAup* lhaUpPtr; + + // Common alphaStrong and alphaElectromagnetic calculation for SigmaProcess. + AlphaStrong alphaS; + AlphaEM alphaEM; + + // Initialization routine for SUSY spectra. + bool initSLHA(); + + // ResonanceDecay object does sequential resonance decays. + ResonanceDecays resonanceDecays; + + // Generate the next event with one interaction. + bool nextOne( Event& process); + + // Generate the next event with two hard interactions. + bool nextTwo( Event& process); + + // Append the second to the first process list. + void combineProcessRecords( Event& process, Event& process2); + + // Check that colours match up. + bool checkColours( Event& process); + + // Print statistics when two hard processes allowed. + void statistics2(bool reset, ostream& os = cout); + + // Statistics for Les Houches event classification. + vector codeLHA, nEvtLHA; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_ProcessLevel_H diff --git a/PYTHIA8/pythia8130/include/Pythia.h b/PYTHIA8/pythia8130/include/Pythia.h new file mode 100644 index 00000000000..8e67e3edf12 --- /dev/null +++ b/PYTHIA8/pythia8130/include/Pythia.h @@ -0,0 +1,263 @@ +// Pythia.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the main class for event generation. +// Pythia: provide the main user interface to everything else. + +#ifndef Pythia8_Pythia_H +#define Pythia8_Pythia_H + +#include "Analysis.h" +#include "Basics.h" +#include "BeamParticle.h" +#include "BeamShape.h" +#include "Event.h" +#include "FragmentationFlavZpT.h" +#include "HadronLevel.h" +#include "Info.h" +#include "LesHouches.h" +#include "PartonLevel.h" +#include "ParticleData.h" +#include "PartonDistributions.h" +#include "ProcessLevel.h" +#include "PythiaStdlib.h" +#include "ResonanceWidths.h" +#include "Settings.h" +#include "SigmaTotal.h" +#include "SpaceShower.h" +#include "SusyLesHouches.h" +#include "TimeShower.h" +#include "UserHooks.h" + +namespace Pythia8 { + +//************************************************************************** + +// The Pythia class contains the top-level routines to generate an event. + +class Pythia { + +public: + + // Constructor. (See Pythia.cc file.) + Pythia(string xmlDir = "../xmldoc"); + + // Destructor. (See Pythia.cc file.) + ~Pythia(); + + // Read in one update for a setting or particle data from a single line. + bool readString(string, bool warn = true); + + // Read in updates for settings or particle data from user-defined file. + bool readFile(string, bool warn = true, int subrun = SUBRUNDEFAULT); + bool readFile(string fileName, int subrun) { + return readFile(fileName, true, subrun);} + + // Possibility to pass in pointers to PDF's. + bool setPDFPtr( PDF* pdfAPtrIn, PDF* pdfBPtrIn, PDF* pdfHardAPtrIn = 0, + PDF* pdfHardBPtrIn = 0); + + // Possibility to pass in pointer for external handling of some decays. + bool setDecayPtr( DecayHandler* decayHandlePtrIn, + vector handledParticlesIn) {decayHandlePtr = decayHandlePtrIn; + handledParticles.resize(0); + for(int i = 0; i < int(handledParticlesIn.size()); ++i) + handledParticles.push_back( handledParticlesIn[i] ); return true;} + + // Possibility to pass in pointer for external random number generation. + bool setRndmEnginePtr( RndmEngine* rndmEnginePtrIn) + { return Rndm::rndmEnginePtr( rndmEnginePtrIn);} + + // Possibility to pass in pointer for user hooks. + bool setUserHooksPtr( UserHooks* userHooksPtrIn) + { userHooksPtr = userHooksPtrIn; return true;} + + // Possibility to pass in pointer for beam shape. + bool setBeamShapePtr( BeamShape* beamShapePtrIn) + { beamShapePtr = beamShapePtrIn; return true;} + + // Possibility to pass in pointer(s) for external cross section. + bool setSigmaPtr( SigmaProcess* sigmaPtrIn) + { sigmaPtrs.push_back( sigmaPtrIn); return true;} + + // Possibility to pass in pointer(s) for external resonance. + bool setResonancePtr( ResonanceWidths* resonancePtrIn) + { resonancePtrs.push_back( resonancePtrIn); return true;} + + // Possibility to pass in pointer for external showers. + bool setShowerPtr( TimeShower* timesDecPtrIn, + TimeShower* timesPtrIn = 0, SpaceShower* spacePtrIn = 0) + { timesDecPtr = timesDecPtrIn; timesPtr = timesPtrIn; + spacePtr = spacePtrIn; return true;} + + // Initialization in the CM frame. + bool init( int idAin, int idBin, double eCMin); + + // Initialization with two collinear beams, including fixed target. + bool init( int idAin, int idBin, double eAin, double eBin); + + // Initialization with two acollinear beams. + bool init( int idAin, int idBin, double pxAin, double pyAin, + double pzAin, double pxBin, double pyBin, double pzBin); + + // Initialization by a Les Houches Event File. + bool init( string LesHouchesEventFile, bool skipInit = false); + + // Initialization using the Main beam variables. + bool init(); + + // Initialization according to the Les Houches Accord. + bool init( LHAup* lhaUpPtrIn); + + // Generate the next event. + bool next(); + + // Generate only the hadronization/decay stage. + bool forceHadronLevel(); + + // Special routine to allow more decays if on/off switches changed. + bool moreDecays() {return hadronLevel.moreDecays(event);} + + // List the current Les Houches event. + void LHAeventList(ostream& os = cout) {lhaUpPtr->listEvent(os);} + + // Main routine to provide final statistics on generation. + void statistics(bool all = false, bool reset = true); + + // Read in settings values: shorthand, not new functionality. + bool flag(string key) {return settings.flag(key);} + int mode(string key) {return settings.mode(key);} + double parm(string key) {return settings.parm(key);} + string word(string key) {return settings.word(key);} + + // The event record for the parton-level central process. + Event process; + + // The event record for the complete event history. + Event event; + + // Information on the generation: current subprocess and error statistics. + Info info; + + // Settings - is static but declared here for ease of use. + Settings settings; + + // ParticleDataTable - is static but declared here for ease of use. + ParticleDataTable particleData; + + // SusyLesHouches - SLHA object for interface to SUSY spectra. + SusyLesHouches slha; + +private: + + // Constants: could only be changed in the code itself. + static const int NTRY, SUBRUNDEFAULT; + + // Initialization data, extracted from database. + bool doProcessLevel, doPartonLevel, doHadronLevel, checkEvent; + int nErrList; + double epTolErr, epTolWarn; + + // Initialization data, extracted from init(...) call. + bool isConstructed, isInit; + int idA, idB, frameType; + double mA, mB, pxA, pxB, pyA, pyB, pzA, pzB, eA, eB, + pzAcm, pzBcm, eCM, betaZ, gammaZ; + Vec4 pAinit, pBinit, pAnow, pBnow; + RotBstMatrix MfromCM, MtoCM; + + // information for error checkout. + int nErrEvent; + vector iErrId, iErrCol, iErrNan; + + // Pointers to the parton distributions of the two incoming beams. + PDF* pdfAPtr; + PDF* pdfBPtr; + + // Extra PDF pointers to be used in hard processes only. + PDF* pdfHardAPtr; + PDF* pdfHardBPtr; + + // Keep track when "new" has been used and needs a "delete" for PDF's. + bool useNewPdfA, useNewPdfB, useNewPdfHard; + + // The two incoming beams. + BeamParticle beamA; + BeamParticle beamB; + + // LHAup object for generating external events. + bool doLHA, useNewLHA; + LHAup* lhaUpPtr; + + // Pointer to external decay handler and list of particles it handles. + DecayHandler* decayHandlePtr; + vector handledParticles; + + // Pointer to UserHooks object for user interaction with program. + UserHooks* userHooksPtr; + bool hasUserHooks, doVetoProcess, doVetoPartons; + + // Pointer to BeamShape object for beam momentum and interaction vertex. + BeamShape* beamShapePtr; + bool useNewBeamShape, doMomentumSpread, doVertexSpread; + + // Pointers to external processes derived from the Pythia base classes. + vector sigmaPtrs; + + // Pointers to external calculation of resonance widths. + vector resonancePtrs; + + // Pointers to timelike and spacelike showers. + TimeShower* timesDecPtr; + TimeShower* timesPtr; + SpaceShower* spacePtr; + bool useNewTimes, useNewSpace; + + // The main generator class to define the core process of the event. + ProcessLevel processLevel; + + // The main generator class to produce the parton level of the event. + PartonLevel partonLevel; + + // The main generator class to produce the hadron level of the event. + HadronLevel hadronLevel; + + // The total cross section class is used both on process and parton level. + SigmaTotal sigmaTot; + + // Write the Pythia banner, with symbol and version information. + void banner(ostream& os = cout); + + // Check for lines in file that mark the beginning of new subrun. + int readSubrun(string line, bool warn = true, ostream& os = cout); + + // Initialization routine to set up the whole generation machinery. + bool initInternal(); + + // Calculate kinematics at initialization. + bool initKinematics(); + + // Initialize tunes to e+e- and pp/ppbar data. + void initTunes(); + + // Recalculate kinematics for each event when beam momentum has a spread. + void nextKinematics(); + + // Boost from CM frame to lab frame, or inverse. Set production vertex. + void boostAndVertex(bool toLab, bool setVertex); + + // Check that the final event makes sense. + bool check(ostream& os = cout); + + // Auxiliary to set parton densities among list of possibilities. + PDF* getPDFPtr(int idIn, int sequence = 1); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_Pythia_H diff --git a/PYTHIA8/pythia8130/include/Pythia6Interface.h b/PYTHIA8/pythia8130/include/Pythia6Interface.h new file mode 100644 index 00000000000..10fa0ec72b2 --- /dev/null +++ b/PYTHIA8/pythia8130/include/Pythia6Interface.h @@ -0,0 +1,78 @@ +// Pythia6Interface.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for the Pythia 6.4 f77 external linkage to C++. +// All required code is contained here, i.e. there is no matching .cc file. + +#ifndef Pythia8_Pythia6Interface_H +#define Pythia8_Pythia6Interface_H + +namespace Pythia8 { + +//************************************************************************** + +// Declare the f77 subroutines that may be used. + +extern "C" { + + extern void pygive_(const char*, int); + + extern void pyinit_(const char*, const char*, const char*, double&, + int, int, int); + + extern void pyupin_(); + + extern void pyupev_(); + + extern void pylist_(int&); + + extern void pystat_(int&); + +} + +//************************************************************************** + +// Interfaces to the above routines, to make the C++ calls similar to f77. + +class Pythia6Interface { + +public: + + // Give in a command to change a setting. + static void pygive(const string cmnd) { + const char* cstring = cmnd.c_str(); int len = cmnd.length(); + pygive_(cstring, len); + } + + // Initialize the generation for the given beam confiuration. + static void pyinit(const string frame, const string beam, + const string target, double wIn) { + const char* cframe = frame.c_str(); int lenframe = frame.length(); + const char* cbeam = beam.c_str(); int lenbeam = beam.length(); + const char* ctarget = target.c_str(); int lentarget = target.length(); + pyinit_(cframe, cbeam, ctarget, wIn, lenframe, lenbeam, lentarget); + } + + // Fill the initialization information in the HEPRUP commonblock. + static void pyupin() {pyupin_();} + + // Generate the next hard process and + // fill the event information in the HEPEUP commonblock + static void pyupev() {pyupev_();} + + // List the event at the process level. + static void pylist(int mode) {pylist_(mode);} + + // Print statistics on the event generation process. + static void pystat(int mode) {pystat_(mode);} + +}; + +//************************************************************************** + + +} // end namespace Pythia8 + +#endif // Pythia8_Pythia6Interface_H diff --git a/PYTHIA8/pythia8130/include/PythiaComplex.h b/PYTHIA8/pythia8130/include/PythiaComplex.h new file mode 100644 index 00000000000..9298f75fe4c --- /dev/null +++ b/PYTHIA8/pythia8130/include/PythiaComplex.h @@ -0,0 +1,21 @@ +// PythiaComplex.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for typedef'd double precision complex numbers. + +#ifndef Pythia8_PythiaComplex_H +#define Pythia8_PythiaComplex_H + +// Stdlib header for complex numbers. +# include + +namespace Pythia8 { + +// Convenient typedef for double precision complex numbers. +typedef std::complex complex; + +} // end namespace Pythia8 + +#endif // Pythia8_PythiaComplex_H diff --git a/PYTHIA8/pythia8130/include/PythiaStdlib.h b/PYTHIA8/pythia8130/include/PythiaStdlib.h new file mode 100644 index 00000000000..cfc1313e1ad --- /dev/null +++ b/PYTHIA8/pythia8130/include/PythiaStdlib.h @@ -0,0 +1,82 @@ +// PythiaStdlib.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for functionality pulled in from Stdlib, +// plus a few useful utilities (small powers). + +#ifndef Pythia8_PythiaStdlib_H +#define Pythia8_PythiaStdlib_H + +// Stdlib header files for mathematics. +#include +#include + +// Stdlib header files for strings and containers. +#include +#include +#include + +// Stdlib header file for input and output. +#include +#include +#include +#include + +// Define pi if not yet done. +#ifndef M_PI +#define M_PI 3.1415926535897932385 +#endif + +// By this declaration you do not need to use std:: qualifier everywhere. +using namespace std; + +// Alternatively you can specify exactly which std:: methods will be used. +/* +namespace Pythia8 { +// Generic utilities and mathematical functions. +using std::swap; +using std::max; +using std::min; +using std::abs; +// Strings and containers. +using std::string; +using std::vector; +using std::map; +// Input/output streams. +using std::cin; +using std::cout; +using std::cerr; +using std::istream; +using std::ostream; +using std::ifstream; +using std::ofstream; +using std::istringstream; +using std::ostringstream; +// Input/output formatting. +using std::endl; +using std::fixed; +using std::scientific; +using std::left; +using std::right; +using std::setw; +using std::setprecision; +} // end namespace Pythia8 +*/ + +namespace Pythia8 { + +// Powers of small integers - for balance speed/code clarity. +inline double pow2(const double& x) {return x*x;} +inline double pow3(const double& x) {return x*x*x;} +inline double pow4(const double& x) {return x*x*x*x;} +inline double pow5(const double& x) {return x*x*x*x*x;} +inline double pow6(const double& x) {return x*x*x*x*x*x;} + +// Avoid problem with negative square root argument (from roundoff). +inline double sqrtpos(const double& x) {return sqrt( max( 0., x));} + +} // end namespace Pythia8 + +#endif // Pythia8_PythiaStdlib_H diff --git a/PYTHIA8/pythia8130/include/ResonanceDecays.h b/PYTHIA8/pythia8130/include/ResonanceDecays.h new file mode 100644 index 00000000000..d974465953f --- /dev/null +++ b/PYTHIA8/pythia8130/include/ResonanceDecays.h @@ -0,0 +1,71 @@ +// ResonanceDecays.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the main class for performing resonance decays. +// ResonanceDecays: handles the sequential decay of resonances in process. + +#ifndef Pythia8_ResonanceDecays_H +#define Pythia8_ResonanceDecays_H + +#include "Basics.h" +#include "Event.h" +#include "Info.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "ResonanceWidths.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// The ResonanceDecays class handles the sequential decay of resonances +// that are part of the hard process (t, W, Z, H, SUSY,...). + +class ResonanceDecays { + +public: + + // Constructor. + ResonanceDecays() {} + + // Store pointer to Info for error messages. + void init(Info* infoPtrIn) {infoPtr = infoPtrIn;} + + // Generate the next decay sequence. + bool next( Event& process); + +private: + + // Constants: could only be changed in the code itself. + static const int NTRYCHANNEL, NTRYMASSES; + static const double MSAFETY, WIDTHCUT, TINY, WTCORRECTION[11]; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Select masses of decay products. + bool pickMasses(); + + // Select colours of decay products. + bool pickColours(int iDec, Event& process); + + // Select kinematics isotropic in phase space. + bool pickKinematics(); + + // Flavour, colour and momentum information. + int id0, mult; + double m0; + vector idProd, cols, acols; + vector mProd; + vector pProd; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_ResonanceDecays_H diff --git a/PYTHIA8/pythia8130/include/ResonanceWidths.h b/PYTHIA8/pythia8130/include/ResonanceWidths.h new file mode 100644 index 00000000000..4d45d85216f --- /dev/null +++ b/PYTHIA8/pythia8130/include/ResonanceWidths.h @@ -0,0 +1,635 @@ +// ResonanceWidths.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for resonance properties: dynamical widths etc. +// ResonanceWidths: base class for all resonances. +// ResonanceGmZ, ...: derived classes for individual resonances. + +#ifndef Pythia8_ResonanceWidths_H +#define Pythia8_ResonanceWidths_H + +#include "Basics.h" +#include "Info.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" +#include "StandardModel.h" + +namespace Pythia8 { + +//************************************************************************** + +// Forward references to ParticleData and StandardModel classes. +class DecayChannel; +class DecayTable; +class ParticleDataEntry; +class AlphaStrong; +class AlphaEM; + +//************************************************************************** + +// The ResonanceWidths is the base class. Also used for generic resonaces. + +class ResonanceWidths { + +public: + + // Destructor. + virtual ~ResonanceWidths() {} + + // Initialize static data members in base class. + static void initStatic(Info* infoPtrIn); + + // Set up standard properties. + bool initBasic(int idResIn); + + // Calculate and store partial and total widths at the nominal mass. + void init(); + + // Return identity of particle species. + int id() const {return idRes;} + + // Calculate the total/open width for given mass, charge and instate. + double width(int idSgn, double mHatIn, int idInFlavIn = 0, + bool openOnly = false, bool setBR = false, int idOutFlav1 = 0, + int idOutFlav2 = 0); + + // Special case to calculate open final-state width. + double widthOpen(int idSgn, double mHatIn, int idIn = 0) { + return width( idSgn, mHatIn, idIn, true, false);} + + // Special case to store open final-state widths for channel selection. + double widthStore(int idSgn, double mHatIn, int idIn = 0) { + return width( idSgn, mHatIn, idIn, true, true);} + + // Return fraction of width open for particle and antiparticle. + double openFrac(int idSgn) {return (idSgn > 0) ? openPos : openNeg;} + + // Return forced rescaling factor of resonance width. + double widthRescaleFactor() {return forceFactor;} + + // Special case to calculate one final-state width. + // Currently only used for Higgs -> qqbar, g g or gamma gamma. + double widthChan(double mHatIn, int idOutFlav1, int idOutFlav2) { + return width( 1, mHatIn, 0, false, false, idOutFlav1, idOutFlav2);} + +protected: + + // Constructor. + ResonanceWidths() {} + + // Static initialization data, normally only set once. + static int alphaSorder, alphaEMorder; + static double alphaSvalue, minWidth, minThreshold; + + // Static alphaStrong and alphaElectromagnetic calculation. + static AlphaStrong alphaS; + static AlphaEM alphaEM; + + // Constants: could only be changed in the code itself. + static const int NPOINT; + static const double MASSMARGIN; + + // Pointer to various information on the generation. + static Info* infoPtr; + + // Pointer to properties of the particle species. + ParticleDataEntry* particlePtr; + + // Particle properties always locally present. + int idRes, hasAntiRes; + bool doForceWidth; + double mRes, GammaRes, m2Res, GamMRat, openPos, openNeg, forceFactor; + + // Properties for currently studied decay channel(s). + int iChannel, onMode, meMode, mult, id1, id2, id3, id1Abs, + id2Abs, id3Abs, idInFlav; + double widNow, mHat, mf1, mf2, mf3, mr1, mr2, mr3, ps, kinFac, + alpEM, alpS, colQ, preFac; + + // Initialize constants. + virtual void initConstants() {} + + // Calculate various common prefactors for the current mass. + // Optional argument calledFromInit only used for Z0. + virtual void calcPreFac(bool = false) {} + + // Calculate width for currently considered channel. + // Optional argument calledFromInit only used for Z0. + virtual void calcWidth(bool = false) {} + + // Simple routines for matrix-element integration over Breit-Wigners. + double numInt1BW(double mHatIn, double m1, double Gamma1, double mMin1, + double m2, int psMode = 1); + double numInt2BW(double mHatIn, double m1, double Gamma1, double mMin1, + double m2, double Gamma2, double mMin2, int psMode = 1); + +}; + +//************************************************************************** + +// The ResonanceGeneric class handles a generic resonance. +// Only needs a constructor; for the rest uses defaults in base class. + +class ResonanceGeneric : public ResonanceWidths { + +public: + + // Constructor. + ResonanceGeneric(int idResIn) {initBasic(idResIn);} + +}; + +//************************************************************************** + +// The ResonanceGmZ class handles the gamma*/Z0 resonance. + +class ResonanceGmZ : public ResonanceWidths { + +public: + + // Constructor. + ResonanceGmZ(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + int gmZmode; + double thetaWRat, ei2, eivi, vi2ai2, gamNorm, intNorm, resNorm; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool calledFromInit = false); + +}; + +//************************************************************************** + +// The ResonanceW class handles the W+- resonance. + +class ResonanceW : public ResonanceWidths { + +public: + + // Constructor. + ResonanceW(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double thetaWRat, alpEM; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceTop class handles the top/antitop resonance. + +class ResonanceTop : public ResonanceWidths { + +public: + + // Constructor. + ResonanceTop(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double thetaWRat, m2W; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceFour class handles fourth-generation resonances. + +class ResonanceFour : public ResonanceWidths { + +public: + + // Constructor. + ResonanceFour(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double thetaWRat, m2W; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceH class handles the SM and BSM Higgs resonance. +// higgsType = 0 : SM H; = 1: h^0/H_1; = 2 : H^0/H_2; = 3 : A^0/A_3. + +class ResonanceH : public ResonanceWidths { + +public: + + // Constructor. + ResonanceH(int higgsTypeIn, int idResIn) : higgsType(higgsTypeIn) + {initBasic(idResIn);} + +private: + + // Constants: could only be changed in the code itself. + static const double MASSMIN, GAMMAMARGIN; + + // Higgs type in current instance. + int higgsType; + + // Locally stored properties and couplings. + bool useCubicWidth, useRunLoopMass; + double sin2tW, cos2tW, mT, mZ, mW, mHchg, GammaT, GammaZ, GammaW, + coup2d, coup2u, coup2l, coup2Z, coup2W, coup2Hchg, coup2H1H1, + coup2A3A3, coup2H1Z, coup2A3Z, coup2A3H1, coup2HchgW, + kinFacT[101], kinFacZ[101], kinFacW[101]; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + + // Sum up loop contributions in Higgs -> g + g. + double eta2gg(); + + // Sum up loop contributions in Higgs -> gamma + gamma. + double eta2gaga(); + + // Sum up loop contributions in Higgs -> gamma + Z0. + double eta2gaZ(); + +}; + +//************************************************************************** + +// The ResonanceHchg class handles the H+- resonance. + +class ResonanceHchg : public ResonanceWidths { + +public: + + // Constructor. + ResonanceHchg(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + bool useCubicWidth; + double thetaWRat, mW, tanBeta, tan2Beta, coup2H1W; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceZprime class handles the gamma*/Z0 /Z'^0 resonance. + +class ResonanceZprime : public ResonanceWidths { + +public: + + // Constructor. + ResonanceZprime(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + int gmZmode; + double sin2tW, cos2tW, thetaWRat, mZ, GammaZ, m2Z, GamMRatZ, afZp[20], + vfZp[20], coupZpWW, ei2, eivi, vai2, eivpi, vaivapi, vapi2, + gamNorm, gamZNorm, ZNorm, gamZpNorm, ZZpNorm, ZpNorm; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool calledFromInit = false); + +}; + +//************************************************************************** + +// The ResonanceWprime class handles the W'+- resonance. + +class ResonanceWprime : public ResonanceWidths { + +public: + + // Constructor. + ResonanceWprime(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double thetaWRat, cos2tW, alpEM, aqWp, vqWp, alWp, vlWp, coupWpWZ; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceRhorizontal class handles the R^0 resonance. + +class ResonanceRhorizontal : public ResonanceWidths { + +public: + + // Constructor. + ResonanceRhorizontal(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double thetaWRat; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceExcited class handles excited-fermion resonances. + +class ResonanceExcited : public ResonanceWidths { + +public: + + // Constructor. + ResonanceExcited(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double Lambda, coupF, coupFprime, coupFcol, sin2tW, cos2tW; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceGraviton class handles the excited Graviton resonance. + +class ResonanceGraviton : public ResonanceWidths { + +public: + + // Constructor. + ResonanceGraviton(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double kappaMG; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceLeptoquark class handles the LQ/LQbar resonance. + +class ResonanceLeptoquark : public ResonanceWidths { + +public: + + // Constructor. + ResonanceLeptoquark(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double kCoup; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceNuRight class handles righthanded Majorana neutrinos. + +class ResonanceNuRight : public ResonanceWidths { + +public: + + // Constructor. + ResonanceNuRight(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double thetaWRat, mWR; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceZRight class handles the Z_R^0 resonance. + +class ResonanceZRight : public ResonanceWidths { + +public: + + // Constructor. + ResonanceZRight(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double sin2tW, thetaWRat; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceWRight class handles the W_R+- resonance. + +class ResonanceWRight : public ResonanceWidths { + +public: + + // Constructor. + ResonanceWRight(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double thetaWRat; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceHchgchgLeft class handles the H++/H-- (left) resonance. + +class ResonanceHchgchgLeft : public ResonanceWidths { + +public: + + // Constructor. + ResonanceHchgchgLeft(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + double yukawa[4][4], gL, vL, mW; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +// The ResonanceHchgchgRight class handles the H++/H-- (right) resonance. + +class ResonanceHchgchgRight : public ResonanceWidths { + +public: + + // Constructor. + ResonanceHchgchgRight(int idResIn) {initBasic(idResIn);} + +private: + + // Locally stored properties and couplings. + int idWR; + double yukawa[4][4], gR; + + // Initialize constants. + virtual void initConstants(); + + // Calculate various common prefactors for the current mass. + virtual void calcPreFac(bool = false); + + // Caclulate width for currently considered channel. + virtual void calcWidth(bool = false); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_ResonanceWidths_H diff --git a/PYTHIA8/pythia8130/include/Settings.h b/PYTHIA8/pythia8130/include/Settings.h new file mode 100644 index 00000000000..42aa1099cc1 --- /dev/null +++ b/PYTHIA8/pythia8130/include/Settings.h @@ -0,0 +1,235 @@ +// Settings.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for the settings database; and for error statistics. +// Flag: helper class with bool flags. +// Mode: helper class with int modes. +// Parm: (short for parameter) helper class with double parameters. +// Word: helper class with string words. +// Settings: maps of flags, modes, parms and words with input/output. + +#ifndef Pythia8_Settings_H +#define Pythia8_Settings_H + +#include "Info.h" +#include "PythiaStdlib.h" + +namespace Pythia8 { + +//************************************************************************** + +// Class for bool flags. + +class Flag { + +public: + + // Constructor + Flag(string nameIn = " ", bool defaultIn = false) : name(nameIn), + valNow(defaultIn) , valDefault(defaultIn) { } + + // Data members. + string name; + bool valNow, valDefault; + +}; + +//************************************************************************** + +// Class for integer modes. + +class Mode { + +public: + + // Constructor + Mode(string nameIn = " ", int defaultIn = 0, bool hasMinIn = false, + bool hasMaxIn = false, int minIn = 0, int maxIn = 0) : name(nameIn), + valNow(defaultIn), valDefault(defaultIn), hasMin(hasMinIn), + hasMax(hasMaxIn), valMin(minIn), valMax(maxIn) { } + + // Data members. + string name; + int valNow, valDefault; + bool hasMin, hasMax; + int valMin, valMax; + +}; + +//************************************************************************** + +// Class for double parms (where parm is shorthand for parameter). + +class Parm { + +public: + + // Constructor + Parm(string nameIn = " ", double defaultIn = 0., + bool hasMinIn = false, bool hasMaxIn = false, double minIn = 0., + double maxIn = 0.) : name(nameIn), valNow(defaultIn), + valDefault(defaultIn), hasMin(hasMinIn), hasMax(hasMaxIn), + valMin(minIn), valMax(maxIn) { } + + // Data members. + string name; + double valNow, valDefault; + bool hasMin, hasMax; + double valMin, valMax; + +}; + +//************************************************************************** + +// Class for string words. + +class Word { + +public: + + // Constructor + Word(string nameIn = " ", string defaultIn = " ") : name(nameIn), + valNow(defaultIn) , valDefault(defaultIn) { } + + // Data members. + string name, valNow, valDefault; + +}; + +//************************************************************************** + +// This class holds info on flags (bool), modes (int), +// parms (double) and words (string). + +class Settings { + +public: + + // Constructor. + Settings() {} + + // Initialize static pointer. + static void initPtr(Info* infoPtrIn) {infoPtr = infoPtrIn;} + + // Read in database from specific file. + static bool init(string startFile = "../xmldoc/Index.xml", + bool append = false, ostream& os = cout) ; + + // Overwrite existing database by reading from specific file. + static bool reInit(string startFile = "../xmldoc/Index.xml") ; + + // Read in one update from a single line. + static bool readString(string line, bool warn = true, + ostream& os = cout) ; + + // Write updates or everything to user-defined file. + static bool writeFile(ostream& os = cout, bool writeAll = false) ; + static bool writeFile(string toFile, bool writeAll = false) ; + + // Print out table of database, either all or only changed ones, + // or ones containing a given string. + static void listAll(ostream& os = cout) { + list( true, false, " ", os); } + static void listChanged(ostream& os = cout) { + list (false, false, " ", os); } + static void list(string match, ostream& os = cout) { + list (false, true, match, os); } + + // Reset all values to their defaults. + static void resetAll() ; + + // Query existence of an entry. + static bool isFlag(string keyIn) { + return (flags.find(toLower(keyIn)) != flags.end()); } + static bool isMode(string keyIn) { + return (modes.find(toLower(keyIn)) != modes.end()); } + static bool isParm(string keyIn) { + return (parms.find(toLower(keyIn)) != parms.end()); } + static bool isWord(string keyIn) { + return (words.find(toLower(keyIn)) != words.end()); } + + // Add new entry. + static void addFlag(string keyIn, bool defaultIn) { + flags[toLower(keyIn)] = Flag(keyIn, defaultIn); } + static void addMode(string keyIn, int defaultIn, bool hasMinIn, + bool hasMaxIn, int minIn, int maxIn) { modes[toLower(keyIn)] + = Mode(keyIn, defaultIn, hasMinIn, hasMaxIn, minIn, maxIn); } + static void addParm(string keyIn, double defaultIn, bool hasMinIn, + bool hasMaxIn, double minIn, double maxIn) { parms[toLower(keyIn)] + = Parm(keyIn, defaultIn, hasMinIn, hasMaxIn, minIn, maxIn); } + static void addWord(string keyIn, string defaultIn) { + words[toLower(keyIn)] = Word(keyIn, defaultIn); } + + // Give back current value, with check that key exists. + static bool flag(string keyIn); + static int mode(string keyIn); + static double parm(string keyIn); + static string word(string keyIn); + + // Change current value, respecting limits. + static void flag(string keyIn, bool nowIn); + static void mode(string keyIn, int nowIn); + static void parm(string keyIn, double nowIn); + static void word(string keyIn, string nowIn); + + // Change current value, disregarding limits. + static void forceMode(string keyIn, int nowIn) { + if (isMode(keyIn)) modes[toLower(keyIn)].valNow = nowIn; } + static void forceParm(string keyIn, double nowIn) { + if (isParm(keyIn)) parms[toLower(keyIn)].valNow = nowIn; } + + // Restore current value to default. + static void resetFlag(string keyIn) { + if (isFlag(keyIn)) flags[toLower(keyIn)].valNow + = flags[toLower(keyIn)].valDefault ; } + static void resetMode(string keyIn) { + if (isMode(keyIn)) modes[toLower(keyIn)].valNow + = modes[toLower(keyIn)].valDefault ; } + static void resetParm(string keyIn) { + if (isParm(keyIn)) parms[toLower(keyIn)].valNow + = parms[toLower(keyIn)].valDefault ; } + static void resetWord(string keyIn) { + if (isWord(keyIn)) words[toLower(keyIn)].valNow + = words[toLower(keyIn)].valDefault ; } + +private: + + // Pointer to various information on the generation. + static Info* infoPtr; + + // Map for bool flags. + static map flags; + + // Map for integer modes. + static map modes; + + // Map for double parms. + static map parms; + + // Map for string words. + static map words; + + // Flag that initialization has been performed. + static bool isInit; + + // Print out table of database, called from listAll and listChanged. + static void list(bool listAll, bool listString, string match, + ostream& os = cout) ; + + // Useful functions for string handling. + static string toLower(const string& name); + static bool boolString(string tag); + static string attributeValue(string line, string attribute); + static bool boolAttributeValue(string line, string attribute); + static int intAttributeValue(string line, string attribute); + static double doubleAttributeValue(string line, string attribute); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_Settings_H diff --git a/PYTHIA8/pythia8130/include/SigmaCompositeness.h b/PYTHIA8/pythia8130/include/SigmaCompositeness.h new file mode 100644 index 00000000000..bc22461e636 --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaCompositeness.h @@ -0,0 +1,184 @@ +// SigmaCompositeness.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for compositiness-process differential cross sections. +// Contains classes derived from SigmaProcess via Sigma(1/2)Process. + +#ifndef Pythia8_SigmaCompositeness_H +#define Pythia8_SigmaCompositeness_H + +#include "SigmaProcess.h" + +namespace Pythia8 { + +//************************************************************************** + +// A derived class for q g -> q^* (excited quark state). + +class Sigma1qg2qStar : public Sigma1Process { + +public: + + // Constructor. + Sigma1qg2qStar(int idqIn) : idq(idqIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for q* decay angles (else inactive). + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qg";} + virtual int resonanceA() const {return idRes;} + +private: + + // Parameters set at initialization or for current kinematics. + int idq, idRes, codeSave; + string nameSave; + double mRes, GammaRes, m2Res, GamMRat, Lambda, coupFcol, widthIn, sigBW; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* qStarPtr; + +}; + +//************************************************************************** + +// A derived class for l gamma -> q^* (excited lepton state). + +class Sigma1lgm2lStar : public Sigma1Process { + +public: + + // Constructor. + Sigma1lgm2lStar(int idlIn) : idl(idlIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for l* decay angles (else inactive). + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "fgm";} + virtual int resonanceA() const {return idRes;} + +private: + + // Parameters set at initialization or for current kinematics. + int idl, idRes, codeSave; + string nameSave; + double mRes, GammaRes, m2Res, GamMRat, Lambda, coupChg, widthIn, sigBW; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* qStarPtr; + +}; + +//************************************************************************** + +// A derived class for q q' -> q^* q' (excited quark state). + +class Sigma2qq2qStarq : public Sigma2Process { + +public: + + // Constructor. + Sigma2qq2qStarq(int idqIn) : idq(idqIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qq";} + virtual int id3Mass() const {return idRes;} + +private: + + // Parameters set at initialization or for current kinematics. + int idq, idRes, codeSave; + string nameSave; + double Lambda, preFac, openFracPos, openFracNeg, sigmaA, sigmaB; + +}; + +//************************************************************************** + +// A derived class for q qbar -> l^* lbar (excited lepton state). + +class Sigma2qqbar2lStarlbar : public Sigma2Process { + +public: + + // Constructor. + Sigma2qqbar2lStarlbar(int idlIn) : idl(idlIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qqbarSame";} + virtual int id3Mass() const {return idRes;} + +private: + + // Parameters set at initialization or for current kinematics. + int idl, idRes, codeSave; + string nameSave; + double Lambda, preFac, openFracPos, openFracNeg, sigma; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SigmaCompositeness_H diff --git a/PYTHIA8/pythia8130/include/SigmaEW.h b/PYTHIA8/pythia8130/include/SigmaEW.h new file mode 100644 index 00000000000..c816c143cec --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaEW.h @@ -0,0 +1,1019 @@ +// SigmaEW.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for electroweak process differential cross sections. +// Contains classes derived from SigmaProcess via Sigma(1/2)Process. + +#ifndef Pythia8_SigmaEW_H +#define Pythia8_SigmaEW_H + +#include "PythiaComplex.h" +#include "SigmaProcess.h" + +namespace Pythia8 { + + +//************************************************************************** + +// A derived class for q g -> q gamma (q = u, d, s, c, b). +// Use massless approximation also for Q since no alternative. + +class Sigma2qg2qgamma : public Sigma2Process { + +public: + + // Constructor. + Sigma2qg2qgamma() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q g -> q gamma (udscb)";} + virtual int code() const {return 201;} + virtual string inFlux() const {return "qg";} + +private: + + // Values stored for later use. + double mNew, m2New, sigUS, sigma0; + +}; + +//************************************************************************** + +// A derived class for q qbar -> g gamma. + +class Sigma2qqbar2ggamma : public Sigma2Process { + +public: + + // Constructor. + Sigma2qqbar2ggamma() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q qbar -> g gamma";} + virtual int code() const {return 202;} + virtual string inFlux() const {return "qqbarSame";} + +private: + + // Values stored for later use. + double sigma0; + +}; + +//************************************************************************** + +// A derived class for g g -> g gamma. + +class Sigma2gg2ggamma : public Sigma2Process { + +public: + + // Constructor. + Sigma2gg2ggamma() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "g g -> g gamma";} + virtual int code() const {return 203;} + virtual string inFlux() const {return "gg";} + +private: + + // Values stored for later use. + double chargeSum, sigma; + +}; + +//************************************************************************** + +// A derived class for f fbar -> gamma gamma. + +class Sigma2ffbar2gammagamma : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbar2gammagamma() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "f fbar -> gamma gamma";} + virtual int code() const {return 204;} + virtual string inFlux() const {return "ffbarSame";} + +private: + + // Values stored for later use. + double sigTU, sigma0; + +}; + +//************************************************************************** + +// A derived class for g g -> gamma gamma. + +class Sigma2gg2gammagamma : public Sigma2Process { + +public: + + // Constructor. + Sigma2gg2gammagamma() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "g g -> gamma gamma";} + virtual int code() const {return 205;} + virtual string inFlux() const {return "gg";} + +private: + + double charge2Sum, sigma; + +}; + +//************************************************************************** + +// A derived class for f f' -> f f' via t-channel gamma*/Z0 exchange. + +class Sigma2ff2fftgmZ : public Sigma2Process { + +public: + + // Constructor. + Sigma2ff2fftgmZ() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "f f' -> f f' (t-channel gamma*/Z0)";} + virtual int code() const {return 211;} + virtual string inFlux() const {return "ff";} + +private: + + // Z parameters for propagator. + int gmZmode; + double mZ, mZS, thetaWRat, sigmagmgm, sigmagmZ, sigmaZZ; + +}; + +//************************************************************************** + +// A derived class for f_1 f_2 -> f_3 f_4 via t-channel W+- exchange. + +class Sigma2ff2fftW : public Sigma2Process { + +public: + + // Constructor. + Sigma2ff2fftW() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "f_1 f_2 -> f_3 f_4 (t-channel W+-)";} + virtual int code() const {return 212;} + virtual string inFlux() const {return "ff";} + +private: + + // W parameters for propagator. + double mW, mWS, thetaWRat, sigma0; + +}; + +//************************************************************************** + +// A derived class for q q' -> Q q" via t-channel W+- exchange. +// Related to Sigma2ff2fftW class, but with massive matrix elements. + +class Sigma2qq2QqtW : public Sigma2Process { + +public: + + // Constructor. + Sigma2qq2QqtW(int idIn, int codeIn) : idNew(idIn), codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W decay angles in top decay (else inactive). + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ff";} + virtual int id3Mass() const {return idNew;} + +private: + + // Values stored for process type. W parameters for propagator. + int idNew, codeSave; + string nameSave; + double mW, mWS, thetaWRat, sigma0, openFracPos, openFracNeg; + +}; + +//************************************************************************** + +// A derived class for f fbar -> gamma*/Z0. + +class Sigma1ffbar2gmZ : public Sigma1Process { + +public: + + // Constructor. + Sigma1ffbar2gmZ() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for Z decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar -> gamma*/Z0";} + virtual int code() const {return 221;} + virtual string inFlux() const {return "ffbarSame";} + virtual int resonanceA() const {return 23;} + +private: + + // Parameters set at initialization or for each new event. + int gmZmode; + double mRes, GammaRes, m2Res, GamMRat, thetaWRat, + gamSum, intSum, resSum, gamProp, intProp, resProp; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* particlePtr; + +}; + +//************************************************************************** + +// A derived class for f fbar' -> W+-. + +class Sigma1ffbar2W : public Sigma1Process { + +public: + + // Constructor. + Sigma1ffbar2W() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar' -> W+-";} + virtual int code() const {return 222;} + virtual string inFlux() const {return "ffbarChg";} + virtual int resonanceA() const {return 24;} + +private: + + // Parameters set at initialization. + double mRes, GammaRes, m2Res, GamMRat, thetaWRat, sigma0Pos, sigma0Neg; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* particlePtr; + +}; + +//************************************************************************** + +// A derived class for f fbar -> gamma* -> f' fbar', summed over light f'. +// Allows pT-ordered evolution for multiple interactions. + +class Sigma2ffbar2ffbarsgm : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbar2ffbarsgm() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const { + return "f fbar -> f' fbar' (s-channel gamma*)";} + virtual int code() const {return 223;} + virtual string inFlux() const {return "ffbarSame";} + virtual bool isSChannel() const {return true;} + +private: + + // Values stored for later use. + int idNew; + double sigma0; + +}; + +//************************************************************************** + +// A derived class for f fbar -> gamma*/Z0 -> F Fbar, for one heavy F. +// Allows pT cuts as for other 2 -> 2 processes. + +class Sigma2ffbar2FFbarsgmZ : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbar2FFbarsgmZ(int idIn, int codeIn) : idNew(idIn), + codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W decay angles in top decay (else inactive). + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ffbarSame";} + virtual bool isSChannel() const {return true;} + virtual int id3Mass() const {return idNew;} + virtual int id4Mass() const {return idNew;} + virtual int resonanceA() const {return 23;} + +private: + + // Values stored for process type. Z parameters for propagator. + int idNew, codeSave, gmZmode; + string nameSave; + bool isPhysical; + double ef, vf, af, mRes, GammaRes, m2Res, GamMRat, thetaWRat, + mr, betaf, cosThe, gamProp, intProp, resProp, openFracPair; + +}; + +//************************************************************************** + +// A derived class for f fbar' -> W+- -> F fbar", for one or two heavy F. +// Allows pT cuts as for other 2 -> 2 processes. + +class Sigma2ffbar2FfbarsW : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbar2FfbarsW(int idIn, int idIn2, int codeIn) : idNew(idIn), + idNew2(idIn2), codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W decay angles in top decay (else inactive). + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ffbarChg";} + virtual bool isSChannel() const {return true;} + virtual int id3Mass() const {return idNew;} + virtual int id4Mass() const {return idPartner;} + virtual int resonanceA() const {return 24;} + +private: + + // Values stored for process type. W parameters for propagator. + int idNew, idNew2, codeSave, idPartner; + string nameSave; + bool isPhysical; + double V2New, mRes, GammaRes, m2Res, GamMRat, thetaWRat, sigma0, + openFracPos, openFracNeg; + +}; + +//************************************************************************** + +// An intermediate class for f fbar -> gamma*/Z0/W+- gamma*/Z0/W-+. + +class Sigma2ffbargmZWgmZW : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbargmZWgmZW() {} + +protected: + + // Internal products. + Vec4 pRot[7]; + complex hA[7][7]; + complex hC[7][7]; + + // Calculate and store internal products. + void setupProd( Event& process, int i1, int i2, int i3, int i4, + int i5, int i6); + + // Evaluate the F function of Gunion and Kunszt. + complex fGK(int i1, int i2, int i3, int i4, int i5, int i6); + + // Evaluate the Xi function of Gunion and Kunszt. + double xiGK( double tHnow, double uHnow); + + // Evaluate the Xj function of Gunion and Kunszt. + double xjGK( double tHnow, double uHnow); + +private: + +}; + +//************************************************************************** + +// A derived class for f fbar -> gamma*/Z0 gamma*/Z0. + +class Sigma2ffbar2gmZgmZ : public Sigma2ffbargmZWgmZW { + +public: + + // Constructor. + Sigma2ffbar2gmZgmZ() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for simultaneous flavour choices. + virtual double weightDecayFlav( Event& process); + + // Evaluate weight for decay angles of the two gamma*/Z0. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar -> gamma*/Z0 gamma*/Z0";} + virtual int code() const {return 231;} + virtual string inFlux() const {return "ffbarSame";} + virtual int id3Mass() const {return 23;} + virtual int id4Mass() const {return 23;} + +private: + + // Parameters set at initialization or for each new event. + int gmZmode, i1, i2, i3, i4, i5, i6; + double mRes, GammaRes, m2Res, GamMRat, thetaWRat, sigma0, + gamSum3, intSum3, resSum3, gamProp3, intProp3, resProp3, + gamSum4, intSum4, resSum4, gamProp4, intProp4, resProp4, + c3LL, c3LR, c3RL, c3RR, c4LL, c4LR, c4RL, c4RR, flavWt; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* particlePtr; + +}; + +//************************************************************************** + +// A derived class for f fbar' -> Z0 W+-. (Here pure Z0, unfortunately.) + +class Sigma2ffbar2ZW : public Sigma2ffbargmZWgmZW { + +public: + + // Constructor. + Sigma2ffbar2ZW() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for Z0 and W+- decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar' -> Z0 W+- (no gamma*!)";} + virtual int code() const {return 232;} + virtual string inFlux() const {return "ffbarChg";} + virtual int id3Mass() const {return 23;} + virtual int id4Mass() const {return 24;} + virtual int resonanceA() const {return 24;} + +private: + + // Store W+- mass and width, and couplings. + double mW, widW, mWS, mwWS, sin2thetaW, cos2thetaW, thetaWRat, + thetaWpt, thetaWmm, lun, lde, sigma0, openFracPos, openFracNeg; + +}; + +//************************************************************************** + +// A derived class for f fbar -> W+ W-. + +class Sigma2ffbar2WW : public Sigma2ffbargmZWgmZW { + +public: + + // Constructor. + Sigma2ffbar2WW() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W+ and W- decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar -> W+ W-";} + virtual int code() const {return 233;} + virtual int id3Mass() const {return 24;} + virtual string inFlux() const {return "ffbarSame";} + virtual int id4Mass() const {return -24;} + virtual int resonanceA() const {return 23;} + +private: + + // Store Z0 mass and width. + double mZ, widZ, mZS, mwZS, thetaWRat, sigma0, cgg, cgZ, cZZ, cfg, + cfZ, cff, gSS, gTT, gST, gUU, gSU, openFracPair; + +}; + +//************************************************************************** + +// An intermediate class for f fbar -> gamma*/Z0 g/gamma and permutations. + +class Sigma2ffbargmZggm : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbargmZggm() {} + + // Initialize process. + virtual void initProc(); + + // Evaluate weight for gamma&/Z0 decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + +protected: + + // Parameters set at initialization or for each new event. + int gmZmode; + double mRes, GammaRes, m2Res, GamMRat, thetaWRat, + gamSum, intSum, resSum, gamProp, intProp, resProp; + + // Evaluate current sum of flavour couplings times phase space. + void flavSum(); + + // Evaluate current propagator terms of cross section. + void propTerm(); + +private: + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* particlePtr; + +}; + +//************************************************************************** + +// A derived class for q qbar -> gamma*/Z0 g. + +class Sigma2qqbar2gmZg : public Sigma2ffbargmZggm { + +public: + + // Constructor. + Sigma2qqbar2gmZg() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q qbar -> gamma*/Z0 g";} + virtual int code() const {return 241;} + virtual string inFlux() const {return "qqbarSame";} + virtual int id3Mass() const {return 23;} + +private: + + // Values stored for later use. + double sigma0; + +}; + +//************************************************************************** + +// A derived class for q g -> gamma*/Z0 q. + +class Sigma2qg2gmZq : public Sigma2ffbargmZggm { + +public: + + // Constructor. + Sigma2qg2gmZq() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q g-> gamma*/Z0 q";} + virtual int code() const {return 242;} + virtual string inFlux() const {return "qg";} + virtual int id3Mass() const {return 23;} + +private: + + // Values stored for later use. + double sigma0; + +}; + +//************************************************************************** + +// A derived class for f fbar' -> gamma*/Z0 gamma. + +class Sigma2ffbar2gmZgm : public Sigma2ffbargmZggm { + +public: + + // Constructor. + Sigma2ffbar2gmZgm() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "f fbar -> gamma*/Z0 gamma";} + virtual int code() const {return 243;} + virtual string inFlux() const {return "ffbarSame";} + virtual int id3Mass() const {return 23;} + +private: + + // Values stored for later use. + double sigma0; + +}; + +//************************************************************************** + +// A derived class for f gamma -> gamma*/Z0 f. + +class Sigma2fgm2gmZf : public Sigma2ffbargmZggm { + +public: + + // Constructor. + Sigma2fgm2gmZf() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "f gamma -> gamma*/Z0 f";} + virtual int code() const {return 244;} + virtual string inFlux() const {return "fgm";} + virtual int id3Mass() const {return 23;} + +private: + + // Values stored for later use. + double sigma0; + +}; + +//************************************************************************** + +// An intermediate class for f fbar -> W+- g/gamma and permutations. + +class Sigma2ffbarWggm : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbarWggm() {} + + // Evaluate weight for gamma&/Z0 decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + +private: + +}; + +//************************************************************************** + +// A derived class for q qbar' -> W+- g. + +class Sigma2qqbar2Wg : public Sigma2ffbarWggm { + +public: + + // Constructor. + Sigma2qqbar2Wg() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q qbar' -> W+- g";} + virtual int code() const {return 251;} + virtual string inFlux() const {return "ffbarChg";} + virtual int id3Mass() const {return 24;} + +private: + + // Values stored for later use. + double sigma0, openFracPos, openFracNeg; + +}; + +//************************************************************************** + +// A derived class for q g -> W+- q'. + +class Sigma2qg2Wq : public Sigma2ffbarWggm { + +public: + + // Constructor. + Sigma2qg2Wq() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q g-> W+- q'";} + virtual int code() const {return 252;} + virtual string inFlux() const {return "qg";} + virtual int id3Mass() const {return 24;} + +private: + + // Values stored for later use. + double sigma0, openFracPos, openFracNeg; + +}; + +//************************************************************************** + +// A derived class for f fbar' -> W+- gamma. + +class Sigma2ffbar2Wgm : public Sigma2ffbarWggm { + +public: + + // Constructor. + Sigma2ffbar2Wgm() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "f fbar' -> W+- gamma";} + virtual int code() const {return 253;} + virtual string inFlux() const {return "ffbarChg";} + virtual int id3Mass() const {return 24;} + +private: + + // Values stored for later use. + double sigma0, openFracPos, openFracNeg; + +}; + +//************************************************************************** + +// A derived class for f gamma -> W+- f'. + +class Sigma2fgm2Wf : public Sigma2ffbarWggm { + +public: + + // Constructor. + Sigma2fgm2Wf() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "f gamma -> W+- f'";} + virtual int code() const {return 254;} + virtual string inFlux() const {return "fgm";} + virtual int id3Mass() const {return 24;} + +private: + + // Values stored for later use. + double sigma0, openFracPos, openFracNeg; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SigmaEW_H diff --git a/PYTHIA8/pythia8130/include/SigmaExtraDim.h b/PYTHIA8/pythia8130/include/SigmaExtraDim.h new file mode 100644 index 00000000000..df210dfd85e --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaExtraDim.h @@ -0,0 +1,226 @@ +// SigmaExtraDim.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for extra-dimensional-process differential cross sections. +// Contains classes derived from SigmaProcess via Sigma(1/2)Process. + +#ifndef Pythia8_SigmaExtraDim_H +#define Pythia8_SigmaExtraDim_H + +#include "SigmaProcess.h" + +namespace Pythia8 { + +//************************************************************************** + +// A derived class for g g -> G^* (excited graviton state). + +class Sigma1gg2GravitonStar : public Sigma1Process { + +public: + + // Constructor. + Sigma1gg2GravitonStar() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for G* decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "g g -> G*";} + virtual int code() const {return 5001;} + virtual string inFlux() const {return "gg";} + virtual int resonanceA() const {return idGstar;} + +private: + + // Parameters set at initialization or for current kinematics. + int idGstar; + double mRes, GammaRes, m2Res, GamMRat, kappaMG, sigma; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* gStarPtr; + +}; + +//************************************************************************** + +// A derived class for f fbar -> G^* (excited graviton state). + +class Sigma1ffbar2GravitonStar : public Sigma1Process { + +public: + + // Constructor. + Sigma1ffbar2GravitonStar() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() {return (abs(id1) < 9) ? sigma0 / 3. : sigma0;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for G* decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar -> G*";} + virtual int code() const {return 5002;} + virtual string inFlux() const {return "ffbarSame";} + virtual int resonanceA() const {return idGstar;} + +private: + + // Parameters set at initialization or for current kinematics. + int idGstar; + double mRes, GammaRes, m2Res, GamMRat, kappaMG, sigma0; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* gStarPtr; + +}; + +//************************************************************************** + +// A derived class for g g -> G^* g (excited graviton state). + +class Sigma2gg2GravitonStarg : public Sigma2Process { + +public: + + // Constructor. + Sigma2gg2GravitonStarg() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight: currently isotropic (except secondary top decay).. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "g g -> G* g";} + virtual int code() const {return 5003;} + virtual string inFlux() const {return "gg";} + virtual int id3Mass() const {return idGstar;} + +private: + + // Parameters set at initialization or for current kinematics. + int idGstar; + double mRes, GammaRes, m2Res, GamMRat, kappaMG, openFrac, sigma; + +}; + +//************************************************************************** + +// A derived class for q g -> G^* q (excited graviton state). + +class Sigma2qg2GravitonStarq : public Sigma2Process { + +public: + + // Constructor. + Sigma2qg2GravitonStarq() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight: currently isotropic (except secondary top decay).. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "q g -> G* q";} + virtual int code() const {return 5004;} + virtual string inFlux() const {return "qg";} + virtual int id3Mass() const {return idGstar;} + +private: + + // Parameters set at initialization or for current kinematics. + int idGstar; + double mRes, GammaRes, m2Res, GamMRat, kappaMG, openFrac, sigma; + +}; + +//************************************************************************** + +// A derived class for q qbar -> G^* g (excited graviton state). + +class Sigma2qqbar2GravitonStarg : public Sigma2Process { + +public: + + // Constructor. + Sigma2qqbar2GravitonStarg() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight: currently isotropic (except secondary top decay).. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "q qbar -> G* g";} + virtual int code() const {return 5005;} + virtual string inFlux() const {return "qqbarSame";} + virtual int id3Mass() const {return idGstar;} + +private: + + // Parameters set at initialization or for current kinematics. + int idGstar; + double mRes, GammaRes, m2Res, GamMRat, kappaMG, openFrac, sigma; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SigmaExtraDim_H diff --git a/PYTHIA8/pythia8130/include/SigmaHiggs.h b/PYTHIA8/pythia8130/include/SigmaHiggs.h new file mode 100644 index 00000000000..444fc82528e --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaHiggs.h @@ -0,0 +1,812 @@ +// SigmaHiggs.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// Part of code written by Marc Montull, CERN summer student 2007. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for Higgs process differential cross sections. +// Contains classes derived from SigmaProcess via Sigma2Process. + +#ifndef Pythia8_SigmaHiggs_H +#define Pythia8_SigmaHiggs_H + +#include "SigmaProcess.h" + +namespace Pythia8 { + +//************************************************************************** + +// A derived class for f fbar -> H0 (SM), H1, H2 or A3 (BSM). + +class Sigma1ffbar2H : public Sigma1Process { + +public: + + // Constructor. + Sigma1ffbar2H(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ffbarSame";} + virtual int resonanceA() const {return idRes;} + +private: + + // An H0, H1, H2 or A3 resonance object provides coupling + // and propagator expressions. + ParticleDataEntry* HResPtr; + double mRes, GammaRes, m2Res, GamMRat, sigBW, widthOut; + int higgsType, codeSave, idRes; + string nameSave; +}; + +//************************************************************************** + +// A derived class for g g -> H0 (SM), H1, H2 or A3 (BSM). + +class Sigma1gg2H : public Sigma1Process { + +public: + + // Constructor. + Sigma1gg2H(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave ;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "gg";} + virtual int resonanceA() const {return idRes;} + +private: + + // A H0, H1, H2 or A3 resonance object provides coupling + // and propagator expressions. + ParticleDataEntry* HResPtr; + double mRes, GammaRes, m2Res, GamMRat, sigma; + int higgsType, codeSave, idRes; + string nameSave; +}; + +//************************************************************************** + +// A derived class for gamma gamma -> H0 (SM Higgs), H1, H2 or A3 (BSM Higgs). + +class Sigma1gmgm2H : public Sigma1Process { + +public: + + // Constructor. + Sigma1gmgm2H(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "gmgm";} + virtual int resonanceA() const {return idRes;} + +private: + + // A H0, H1, H2 or A3 resonance object provides coupling + // and propagator expressions. + ParticleDataEntry* HResPtr; + double mRes, GammaRes, m2Res, GamMRat, sigma; + int higgsType, codeSave, idRes; + string nameSave; +}; + +//************************************************************************** + +// A derived class for f fbar -> H Z0. +// (H can be H0 SM or H1, H2, A3 from BSM). +class Sigma2ffbar2HZ : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbar2HZ(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ffbarSame";} + virtual bool isSChannel() const {return true;} + virtual int id3Mass() const {return idRes;} + virtual int id4Mass() const {return 23;} + virtual int resonanceA() const {return 23;} + virtual int gmZmode() const {return 2;} + +private: + + // Store Z0 mass and width. + double mZ, widZ, mZS, mwZS, thetaWRat, sigma0, openFracPair, coup2Z; + int higgsType, codeSave, idRes; + string nameSave; +}; + +//************************************************************************** + +// A derived class for f fbar -> H W+- (Standard Model Higgs). +// (H can be H0 SM or H1, H2, A3 from BSM). + +class Sigma2ffbar2HW : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbar2HW(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ffbarChg";} + virtual bool isSChannel() const {return true;} + virtual int id3Mass() const {return idRes;} + virtual int id4Mass() const {return 24;} + virtual int resonanceA() const {return 24;} + +private: + + // Store W+- mass and width, and couplings. + double mW, widW, mWS, mwWS, thetaWRat, sigma0, openFracPairPos, + openFracPairNeg, coup2W; + int higgsType, codeSave, idRes; + string nameSave; +}; + +//************************************************************************** + +// A derived class for f f' -> H f f' (Z0 Z0 fusion of SM or BSM Higgs). +// (H can be H0 SM or H1, H2, A3 from BSM). + +class Sigma3ff2HfftZZ : public Sigma3Process { + +public: + + // Constructor. + Sigma3ff2HfftZZ(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ff";} + virtual int id3Mass() const {return idRes;} + + // Instructions for 3-body phase space with t-channel propagators. + virtual int idTchan1() const {return 23;} + virtual int idTchan2() const {return 23;} + virtual double tChanFracPow1() const {return 0.05;} + virtual double tChanFracPow2() const {return 0.9;} + virtual bool useMirrorWeight() const {return true;} + +private: + + // Store standard factors. + double mZS, prefac, sigma1, sigma2, openFrac, coup2Z; + int higgsType, codeSave, idRes; + string nameSave; +}; + +//************************************************************************** + +// A derived class for f_1 f_2 -> H f_3 f_4 (W+ W- fusion of SM or BSM Higgs). +// (H can be H0 SM or H1, H2, A3 from BSM). + +class Sigma3ff2HfftWW : public Sigma3Process { + +public: + + // Constructor. + Sigma3ff2HfftWW(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ff";} + virtual int id3Mass() const {return idRes;} + + // Instructions for 3-body phase space with t-channel propagators. + virtual int idTchan1() const {return 24;} + virtual int idTchan2() const {return 24;} + virtual double tChanFracPow1() const {return 0.05;} + virtual double tChanFracPow2() const {return 0.9;} + virtual bool useMirrorWeight() const {return true;} + +private: + + // Store standard prefactor. + double mWS, prefac, sigma0, openFrac, coup2W; + int higgsType, codeSave, idRes; + string nameSave; +}; + +//************************************************************************** + +// A derived class for g g -> H Q Qbar (Q Qbar fusion of SM or BSM Higgs). +// (H can be H0 SM or H1, H2, A3 from BSM). + +class Sigma3gg2HQQbar : public Sigma3Process { + +public: + + // Constructor. + Sigma3gg2HQQbar(int idIn, int higgsTypeIn) : idNew(idIn), + higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "gg";} + virtual int id3Mass() const {return idRes;} + virtual int id4Mass() const {return idNew;} + virtual int id5Mass() const {return idNew;} + + // Instructions for 3-body phase space with t-channel propagators. + virtual int idTchan1() const {return idNew;} + virtual int idTchan2() const {return idNew;} + virtual double tChanFracPow1() const {return 0.4;} + virtual double tChanFracPow2() const {return 0.2;} + virtual bool useMirrorWeight() const {return false;} + +private: + + // Store flavour-specific process information and standard prefactor. + double prefac, sigma, openFracTriplet, coup2Q; + int idNew, higgsType, codeSave, idRes; + string nameSave; + +}; + +//************************************************************************** + +// A derived class for q qbar -> H Q Qbar (Q Qbar fusion of SM or BSM Higgs). +// (H can be H0 SM or H1, H2, A3 from BSM). + +class Sigma3qqbar2HQQbar : public Sigma3Process { + +public: + + // Constructor. + Sigma3qqbar2HQQbar(int idIn, int higgsTypeIn) : idNew(idIn), + higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qqbarSame";} + virtual int id3Mass() const {return idRes;} + virtual int id4Mass() const {return idNew;} + virtual int id5Mass() const {return idNew;} + + // Instructions for 3-body phase space with t-channel propagators. + virtual int idTchan1() const {return idNew;} + virtual int idTchan2() const {return idNew;} + virtual double tChanFracPow1() const {return 0.4;} + virtual double tChanFracPow2() const {return 0.2;} + virtual bool useMirrorWeight() const {return false;} + +private: + + // Store flavour-specific process information and standard prefactor. + double prefac, sigma, openFracTriplet, coup2Q; + int idNew, higgsType, codeSave, idRes; + string nameSave; + +}; + +//************************************************************************** + +// A derived class for q g -> H q (SM or BSM Higgs). +// (H can be H0 SM or H1, H2, A3 from BSM). + +class Sigma2qg2Hq : public Sigma2Process { + +public: + + // Constructor. + Sigma2qg2Hq(int idIn, int higgsTypeIn) : idNew(idIn), + higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qg";} + virtual int id3Mass() const {return idRes;} + virtual int id4Mass() const {return idNew;} + +private: + + // Store flavour-specific process information and standard prefactor. + double m2W, thetaWRat, sigma, openFrac; + int idNew, higgsType, codeSave, idRes; + string nameSave; + +}; + +//************************************************************************** + +// A derived class for g g -> H0 g (SM or BSM Higgs via heavy top loop). +// (H can be H0 SM or H1, H2, A3 from BSM). + +class Sigma2gg2Hglt : public Sigma2Process { + +public: + + // Constructor. + Sigma2gg2Hglt(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "gg";} + virtual int id3Mass() const {return idRes;} + +private: + + // Store standard prefactor. + double widHgg, sigma, openFrac; + int higgsType, codeSave, idRes; + string nameSave; +}; + +//************************************************************************** + +// A derived class for q g -> H q (SM or BSM Higgs via heavy top loop). +// (H can be H0 SM or H1, H2, A3 from BSM). + +class Sigma2qg2Hqlt : public Sigma2Process { + +public: + + // Constructor. + Sigma2qg2Hqlt(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qg";} + virtual int id3Mass() const {return idRes;} + +private: + + // Store standard prefactor. + double widHgg, sigma, openFrac; + int higgsType, codeSave, idRes; + string nameSave; +}; + +//************************************************************************** + +// A derived class for q qbar -> H g (SM or BSM Higgs via heavy top loop). +// (H can be H0 SM or H1, H2, A3 from BSM). + +class Sigma2qqbar2Hglt : public Sigma2Process { + +public: + + // Constructor. + Sigma2qqbar2Hglt(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qqbarSame";} + virtual int id3Mass() const {return idRes;} + +private: + + // Store standard prefactor. + double widHgg, sigma, openFrac; + int higgsType, codeSave, idRes; + string nameSave; +}; + +//************************************************************************** + +// A derived class for f fbar' -> H+-. + +class Sigma1ffbar2Hchg : public Sigma1Process { + +public: + + // Constructor. + Sigma1ffbar2Hchg() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar' -> H+-";} + virtual int code() const {return 961;} + virtual string inFlux() const {return "ffbarChg";} + virtual int resonanceA() const {return 37;} + +private: + + // A H0 resonance object provides coupling and propagator expressions. + ParticleDataEntry* HResPtr; + double mRes, GammaRes, m2Res, GamMRat, m2W, thetaWRat, tan2Beta, sigBW, + widthOutPos, widthOutNeg; + +}; + +//************************************************************************** + +// A derived class for q g -> H+- q'. + +class Sigma2qg2Hchgq : public Sigma2Process { + +public: + + // Constructor. + Sigma2qg2Hchgq(int idIn, int codeIn, string nameIn) : idNew(idIn), + codeSave(codeIn), nameSave(nameIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qg";} + virtual int id3Mass() const {return 37;} + virtual int id4Mass() const {return idNew;} + +private: + + // Store flavour-specific process information and standard prefactor. + int idNew, codeSave, idOld, idUp, idDn; + string nameSave; + double m2W, thetaWRat, tan2Beta, sigma, openFracPos, openFracNeg; + +}; + +//************************************************************************** + +// A derived class for f fbar -> A0(H_3) h0(H_1) or A0(H_3) H0(H_2). + +class Sigma2ffbar2A3H12 : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbar2A3H12(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ffbarSame";} + virtual int id3Mass() const {return 36;} + virtual int id4Mass() const {return higgs12;} + +private: + + // Store flavour-specific process information and standard prefactor. + int higgsType, higgs12, codeSave; + string nameSave; + double coupZA3H12, m2Z, mGammaZ, thetaWRat, openFrac, sigma0; + +}; + +//************************************************************************** + +// A derived class for f fbar -> H+- h0(H_1) or H+- H0(H_2). + +class Sigma2ffbar2HchgH12 : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbar2HchgH12(int higgsTypeIn) : higgsType(higgsTypeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ffbarChg";} + virtual int id3Mass() const {return 37;} + virtual int id4Mass() const {return higgs12;} + +private: + + // Store flavour-specific process information and standard prefactor. + int higgsType, higgs12, codeSave; + string nameSave; + double coupWHchgH12, m2W, mGammaW, thetaWRat, openFracPos, openFracNeg, + sigma0; + +}; + +//************************************************************************** + +// A derived class for f fbar -> H+ H-. + +class Sigma2ffbar2HposHneg : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbar2HposHneg() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar -> H+ H-";} + virtual int code() const {return 1085;} + virtual string inFlux() const {return "ffbarSame";} + virtual int id3Mass() const {return 37;} + virtual int id4Mass() const {return 37;} + +private: + + // Store flavour-specific process information and standard prefactor. + double m2Z, mGammaZ, thetaWRat, eH, lH, openFrac, gamSig, intSig, resSig; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SigmaHiggs_H diff --git a/PYTHIA8/pythia8130/include/SigmaLeftRightSym.h b/PYTHIA8/pythia8130/include/SigmaLeftRightSym.h new file mode 100644 index 00000000000..13ff8df2721 --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaLeftRightSym.h @@ -0,0 +1,275 @@ +// SigmaLeftRightSym.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for left-rights-symmetry differential cross sections. +// Contains classes derived from SigmaProcess via Sigma(1/2/3)Process. + +#ifndef Pythia8_SigmaLeftRightSym_H +#define Pythia8_SigmaLeftRightSym_H + +#include "SigmaProcess.h" + +namespace Pythia8 { + +//************************************************************************** + +// A derived class for f fbar -> Z_R^0 (righthanded gauge boson). + +class Sigma1ffbar2ZRight : public Sigma1Process { + +public: + + // Constructor. + Sigma1ffbar2ZRight() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for G* decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar -> Z_R^0";} + virtual int code() const {return 3101;} + virtual string inFlux() const {return "ffbarSame";} + virtual int resonanceA() const {return idZR;} + +private: + + // Parameters set at initialization or for current kinematics. + int idZR; + double mRes, GammaRes, m2Res, GamMRat, sin2tW, sigma0; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* ZRPtr; + +}; + +//************************************************************************** + +// A derived class for f fbar' -> W_R^+- (righthanded gauge boson). + +class Sigma1ffbar2WRight : public Sigma1Process { + +public: + + // Constructor. + Sigma1ffbar2WRight() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar' -> W_R^+-";} + virtual int code() const {return 3102;} + virtual string inFlux() const {return "ffbarChg";} + virtual int resonanceA() const {return idWR;} + +private: + + // Parameters set at initialization. + int idWR; + double mRes, GammaRes, m2Res, GamMRat, thetaWRat, sigma0Pos, sigma0Neg; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* particlePtr; + +}; + +//************************************************************************** + +// A derived class for l l -> H_L^++-- or H_R^++-- (doubly charged Higgs). + +class Sigma1ll2Hchgchg : public Sigma1Process { + +public: + + // Constructor. + Sigma1ll2Hchgchg(int leftRightIn ) : leftRight(leftRightIn) {} + + // Initialize process. + virtual void initProc(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ff";} + virtual int resonanceA() const {return idHLR;} + +private: + + // Parameters set at initialization. + int leftRight, idHLR, codeSave; + string nameSave; + double mRes, GammaRes, m2Res, GamMRat, thetaWRat, yukawa[4][4]; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* particlePtr; + +}; + +//************************************************************************** + +// A derived class for l- gamma -> H_(L/R)^-- l+ (doubly charged Higgs). + +class Sigma2lgm2Hchgchgl : public Sigma2Process { + +public: + + // Constructor. + Sigma2lgm2Hchgchgl(int leftRightIn, int idLepIn ) : leftRight(leftRightIn), + idLep(idLepIn) {} + + // Initialize process. + virtual void initProc(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "fgm";} + virtual int resonanceA() const {return idHLR;} + +private: + + // Parameters set at initialization. + int leftRight, idHLR, idLep, codeSave; + string nameSave; + double yukawa[4], openFracPos, openFracNeg; + +}; + +//************************************************************************** + +// A derived class for f_1 f_2 -> H_(L/R)^++-- f_3 f_4 (W+- W+- fusion). + +class Sigma3ff2HchgchgfftWW : public Sigma3Process { + +public: + + // Constructor. + Sigma3ff2HchgchgfftWW(int leftRightIn) : leftRight(leftRightIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for decay angles. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ff";} + virtual int id3Mass() const {return idHLR;} + + // Instructions for 3-body phase space with t-channel propagators. + virtual int idTchan1() const {return 9900024;} + virtual int idTchan2() const {return 9900024;} + virtual double tChanFracPow1() const {return 0.05;} + virtual double tChanFracPow2() const {return 0.9;} + virtual bool useMirrorWeight() const {return true;} + +private: + + // Store standard prefactor. + int leftRight, idHLR, codeSave; + string nameSave; + double mWS, prefac, sigma0TU, sigma0T, openFracPos, openFracNeg; + +}; + +//************************************************************************** + +// A derived class for f fbar -> H_(L/R)^++ H_(L/R)^-- (doubly charged Higgs). + +class Sigma2ffbar2HchgchgHchgchg : public Sigma2Process { + +public: + + // Constructor. + Sigma2ffbar2HchgchgHchgchg(int leftRightIn) : leftRight(leftRightIn) {} + + // Initialize process. + virtual void initProc(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "ffbarSame";} + virtual int id3Mass() const {return idHLR;} + virtual int id4Mass() const {return idHLR;} + virtual int resonanceA() const {return 23;} + +private: + + // Parameters set at initialization. + int leftRight, idHLR, codeSave; + string nameSave; + double mRes, GammaRes, m2Res, GamMRat, sin2tW, preFac, yukawa[4][4], + openFrac; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SigmaLeftRightSym_H diff --git a/PYTHIA8/pythia8130/include/SigmaLeptoquark.h b/PYTHIA8/pythia8130/include/SigmaLeptoquark.h new file mode 100644 index 00000000000..2a1c39b7ae2 --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaLeptoquark.h @@ -0,0 +1,176 @@ +// SigmaLeptoquark.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for leptoquark-process differential cross sections. +// Contains classes derived from SigmaProcess via Sigma(1/2)Process. +// Note: since leptoquark assumed scalar no need for decay-angles routines. + +#ifndef Pythia8_SigmaLeptoquark_H +#define Pythia8_SigmaLeptoquark_H + +#include "SigmaProcess.h" + +namespace Pythia8 { + +//************************************************************************** + +// A derived class for q l -> LQ (leptoquark). + +class Sigma1ql2LeptoQuark : public Sigma1Process { + +public: + + // Constructor. + Sigma1ql2LeptoQuark() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q l -> LQ (leptoquark)";} + virtual int code() const {return 3201;} + virtual string inFlux() const {return "ff";} + virtual int resonanceA() const {return 42;} + +private: + + // Parameters set at initialization or for current kinematics. + int idQuark, idLepton; + double mRes, GammaRes, m2Res, GamMRat, kCoup, widthIn, sigBW; + + // Pointer to properties of the particle species, to access decay channel. + ParticleDataEntry* LQPtr; + +}; + +//************************************************************************** + +// A derived class for q g -> LQ l (leptoquark). + +class Sigma2qg2LeptoQuarkl : public Sigma2Process { + +public: + + // Constructor. + Sigma2qg2LeptoQuarkl() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q g -> LQ l (leptoquark)";} + virtual int code() const {return 3202;} + virtual string inFlux() const {return "qg";} + virtual int id3Mass() const {return 42;} + +private: + + // Parameters set at initialization or for current kinematics. + int idQuark, idLepton; + double mRes, GammaRes, m2Res, GamMRat, kCoup, openFracPos, openFracNeg, + sigma0; + +}; + +//************************************************************************** + +// A derived class for g g -> LQ LQbar (leptoquark). + +class Sigma2gg2LQLQbar : public Sigma2Process { + +public: + + // Constructor. + Sigma2gg2LQLQbar() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "g g -> LQ LQbar (leptoquark)";} + virtual int code() const {return 3203;} + virtual string inFlux() const {return "gg";} + virtual int id3Mass() const {return 42;} + virtual int id4Mass() const {return 42;} + +private: + + // Parameters set at initialization or for current kinematics. + double mRes, GammaRes, m2Res, GamMRat, openFrac, sigma; + +}; + +//************************************************************************** + +// A derived class for q qbar -> LQ LQbar (leptoquark). + +class Sigma2qqbar2LQLQbar : public Sigma2Process { + +public: + + // Constructor. + Sigma2qqbar2LQLQbar() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat() { + return (abs(id1) == idQuark) ? sigmaSame : sigmaDiff;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q qbar -> LQ LQbar (leptoquark)";} + virtual int code() const {return 3204;} + virtual string inFlux() const {return "qqbarSame";} + virtual int id3Mass() const {return 42;} + virtual int id4Mass() const {return 42;} + +private: + + // Parameters set at initialization or for current kinematics. + int idQuark; + double mRes, GammaRes, m2Res, GamMRat, kCoup, openFrac, sigmaDiff, + sigmaSame; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SigmaLeptoquark_H diff --git a/PYTHIA8/pythia8130/include/SigmaNewGaugeBosons.h b/PYTHIA8/pythia8130/include/SigmaNewGaugeBosons.h new file mode 100644 index 00000000000..b8a0248bea6 --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaNewGaugeBosons.h @@ -0,0 +1,185 @@ +// SigmaNewGaugeBosons.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for new-gauge-boson-process differential cross sections. +// Contains classes derived from SigmaProcess via Sigma1Process. + +#ifndef Pythia8_SigmaNewGaugeBosons_H +#define Pythia8_SigmaNewGaugeBosons_H + +#include "PythiaComplex.h" +#include "SigmaProcess.h" + +namespace Pythia8 { + +//************************************************************************** + +// An intermediate class for f fbar -> Z'/W' -> WW/WZ -> 4 fermions. +// Copied from SigmaEW for gauge-boson-pair production. + +class Sigma1ffbarZprimeWprime: public Sigma1Process { + +public: + + // Constructor. + Sigma1ffbarZprimeWprime() {} + +protected: + + // Internal products. + Vec4 pRot[7]; + complex hA[7][7]; + complex hC[7][7]; + + // Calculate and store internal products. + void setupProd( Event& process, int i1, int i2, int i3, int i4, + int i5, int i6); + + // Evaluate the F function of Gunion and Kunszt. + complex fGK(int i1, int i2, int i3, int i4, int i5, int i6); + + // Evaluate the Xi function of Gunion and Kunszt. + double xiGK( double tHnow, double uHnow, double s3now, double s4now); + + // Evaluate the Xj function of Gunion and Kunszt. + double xjGK( double tHnow, double uHnow, double s3now, double s4now); + +private: + +}; + +//************************************************************************** + +// A derived class for f fbar -> gamma*/Z0/Z'0. + +class Sigma1ffbar2gmZZprime : public Sigma1ffbarZprimeWprime { + +public: + + // Constructor. + Sigma1ffbar2gmZZprime() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for Z' decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar -> gamma*/Z0/Zprime0";} + virtual int code() const {return 3001;} + virtual string inFlux() const {return "ffbarSame";} + virtual int resonanceA() const {return 23;} + virtual int resonanceB() const {return 32;} + +private: + + // Parameters set at initialization or for each new event. + int gmZmode; + double mRes, GammaRes, m2Res, GamMRat, sin2tW, cos2tW, thetaWRat, + mZ, GammaZ, m2Z, GamMRatZ, afZp[20], vfZp[20], coupZpWW, + anglesZpWW, gamSum, gamZSum, ZSum, gamZpSum, ZZpSum, ZpSum, + gamNorm, gamZNorm, ZNorm, gamZpNorm, ZZpNorm, ZpNorm; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* particlePtr; + +}; + +//************************************************************************** + +// A derived class for f fbar' -> W'+-. + +class Sigma1ffbar2Wprime : public Sigma1ffbarZprimeWprime { + +public: + + // Constructor. + Sigma1ffbar2Wprime() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W decay angle. + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return "f fbar' -> W'+-";} + virtual int code() const {return 3021;} + virtual string inFlux() const {return "ffbarChg";} + virtual int resonanceA() const {return 34;} + +private: + + // Parameters set at initialization. + double mRes, GammaRes, m2Res, GamMRat, thetaWRat, sigma0Pos, sigma0Neg, + aqWp, vqWp, alWp, vlWp, coupWpWZ, anglesWpWZ; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* particlePtr; + +}; +//************************************************************************** + +// A derived class for f fbar' -> R^0 (horizontal gauge boson). + +class Sigma1ffbar2Rhorizontal : public Sigma1Process { + +public: + + // Constructor. + Sigma1ffbar2Rhorizontal() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate sigmaHat(sHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "f fbar' -> R^0";} + virtual int code() const {return 3041;} + virtual string inFlux() const {return "ffbar";} + virtual int resonanceA() const {return 41;} + +private: + + // Parameters set at initialization. + double mRes, GammaRes, m2Res, GamMRat, thetaWRat, sigma0Pos, sigma0Neg; + + // Pointer to properties of the particle species, to access decay channels. + ParticleDataEntry* particlePtr; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia_SigmaNewGaugeBosons_H diff --git a/PYTHIA8/pythia8130/include/SigmaOnia.h b/PYTHIA8/pythia8130/include/SigmaOnia.h new file mode 100644 index 00000000000..3f5ee6e24f9 --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaOnia.h @@ -0,0 +1,294 @@ +// SigmaOnia.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for charmonia/bottomonia process differential cross sections. +// Contains classes derived from SigmaProcess via Sigma2Process. + +#ifndef Pythia8_SigmaOnia_H +#define Pythia8_SigmaOnia_H + +#include "SigmaProcess.h" + +namespace Pythia8 { + +//************************************************************************** + +// A derived class for g g -> QQbar[3S1(1)] g (Q = c or b). + +class Sigma2gg2QQbar3S11g : public Sigma2Process { + +public: + + // Constructor. + Sigma2gg2QQbar3S11g(int idIn, int codeIn) : idNew(idIn), + codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "gg";} + virtual int id3Mass() const {return idHad;} + + private: + + // Values stored for process type and colour flow selection. + int idNew, idHad, codeSave; + string nameSave; + double oniumME, sigma; + +}; + +//************************************************************************** + +// A derived class for g g -> QQbar[3PJ(1)] g (Q = c or b, J = 0, 1 or 2). + +class Sigma2gg2QQbar3PJ1g : public Sigma2Process { + +public: + + // Constructor. + Sigma2gg2QQbar3PJ1g(int idIn, int jIn, int codeIn) : idNew(idIn), + jSave(jIn), codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "gg";} + virtual int id3Mass() const {return idHad;} + + private: + + // Values stored for process type and colour flow selection. + int idNew, idHad, jSave, codeSave; + string nameSave; + double oniumME, sigma; + +}; + +//************************************************************************** + +// A derived class for q g -> QQbar[3PJ(1)] q (Q = c or b, J = 0, 1 or 2). + +class Sigma2qg2QQbar3PJ1q : public Sigma2Process { + +public: + + // Constructor. + Sigma2qg2QQbar3PJ1q(int idIn, int jIn, int codeIn) : idNew(idIn), + jSave(jIn), codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qg";} + virtual int id3Mass() const {return idHad;} + + private: + + // Values stored for process type and colour flow selection. + int idNew, idHad, jSave, codeSave; + string nameSave; + double oniumME, sigma; + +}; + +//************************************************************************** + +// A derived class for q qbar -> QQbar[3PJ(1)] g (Q = c or b, J = 0, 1 or 2). + +class Sigma2qqbar2QQbar3PJ1g : public Sigma2Process { + +public: + + // Constructor. + Sigma2qqbar2QQbar3PJ1g(int idIn, int jIn, int codeIn) : idNew(idIn), + jSave(jIn), codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qqbarSame";} + virtual int id3Mass() const {return idHad;} + + private: + + // Values stored for process type and colour flow selection. + int idNew, idHad, jSave, codeSave; + string nameSave; + double oniumME, sigma; + +}; + +//************************************************************************** + +// A derived class for g g -> QQbar[X(8)] g (Q = c or b, X = 3S1, 1S0 or 3PJ). + +class Sigma2gg2QQbarX8g : public Sigma2Process { + +public: + + // Constructor. + Sigma2gg2QQbarX8g(int idIn, int stateIn, int codeIn) : idNew(idIn), + stateSave(stateIn), codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "gg";} + virtual int id3Mass() const {return idHad;} + + private: + + // Values stored for process type and colour flow selection. + int idNew, idHad, stateSave, codeSave; + string nameSave; + double oniumME, sigma; + +}; + +//************************************************************************** + +// A derived class for q g -> QQbar[X(8)] q (Q = c or b, X = 3S1, 1S0 or 3PJ). + +class Sigma2qg2QQbarX8q : public Sigma2Process { + +public: + + // Constructor. + Sigma2qg2QQbarX8q(int idIn, int stateIn, int codeIn) : idNew(idIn), + stateSave(stateIn), codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qg";} + virtual int id3Mass() const {return idHad;} + + private: + + // Values stored for process type and colour flow selection. + int idNew, idHad, stateSave, codeSave; + string nameSave; + double oniumME, sigma; + +}; + +//************************************************************************** + +// A derived class for q qbar -> QQbar[X(8)] g (Q = c or b, +// X = 3S1, 1S0 or 3PJ). + +class Sigma2qqbar2QQbarX8g : public Sigma2Process { + +public: + + // Constructor. + Sigma2qqbar2QQbarX8g(int idIn, int stateIn, int codeIn) : idNew(idIn), + stateSave(stateIn), codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qqbarSame";} + virtual int id3Mass() const {return idHad;} + + private: + + // Values stored for process type and colour flow selection. + int idNew, idHad, stateSave, codeSave; + string nameSave; + double oniumME, sigma; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SigmaOnia_H diff --git a/PYTHIA8/pythia8130/include/SigmaProcess.h b/PYTHIA8/pythia8130/include/SigmaProcess.h new file mode 100644 index 00000000000..3fec34f65dd --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaProcess.h @@ -0,0 +1,537 @@ +// SigmaProcess.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for hard-process differential cross sections. +// SigmaProcess: base class for cross sections. +// Sigma0Process: base class for unresolved processes, derived from above. +// Sigma1Process: base class for 2 -> 1 processes, derived from above. +// Sigma2Process: base class for 2 -> 2 processes, derived from above. +// Sigma3Process: base class for 2 -> 3 processes, derived from above. +// SigmaLHAProcess: wrapper class for Les Houches Accord external input. +// Actual physics processes are found in separate files: +// SigmaQCD for QCD processes; +// SigmaEW for electroweak processes (including photon production); +// SigmaOnia for charmonium and bottomonium processes; +// SigmaHiggs for Higgs processes; +// SigmaSUSY for supersymmetric production; +// SigmaLeftRightSym for processes in left-right-symmetric scenarios; +// SigmaLeptoquark for leptoquark production. +// SigmaExtraDim for processes in scenarios for extra dimensions. + +#ifndef Pythia8_SigmaProcess_H +#define Pythia8_SigmaProcess_H + +#include "Basics.h" +#include "BeamParticle.h" +#include "Event.h" +#include "Info.h" +#include "LesHouches.h" +#include "ParticleData.h" +#include "PartonDistributions.h" +#include "PythiaStdlib.h" +#include "ResonanceWidths.h" +#include "Settings.h" +#include "SigmaTotal.h" +#include "StandardModel.h" +#include "SusyLesHouches.h" + +namespace Pythia8 { + +//************************************************************************** + +// InBeam is a simple helper class for partons and their flux in a beam. + +class InBeam { + +public: + + // Constructor. + InBeam( int idIn = 0) : id(idIn), pdf(0.) {} + + // Values. + int id; + double pdf; + +}; + +//************************************************************************** + +// InPair is a simple helper class for colliding parton pairs and their flux. + +class InPair { + +public: + + // Constructor. + InPair( int idAIn = 0, int idBIn = 0) : idA(idAIn), idB(idBIn), + pdfA(0.), pdfB(0.), pdfSigma(0.) {} + + // Values. + int idA, idB; + double pdfA, pdfB, pdfSigma; + +}; + +//************************************************************************** + +// SigmaProcess is the base class for cross section calculations. + +class SigmaProcess { + +public: + + // Destructor. + virtual ~SigmaProcess() {} + + // Perform simple initialization and store pointers. + void init(Info* infoPtrIn, BeamParticle* beamAPtrIn, + BeamParticle* beamBPtrIn, AlphaStrong* alphaSPtrIn, + AlphaEM* alphaEMPtrIn, SigmaTotal* sigmaTotPtrIn, + SusyLesHouches* slhaPtrIn); + + // Store or replace Les Houches pointer. + void setLHAPtr( LHAup* lhaUpPtrIn) {lhaUpPtr = lhaUpPtrIn;} + + // Initialize process. Only used for some processes. + virtual void initProc() {} + + // Set up allowed flux of incoming partons. Default is no flux. + virtual bool initFlux(); + + // Input and complement kinematics for resolved 2 -> 1 process. + // Usage: set1Kin( x1in, x2in, sHin). + virtual void set1Kin( double , double , double ) {} + + // Input and complement kinematics for resolved 2 -> 2 process. + // Usage: set2Kin( x1in, x2in, sHin, tHin, m3in, m4in, runBW3in, runBW4in). + virtual void set2Kin( double , double , double , double , double , + double, double, double ) {} + + // Ditto, but for Multiple Interactions applications, so different input. + // Usage: set2KinMI( x1in, x2in, sHin, tHin, uHin, + // alpSin, alpEMin, needMasses, m3in, m4in) + virtual void set2KinMI( double , double , double , double , + double , double , double , bool , double , double ) {} + + // Input and complement kinematics for resolved 2 -> 3 process. + // Usage: set3Kin( x1in, x2in, sHin, p3prel, p4prel, p5prel, + // m3in, m4in, m5in, runBW3in, runBW4in, runBW5in); + virtual void set3Kin( double , double , double , Vec4 , Vec4 , Vec4 , + double , double , double , double , double , double ) {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin() {} + + // Evaluate sigma for unresolved, sigmaHat(sHat) for 2 -> 1 processes, + // d(sigmaHat)/d(tHat) for (resolved) 2 -> 2 processes, and |M|^2 for + // 2 -> 3 processes. Answer in "native" units, either mb or GeV^-2. + virtual double sigmaHat() {return 0.;} + + // Wrapper to sigmaHat, to (a) store current incoming flavours and + // (b) convert from GeV^-2 to mb where required. + double sigmaHatWrap(int id1in = 0, int id2in = 0) { + id1 = id1in; id2 = id2in; + return ( convert2mb() ? CONVERT2MB * sigmaHat() : sigmaHat() ); } + + // Convolute above with parton flux and K factor. Sum over open channels. + virtual double sigmaPDF(); + + // Select incoming parton channel and extract parton densities (resolved). + void pickInState(int id1in = 0, int id2in = 0); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol() {} + + // Perform kinematics for a Multiple Interaction, in its rest frame. + virtual bool final2KinMI() {return true;} + + // Evaluate weight for simultaneous flavours (only gamma*/Z0 gamma*/Z0). + // Usage: weightDecayFlav( process). + virtual double weightDecayFlav( Event&) {return 1.;} + + // Evaluate weight for decay angular configuration. + // Usage: weightDecay( process, iResBeg, iResEnd), where + // iResBeg <= i < iResEnd is range of sister partons to test decays of. + virtual double weightDecay( Event&, int, int) {return 1.;} + + // Process name and code, and the number of final-state particles. + virtual string name() const {return "unnamed process";} + virtual int code() const {return 0;} + virtual int nFinal() const {return 2;} + + // Need to know which incoming partons to set up interaction for. + virtual string inFlux() const {return "unknown";} + + // Need to know whether to convert cross section answer from GeV^-2 to mb. + virtual bool convert2mb() const {return true;} + + // Special treatment needed for Les Houches processes. + virtual bool isLHA() const {return false;} + + // Special treatment needed for elastic and diffractive processes. + virtual bool isMinBias() const {return false;} + virtual bool isResolved() const {return true;} + virtual bool isDiffA() const {return false;} + virtual bool isDiffB() const {return false;} + + // Special treatment needed if negative cross sections allowed. + virtual bool allowNegativeSigma() const {return false;} + + // Flavours in 2 -> 2/3 processes where masses needed from beginning. + // (For a light quark masses will be used in the final kinematics, + // but not at the matrix-element level. For a gluon no masses at all.) + virtual int id3Mass() const {return 0;} + virtual int id4Mass() const {return 0;} + virtual int id5Mass() const {return 0;} + + // Special treatment needed if process contains an s-channel resonance. + virtual int resonanceA() const {return 0;} + virtual int resonanceB() const {return 0;} + + // 2 -> 2 and 2 -> 3 processes only through s-channel exchange. + virtual bool isSChannel() const {return false;} + + // Special treatment in 2 -> 3 with two massive propagators. + virtual int idTchan1() const {return 0;} + virtual int idTchan2() const {return 0;} + virtual double tChanFracPow1() const {return 0.3;} + virtual double tChanFracPow2() const {return 0.3;} + virtual bool useMirrorWeight() const {return false;} + + // Special process-specific gamma*/Z0 choice if >=0 (e.g. f fbar -> H0 Z0). + virtual int gmZmode() const {return -1;} + + // Tell whether tHat and uHat are swapped (= same as swap 3 and 4). + bool swappedTU() const {return swapTU;} + + // Give back particle properties: flavours, colours, masses, or all. + int id(int i) const {return idSave[i];} + int col(int i) const {return colSave[i];} + int acol(int i) const {return acolSave[i];} + double m(int i) const {return mSave[i];} + Particle getParton(int i) const {return parton[i];} + + // Give back couplings and parton densities. Not all known for minbias. + double Q2Ren() const {return Q2RenSave;} + double alphaEMRen() const {return alpEM;} + double alphaSRen() const {return alpS;} + double Q2Fac() const {return Q2FacSave;} + double pdf1() const {return pdf1Save;} + double pdf2() const {return pdf2Save;} + + // Give back angles; relevant only for multipe-interactions processes. + double thetaMI() const {return atan2( sinTheta, cosTheta);} + double phiMI() const {return phi;} + double sHBetaMI() const {return sHBeta;} + double pT2MI() const {return pT2Mass;} + +protected: + + // Constructor. + SigmaProcess() {for (int i = 0; i < 6; ++i) mSave[i] = 0.;} + + // Constants: could only be changed in the code itself. + static const double CONVERT2MB, MASSMARGIN; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointers to incoming beams. + BeamParticle* beamAPtr; + BeamParticle* beamBPtr; + + // Pointers to alphaStrong and alphaElectromagnetic calculation. + AlphaStrong* alphaSPtr; + AlphaEM* alphaEMPtr; + + // Pointer to the total/elastic/diffractive cross section object. + SigmaTotal* sigmaTotPtr; + + // Pointer to LHAup for generating external events. + LHAup* lhaUpPtr; + + // Pointer to the SLHA object. + SusyLesHouches* slhaPtr; + + // Initialization data, normally only set once. + int nQuarkIn, renormScale1, renormScale2, renormScale3, renormScale3VV, + factorScale1, factorScale2, factorScale3, factorScale3VV; + double Kfactor, renormMultFac, renormFixScale, factorMultFac, + factorFixScale; + + // CP violation parameters for Higgs sector, normally only set once. + int higgsH1parity, higgsH2parity, higgsA3parity; + double higgsH1eta, higgsH2eta, higgsA3eta; + + // Information on incoming beams. + int idA, idB; + double mA, mB; + bool isLeptonA, isLeptonB, hasLeptonBeams; + + // Partons in beams, with PDF's. + vector inBeamA; + vector inBeamB; + void addBeamA(int idIn) {inBeamA.push_back(InBeam(idIn));} + void addBeamB(int idIn) {inBeamB.push_back(InBeam(idIn));} + int sizeBeamA() const {return inBeamA.size();} + int sizeBeamB() const {return inBeamB.size();} + + // Allowed colliding parton pairs, with pdf's. + vector inPair; + void addPair(int idAIn, int idBIn) { + inPair.push_back(InPair(idAIn, idBIn));} + int sizePair() const {return inPair.size();} + + // Store Q2 renormalization and factorization scales, and related values. + double Q2RenSave, alpEM, alpS, Q2FacSave, x1Save, x2Save, pdf1Save, + pdf2Save, sigmaSumSave; + + // Store flavour, colour, anticolour, mass, angles and the whole particle. + int id1, id2, id3, id4, id5; + int idSave[6], colSave[6], acolSave[6]; + double mSave[6], cosTheta, sinTheta, phi, sHMass, sHBeta, pT2Mass; + Particle parton[6]; + + // Store whether tHat and uHat are swapped (= same as swap 3 and 4). + bool swapTU; + + // Set flavour, colour and anticolour. + void setId( int id1in = 0, int id2in = 0, int id3in = 0, int id4in = 0, + int id5in = 0) {idSave[1] = id1in; idSave[2] = id2in; idSave[3] = id3in; + idSave[4] = id4in; idSave[5] = id5in;} + void setColAcol( int col1 = 0, int acol1 = 0, + int col2 = 0, int acol2 = 0, int col3 = 0, int acol3 = 0, + int col4 = 0, int acol4 = 0, int col5 = 0, int acol5 = 0) { + colSave[1] = col1; acolSave[1] = acol1; colSave[2] = col2; + acolSave[2] = acol2; colSave[3] = col3; acolSave[3] = acol3; + colSave[4] = col4; acolSave[4] = acol4; colSave[5] = col5; + acolSave[5] = acol5; } + void swapColAcol() { swap(colSave[1], acolSave[1]); + swap(colSave[2], acolSave[2]); swap(colSave[3], acolSave[3]); + swap(colSave[4], acolSave[4]); swap(colSave[5], acolSave[5]);} + void swapCol1234() { swap(colSave[1], colSave[2]); + swap(colSave[3], colSave[4]); swap(acolSave[1], acolSave[2]); + swap(acolSave[3], acolSave[4]);} + void swapCol12() { swap(colSave[1], colSave[2]); + swap(acolSave[1], acolSave[2]);} + void swapCol34() { swap(colSave[3], colSave[4]); + swap(acolSave[3], acolSave[4]);} + + // Common code for top and Higgs secondary decay angular weights. + double weightTopDecay( Event& process, int iResBeg, int iResEnd); + double weightHiggsDecay( Event& process, int iResBeg, int iResEnd); + +}; + +//************************************************************************** + +// Sigma0Process is the base class for unresolved and minimum-bias processes. +// It is derived from SigmaProcess. + +class Sigma0Process : public SigmaProcess { + +public: + + // Destructor. + virtual ~Sigma0Process() {} + + // Number of final-state particles. + virtual int nFinal() const {return 2;}; + + // No partonic flux to be set up. + virtual bool initFlux() {return true;} + + // Evaluate sigma for unresolved processes. + virtual double sigmaHat() {return 0.;} + + // Since no PDF's there is no difference from above. + virtual double sigmaPDF() {return sigmaHat();} + + // Answer for these processes already in mb, so do not convert. + virtual bool convert2mb() const {return false;} + +protected: + + // Constructor. + Sigma0Process() {} + +}; + +//************************************************************************** + +// Sigma1Process is the base class for 2 -> 1 processes. +// It is derived from SigmaProcess. + +class Sigma1Process : public SigmaProcess { + +public: + + // Destructor. + virtual ~Sigma1Process() {} + + // Number of final-state particles. + virtual int nFinal() const {return 1;}; + + // Input and complement kinematics for resolved 2 -> 1 process. + virtual void set1Kin( double x1in, double x2in, double sHin) { + store1Kin( x1in, x2in, sHin); sigmaKin();} + + // Evaluate sigmaHat(sHat) for resolved 2 -> 1 processes. + virtual double sigmaHat() {return 0.;} + +protected: + + // Constructor. + Sigma1Process() {} + + // Store kinematics and set scales for resolved 2 -> 1 process. + virtual void store1Kin( double x1in, double x2in, double sHin); + + // Store subprocess kinematics quantities. + double mH, sH, sH2; + +}; + +//************************************************************************** + +// Sigma2Process is the base class for 2 -> 2 processes. +// It is derived from SigmaProcess. + +class Sigma2Process : public SigmaProcess { + +public: + + // Destructor. + virtual ~Sigma2Process() {} + + // Number of final-state particles. + virtual int nFinal() const {return 2;}; + + // Input and complement kinematics for resolved 2 -> 2 process. + virtual void set2Kin( double x1in, double x2in, double sHin, + double tHin, double m3in, double m4in, double runBW3in, + double runBW4in) { store2Kin( x1in, x2in, sHin, tHin, m3in, m4in, + runBW3in, runBW4in); sigmaKin();} + + // Ditto, but for Multiple Interactions applications, so different input. + virtual void set2KinMI( double x1in, double x2in, double sHin, + double tHin, double uHin, double alpSin, double alpEMin, + bool needMasses, double m3in, double m4in) { + store2KinMI( x1in, x2in, sHin, tHin, uHin, alpSin, alpEMin, + needMasses, m3in, m4in); sigmaKin();} + + // Evaluate d(sigmaHat)/d(tHat) for resolved 2 -> 2 processes. + virtual double sigmaHat() {return 0.;} + + // Perform kinematics for a Multiple Interaction, in its rest frame. + virtual bool final2KinMI(); + +protected: + + // Constructor. + Sigma2Process() {} + + // Store kinematics and set scales for resolved 2 -> 2 process. + virtual void store2Kin( double x1in, double x2in, double sHin, + double tHin, double m3in, double m4in, double runBW3in, + double runBW4in); + virtual void store2KinMI( double x1in, double x2in, double sHin, + double tHin, double uHin, double alpSin, double alpEMin, + bool needMasses, double m3in, double m4in); + + // Store subprocess kinematics quantities. + double mH, sH, tH, uH, sH2, tH2, uH2, m3, s3, m4, s4, pT2, runBW3, runBW4; + +}; + +//************************************************************************** + +// Sigma3Process is the base class for 2 -> 3 processes. +// It is derived from SigmaProcess. + +class Sigma3Process : public SigmaProcess { + +public: + + // Destructor. + virtual ~Sigma3Process() {} + + // Number of final-state particles. + virtual int nFinal() const {return 3;}; + + // Input and complement kinematics for resolved 2 -> 3 process. + virtual void set3Kin( double x1in, double x2in, double sHin, + Vec4 p3cmIn, Vec4 p4cmIn, Vec4 p5cmIn, double m3in, double m4in, + double m5in, double runBW3in, double runBW4in, double runBW5in) { + store3Kin( x1in, x2in, sHin, p3cmIn, p4cmIn, p5cmIn, m3in, m4in, m5in, + runBW3in, runBW4in, runBW5in); sigmaKin();} + + // Evaluate d(sigmaHat)/d(tHat) for resolved 2 -> 3 processes. + virtual double sigmaHat() {return 0.;} + +protected: + + // Constructor. + Sigma3Process() {} + + // Store kinematics and set scales for resolved 2 -> 3 process. + virtual void store3Kin( double x1in, double x2in, double sHin, + Vec4 p3cmIn, Vec4 p4cmIn, Vec4 p5cmIn, double m3in, double m4in, + double m5in, double runBW3in, double runBW4in, double runBW5in); + + // Store subprocess kinematics quantities. + double mH, sH, m3, s3, m4, s4, m5, s5, runBW3, runBW4, runBW5; + Vec4 p3cm, p4cm, p5cm; + +}; + +//************************************************************************** + +// SigmaLHAProcess is a wrapper class for Les Houches Accord external input. +// It is derived from SigmaProcess. + +class SigmaLHAProcess : public SigmaProcess { + +public: + + // Constructor. + SigmaLHAProcess() {} + + // Destructor. + virtual ~SigmaLHAProcess() {} + + // No partonic flux to be set up. + virtual bool initFlux() {return true;} + + // Dummy function: action is put in PhaseSpaceLHA. + virtual double sigmaPDF() {return 1.;} + + // Info on the subprocess. + virtual string name() const {return "Les Houches User Process(es)";} + virtual int code() const {return 9999;} + + // Number of final-state particles depends on current process choice. + virtual int nFinal() const; + + // Answer for these processes not in GeV^-2, so do not do this conversion. + virtual bool convert2mb() const {return false;} + + // Ensure special treatment of Les Houches processes. + virtual bool isLHA() const {return true;} + + // Special treatment needed if negative cross sections allowed. + virtual bool allowNegativeSigma() const { + return (lhaUpPtr->strategy() < 0);} + +private: + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SigmaProcess_H + diff --git a/PYTHIA8/pythia8130/include/SigmaQCD.h b/PYTHIA8/pythia8130/include/SigmaQCD.h new file mode 100644 index 00000000000..82768534376 --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaQCD.h @@ -0,0 +1,446 @@ +// SigmaQCD.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for QCD process differential cross sections. +// Contains classes derived from SigmaProcess via Sigma(0/2)Process. + +#ifndef Pythia8_SigmaQCD_H +#define Pythia8_SigmaQCD_H + +#include "SigmaProcess.h" + +namespace Pythia8 { + +//************************************************************************** + +// A derived class for minimum-bias (inelastic, nondiffractive) events. + +class Sigma0minBias : public Sigma0Process { + +public: + + // Constructor. + Sigma0minBias() {} + + // Evaluate sigma. + virtual double sigmaHat() {return sigmaTotPtr->sigmaND();} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol() {} + + // Info on the subprocess. + virtual string name() const {return "minimum bias";} + virtual int code() const {return 101;} + virtual bool isMinBias() const {return true;} + +private: + +}; + +//************************************************************************** + +// A derived class for elastic scattering A B -> A B. + +class Sigma0AB2AB : public Sigma0Process { + +public: + + // Constructor. + Sigma0AB2AB() {} + + // Evaluate sigma. + virtual double sigmaHat() {return sigmaTotPtr->sigmaEl();} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "A B -> A B elastic";} + virtual int code() const {return 102;} + virtual bool isResolved() const {return false;} + +private: + +}; + +//************************************************************************** + +// A derived class for single diffractive scattering A B -> X B. + +class Sigma0AB2XB : public Sigma0Process { + +public: + + // Constructor. + Sigma0AB2XB() {} + + // Evaluate sigma. + virtual double sigmaHat() {return sigmaTotPtr->sigmaXB();} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "A B -> X B single diffractive";} + virtual int code() const {return 103;} + virtual bool isResolved() const {return false;} + virtual bool isDiffA() const {return true;}; + +private: + +}; + +//************************************************************************** + +// A derived class for single diffractive scattering A B -> A X. + +class Sigma0AB2AX : public Sigma0Process { + +public: + + // Constructor. + Sigma0AB2AX() {} + + // Evaluate sigma. + virtual double sigmaHat() {return sigmaTotPtr->sigmaAX();} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "A B -> A X single diffractive";} + virtual int code() const {return 104;} + virtual bool isResolved() const {return false;} + virtual bool isDiffB() const {return true;}; + +private: + +}; + +//************************************************************************** + +// A derived class for double diffractive scattering A B -> X X. + +class Sigma0AB2XX : public Sigma0Process { + +public: + + // Constructor. + Sigma0AB2XX() {} + + // Evaluate sigma. + virtual double sigmaHat() {return sigmaTotPtr->sigmaXX();} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "A B -> X X double diffractive";} + virtual int code() const {return 105;} + virtual bool isResolved() const {return false;} + virtual bool isDiffA() const {return true;}; + virtual bool isDiffB() const {return true;}; + +private: + +}; + +//************************************************************************** + +// A derived class for g g -> g g. + +class Sigma2gg2gg : public Sigma2Process { + +public: + + // Constructor. + Sigma2gg2gg() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "g g -> g g";} + virtual int code() const {return 111;} + virtual string inFlux() const {return "gg";} + +private: + + // Values stored for colour flow selection. + double sigTS, sigUS, sigTU, sigSum, sigma; + +}; + +//************************************************************************** + +// A derived class for g g -> q qbar (q = u, d, s, i.e. almost massless). + +class Sigma2gg2qqbar : public Sigma2Process { + +public: + + // Constructor. + Sigma2gg2qqbar() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "g g -> q qbar (uds)";} + virtual int code() const {return 112;} + virtual string inFlux() const {return "gg";} + +private: + + // Number of quarks to be considered in massless approximation. + int nQuarkNew; + + // Values stored for colour flow selection. + int idNew; + double mNew, m2New, sigTS, sigUS, sigSum, sigma; + +}; + +//************************************************************************** + +// A derived class for q g -> q g (q = u, d, s, c, b). +// Use massless approximation also for Q since no alternative. + +class Sigma2qg2qg : public Sigma2Process { + +public: + + // Constructor. + Sigma2qg2qg() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q g -> q g";} + virtual int code() const {return 113;} + virtual string inFlux() const {return "qg";} + +private: + + // Values stored for colour flow selection. + double mNew, m2New, sigTS, sigTU, sigSum, sigma; + +}; + +//************************************************************************** + +// A derived class for q qbar' -> q qbar' or q q' -> q q' +// (qbar qbar' -> qbar qbar'), q' may be same as q. + +class Sigma2qq2qq : public Sigma2Process { + +public: + + // Constructor. + Sigma2qq2qq() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q q(bar)' -> q q(bar)'";} + virtual int code() const {return 114;} + virtual string inFlux() const {return "qq";} + + private: + + // Values stored for colour flow selection. + double sigT, sigU, sigTU, sigST, sigSum; + +}; + +//************************************************************************** + +// A derived class for q qbar -> g g. + +class Sigma2qqbar2gg : public Sigma2Process { + +public: + + // Constructor. + Sigma2qqbar2gg() {} + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q qbar -> g g";} + virtual int code() const {return 115;} + virtual string inFlux() const {return "qqbarSame";} + + private: + + // Values stored for colour flow selection. + double sigTS, sigUS, sigSum, sigma; + +}; + +//************************************************************************** + +// A derived class for q qbar -> q' qbar'. + +class Sigma2qqbar2qqbarNew : public Sigma2Process { + +public: + + // Constructor. + Sigma2qqbar2qqbarNew() {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return "q qbar -> q' qbar' (uds)";} + virtual int code() const {return 116;} + virtual string inFlux() const {return "qqbarSame";} + + private: + + // Number of quarks to be considered in massless approximation. + int nQuarkNew; + + // Values stored for colour flow selection. + int idNew; + double mNew, m2New, sigS, sigma; + +}; + +//************************************************************************** + +// A derived class for g g -> Q Qbar (Q = c, b or t). + +class Sigma2gg2QQbar : public Sigma2Process { + +public: + + // Constructor. + Sigma2gg2QQbar(int idIn, int codeIn) : idNew(idIn), codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W decay angles in top decay (else inactive). + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "gg";} + virtual int id3Mass() const {return idNew;} + virtual int id4Mass() const {return idNew;} + + private: + + // Values stored for process type and colour flow selection. + int idNew, codeSave; + string nameSave; + double sigTS, sigUS, sigSum, sigma, openFracPair; + +}; + +//************************************************************************** + +// A derived class for q qbar -> Q Qbar (Q = c, b or t). + +class Sigma2qqbar2QQbar : public Sigma2Process { + +public: + + // Constructor. + Sigma2qqbar2QQbar(int idIn, int codeIn) : idNew(idIn), codeSave(codeIn) {} + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat() {return sigma;} + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Evaluate weight for W decay angles in top decay (else inactive). + virtual double weightDecay( Event& process, int iResBeg, int iResEnd); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qqbarSame";} + virtual int id3Mass() const {return idNew;} + virtual int id4Mass() const {return idNew;} + + private: + + // Values stored for process type. + int idNew, codeSave; + string nameSave; + double sigma, openFracPair; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SigmaQCD_H diff --git a/PYTHIA8/pythia8130/include/SigmaSUSY.h b/PYTHIA8/pythia8130/include/SigmaSUSY.h new file mode 100644 index 00000000000..b91c6205e49 --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaSUSY.h @@ -0,0 +1,164 @@ +// SigmaSUSY.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for Supersymmetric process differential cross sections. +// Contains classes derived from SigmaProcess via Sigma2Process. + +#ifndef Pythia8_SigmaSUSY_H +#define Pythia8_SigmaSUSY_H + +#include "PythiaComplex.h" +#include "SigmaProcess.h" + +namespace Pythia8 { + +//************************************************************************** + +// A derived class for q qbar -> gaugino_i gaugino_j. + +class Sigma2qqbar2gauginogaugino : public Sigma2Process { + +public: + + // Constructor. + Sigma2qqbar2gauginogaugino() { } + + // Initialize process. + virtual void initProc(); + + // Calculate flavour-independent parts of cross section. + virtual void sigmaKin(); + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + + // Select flavour, colour and anticolour. + virtual void setIdColAcol(); + + // Info on the subprocess. + virtual string name() const {return nameSave;} + virtual int code() const {return codeSave;} + virtual string inFlux() const {return "qq";} + virtual int id3Mass() const {return id3;} + virtual int id4Mass() const {return id4;} + + protected: + + // Values stored for later use. + int id3chi, id4chi, codeSave; + string nameSave; + double sigma0, ui, uj, ti, tj, sz, d; + complex propZ; + + // Couplings. + // Shorthand for sin2thetaW, mZ, and GammaZ. + double sin2W, mZpole, wZpole; + // qqZ couplings. + double LqqZ[10], RqqZ[10]; + // qsqchi_i couplings. + complex LsqXi[10][10], RsqXi[10][10]; + complex LsqCi[10][10], RsqCi[10][10]; + // qsqchi_j couplings. + complex LsqXj[10][10], RsqXj[10][10]; + complex LsqCj[10][10], RsqCj[10][10]; + // W/Z chi chi couplings + complex OL, OR, OLp, ORp, OLpp, ORpp; + + // Code to say whether it is chi0chi0, chi+chi0, or chi+chi+ + int nCharged; + +}; + +class Sigma2qqbar2chi0chi0 : public Sigma2qqbar2gauginogaugino { + +public: + + // Constructor. + Sigma2qqbar2chi0chi0(int id3chiIn, int id4chiIn, int codeIn) { + + // Save ordering indices and process code + id3chi=id3chiIn; + id4chi=id4chiIn; + codeSave=codeIn; + + // Construct id codes from ordering indices. + id3 = 1000022; + if (id3chi == 2) id3 = 1000023; + if (id3chi == 3) id3 = 1000025; + if (id3chi == 4) id3 = 1000035; + if (id3chi == 5) id3 = 1000045; + id4 = 1000022; + if (id4chi == 2) id4 = 1000023; + if (id4chi == 3) id4 = 1000025; + if (id4chi == 4) id4 = 1000035; + if (id4chi == 5) id4 = 1000045; + + } + +}; + +// A derived class for q qbar -> neutralino_i chargino_j. + +class Sigma2qqbar2chi0char : public Sigma2qqbar2gauginogaugino { + +public: + + // Constructor. + Sigma2qqbar2chi0char(int id3chiIn, int id4chiIn, int codeIn) { + + // Save ordering indices and process code + id3chi=id3chiIn; + id4chi=id4chiIn; + codeSave=codeIn; + + // Construct id codes from ordering indices. + id3 = 1000022; + if (id3chi == 2) id3 = 1000023; + if (id3chi == 3) id3 = 1000025; + if (id3chi == 4) id3 = 1000035; + if (id3chi == 5) id3 = 1000045; + id4 = 1000024; + if (id4chi == 2) id4 = 1000037; + + } + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + +}; + +// A derived class for q qbar -> chargino_i chargino_j. + +class Sigma2qqbar2charchar : public Sigma2qqbar2gauginogaugino { + +public: + + // Constructor. + Sigma2qqbar2charchar(int id3chiIn, int id4chiIn, int codeIn) { + + // Save ordering indices and process code + id3chi=id3chiIn; + id4chi=id4chiIn; + codeSave=codeIn; + + // Construct id codes from ordering indices. + id3 = -1000024; + if (id3chi == 2) id3 = -1000037; + id4 = 1000024; + if (id4chi == 2) id4 = 1000037; + + } + + // Evaluate d(sigmaHat)/d(tHat). + virtual double sigmaHat(); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SigmaSUSY_H + diff --git a/PYTHIA8/pythia8130/include/SigmaTotal.h b/PYTHIA8/pythia8130/include/SigmaTotal.h new file mode 100644 index 00000000000..b0baa244071 --- /dev/null +++ b/PYTHIA8/pythia8130/include/SigmaTotal.h @@ -0,0 +1,94 @@ +// SigmaTotal.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the class for cross section parametrizations. +// SigmaTotal: total and partial cross section in hadron-hadron collisions. + +#ifndef Pythia8_SigmaTotal_H +#define Pythia8_SigmaTotal_H + +#include "Info.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// The SigmaTotal class contains parametrizations of total, elastic and +// diffractive cross sections, and of the respective slope parameter. + +class SigmaTotal { + +public: + + // Constructor. + SigmaTotal() : isCalc(false) {}; + + // Storee pointer to Info and initialize data members. + void init(Info* infoPtrIn); + + // Calculate, or recalculate for new beams or new energy. + bool calc(int idA, int idB, double eCM); + + // Confirm that initialization worked. + bool hasSigmaTot() const {return isCalc;} + + // Read out total and partial cross sections. + double sigmaTot() const {return sigTot;} + double sigmaEl() const {return sigEl;} + double sigmaXB() const {return sigXB;} + double sigmaAX() const {return sigAX;} + double sigmaXX() const {return sigXX;} + double sigmaND() const {return sigND;} + + // Read out slope b in exp(b*t) dependence. + double bSlopeEl() const {return bEl;} + double bSlopeXB(double sX) const { return 2.*bB + alP2 * log(s/sX) ;} + double bSlopeAX(double sX) const { return 2.*bA + alP2 * log(s/sX) ;} + double bSlopeXX(double sX1, double sX2) const { + return alP2 * log( exp(4.) + s * s0 / (sX1 * sX2) ) ;} + + // Read out parameters of diffractive mass spectra. + double mMinXB() const {return mMinXBsave;} + double mMinAX() const {return mMinAXsave;} + double cRes() const {return CRES;} + double mResXB() const {return mResXBsave;} + double mResAX() const {return mResAXsave;} + double sProton() const {return SPROTON;} + + // Read out parameters of trial t spectra. + double bMinSlopeXB() const { return max(2., 2. * bB);} + double bMinSlopeAX() const { return max(2., 2. * bA);} + double bMinSlopeXX() const { return alP2 * 4.;} + +private: + + // Initialization data, normally only set once. + bool isCalc, setTotal, setElastic; + double sigTotOwn, sigElOwn, sigXBOwn, sigAXOwn, sigXXOwn, + bSlope, rho, lambda, tAbsMin, alphaEM0; + + // Constants: could only be changed in the code itself. + static const int IHADATABLE[], IHADBTABLE[], ISDTABLE[], IDDTABLE[]; + static const double MMIN, EPSILON, ETA, X[], Y[], BETA0[], BHAD[], + ALPHAPRIME, CONVERTEL, CONVERTSD, CONVERTDD, MMIN0, + CRES, MRES0, CSD[10][8], CDD[10][9], SPROTON; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Store values found by calc. + double sigTot, sigEl, sigXB, sigAX, sigXX, sigND, bEl, s, bA, bB, + alP2, s0, exp4, mMinXBsave, mMinAXsave, mResXBsave, mResAXsave; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SigmaTotal_H diff --git a/PYTHIA8/pythia8130/include/SpaceShower.h b/PYTHIA8/pythia8130/include/SpaceShower.h new file mode 100644 index 00000000000..84c7918f626 --- /dev/null +++ b/PYTHIA8/pythia8130/include/SpaceShower.h @@ -0,0 +1,185 @@ +// SpaceShower.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for the spacelike initial-state showers. +// SpaceDipoleEnd: radiating dipole end in ISR. +// SpaceSystem: info on one interaction (among multiple ones). +// SpaceShower: handles the showering description. + +#ifndef Pythia8_SpaceShower_H +#define Pythia8_SpaceShower_H + +#include "Basics.h" +#include "BeamParticle.h" +#include "Event.h" +#include "Info.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" +#include "StandardModel.h" + +namespace Pythia8 { + +//************************************************************************** + +// Data on radiating dipole ends, only used inside SpaceSystem and SpaceShower. + +class SpaceDipoleEnd { + +public: + + // Constructor. + SpaceDipoleEnd( int systemIn = 0, int sideIn = 0, int iRadiatorIn = 0, + int iRecoilerIn = 0, double pTmaxIn = 0., int colTypeIn = 0, + int chgTypeIn = 0, int MEtypeIn = 0) : system(systemIn), side(sideIn), + iRadiator(iRadiatorIn), iRecoiler(iRecoilerIn), pTmax(pTmaxIn), + colType(colTypeIn), chgType(chgTypeIn), MEtype(MEtypeIn), nBranch(0) { } + + // Store values for trial emission. + void store( int idDaughterIn, int idMotherIn, int idSisterIn, + double x1In, double x2In, double m2DipIn, double pT2In, double zIn, + double Q2In, double mSisterIn, double m2SisterIn, double pT2corrIn, + double phiIn) {idDaughter = idDaughterIn; idMother = idMotherIn; + idSister = idSisterIn; x1 = x1In; x2 = x2In; m2Dip = m2DipIn; + pT2 = pT2In; z = zIn; Q2 = Q2In; mSister = mSisterIn; + m2Sister = m2SisterIn; pT2corr = pT2corrIn; phi = phiIn;} + + // Basic properties related to evolution and matrix element corrections. + int system, side, iRadiator, iRecoiler; + double pTmax; + int colType, chgType, MEtype; + + // Properties specific to current trial emission. + int idDaughter, idMother, idSister, nBranch; + double x1, x2, m2Dip, pT2, z, Q2, mSister, m2Sister, pT2corr, phi, + pT2Old, zOld; + +} ; + +//************************************************************************** + +// The SpaceShower class does spacelike showers. + +class SpaceShower { + +public: + + // Constructor. + SpaceShower() {} + + // Destructor. + virtual ~SpaceShower() {} + + // Initialize pointer to Info for error messages. + // (Separated from rest of init since not virtual.) + void initPtr(Info* infoPtrIn) {infoPtr = infoPtrIn;} + + // Initialize generation. Possibility to force re-initialization by hand. + virtual void init(BeamParticle* beamAPtrIn, BeamParticle* beamBPtrIn); + + // Find whether to limit maximum scale of emissions. + virtual bool limitPTmax( Event& event, double Q2Fac = 0., + double Q2Ren = 0.); + + // Potential enhancement factor of pTmax scale for hardest emission. + virtual double enhancePTmax() {return pTmaxFudge;} + + // Prepare system for evolution; identify ME. + virtual void prepare( int iSys, Event& event, bool limitPTmaxIn = true); + + // Update dipole list after each FSR emission. Currently superfluous. + // Usage: update( iSys, event). + virtual void update( int , Event& ) {} + + // Select next pT in downwards evolution. + virtual double pTnext( Event& event, double pTbegAll, double pTendAll, + int nRadIn = -1); + + // ME corrections and kinematics that may give failure, + virtual bool branch( Event& event); + + // Tell which system was the last processed one. + int system() const {return iSysSel;} + + // Print dipole list; for debug mainly. + virtual void list(ostream& os = cout); + +protected: + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointers to the two incoming beams. + BeamParticle* beamAPtr; + BeamParticle* beamBPtr; + + // Store index of last processed system. + int iSysSel; + +private: + + // Constants: could only be changed in the code itself. + static const int MAXLOOPTINYPDF; + static const double CTHRESHOLD, BTHRESHOLD, EVALPDFSTEP, TINYPDF, + TINYKERNELPDF, TINYPT2, HEAVYPT2EVOL, HEAVYXEVOL, EXTRASPACEQ, + LAMBDA3MARGIN, LEPTONXMIN, LEPTONXMAX, LEPTONPT2MIN, LEPTONFUDGE; + + // Initialization data, normally only set once. + bool doQCDshower, doQEDshowerByQ, doQEDshowerByL, useSamePTasMI, + doMEcorrections, doPhiPolAsym, doRapidityOrder; + int pTmaxMatch, pTdampMatch, alphaSorder, alphaEMorder, nQuarkIn; + double pTmaxFudge, pTdampFudge, mc, mb, m2c, m2b, alphaSvalue, alphaS2pi, + Lambda3flav, Lambda4flav, Lambda5flav, Lambda3flav2, Lambda4flav2, + Lambda5flav2, pT0Ref, ecmRef, ecmPow, pTmin, sCM, eCM, pT0, + pTminChgQ, pTminChgL, pT20, pT2min, pT2minChgQ, pT2minChgL; + + // alphaStrong and alphaEM calculations. + AlphaStrong alphaS; + AlphaEM alphaEM; + + // Some current values. + bool dopTdamp; + int iNow, iRec, idDaughter, nRad; + double xDaughter, x1Now, x2Now, m2Dip, pT2damp; + + // All dipole ends + vector dipEnd; + + // Pointers to the current and hardest (so far) dipole ends. + int iDipNow, iSysNow; + SpaceDipoleEnd* dipEndNow; + int iDipSel; + SpaceDipoleEnd* dipEndSel; + + // Evolve a QCD dipole end. + void pT2nextQCD( double pT2begDip, double pT2endDip); + + // Evolve a QCD dipole end near heavy quark threshold region. + void pT2nearQCDthreshold( BeamParticle& beam, double m2Massive, + double m2Threshold, double zMinAbs, double zMaxMassive); + + // Evolve a QED dipole end. + void pT2nextQED( double pT2begDip, double pT2endDip); + + // Find class of ME correction. + int findMEtype( int iSys, Event& event); + + // Provide maximum of expected ME weight; for preweighting of evolution. + double calcMEmax( int MEtype, int idMother, int idDaughterIn); + + // Provide actual ME weight for current branching. + double calcMEcorr(int MEtype, int idMother, int idDaughterIn, double M2, + double z, double Q2); + + // Find coefficient of azimuthal asymmetry from gluon polarization. + // void findAsymPol(DipoleEnd*); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_SpaceShower_H diff --git a/PYTHIA8/pythia8130/include/StandardModel.h b/PYTHIA8/pythia8130/include/StandardModel.h new file mode 100644 index 00000000000..8fad27630ab --- /dev/null +++ b/PYTHIA8/pythia8130/include/StandardModel.h @@ -0,0 +1,169 @@ +// StandardModel.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file gives access to some Standard Model parameters. +// AlphaStrong: fix or first- or second-order running alpha_strong. + +#ifndef Pythia8_StandardModel_H +#define Pythia8_StandardModel_H + +#include "ParticleData.h" +#include "PythiaStdlib.h" + +namespace Pythia8 { + +//************************************************************************** + +// The AlphaStrong class calculates the alpha_strong value at an arbitrary +// scale, given the value at m_Z, to zeroth, first or second order. + +class AlphaStrong { + +public: + + // Constructors. + AlphaStrong() : isInit(false) {} + AlphaStrong(double valueIn, int orderIn = 1) { + init( valueIn, orderIn) ;} + + // Initialization for given value at M_Z and given order. + void init(double valueIn = 0.12, int orderIn = 1); + + // alpha_S value and Lambda values. + double alphaS(double scale2); + double alphaS1Ord(double scale2); + double alphaS2OrdCorr(double scale2); + double Lambda3() const { return Lambda3Save; } + double Lambda4() const { return Lambda4Save; } + double Lambda5() const { return Lambda5Save; } + +private: + + // Constants: could only be changed in the code itself. + static const int NITER; + static const double SAFETYMARGIN1, SAFETYMARGIN2; + + // Data members. + bool isInit, lastCallToFull; + int order; + double valueRef, valueNow, scale2Now, scale2Min, Lambda3Save, + Lambda4Save, Lambda5Save, Lambda3Save2, Lambda4Save2, + Lambda5Save2, mc, mb, mZ, mc2, mb2; + +}; + +//************************************************************************** + +// The AlphaEM class calculates the alpha_electromagnetic value at an +// arbitrary scale, given the value at 0 and m_Z, to zeroth or first order. + +class AlphaEM { + +public: + + // Constructors. + AlphaEM(int orderIn = 1) {init(orderIn);} + + // First-order initialization for given value at M_Z. + static void initStatic(); + + // Initialization for a given order. + void init(int orderIn = 1) {order = orderIn;} + + // alpha_EM value. + double alphaEM(double scale2); + +private: + + // Static data members, mostly for first-order matching. + static double alpEM0, alpEMmZ, mZ2, Q2step[5], bRun[5], alpEMstep[5]; + + // Data members. + int order; + +}; + +//************************************************************************** + +// The CoupEW class stores and returns electroweak couplings. + +class CoupEW { + +public: + + // Constructor. + CoupEW() {} + + // Initialize, normally from Pythia::init(). + static void initStatic(); + + // Return electroweak mixing angle. + static double sin2thetaW() {return s2tW;} + static double cos2thetaW() {return c2tW;} + static double sin2thetaWbar() {return s2tWbar;} + + // Return electroweak couplings of quarks and leptons. + static double ef(int idAbs) {return efSave[idAbs];} + static double vf(int idAbs) {return vfSave[idAbs];} + static double af(int idAbs) {return afSave[idAbs];} + static double t3f(int idAbs) {return 0.5*afSave[idAbs];} + static double lf(int idAbs) {return lfSave[idAbs];} + static double rf(int idAbs) {return rfSave[idAbs];} + + // Return some squared couplings and other combinations. + static double ef2(int idAbs) {return ef2Save[idAbs];} + static double vf2(int idAbs) {return vf2Save[idAbs];} + static double af2(int idAbs) {return af2Save[idAbs];} + static double efvf(int idAbs) {return efvfSave[idAbs];} + static double vf2af2(int idAbs) {return vf2af2Save[idAbs];} + +private: + + // Store couplings. + static double s2tW, c2tW, s2tWbar, efSave[20], vfSave[20], afSave[20], + lfSave[20], rfSave[20], ef2Save[20], vf2Save[20], + af2Save[20], efvfSave[20], vf2af2Save[20]; + +}; + +//************************************************************************** + +// The VCKM class stores and returns Cabibbo-Kobayashi-Maskawa + +class VCKM { + +public: + + // Constructor. + VCKM() {} + + // Initialize, normally from Pythia::init(). + static void initStatic(); + + // Return value or square: first index 1/2/3/4 = u/c/t/t', + // second 1/2/3/4 = d/s/b/b'. + static double Vgen(int genU, int genD) {return Vsave[genU][genD];} + static double V2gen(int genU, int genD) {return V2save[genU][genD];} + + // Return value or square for incoming flavours (sign irrelevant). + static double Vid(int id1, int id2); + static double V2id(int id1, int id2); + + // Return sum of squares for given inflavour, or random outflavour. + static double V2sum(int id) {return V2out[abs(id)];} + static int V2pick(int id); + +private: + + // Store VCKM matrix (index 0 not used) and sum of squares. + static double Vsave[5][5], V2save[5][5], V2out[20]; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_StandardModel_H diff --git a/PYTHIA8/pythia8130/include/StringFragmentation.h b/PYTHIA8/pythia8130/include/StringFragmentation.h new file mode 100644 index 00000000000..ff3e83cd3da --- /dev/null +++ b/PYTHIA8/pythia8130/include/StringFragmentation.h @@ -0,0 +1,163 @@ +// StringFragmentation.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// This file contains the classes for string fragmentation. +// StringEnd: keeps track of the fragmentation step. +// StringFragmentation: is the top-level class. + +#ifndef Pythia8_StringFragmentation_H +#define Pythia8_StringFragmentation_H + +#include "Basics.h" +#include "Event.h" +#include "Info.h" +#include "FragmentationFlavZpT.h" +#include "FragmentationSystems.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" + +namespace Pythia8 { + +//************************************************************************** + +// The StringEnd class contains the information related to +// one of the current endpoints of the string system. +// Only to be used inside StringFragmentation, so no private members. + +class StringEnd { + +public: + + // Constructor. + StringEnd() {} + + // Save pointers. + void init(StringFlav* flavSelPtrIn, StringPT* pTSelPtrIn, + StringZ* zSelPtrIn) {flavSelPtr = flavSelPtrIn; + pTSelPtr = pTSelPtrIn; zSelPtr = zSelPtrIn;} + + // Set up initial endpoint values from input. + void setUp(bool fromPosIn, int iEndIn, int idOldIn, int iMaxIn, + double pxIn, double pyIn, double GammaIn, double xPosIn, double xNegIn); + + // Fragment off one hadron from the string system, in flavour and pT. + void newHadron(); + + // Fragment off one hadron from the string system, in momentum space, + // by taking steps either from positive or from negative end. + Vec4 kinematicsHadron(StringSystem& system); + + // Update string end information after a hadron has been removed. + void update(); + + // Constants: could only be changed in the code itself. + static const double TINY, PT2SAME; + + // Pointers to classes for flavour, pT and z generation. + StringFlav* flavSelPtr; + StringPT* pTSelPtr; + StringZ* zSelPtr; + + // Data members. + bool fromPos; + int iEnd, iMax, idHad, iPosOld, iNegOld, iPosNew, iNegNew; + double pxOld, pyOld, pxNew, pyNew, pxHad, pyHad, mHad, mT2Had, zHad, + GammaOld, GammaNew, xPosOld, xPosNew, xPosHad, xNegOld, xNegNew, + xNegHad; + FlavContainer flavOld, flavNew; + Vec4 pHad, pSoFar; + +}; + +//************************************************************************** + +// The StringFragmentation class contains the top-level routines +// to fragment a colour singlet partonic system. + +class StringFragmentation { + +public: + + // Constructor. + StringFragmentation() {} + + // Initialize and save pointers. + void init(Info* infoPtrIn, StringFlav* flavSelPtrIn, + StringPT* pTSelPtrIn, StringZ* zSelPtrIn); + + // Do the fragmentation: driver routine. + bool fragment( int iSub, ColConfig& colConfig, Event& event); + + // Find the boost matrix to the rest frame of a junction. + RotBstMatrix junctionRestFrame(Vec4& p0, Vec4& p1, Vec4& p2); + +private: + + // Constants: could only be changed in the code itself. + static const int NTRYFLAV, NTRYJOIN, NSTOPMASS, NTRYJNREST, + NTRYJNMATCH, NTRYJRFEQ; + static const double FACSTOPMASS, CLOSEDM2MAX, CLOSEDM2FRAC, EXPMAX, + MATCHPOSNEG, EJNWEIGHTMAX, CONVJNREST, M2MAXJRF, + CONVJRFEQ; + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointers to classes for flavour, pT and z generation. + StringFlav* flavSelPtr; + StringPT* pTSelPtr; + StringZ* zSelPtr; + + // Initialization data, read from Settings. + double stopMass, stopNewFlav, stopSmear, eNormJunction, + eBothLeftJunction, eMaxLeftJunction, eMinLeftJunction, bLund; + + // Data members. + bool hasJunction, isClosed; + int iPos, iNeg; + double w2Rem, stopMassNow; + Vec4 pSum, pRem, pJunctionHadrons; + + // List of partons in string system. + vector iParton; + + // Temporary event record for the produced particles. + Event hadrons; + + // Information on the system of string regions. + StringSystem system, systemMin, systemMid; + + // Information on the two current endpoints of the fragmenting system. + StringEnd posEnd, negEnd; + + // Find region where to put first string break for closed gluon loop. + vector findFirstRegion(vector& iPartonIn, Event& event); + + // Set flavours and momentum position for initial string endpoints. + void setStartEnds(int idPos, int idNeg, StringSystem systemNow); + + // Check remaining energy-momentum whether it is OK to continue. + bool energyUsedUp(bool fromPos); + + // Produce the final two partons to complete the system. + bool finalTwo(bool fromPos); + + // Construct a special joining region for the final two hadrons. + StringRegion finalRegion(); + + // Store the hadrons in the normal event record, ordered from one end. + void store(Event& event); + + // Fragment off two of the string legs in to a junction. + bool fragmentToJunction(Event& event); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_StringFragmentation_H diff --git a/PYTHIA8/pythia8130/include/SusyLesHouches.h b/PYTHIA8/pythia8130/include/SusyLesHouches.h new file mode 100644 index 00000000000..cf159c168a3 --- /dev/null +++ b/PYTHIA8/pythia8130/include/SusyLesHouches.h @@ -0,0 +1,489 @@ +// SusyLesHouches.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Peter Skands, Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +#ifndef SLHA_H +#define SLHA_H + +// Stdlib header files for string and character manipulation. +#include +#include +// Stdlib header files for containers. +#include +#include +// Stdlib header files for input/output. +#include +#include +#include +#include +// Stdlib header files for mathematics. +#include + +// Stdlib namespace +using namespace std; + +class SusyLesHouches { + +public: + + //Constructor, with and without filename. + SusyLesHouches(int verboseIn=1) : verbose(verboseIn), + headerPrinted(false), footerPrinted(false), + slhaRead(false), lhefRead(false), lhefSlha(false) {}; + SusyLesHouches(string filename, int verboseIn=1) : verbose(verboseIn), + headerPrinted(false), footerPrinted(false), + slhaRead(true), lhefRead(false), lhefSlha(false) {readFile(filename);}; + + //***************************** SLHA FILE I/O *****************************// + int readFile(string slhaFile="slha.spc"); // read in SLHA file + //int writeFile(string filename): write SLHA file on filename + int checkSpectrum(); + + //Output utilities + void printHeader(); // print Header + void printFooter(); // print Footer + void printSpectrum(); // print Spectrum + + // Class for SLHA data entry + class Entry { + + public: + //Constructor. + Entry() : isIntP(false), isDoubleP(false), + isStringP(false), n(0), d(0.0), s(""), commentP("") {} + + // Generic functions to inquire whether an int, double, or string + bool isInt(){return isIntP;} + bool isDouble(){return isDoubleP;} + bool isString(){return isStringP;} + + // = Overloading: Set entry to int, double, or string + Entry& operator=(double& val) { + d=val;isIntP=false;isDoubleP=true;isStringP=false; + return *this; + }; + Entry& operator=(int& val) { + n=val;isIntP=true;isDoubleP=false;isStringP=false; + return *this; + }; + Entry& operator=(string& val) { + s=val;isIntP=false;isDoubleP=false;isStringP=true; + return *this; + }; + + // Set and Get comment + void setComment(string comment) {commentP=comment;} + void getComment(string comment) {comment=commentP;} + + // Generic functions to get value + bool get(int& val) {val=n; return isIntP;} + bool get(double& val) {val=d; return isDoubleP;} + bool get(string& val) {val=s; return isStringP;} + + private: + bool isIntP, isDoubleP, isStringP; + int n; + double d; + string s; + string commentP; + + }; + + //***************************** SLHA CLASSES *****************************// + + + //class block: the generic SLHA block (see below for matrices) + //Explicit typing required, e.g. block minpar; + template class block { + + public: + + //Constructor. + block() : idnow(0) { } ; + + //Does block exist? + bool exists() { return entry.size() == 0 ? false : true ; }; + //Clear block + void clear() { entry.clear(); }; + + //set: set block entry values. + //Possible return values from set: + // 0: normal return. Entry did not previously exist and has been created. + // 1: normal return. Entry did previously exist and has been overwritten. + //-1: failure. + int set(int iIn,T valIn) { + int alreadyexisting=exists(iIn)?1:0; + entry[iIn]=valIn; + return alreadyexisting; + }; + // Read index and value from SLHA data line + int set(istringstream& linestream) { + linestream >> i >> val; + return linestream ? set(i,val) : -1; + }; + // With i already given, read value from remaining SLHA data line + int set(int iIn,istringstream& linestream) { + linestream >> val; + return linestream ? set(iIn,val) : -1; + }; + // Shorthand for entry[0]. Used e.g. for block ALPHA. + void set(T valIn) { entry[0]=valIn; }; + + // Does entry i already exist in this block? + bool exists(int iIn) {return entry.find(iIn) != entry.end() + ? true : false;}; + + // Indexing with (). Output only. + T operator()(int iIn=0) { + if (exists(iIn)) {return entry[iIn];} else {T dummy(0); return dummy;}; + }; + + // Size of map + int size() {return entry.size();}; + + // First and next key code + int first() { idnow = entry.begin()->first; return idnow; }; + int next() { + typename map::iterator itnow; + itnow = ++entry.find(idnow); + if ( itnow == entry.end() ) itnow=entry.begin(); + return idnow = itnow->first; + }; + + // Simple print utility + void print() { + bool finished=false; + int ibegin=first(); + i=ibegin; + while (!finished) { + cout << " "<< i << " " << entry[i] < entry; + int idnow; + double qDRbar; + //Auxiliary vars + int i; + T val; + }; + + // class matrixblock: the generic SLHA matrix + // Explicit sizing required, e.g. matrixblock<4> nmix; + template class matrixblock { + public: + //Constructor. Set uninitialized and explicitly zero. + matrixblock() : i(0), j(0), val(0) { + initialized=false; + for (i=1;i<=size;i++) { + for (j=1;j<=size;j++) { + entry[i][j]=0.0; + }; + }; + }; + + // Assignment + matrixblock& operator=(const matrixblock& m) { + if (this != &m) { + for (i=0;i0 && jIn>0 && iIn<=size && jIn<=size) { + entry[iIn][jIn]=valIn; + initialized=true; + return 0; + } else { + return -1; + }; + }; + + // Set entry from linestream (used during file read) + int set(istringstream& linestream) { + linestream >> i >> j >> val; + return linestream ? set(i,j,val) : -1; + }; + + // () Overloading: Get entry + double operator()(int iIn, int jIn) const { + return (iIn <= size && jIn <= size && iIn > 0 && jIn > 0) ? + entry[iIn][jIn] : 0.0; + }; + + // Set and get scale for DRbar running blocks. + void setq(double qIn) { qDRbar=qIn; } + double q() { return qDRbar; } + + // Simple print utility, to be elaborated on. + void print() { + for (i=1;i<=size;i++) { + cout << " "< rvlam; + template class tensor3block { + public: + //Constructor. Set uninitialized and explicitly zero. + tensor3block() { + initialized=false; + for (i=1;i<=size;i++) { + for (j=1;j<=size;j++) { + for (k=1;k<=size;k++) { + entry[i][j][k]=0.0; + }; + }; + }; + }; + + // Assignment + tensor3block& operator=(const tensor3block& m) { + if (this != &m) { + for (i=0;i0 && jIn>0 && kIn>0 && iIn<=size && jIn<=size && kIn<=size) { + entry[iIn][jIn][kIn]=valIn; + initialized=true; + return 0; + } else { + return -1; + }; + }; + + // Set entry from linestream (used during file read) + int set(istringstream& linestream) { + linestream >> i >> j >> k >> val; + return linestream ? set(i,j,k,val) : -1; + }; + + // () Overloading: Get entry + double operator()(int iIn, int jIn, int kIn) const { + return (iIn <= size && jIn <= size && kIn <= size && iIn > 0 + && jIn > 0 && kIn > 0) ? entry[iIn][jIn][kIn] : 0.0; + }; + + // Set and get scale for DRbar running blocks. + void setq(double qIn) { qDRbar=qIn; } + double q() { return qDRbar; } + + // Simple print utility, to be elaborated on. + void print() { + for (i=1;i<=size;i++) { + for (j=1;j<=size;j++) { + cout << " "< modsel; + block modsel21; + block modsel12; + block minpar; + block extpar; + block sminputs; + //blocks for RGE program specific output + block spinfo; + block spinfo3; + block spinfo4; + //blocks for DCY program specific output + block dcinfo; + block dcinfo3; + block dcinfo4; + //blocks for mass and coupling spectrum + block mass; + matrixblock<4> nmix; + matrixblock<2> umix; + matrixblock<2> vmix; + matrixblock<2> stopmix; + matrixblock<2> sbotmix; + matrixblock<2> staumix; + block alpha; + block hmix; + block gauge; + block msoft; + matrixblock<3> au; + matrixblock<3> ad; + matrixblock<3> ae; + matrixblock<3> yu; + matrixblock<3> yd; + matrixblock<3> ye; + + //*************************** THE SLHA2 BLOCKS ***************************// + //Additions to SLHA1 + block qextpar; + + //FLV Input + block vckmin; // The input CKM Wolfenstein parms. + block upmnsin; // The input PMNS PDG parms. + matrixblock<3> msq2in; // The input upper off-diagonal msq2 + matrixblock<3> msu2in; // The input upper off-diagonal msu2 + matrixblock<3> msd2in; // The input upper off-diagonal msd2 + matrixblock<3> msl2in; // The input upper off-diagonal msl2 + matrixblock<3> mse2in; // The input upper off-diagonal mse2 + matrixblock<3> tuin; // The input upper off-diagonal TU + matrixblock<3> tdin; // The input upper off-diagonal TD + matrixblock<3> tein; // The input upper off-diagonal TE + //FLV Output + matrixblock<3> vckm; // The output DRbar running Re{VCKM} at Q + matrixblock<3> upmns; // The output DRbar running Re{UPMNS} at Q + matrixblock<3> msq2; // The output DRbar running msq2 at Q + matrixblock<3> msu2; // The output DRbar running msu2 at Q + matrixblock<3> msd2; // The output DRbar running msd2 at Q + matrixblock<3> msl2; // The output DRbar running msl2 at Q + matrixblock<3> mse2; // The output DRbar running mse2 at Q + matrixblock<3> tu; // The output DRbar running TU at Q + matrixblock<3> td; // The output DRbar running TD at Q + matrixblock<3> te; // The output DRbar running TE at Q + matrixblock<6> usqmix; // The Re{} up squark mixing matrix + matrixblock<6> dsqmix; // The Re{} down squark mixing matrix + matrixblock<6> selmix; // The Re{} selectron mixing matrix + matrixblock<3> snumix; // The Re{} sneutrino mixing matrix + matrixblock<3> snsmix; // The scalar sneutrino mixing matrix + matrixblock<3> snamix; // The pseudoscalar neutrino mixing matrix + + //RPV Input + tensor3block<3> rvlamllein; // The input LNV lambda couplings + tensor3block<3> rvlamlqdin; // The input LNV lambda' couplings + tensor3block<3> rvlamuddin; // The input BNV lambda'' couplings + tensor3block<3> rvtllein; // The input LNV T couplings + tensor3block<3> rvtlqdin; // The input LNV T' couplings + tensor3block<3> rvtuddin; // The input BNV T'' couplings + block rvkappain; // The input LNV kappa couplings + block rvdin; // The input LNV D terms + block rvm2lh1in; // The input LNV m2LH1 couplings + block rvsnvevin; // The input LNV sneutrino vevs + //RPV Output + tensor3block<3> rvlamlle; // The output LNV lambda couplings + tensor3block<3> rvlamlqd; // The output LNV lambda' couplings + tensor3block<3> rvlamudd; // The output BNV lambda'' couplings + tensor3block<3> rvtlle; // The output LNV T couplings + tensor3block<3> rvtlqd; // The output LNV T' couplings + tensor3block<3> rvtudd; // The output BNV T'' couplings + block rvkappa; // The output LNV kappa couplings + block rvd; // The output LNV D terms + block rvm2lh1; // The output LNV m2LH1 couplings + block rvsnvev; // The output LNV sneutrino vevs + matrixblock<7> rvnmix; // The RPV neutralino mixing matrix + matrixblock<5> rvumix; // The RPV chargino L mixing matrix + matrixblock<5> rvvmix; // The RPV chargino R mixing matrix + matrixblock<5> rvhmix; // The RPV neutral scalar mixing matrix + matrixblock<5> rvamix; // The RPV neutral pseudoscalar mixing matrix + matrixblock<7> rvlmix; // The RPV charged fermion mixing matrix + + //CPV Input + block imminpar; + block imextpar; + //CPV Output + matrixblock<4> cvhmix; // The CPV Higgs mixing matrix + matrixblock<4> imcvhmix; // Optional: imaginary components + matrixblock<3> imau,imad,imae; // Im{} of AU, AD, AE + + //CPV + FLV Input + matrixblock<3> immsq2in; // The Im{} input upper off-diagonal msq2 + matrixblock<3> immsu2in; // The Im{} input upper off-diagonal msu2 + matrixblock<3> immsd2in; // The Im{} input upper off-diagonal msd2 + matrixblock<3> immsl2in; // The Im{} input upper off-diagonal msl2 + matrixblock<3> immse2in; // The Im{} input upper off-diagonal mse2 + matrixblock<3> imtuin,imtdin,imtein; // The Im{} input upper off-diagonal T + //CPV + FLV Output + matrixblock<3> imvckm; // The output DRbar running Im{VCKM} at Q + matrixblock<3> imupmns; // The output DRbar running Im{UPMNS} at Q + matrixblock<3> immsq2; // The output DRbar running msq2 at Q + matrixblock<3> immsu2; // The output DRbar running msu2 at Q + matrixblock<3> immsd2; // The output DRbar running msd2 at Q + matrixblock<3> immsl2; // The output DRbar running msl2 at Q + matrixblock<3> immse2; // The output DRbar running mse2 at Q + matrixblock<3> imtu,imtd,imte; // Im{} of TU, TD, TE + matrixblock<6> imusqmix;// The Im{} up squark mixing matrix + matrixblock<6> imdsqmix; // The Im{} down squark mixing matrix + matrixblock<6> imselmix; // The Im{} selectron mixing matrix + matrixblock<3> imsnumix; // The Im{} sneutrino mixing matrix + matrixblock<4> imnmix; // The Im{} neutralino mixing matrix + matrixblock<4> imumix; // The Im{} chargino L mixing matrix + matrixblock<4> imvmix; // The Im{} chargino R mixing matrix + + //NMSSM Input + // All input is in EXTPAR + //NMSSM Output + block nmssmrun; // The block of NMSSM running parameters + matrixblock<3> nmhmix; // The NMSSM scalar Higgs mixing + matrixblock<3> nmamix; // The NMSSM pseudoscalar Higgs mixing + matrixblock<5> nmnmix; // The NMSSM neutralino mixing + matrixblock<5> imnmnmix; // Im{} (for future use) + + //*************************** SET BLOCK VALUE ****************************// + template int set(string,T); + template int set(string,int,T); + template int set(string,int,int,T); + template int set(string,int,int,int,T); + + //***************************** SLHA PRIVATE *****************************// +private: + //SLHA I/O + string spectrumFile; + void message(int, string,string ,int line=0); + int verbose; + bool headerPrinted, footerPrinted; + bool slhaRead, lhefRead, lhefSlha; + +}; + +#endif + + diff --git a/PYTHIA8/pythia8130/include/TimeShower.h b/PYTHIA8/pythia8130/include/TimeShower.h new file mode 100644 index 00000000000..e77931e0b06 --- /dev/null +++ b/PYTHIA8/pythia8130/include/TimeShower.h @@ -0,0 +1,185 @@ +// TimeShower.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file for the timelike final-state showers. +// TimeDipoleEnd: data on a radiating dipole end. +// TimeShower: handles the showering description. + +#ifndef Pythia8_TimeShower_H +#define Pythia8_TimeShower_H + +#include "Basics.h" +#include "BeamParticle.h" +#include "Event.h" +#include "Info.h" +#include "ParticleData.h" +#include "PythiaStdlib.h" +#include "Settings.h" +#include "StandardModel.h" + +namespace Pythia8 { + +//************************************************************************** + +// Data on radiating dipole ends; only used inside TimeShower class. + +class TimeDipoleEnd { + +public: + + // Constructors. + TimeDipoleEnd() : iRadiator(-1), iRecoiler(-1), pTmax(0.), colType(0), + chgType(0), gamType(0), isrType(0), system(0), MEtype(0), + iMEpartner(-1), isOctetOnium(false), MEmix(0.), MEorder(true), + MEsplit(true), MEgluinoRec(false) { } + TimeDipoleEnd(int iRadiatorIn, int iRecoilerIn, double pTmaxIn = 0., + int colIn = 0, int chgIn = 0, int gamIn = 0, int isrIn = 0, + int systemIn = 0, int MEtypeIn = 0, int iMEpartnerIn = -1, + bool isOctetOniumIn = false, double MEmixIn = 0., bool MEorderIn = true, + bool MEsplitIn = true, bool MEgluinoRecIn = false) : + iRadiator(iRadiatorIn), iRecoiler(iRecoilerIn), pTmax(pTmaxIn), + colType(colIn), chgType(chgIn), gamType(gamIn), isrType(isrIn), + system(systemIn), MEtype(MEtypeIn), iMEpartner(iMEpartnerIn), + isOctetOnium(isOctetOniumIn), MEmix(MEmixIn), MEorder (MEorderIn), + MEsplit(MEsplitIn), MEgluinoRec(MEgluinoRecIn) { } + + // Basic properties related to dipole and matrix element corrections. + int iRadiator, iRecoiler; + double pTmax; + int colType, chgType, gamType, isrType, system, MEtype, iMEpartner; + bool isOctetOnium; + double MEmix; + bool MEorder, MEsplit, MEgluinoRec; + + // Properties specific to current trial emission. + int flavour, iAunt; + double mRad, m2Rad, mRec, m2Rec, mDip, m2Dip, m2DipCorr, + pT2, m2, z, mFlavour, asymPol; + +} ; + +//************************************************************************** + +// The TimeShower class does timelike showers. + +class TimeShower { + +public: + + // Constructor. + TimeShower() {} + + // Destructor. + virtual ~TimeShower() {} + + // Initialize pointer to Info for error messages. + // (Separated from rest of init since not virtual.) + void initPtr(Info* infoPtrIn) {infoPtr = infoPtrIn;} + + // Initialize alphaStrong and related pTmin parameters. + virtual void init( BeamParticle* beamAPtrIn = 0, + BeamParticle* beamBPtrIn = 0); + + // Potential enhancement factor of pTmax scale for hardest emission. + virtual double enhancePTmax() {return pTmaxFudge;} + + // Top-level routine to do a full time-like shower in resonance decay. + virtual int shower( int iBeg, int iEnd, Event& event, double pTmax); + + // Prepare system for evolution after each new interaction; identify ME. + virtual void prepare( int iSys, Event& event); + + // Update dipole list after each ISR emission. + virtual void update( int iSys, Event& event); + + // Select next pT in downwards evolution. + virtual double pTnext( Event& event, double pTbegAll, double pTendAll); + + // ME corrections and kinematics that may give failure, + virtual bool branch( Event& event); + + // Tell which system was the last processed one. + int system() const {return iSysSel;}; + + // Print dipole list; for debug mainly. + virtual void list( ostream& os = cout); + +protected: + + // Pointer to various information on the generation. + Info* infoPtr; + + // Pointers to the two incoming beams. + BeamParticle* beamAPtr; + BeamParticle* beamBPtr; + + // Store index of last processed system. + int iSysSel; + +private: + + // Constants: could only be changed in the code itself. + static const double SIMPLIFYROOT, XMARGIN, XMARGINCOMB, TINYPDF, LARGEM2, + THRESHM2, LAMBDA3MARGIN; + + // Initialization data, normally only set once. + bool doQCDshower, doQEDshowerByQ, doQEDshowerByL, doQEDshowerByGamma, + doMEcorrections, doPhiPolAsym, allowBeamRecoil; + int alphaSorder, nGluonToQuark, alphaEMorder, nGammaToQuark, + nGammaToLepton; + double pTmaxFudge, mc, mb, m2c, m2b, alphaSvalue, alphaS2pi, + Lambda3flav, Lambda4flav, Lambda5flav, Lambda3flav2, Lambda4flav2, + Lambda5flav2, pTcolCutMin, pTcolCut, pT2colCut, pTchgQCut, + pT2chgQCut, pTchgLCut, pT2chgLCut, mMaxGamma, m2MaxGamma, + octetOniumFraction, octetOniumColFac, mZ, gammaZ, thetaWRat; + + // alphaStrong and alphaEM calculations. + AlphaStrong alphaS; + AlphaEM alphaEM; + + // All dipole ends and a pointer to the selected hardest dipole end. + vector dipEnd; + TimeDipoleEnd* dipSel; + + // Setup a dipole end, either QCD or QED/photon one. + void setupQCDdip( int iSys, int i, int colTag, int colSign, Event& event, + bool isOctetOnium = false); + void setupQEDdip( int iSys, int i, int chgType, int gamType, Event& event); + + // Evolve a QCD dipole end. + void pT2nextQCD( double pT2begDip, double pT2sel, TimeDipoleEnd& dip, + Event& event); + + // Evolve a QED dipole end (except photon). + void pT2nextQED( double pT2begDip, double pT2sel, TimeDipoleEnd& dip, + Event& event); + + // Find kind of QCD ME correction. + void findMEtype( Event& event, TimeDipoleEnd& dip); + + // Find type of particle; used by findMEtype. + int findMEparticle( int id); + + // Find mixture of V and A in gamma/Z: energy- and flavour-dependent. + double gammaZmix( Event& event, int iRes, int iDau1, int iDau2); + + // Set up to calculate QCD ME correction with calcMEcorr. + double findMEcorr(TimeDipoleEnd* dip, Particle& rad, Particle& partner, + Particle& emt); + + // Calculate value of QCD ME correction. + double calcMEcorr( int kind, int combiIn, double mixIn, double x1, + double x2, double r1, double r2); + + // Find coefficient of azimuthal asymmetry from gluon polarization. + void findAsymPol( Event& event, TimeDipoleEnd* dip); + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_TimeShower_H diff --git a/PYTHIA8/pythia8130/include/UserHooks.h b/PYTHIA8/pythia8130/include/UserHooks.h new file mode 100644 index 00000000000..664048ed679 --- /dev/null +++ b/PYTHIA8/pythia8130/include/UserHooks.h @@ -0,0 +1,170 @@ +// UserHooks.h is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Header file to allow user access to program at different stages. +// UserHooks: almost empty base class, with user to write the rela code. +// MyUserHooks: derived class, only intended as an example. + +#ifndef Pythia8_UserHooks_H +#define Pythia8_UserHooks_H + +#include "Event.h" +#include "PhaseSpace.h" +#include "PythiaStdlib.h" +#include "SigmaProcess.h" + +namespace Pythia8 { + +//************************************************************************** + +// Forward reference to the PhaseSpace class. +class PhaseSpace; + +//************************************************************************** + +// UserHooks is base class for user access to program execution. + +class UserHooks { + +public: + + // Destructor. + virtual ~UserHooks() {} + + // Possibility to modify cross section of process. + virtual bool canModifySigma() {return false;} + + // Multiplicative factor modifying the cross section of a hard process. + virtual double multiplySigmaBy(const SigmaProcess* sigmaProcessPtr, + const PhaseSpace* phaseSpacePtr, bool inEvent); + + // Possibility to veto event after process-level selection. + virtual bool canVetoProcessLevel() {return false;} + + // Decide whether to veto current process or not, based on process record. + // Usage: doVetoProcessLevel( process). + virtual bool doVetoProcessLevel( const Event& ) {return false;} + + // Possibility to veto MI + ISR + FSR evolution and kill event, + // making decision at a fixed pT scale. Useful for MLM-style matching. + virtual bool canVetoPT() {return false;} + + // Transverse-momentum scale for veto test. + virtual double scaleVetoPT() {return 0.;} + + // Decide whether to veto current event or not, based on event record. + // Usage: doVetoPT( iPos, event), where iPos = 0: no emissions so far; + // iPos = 1/2/3 joint evolution, latest step was MI/ISR/FSR; + // iPos = 4: FSR only afterwards; iPos = 5: FSR in resonance decay. + virtual bool doVetoPT( int , const Event& ) {return false;} + + // Possibility to veto MI + ISR + FSR evolution and kill event, + // making decision after fixed number of ISR or FSR steps. + virtual bool canVetoStep() {return false;} + + // Up to how many steps should be checked. + virtual int numberVetoStep() {return 1;} + + // Decide whether to veto current event or not, based on event record. + // Usage: doVetoStep( iPos, nISR, nFSR, event), where iPos as above, + // nISR and nFSR number of emissions so far for hard interaction only. + virtual bool doVetoStep( int , int , int , const Event& ) {return false;} + + // Possibility to veto event after parton-level selection. + virtual bool canVetoPartonLevel() {return false;} + + // Decide whether to veto current partons or not, based on event record. + // Usage: doVetoPartonLevel( event). + virtual bool doVetoPartonLevel( const Event& ) {return false;} + +protected: + + // Constructor. + UserHooks() {} + + // subEvent extracts currently resolved partons in the hard process. + void subEvent(const Event& event, bool isHardest = true); + + // Have one event object around as work area. + Event workEvent; + +}; + +//************************************************************************** + +// SuppressSmallPT is a derived class for user access to program execution. +// It is a simple example, illustrating how to suppress the cross section +// of 2 -> 2 processes by a factor pT^4 / (pT0^2 + pT^2)^2, with pT0 input, +// and also modify alpha_strong scale similarly. + +class SuppressSmallPT : public UserHooks { + +public: + + // Constructor. + SuppressSmallPT( double pT0timesMIIn = 1., int numberAlphaSIn = 0, + bool useSameAlphaSasMIIn = true) {isInit = false; + pT0timesMI = pT0timesMIIn; numberAlphaS = numberAlphaSIn; + useSameAlphaSasMI = useSameAlphaSasMIIn;} + + // Possibility to modify cross section of process. + virtual bool canModifySigma() {return true;} + + // Multiplicative factor modifying the cross section of a hard process. + // Usage: inEvent is true for event generation, false for initialization. + virtual double multiplySigmaBy(const SigmaProcess* sigmaProcessPtr, + const PhaseSpace* phaseSpacePtr, bool ); + +private: + + // Save input properties and the squared pT0 scale. + bool isInit, useSameAlphaSasMI; + int numberAlphaS; + double pT0timesMI, pT20; + + // Alpha_strong calculation. + AlphaStrong alphaS; + +}; + +//************************************************************************** + +// VetoEvolution is a derived class for user access to program execution. +// It is a simple example, to kill events with > nMax partons at scale +// pTcheck in the combined evolution, but only counting partons in the +// hardest interaction and its associated ISR + FSR activity. + +class VetoEvolution : public UserHooks { + +public: + + // Constructor. + VetoEvolution( int nMaxIn, double pTcheckIn) : nMax(nMaxIn), + pTcheck (pTcheckIn){} + + // Possibility to veto combined MI + ISR + FSR evolution and + // kill event, e.g. for MLM-style matching of matrix elements. + virtual bool canVetoEvolution() {return true;} + + // Transverse-momentum scale for veto test. + virtual double scaleVetoEvolution() {return pTcheck;} + + // Decide whether to veto current event or not. + virtual bool doVetoEvolution(const Event& event) { + subEvent( event); return (workEvent.size() > nMax);} + +private: + + // Saved values from constructor. + int nMax; + double pTcheck; + +}; + +//************************************************************************** + +} // end namespace Pythia8 + +#endif // Pythia8_UserHooks_H diff --git a/PYTHIA8/pythia8130/src/Analysis.cxx b/PYTHIA8/pythia8130/src/Analysis.cxx new file mode 100644 index 00000000000..4e3b05e85b7 --- /dev/null +++ b/PYTHIA8/pythia8130/src/Analysis.cxx @@ -0,0 +1,886 @@ +// Analysis.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// Sphericity, Thrust, ClusJet and CellJet classes. + +#include "Analysis.h" + +namespace Pythia8 { + +//************************************************************************** + +// Sphericity class. +// This class finds sphericity-related properties of an event. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Minimum number of particles to perform study. +const int Sphericity::NSTUDYMIN = 2; + +// Maximum number of times that an error warning will be printed. +const int Sphericity::TIMESTOPRINT = 1; + +// Assign mimimum squared momentum in weight to avoid division by zero. +const double Sphericity::P2MIN = 1e-20; + +// Second eigenvalue not too low or not possible to find eigenvectors. +const double Sphericity::EIGENVALUEMIN = 1e-10; + +//********* + +// Analyze event. + +bool Sphericity::analyze(const Event& event, ostream& os) { + + // Initial values, tensor and counters zero. + eVal1 = eVal2 = eVal3 = 0.; + eVec1 = eVec2 = eVec3 = 0.; + double tt[4][4]; + for (int j = 1; j < 4; ++j) + for (int k = j; k < 4; ++k) tt[j][k] = 0.; + int nStudy = 0; + double denom = 0.; + + // Loop over desired particles in the event. + for (int i = 0; i < event.size(); ++i) + if (event[i].isFinal()) { + if (select > 2 && event[i].isNeutral() ) continue; + if (select == 2 && !event[i].isVisible() ) continue; + ++nStudy; + + // Calculate matrix to be diagonalized. Special cases for speed. + double pNow[4]; + pNow[1] = event[i].px(); + pNow[2] = event[i].py(); + pNow[3] = event[i].pz(); + double p2Now = pNow[1]*pNow[1] + pNow[2]*pNow[2] + pNow[3]*pNow[3]; + double pWeight = 1.; + if (powerInt == 1) pWeight = 1. / sqrt(max(P2MIN, p2Now)); + else if (powerInt == 0) pWeight = pow( max(P2MIN, p2Now), powerMod); + for (int j = 1; j < 4; ++j) + for (int k = j; k < 4; ++k) tt[j][k] += pWeight * pNow[j] * pNow[k]; + denom += pWeight * p2Now; + } + + // Very low multiplicities (0 or 1) not considered. + if (nStudy < NSTUDYMIN) { + if (nFew < TIMESTOPRINT) os << " PYTHIA Error in " << + "Sphericity::analyze: too few particles" << endl; + ++nFew; + return false; + } + + // Normalize tensor to trace = 1. + for (int j = 1; j < 4; ++j) + for (int k = j; k < 4; ++k) tt[j][k] /= denom; + + // Find eigenvalues to matrix (third degree equation). + double qCoef = ( tt[1][1] * tt[2][2] + tt[1][1] * tt[3][3] + + tt[2][2] * tt[3][3] - pow2(tt[1][2]) - pow2(tt[1][3]) + - pow2(tt[2][3]) ) / 3. - 1./9.; + double qCoefRt = sqrt( -qCoef); + double rCoef = -0.5 * ( qCoef + 1./9. + tt[1][1] * pow2(tt[2][3]) + + tt[2][2] * pow2(tt[1][3]) + tt[3][3] * pow2(tt[1][2]) + - tt[1][1] * tt[2][2] * tt[3][3] ) + + tt[1][2] * tt[1][3] * tt[2][3] + 1./27.; + double pTemp = max( min( rCoef / pow3(qCoefRt), 1.), -1.); + double pCoef = cos( acos(pTemp) / 3.); + double pCoefRt = sqrt( 3. * (1. - pow2(pCoef)) ); + eVal1 = 1./3. + qCoefRt * max( 2. * pCoef, pCoefRt - pCoef); + eVal3 = 1./3. + qCoefRt * min( 2. * pCoef, -pCoefRt - pCoef); + eVal2 = 1. - eVal1 - eVal3; + + // Begin find first and last eigenvector. + for (int iVal = 0; iVal < 2; ++iVal) { + double eVal = (iVal == 0) ? eVal1 : eVal3; + + // If all particles are back-to-back then only first axis meaningful. + if (iVal > 1 && eVal2 < EIGENVALUEMIN) { + if (nBack < TIMESTOPRINT) os << " PYTHIA Error in " + "Sphericity::analyze: particles too back-to-back" << endl; + ++nBack; + return false; + } + + // Set up matrix to diagonalize. + double dd[4][4]; + for (int j = 1; j < 4; ++j) { + dd[j][j] = tt[j][j] - eVal; + for (int k = j + 1; k < 4; ++k) { + dd[j][k] = tt[j][k]; + dd[k][j] = tt[j][k]; + } + } + + // Find largest = pivotal element in matrix. + int jMax = 0; + int kMax = 0; + double ddMax = 0.; + for (int j = 1; j < 4; ++j) + for (int k = 1; k < 4; ++k) + if (abs(dd[j][k]) > ddMax) { + jMax = j; + kMax = k; + ddMax = abs(dd[j][k]); + } + + // Subtract one row from the other two; find new largest element. + int jMax2 = 0; + ddMax = 0.; + for (int j = 1; j < 4; ++j) + if ( j != jMax) { + double pivot = dd[j][kMax] / dd[jMax][kMax]; + for (int k = 1; k < 4; ++k) { + dd[j][k] -= pivot * dd[jMax][k]; + if (abs(dd[j][k]) > ddMax) { + jMax2 = j; + ddMax = abs(dd[j][k]); + } + } + } + + // Construct eigenvector. Normalize to unit length. Random sign. + int k1 = kMax + 1; if (k1 > 3) k1 -= 3; + int k2 = kMax + 2; if (k2 > 3) k2 -= 3; + double eVec[4]; + eVec[k1] = -dd[jMax2][k2]; + eVec[k2] = dd[jMax2][k1]; + eVec[kMax] = (dd[jMax][k1] * dd[jMax2][k2] + - dd[jMax][k2] * dd[jMax2][k1]) / dd[jMax][kMax]; + double length = sqrt( pow2(eVec[1]) + pow2(eVec[2]) + + pow2(eVec[3]) ); + if (Rndm::flat() > 0.5) length = -length; + + // Store eigenvectors. + if (iVal == 0) eVec1 = Vec4( eVec[1] / length, + eVec[2] / length, eVec[3] / length, 0.); + else eVec3 = Vec4( eVec[1] / length, + eVec[2] / length, eVec[3] / length, 0.); + } + + // Middle eigenvector is orthogonal to the other two. + eVec2 = cross3( eVec1, eVec3); + if (Rndm::flat() > 0.5) eVec2 = -eVec2; + + // Done. + return true; + +} + +//********* + +// Provide a listing of the info. + +void Sphericity::list(ostream& os) { + + // Header. + os << "\n -------- PYTHIA Sphericity Listing -------- \n"; + if (powerInt !=2) os << " Nonstandard momentum power = " + << fixed << setprecision(3) << setw(6) << power << "\n"; + os << "\n no lambda e_x e_y e_z \n"; + + // The three eigenvalues and eigenvectors. + os << setprecision(5); + os << " 1" << setw(11) << eVal1 << setw(11) << eVec1.px() + << setw(10) << eVec1.py() << setw(10) << eVec1.pz() << "\n"; + os << " 2" << setw(11) << eVal2 << setw(11) << eVec2.px() + << setw(10) << eVec2.py() << setw(10) << eVec2.pz() << "\n"; + os << " 3" << setw(11) << eVal3 << setw(11) << eVec3.px() + << setw(10) << eVec3.py() << setw(10) << eVec3.pz() << "\n"; + + // Listing finished. + os << "\n -------- End PYTHIA Sphericity Listing ----" << endl; + +} + + +//************************************************************************** + +// Thrust class. +// This class finds thrust-related properties of an event. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Minimum number of particles to perform study. +const int Thrust::NSTUDYMIN = 2; + +// Maximum number of times that an error warning will be printed. +const int Thrust::TIMESTOPRINT = 1; + +// Major not too low or not possible to find major axis. +const double Thrust::MAJORMIN = 1e-10; + +//********* + +// Analyze event. + +bool Thrust::analyze(const Event& event, ostream& os) { + + // Initial values and counters zero. + eVal1 = eVal2 = eVal3 = 0.; + eVec1 = eVec2 = eVec3 = 0.; + int nStudy = 0; + vector pOrder; + Vec4 pSum, nRef, pPart, pFull, pMax; + + // Loop over desired particles in the event. + for (int i = 0; i < event.size(); ++i) + if (event[i].isFinal()) { + if (select > 2 && event[i].isNeutral() ) continue; + if (select == 2 && !event[i].isVisible() ) continue; + ++nStudy; + + // Store momenta. Use energy component for absolute momentum. + Vec4 pNow = event[i].p(); + pNow.e(pNow.pAbs()); + pSum += pNow; + pOrder.push_back(pNow); + } + + // Very low multiplicities (0 or 1) not considered. + if (nStudy < NSTUDYMIN) { + if (nFew < TIMESTOPRINT) os << " PYTHIA Error in " << + "Thrust::analyze: too few particles" << endl; + ++nFew; + return false; + } + + // Try all combinations of reference vector orthogonal to two particles. + for (int i1 = 0; i1 < nStudy - 1; ++i1) + for (int i2 = i1 + 1; i2 < nStudy; ++i2) { + nRef = cross3( pOrder[i1], pOrder[i2]); + nRef /= nRef.pAbs(); + pPart = 0.; + + // Add all momenta with sign; two choices for each reference particle. + for (int i = 0; i < nStudy; ++i) if (i != i1 && i != i2) { + if (dot3(pOrder[i], nRef) > 0.) pPart += pOrder[i]; + else pPart -= pOrder[i]; + } + for (int j = 0; j < 4; ++j) { + if (j == 0) pFull = pPart + pOrder[i1] + pOrder[i2]; + else if (j == 1) pFull = pPart + pOrder[i1] - pOrder[i2]; + else if (j == 2) pFull = pPart - pOrder[i1] + pOrder[i2]; + else pFull = pPart - pOrder[i1] - pOrder[i2]; + pFull.e(pFull.pAbs()); + if (pFull.e() > pMax.e()) pMax = pFull; + } + } + + // Maximum gives thrust axis and value. + eVal1 = pMax.e() / pSum.e(); + eVec1 = pMax / pMax.e(); + eVec1.e(0.); + + // Subtract momentum along thrust axis. + double pAbsSum = 0.; + for (int i = 0; i < nStudy; ++i) { + pOrder[i] -= dot3( eVec1, pOrder[i]) * eVec1; + pOrder[i].e(pOrder[i].pAbs()); + pAbsSum += pOrder[i].e(); + } + + // Simpleminded major and minor axes if too little transverse left. + if (pAbsSum < MAJORMIN * pSum.e()) { + if ( abs(eVec1.pz()) > 0.5) eVec2 = Vec4( 1., 0., 0., 0.); + else eVec2 = Vec4( 0., 0., 1., 0.); + eVec2 -= dot3( eVec1, eVec2) * eVec1; + eVec2 /= eVec2.pAbs(); + eVec3 = cross3( eVec1, eVec2); + return true; + } + + // Try all reference vectors orthogonal to one particles. + pMax = 0.; + for (int i1 = 0; i1 < nStudy; ++i1) { + nRef = cross3( pOrder[i1], eVec1); + nRef /= nRef.pAbs(); + pPart = 0.; + + // Add all momenta with sign; two choices for each reference particle. + for (int i = 0; i < nStudy; ++i) if (i != i1) { + if (dot3(pOrder[i], nRef) > 0.) pPart += pOrder[i]; + else pPart -= pOrder[i]; + } + pFull = pPart + pOrder[i1]; + pFull.e(pFull.pAbs()); + if (pFull.e() > pMax.e()) pMax = pFull; + pFull = pPart - pOrder[i1]; + pFull.e(pFull.pAbs()); + if (pFull.e() > pMax.e()) pMax = pFull; + } + + // Maximum gives major axis and value. + eVal2 = pMax.e() / pSum.e(); + eVec2 = pMax / pMax.e(); + eVec2.e(0.); + + // Orthogonal direction gives minor axis, and from there value. + eVec3 = cross3( eVec1, eVec2); + pAbsSum = 0.; + for (int i = 0; i < nStudy; ++i) + pAbsSum += abs( dot3(eVec3, pOrder[i]) ); + eVal3 = pAbsSum / pSum.e(); + + // Done. + return true; + +} + +//********* + +// Provide a listing of the info. + +void Thrust::list(ostream& os) { + + // Header. + os << "\n -------- PYTHIA Thrust Listing ------------ \n" + << "\n value e_x e_y e_z \n"; + + // The thrust, major and minor values and related event axes. + os << setprecision(5); + os << " Thr" << setw(11) << eVal1 << setw(11) << eVec1.px() + << setw(10) << eVec1.py() << setw(10) << eVec1.pz() << "\n"; + os << " Maj" << setw(11) << eVal2 << setw(11) << eVec2.px() + << setw(10) << eVec2.py() << setw(10) << eVec2.pz() << "\n"; + os << " Min" << setw(11) << eVal3 << setw(11) << eVec3.px() + << setw(10) << eVec3.py() << setw(10) << eVec3.pz() << "\n"; + + // Listing finished. + os << "\n -------- End PYTHIA Thrust Listing --------" << endl; + +} + +//************************************************************************** + +// SingleClusterJet class. +// Simple helper class to ClusterJet for a jet and its contents. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Assign minimal pAbs to avoid division by zero. +const double SingleClusterJet::PABSMIN = 1e-10; + +//********* + +// Distance measures between two SingleClusterJet objects. + +double dist2Fun(int measure, const SingleClusterJet& j1, + const SingleClusterJet& j2) { + + // JADE distance. + if (measure == 2) return 2. * j1.pJet.e() * j2.pJet.e() + * (1. - dot3( j1.pJet, j2.pJet) / (j1.pAbs * j2.pAbs) ); + + // Durham distance. + if (measure == 3) return 2. * pow2( min( j1.pJet.e(), j2.pJet.e() ) ) + * (1. - dot3( j1.pJet, j2.pJet) / (j1.pAbs * j2.pAbs) ); + + // Lund distance; "default". + return (j1.pAbs * j2.pAbs - dot3( j1.pJet, j2.pJet)) + * 2. * j1.pAbs * j2.pAbs / pow2(j1.pAbs + j2.pAbs); + +} + +//************************************************************************** + +// ClusterJet class. +// This class performs a jet clustering according to different +// distance measures: Lund, JADE or Durham. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Maximum number of times that an error warning will be printed. +const int ClusterJet::TIMESTOPRINT = 1; + +// Assign minimal pAbs to avoid division by zero. +const double ClusterJet::PABSMIN = 1e-10; + +// Initial pT/m preclustering scale as fraction of clustering one. +const double ClusterJet::PRECLUSTERFRAC = 0.1; + +// Step with which pT/m is reduced if preclustering gives too few jets. +const double ClusterJet::PRECLUSTERSTEP = 0.8; + +//********* + +// Analyze event. + +bool ClusterJet::analyze(const Event& event, double yScaleIn, + double pTscaleIn, int nJetMinIn, int nJetMaxIn, ostream& os) { + + // Input values. Initial values zero. + yScale = yScaleIn; + pTscale = pTscaleIn; + nJetMin = nJetMinIn; + nJetMax = nJetMaxIn; + particles.resize(0); + jets.resize(0); + Vec4 pSum; + + // Loop over desired particles in the event. + for (int i = 0; i < event.size(); ++i) + if (event[i].isFinal()) { + if (select > 2 && event[i].isNeutral() ) continue; + if (select == 2 && !event[i].isVisible() ) continue; + + // Store them, possibly with modified mass => new energy. + Vec4 pTemp = event[i].p(); + if (massSet == 0 || massSet == 1) { + double mTemp = (massSet == 0 || event[i].id() == 22) + ? 0. : piMass; + double eTemp = sqrt(pTemp.pAbs2() + pow2(mTemp)); + pTemp.e(eTemp); + } + particles.push_back( SingleClusterJet(pTemp, i) ); + pSum += pTemp; + } + + // Very low multiplicities not considered. + nParticles = particles.size(); + if (nParticles < nJetMin) { + if (nFew < TIMESTOPRINT) os << " PYTHIA Error in " << + "ClusterJet::analyze: too few particles" << endl; + ++nFew; + return false; + } + + // Squared maximum distance in GeV^2 for joining. + double p2Sum = pSum.m2Calc(); + dist2Join = max( yScale * p2Sum, pow2(pTscale)); + dist2BigMin = 2. * max( dist2Join, p2Sum); + + // Do preclustering if desired and possible. + if (doPrecluster && nParticles > nJetMin + 2) { + precluster(); + if (doReassign) reassign(); + } + + // If no preclustering: each particle is a starting jet. + else for (int i = 0; i < nParticles; ++i) { + jets.push_back( SingleClusterJet(particles[i]) ); + particles[i].daughter = i; + } + + // Begin iteration towards fewer jets. + for ( ; ; ) { + + // Find the two closest jets. + double dist2Min = dist2BigMin; + int jMin = 0; + int kMin = 0; + for (int j = 0; j < int(jets.size()) - 1; ++j) + for (int k = j + 1; k < int(jets.size()); ++k) { + double dist2 = dist2Fun( measure, jets[j], jets[k]); + if (dist2 < dist2Min) { + dist2Min = dist2; + jMin = j; + kMin = k; + } + } + + // Stop if no pair below cut and not more jets than allowed. + if ( dist2Min > dist2Join + && (nJetMax < nJetMin || int(jets.size()) <= nJetMax) ) break; + + // Join two closest jets. + jets[jMin].pJet += jets[kMin].pJet; + jets[jMin].pAbs = max( PABSMIN, jets[jMin].pJet.pAbs()); + jets[jMin].multiplicity += jets[kMin].multiplicity; + for (int i = 0; i < nParticles; ++i) + if (particles[i].daughter == kMin) particles[i].daughter = jMin; + + // Move up last jet to empty slot to shrink list. + jets[kMin] = jets.back(); + jets.pop_back(); + int iEnd = jets.size(); + for (int i = 0; i < nParticles; ++i) + if (particles[i].daughter == iEnd) particles[i].daughter = kMin; + + // Do reassignments of particles to nearest jet if desired. + if (doReassign) reassign(); + + // Stop if reached minimum allowed number of jets. Else continue. + if (int(jets.size()) <= nJetMin) break; + } + + // Order jets in decreasing energy. + for (int j = 0; j < int(jets.size()) - 1; ++j) + for (int k = int(jets.size()) - 1; k > j; --k) + if (jets[k].pJet.e() > jets[k-1].pJet.e()) { + swap( jets[k], jets[k-1]); + for (int i = 0; i < nParticles; ++i) { + if (particles[i].daughter == k) particles[i].daughter = k-1; + else if (particles[i].daughter == k-1) particles[i].daughter = k; + } + } + + // Done. + return true; +} + +//********* + +// Precluster nearby particles to save computer time. + +void ClusterJet::precluster() { + + // Begin iteration over preclustering scale. + distPre = PRECLUSTERFRAC * sqrt(dist2Join) / PRECLUSTERSTEP; + for ( ; ;) { + distPre *= PRECLUSTERSTEP; + dist2Pre = pow2(distPre); + for (int i = 0; i < nParticles; ++i) { + particles[i].daughter = -1; + particles[i].isAssigned = false; + } + + // Sum up low-momentum region. Jet if enough momentum. + Vec4 pCentral; + int multCentral = 0; + for (int i = 0; i < nParticles; ++i) + if (particles[i].pAbs < 2. * distPre) { + pCentral += particles[i].pJet; + multCentral += particles[i].multiplicity; + particles[i].isAssigned = true; + } + if (pCentral.pAbs() > 2. * distPre) { + jets.push_back( SingleClusterJet(pCentral) ); + jets.back().multiplicity = multCentral; + for (int i = 0; i < nParticles; ++i) + if (particles[i].isAssigned) particles[i].daughter = 0; + } + + // Find fastest remaining particle until none left. + for ( ; ;) { + int iMax = -1; + double pMax = 0.; + for (int i = 0; i < nParticles; ++i) + if ( !particles[i].isAssigned && particles[i].pAbs > pMax) { + iMax = i; + pMax = particles[i].pAbs; + } + if (iMax == -1) break; + + // Sum up precluster around it according to distance function. + Vec4 pPre; + int multPre = 0; + int nRemain = 0; + for (int i = 0; i < nParticles; ++i) + if ( !particles[i].isAssigned) { + double dist2 = dist2Fun( measure, particles[iMax], + particles[i]); + if (dist2 < dist2Pre) { + pPre += particles[i].pJet; + ++multPre; + particles[i].isAssigned = true; + particles[i].daughter = jets.size(); + } else ++nRemain; + } + jets.push_back( SingleClusterJet(pPre) ); + jets.back().multiplicity = multPre; + + // Decide whether sensible starting configuration or iterate. + if (int(jets.size()) + nRemain < nJetMin) break; + } + if (int(jets.size()) >= nJetMin) break; + } + +} + +//********* + +// Reassign particles to nearest jet to correct misclustering. + +void ClusterJet::reassign() { + + // Reset clustered momenta. + for (int j = 0; j < int(jets.size()); ++j) { + jets[j].pTemp = 0.; + jets[j].multiplicity = 0; + } + + // Loop through particles to find closest jet. + for (int i = 0; i < nParticles; ++i) { + particles[i].daughter = -1; + double dist2Min = dist2BigMin; + int jMin = 0; + for (int j = 0; j < int(jets.size()); ++j) { + double dist2 = dist2Fun( measure, particles[i], jets[j]); + if (dist2 < dist2Min) { + dist2Min = dist2; + jMin = j; + } + } + jets[jMin].pTemp += particles[i].pJet; + ++jets[jMin].multiplicity; + particles[i].daughter = jMin; + } + + // Replace old by new jet momenta. + for (int j = 0; j < int(jets.size()); ++j) { + jets[j].pJet = jets[j].pTemp; + jets[j].pAbs = max( PABSMIN, jets[j].pJet.pAbs()); + } + + // Check that no empty clusters after reassignments. + for ( ; ; ) { + + // If no empty jets then done. + int jEmpty = -1; + for (int j = 0; j < int(jets.size()); ++j) + if (jets[j].multiplicity == 0) jEmpty = j; + if (jEmpty == -1) return; + + // Find particle assigned to jet with largest distance to it. + int iSplit = -1; + double dist2Max = 0.; + for (int i = 0; i < nParticles; ++i) { + int j = particles[i].daughter; + double dist2 = dist2Fun( measure, particles[i], jets[j]); + if (dist2 > dist2Max) { + iSplit = i; + dist2Max = dist2; + } + } + + // Let this particle form new jet and subtract off from existing. + int jSplit = particles[iSplit].daughter; + jets[jEmpty] = SingleClusterJet( particles[iSplit].pJet ); + jets[jSplit].pJet -= particles[iSplit].pJet; + jets[jSplit].pAbs = max( PABSMIN,jets[jSplit].pJet.pAbs()); + particles[iSplit].daughter = jEmpty; + --jets[jSplit].multiplicity; + } + +} + +//********* + +// Provide a listing of the info. + +void ClusterJet::list(ostream& os) { + + // Header. + string method = (measure == 1) ? "Lund pT" + : ( (measure == 2) ? "JADE m" : "Durham kT" ) ; + os << "\n -------- PYTHIA ClusterJet Listing, " << setw(9) << method + << " =" << fixed << setprecision(3) << setw(7) << sqrt(dist2Join) + << " GeV --- \n \n no mult p_x p_y p_z " + << " e m \n"; + + // The jets. + for (int i = 0; i < int(jets.size()); ++i) { + os << setw(4) << i << setw(6) << jets[i].multiplicity << setw(11) + << jets[i].pJet.px() << setw(11) << jets[i].pJet.py() + << setw(11) << jets[i].pJet.pz() << setw(11) + << jets[i].pJet.e() << setw(11) << jets[i].pJet.mCalc() + << "\n"; + } + + // Listing finished. + os << "\n -------- End PYTHIA ClusterJet Listing ---------------" + << "--------" << endl; +} + +//************************************************************************** + +// CellJet class. +// This class performs a cone jet search in (eta, phi, E_T) space. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Minimum number of particles to perform study. +const int CellJet::TIMESTOPRINT = 1; + +//********* + +// Analyze event. + +bool CellJet::analyze(const Event& event, double eTjetMinIn, + double coneRadiusIn, double eTseedIn, ostream& ) { + + // Input values. Initial values zero. + eTjetMin = eTjetMinIn; + coneRadius = coneRadiusIn; + eTseed = eTseedIn; + jets.resize(0); + vector cells; + + // Loop over desired particles in the event. + for (int i = 0; i < event.size(); ++i) + if (event[i].isFinal()) { + if (select > 2 && event[i].isNeutral() ) continue; + if (select == 2 && !event[i].isVisible() ) continue; + + // Find particle position in (eta, phi, pT) space. + double etaNow = event[i].eta(); + if (abs(etaNow) > etaMax) continue; + double phiNow = event[i].phi(); + double pTnow = event[i].pT(); + int iEtaNow = max(1, min( nEta, 1 + int(nEta * 0.5 + * (1. + etaNow / etaMax) ) ) ); + int iPhiNow = max(1, min( nPhi, 1 + int(nPhi * 0.5 + * (1. + phiNow / M_PI) ) ) ); + int iCell = nPhi * iEtaNow + iPhiNow; + + // Add pT to cell already hit or book a new cell. + bool found = false; + for (int j = 0; j < int(cells.size()); ++j) { + if (iCell == cells[j].iCell) { + found = true; + ++cells[j].multiplicity; + cells[j].eTcell += pTnow; + continue; + } + } + if (!found) { + double etaCell = (etaMax / nEta) * (2 * iEtaNow - 1 - nEta); + double phiCell = (M_PI / nPhi) * (2 * iPhiNow - 1 - nPhi); + cells.push_back( SingleCell( iCell, etaCell, phiCell, pTnow, 1) ); + } + } + + // Smear true bin content by calorimeter resolution. + if (smear > 0) + for (int j = 0; j < int(cells.size()); ++j) { + double eTeConv = (smear < 2) ? 1. : cosh( cells[j].etaCell ); + double eBef = cells[j].eTcell * eTeConv; + double eAft = 0.; + do eAft = eBef + resolution * sqrt(eBef) * Rndm::gauss(); + while (eAft < 0 || eAft > upperCut * eBef); + cells[j].eTcell = eAft / eTeConv; + } + + // Remove cells below threshold for seed or for use at all. + for (int j = 0; j < int(cells.size()); ++j) { + if (cells[j].eTcell < eTseed) cells[j].canBeSeed = false; + if (cells[j].eTcell < threshold) cells[j].isUsed = true; + } + + // Find seed cell: the one with highest pT of not yet probed ones. + for ( ; ; ) { + int jMax = 0; + double eTmax = 0.; + for (int j = 0; j < int(cells.size()); ++j) + if (cells[j].canBeSeed && cells[j].eTcell > eTmax) { + jMax = j; + eTmax = cells[j].eTcell; + } + + // If too small cell eT then done, else start new trial jet. + if (eTmax < eTseed) break; + double etaCenterNow = cells[jMax].etaCell; + double phiCenterNow = cells[jMax].phiCell; + double eTjetNow = 0.; + + // Sum up unused cells within required distance of seed. + for (int j = 0; j < int(cells.size()); ++j) { + if (cells[j].isUsed) continue; + double dEta = abs( cells[j].etaCell - etaCenterNow ); + if (dEta > coneRadius) continue; + double dPhi = abs( cells[j].phiCell - phiCenterNow ); + if (dPhi > M_PI) dPhi = 2. * M_PI - dPhi; + if (dPhi > coneRadius) continue; + if (pow2(dEta) + pow2(dPhi) > pow2(coneRadius)) continue; + cells[j].isAssigned = true; + eTjetNow += cells[j].eTcell; + } + + // Reject cluster below minimum ET. + if (eTjetNow < eTjetMin) { + cells[jMax].canBeSeed = false; + for (int j = 0; j < int(cells.size()); ++j) + cells[j].isAssigned = false; + + // Else find new jet properties. + } else { + double etaWeightedNow = 0.; + double phiWeightedNow = 0.; + int multiplicityNow = 0; + Vec4 pMassiveNow; + for (int j = 0; j < int(cells.size()); ++j) + if (cells[j].isAssigned) { + cells[j].canBeSeed = false; + cells[j].isUsed = true; + cells[j].isAssigned = false; + etaWeightedNow += cells[j].eTcell * cells[j].etaCell; + double phiCell = cells[j].phiCell; + if (abs(phiCell - phiCenterNow) > M_PI) + phiCell += (phiCenterNow > 0.) ? 2. * M_PI : -2. * M_PI; + phiWeightedNow += cells[j].eTcell * phiCell; + multiplicityNow += cells[j].multiplicity; + pMassiveNow += cells[j].eTcell * Vec4( + cos(cells[j].phiCell), sin(cells[j].phiCell), + sinh(cells[j].etaCell), cosh(cells[j].etaCell) ); + } + etaWeightedNow /= eTjetNow; + phiWeightedNow /= eTjetNow; + + // Bookkeep new jet, in decreasing ET order. + jets.push_back( SingleCellJet( eTjetNow, etaCenterNow, phiCenterNow, + etaWeightedNow, phiWeightedNow, multiplicityNow, pMassiveNow) ); + for (int i = int(jets.size()) - 1; i > 0; --i) { + if (jets[i-1].eTjet > jets[i].eTjet) break; + swap( jets[i-1], jets[i]); + } + } + } + + // Done. + return true; +} + +//********* + +// Provide a listing of the info. + +void CellJet::list(ostream& os) { + + // Header. + os << "\n -------- PYTHIA CellJet Listing, eTjetMin = " + << fixed << setprecision(3) << setw(8) << eTjetMin + << ", coneRadius = " << setw(5) << coneRadius + << " ------------------------------ \n \n no " + << " eTjet etaCtr phiCtr etaWt phiWt mult p_x" + << " p_y p_z e m \n"; + + // The jets. + for (int i = 0; i < int(jets.size()); ++i) { + os << setw(4) << i << setw(10) << jets[i].eTjet << setw(8) + << jets[i].etaCenter << setw(8) << jets[i].phiCenter << setw(8) + << jets[i].etaWeighted << setw(8) << jets[i].phiWeighted + << setw(5) << jets[i].multiplicity << setw(11) + << jets[i].pMassive.px() << setw(11) << jets[i].pMassive.py() + << setw(11) << jets[i].pMassive.pz() << setw(11) + << jets[i].pMassive.e() << setw(11) + << jets[i].pMassive.mCalc() << "\n"; + } + + // Listing finished. + os << "\n -------- End PYTHIA CellJet Listing ------------------" + << "-------------------------------------------------" + << endl; +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/Basics.cxx b/PYTHIA8/pythia8130/src/Basics.cxx new file mode 100644 index 00000000000..0848bc56a69 --- /dev/null +++ b/PYTHIA8/pythia8130/src/Basics.cxx @@ -0,0 +1,1175 @@ +// Basics.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the Rndm, Vec4, +// RotBstMatrix and Hist classes, and some related global functions. + +#include "Basics.h" + +// Access time information. +#include + +namespace Pythia8 { + +//************************************************************************** + +// Rndm class. +// This class handles random number generation according to the +// Marsaglia-Zaman-Tsang algorithm + +//********* + +// Definitions of static variables. + +bool Rndm::initRndm = false; +bool Rndm::saveGauss = false; +int Rndm::i97, Rndm::j97; +int Rndm::defaultSeed = 19780503; +double Rndm::u[97], Rndm::c, Rndm::cd, Rndm::cm, Rndm::save; +bool Rndm::useExternalRndm = false; +RndmEngine* Rndm::rndmPtr = 0; + +//********* + +// Method to pass in pointer for external random number generation. + +bool Rndm::rndmEnginePtr( RndmEngine* rndmPtrIn) { + + // Save pointer. + if (rndmPtrIn == 0) return false; + rndmPtr = rndmPtrIn; + useExternalRndm = true; + + // Done. + return true; + +} + +//********* + +// Initialize, normally at construction or in first call. + +void Rndm::init(int seedIn) { + + // Pick seed in convenient way. Assure it to be non-negative. + int seed = seedIn; + if (seedIn < 0) seed = defaultSeed; + else if (seedIn == 0) seed = int(time(0)); + if (seed < 0) seed = -seed; + + // Unpack seed. + int ij = (seed/30082) % 31329; + int kl = seed % 30082; + int i = (ij/177) % 177 + 2; + int j = ij % 177 + 2; + int k = (kl/169) % 178 + 1; + int l = kl % 169; + + // Initialize random number array. + for (int ii = 0; ii < 97; ++ii) { + double s = 0.; + double t = 0.5; + for (int jj = 0; jj < 48; ++jj) { + int m = (( (i*j)%179 )*k) % 179; + i = j; + j = k; + k = m; + l = (53*l+1) % 169; + if ( (l*m) % 64 >= 32) s += t; + t *= 0.5; + } + u[ii] = s; + } + + // Initialize other variables. + double twom24 = 1.; + for (int i24 = 0; i24 < 24; ++i24) twom24 *= 0.5; + c = 362436. * twom24; + cd = 7654321. * twom24; + cm = 16777213. * twom24; + i97 = 96; + j97 = 32; + + // Finished. + initRndm = true; + +} + +//********* + +// Generate next random number uniformly between 0 and 1. + +double Rndm::flat() { + + // Use external random number generator if such has been linked. + if(useExternalRndm) return rndmPtr->flat(); + + // Ensure that already initialized. + if (!initRndm) init(defaultSeed); + + // Find next random number and update saved state. + double uni; + do { + uni = u[i97] - u[j97]; + if (uni < 0.) uni += 1.; + u[i97] = uni; + if (--i97 < 0) i97 = 96; + if (--j97 < 0) j97 = 96; + c -= cd; + if (c < 0.) c += cm; + uni -= c; + if(uni < 0.) uni += 1.; + } while (uni <= 0. || uni >= 1.); + return uni; + +} + +//********* + +// Generate random numbers according to exp(-x^2/2). + +double Rndm::gauss() { + + // Generate pair of Gaussian random numbers. + if (!saveGauss) { + saveGauss = true; + double r = sqrt(-2. * log(flat())); + double phi = 2. * M_PI * flat(); + save = r * sin(phi); + return r * cos(phi); + + // Use saved element of pair. + } else { + saveGauss = false; + return save; + } + +} + +//********* + +// Pick one option among vector of (positive) probabilities. + +int Rndm::pick(const vector& prob) { + + double work = 0.; + for (int i = 0; i < int(prob.size()); ++i) {work += prob[i];} + work *= flat(); + int index = -1; + do { work -= prob[++index]; } while (work > 0 && index < int(prob.size())); + return index; + +} + +//************************************************************************** + +// Vec4 class. +// This class implements four-vectors, in energy-momentum space. +// (But could also be used to hold space-time four-vectors.) + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Small number to avoid division by zero. +const double Vec4::TINY = 1e-20; + +//********* + +// Rotation (simple). + +void Vec4::rot(double thetaIn, double phiIn) { + + double cthe = cos(thetaIn); + double sthe = sin(thetaIn); + double cphi = cos(phiIn); + double sphi = sin(phiIn); + double tmpx = cthe * cphi * xx - sphi * yy + sthe * cphi * zz; + double tmpy = cthe * sphi * xx + cphi * yy + sthe * sphi * zz; + double tmpz = -sthe * xx + cthe * zz; + xx = tmpx; + yy = tmpy; + zz = tmpz; + +} + +//********* + +// Azimuthal rotation phi around an arbitrary axis (nz, ny, nz). + +void Vec4::rotaxis(double phiIn, double nx, double ny, double nz) { + + double norm = 1./sqrt(nx*nx + ny*ny + nz*nz); + nx *= norm; + ny *= norm; + nz *= norm; + double cphi = cos(phiIn); + double sphi = sin(phiIn); + double comb = (nx * xx + ny * yy + nz * zz) * (1. - cphi); + double tmpx = cphi * xx + comb * nx + sphi * (ny * zz - nz * yy); + double tmpy = cphi * yy + comb * ny + sphi * (nz * xx - nx * zz); + double tmpz = cphi * zz + comb * nz + sphi * (nx * yy - ny * xx); + xx = tmpx; + yy = tmpy; + zz = tmpz; + +} + +//********* + +// Azimuthal rotation phi around an arbitrary (3-vector component of) axis. + +void Vec4::rotaxis(double phiIn, const Vec4& n) { + + double nx = n.xx; + double ny = n.yy; + double nz = n.zz; + double norm = 1./sqrt(nx*nx + ny*ny + nz*nz); + nx *= norm; + ny *=norm; + nz *=norm; + double cphi = cos(phiIn); + double sphi = sin(phiIn); + double comb = (nx * xx + ny * yy + nz * zz) * (1. - cphi); + double tmpx = cphi * xx + comb * nx + sphi * (ny * zz - nz * yy); + double tmpy = cphi * yy + comb * ny + sphi * (nz * xx - nx * zz); + double tmpz = cphi * zz + comb * nz + sphi * (nx * yy - ny * xx); + xx = tmpx; + yy = tmpy; + zz = tmpz; + +} + +//********* + +// Boost (simple). + +void Vec4::bst(double betaX, double betaY, double betaZ) { + + double beta2 = betaX*betaX + betaY*betaY + betaZ*betaZ; + double gamma = 1. / sqrt(1. - beta2); + double prod1 = betaX * xx + betaY * yy + betaZ * zz; + double prod2 = gamma * (gamma * prod1 / (1. + gamma) + tt); + xx += prod2 * betaX; + yy += prod2 * betaY; + zz += prod2 * betaZ; + tt = gamma * (tt + prod1); + +} + +//********* + +// Boost (simple, given gamma). + +void Vec4::bst(double betaX, double betaY, double betaZ, double gamma) { + + double prod1 = betaX * xx + betaY * yy + betaZ * zz; + double prod2 = gamma * (gamma * prod1 / (1. + gamma) + tt); + xx += prod2 * betaX; + yy += prod2 * betaY; + zz += prod2 * betaZ; + tt = gamma * (tt + prod1); + +} + +//********* + +// Boost given by a Vec4 p. + +void Vec4::bst(const Vec4& pIn) { + + double betaX = pIn.xx / pIn.tt; + double betaY = pIn.yy / pIn.tt; + double betaZ = pIn.zz / pIn.tt; + double beta2 = betaX*betaX + betaY*betaY + betaZ*betaZ; + double gamma = 1. / sqrt(1. - beta2); + double prod1 = betaX * xx + betaY * yy + betaZ * zz; + double prod2 = gamma * (gamma * prod1 / (1. + gamma) + tt); + xx += prod2 * betaX; + yy += prod2 * betaY; + zz += prod2 * betaZ; + tt = gamma * (tt + prod1); + +} + +//********* + +// Boost given by a Vec4 p and double m. + +void Vec4::bst(const Vec4& pIn, double mIn) { + + double betaX = pIn.xx / pIn.tt; + double betaY = pIn.yy / pIn.tt; + double betaZ = pIn.zz / pIn.tt; + double gamma = pIn.tt / mIn; + double prod1 = betaX * xx + betaY * yy + betaZ * zz; + double prod2 = gamma * (gamma * prod1 / (1. + gamma) + tt); + xx += prod2 * betaX; + yy += prod2 * betaY; + zz += prod2 * betaZ; + tt = gamma * (tt + prod1); + +} + +//********* + +// Boost given by a Vec4 p; boost in opposite direction. + +void Vec4::bstback(const Vec4& pIn) { + + double betaX = -pIn.xx / pIn.tt; + double betaY = -pIn.yy / pIn.tt; + double betaZ = -pIn.zz / pIn.tt; + double beta2 = betaX*betaX + betaY*betaY + betaZ*betaZ; + double gamma = 1. / sqrt(1. - beta2); + double prod1 = betaX * xx + betaY * yy + betaZ * zz; + double prod2 = gamma * (gamma * prod1 / (1. + gamma) + tt); + xx += prod2 * betaX; + yy += prod2 * betaY; + zz += prod2 * betaZ; + tt = gamma * (tt + prod1); + +} + +//********* + +// Boost given by a Vec4 p and double m; boost in opposite direction. + +void Vec4::bstback(const Vec4& pIn, double mIn) { + + double betaX = -pIn.xx / pIn.tt; + double betaY = -pIn.yy / pIn.tt; + double betaZ = -pIn.zz / pIn.tt; + double gamma = pIn.tt / mIn; + double prod1 = betaX * xx + betaY * yy + betaZ * zz; + double prod2 = gamma * (gamma * prod1 / (1. + gamma) + tt); + xx += prod2 * betaX; + yy += prod2 * betaY; + zz += prod2 * betaZ; + tt = gamma * (tt + prod1); + +} + +//********* + +// Arbitrary combination of rotations and boosts defined by 4 * 4 matrix. + +void Vec4::rotbst(const RotBstMatrix& M) { + + double x = xx; double y = yy; double z = zz; double t = tt; + tt = M.M[0][0] * t + M.M[0][1] * x + M.M[0][2] * y + M.M[0][3] * z; + xx = M.M[1][0] * t + M.M[1][1] * x + M.M[1][2] * y + M.M[1][3] * z; + yy = M.M[2][0] * t + M.M[2][1] * x + M.M[2][2] * y + M.M[2][3] * z; + zz = M.M[3][0] * t + M.M[3][1] * x + M.M[3][2] * y + M.M[3][3] * z; + +} + +//********* + +// The invariant mass of two four-vectors. + +double m(const Vec4& v1, const Vec4& v2) { + double m2 = pow2(v1.tt + v2.tt) - pow2(v1.xx + v2.xx) + - pow2(v1.yy + v2.yy) - pow2(v1.zz + v2.zz); + return (m2 > 0.) ? sqrt(m2) : 0.; +} + +//********* + +// The squared invariant mass of two four-vectors. + +double m2(const Vec4& v1, const Vec4& v2) { + double m2 = pow2(v1.tt + v2.tt) - pow2(v1.xx + v2.xx) + - pow2(v1.yy + v2.yy) - pow2(v1.zz + v2.zz); + return m2; +} + +//********* + +// The scalar product of two three-vectors. + +double dot3(const Vec4& v1, const Vec4& v2) { + return v1.xx*v2.xx + v1.yy*v2.yy + v1.zz*v2.zz; +} + +//********* + +// The cross product of two three-vectors. + +Vec4 cross3(const Vec4& v1, const Vec4& v2) { + Vec4 v; + v.xx = v1.yy * v2.zz - v1.zz * v2.yy; + v.yy = v1.zz * v2.xx - v1.xx * v2.zz; + v.zz = v1.xx * v2.yy - v1.yy * v2.xx; return v; +} + +//********* + +// Opening angle between two three-vectors. + +double theta(const Vec4& v1, const Vec4& v2) { + double cthe = (v1.xx * v2.xx + v1.yy * v2.yy + v1.zz * v2.zz) + / sqrt( (v1.xx*v1.xx + v1.yy*v1.yy + v1.zz*v1.zz) + * (v2.xx*v2.xx + v2.yy*v2.yy + v2.zz*v2.zz) ); + cthe = max(-1., min(1., cthe)); + return acos(cthe); +} + +//********* + +// Cosine of the opening angle between two three-vectors. + +double costheta(const Vec4& v1, const Vec4& v2) { + double cthe = (v1.xx * v2.xx + v1.yy * v2.yy + v1.zz * v2.zz) + / sqrt( (v1.xx*v1.xx + v1.yy*v1.yy + v1.zz*v1.zz) + * (v2.xx*v2.xx + v2.yy*v2.yy + v2.zz*v2.zz) ); + cthe = max(-1., min(1., cthe)); + return cthe; +} + +//********* + +// Azimuthal angle between two three-vectors. + +double phi(const Vec4& v1, const Vec4& v2) { + double cphi = (v1.xx * v2.xx + v1.yy * v2.yy) / sqrt( max( Vec4::TINY, + (v1.xx*v1.xx + v1.yy*v1.yy) * (v2.xx*v2.xx + v2.yy*v2.yy) )); + cphi = max(-1., min(1., cphi)); + return acos(cphi); +} + +//********* + +// Cosine of the azimuthal angle between two three-vectors. + +double cosphi(const Vec4& v1, const Vec4& v2) { + double cphi = (v1.xx * v2.xx + v1.yy * v2.yy) / sqrt( max( Vec4::TINY, + (v1.xx*v1.xx + v1.yy*v1.yy) * (v2.xx*v2.xx + v2.yy*v2.yy) )); + cphi = max(-1., min(1., cphi)); + return cphi; +} + +//********* + +// Azimuthal angle between two three-vectors around a third. + +double phi(const Vec4& v1, const Vec4& v2, const Vec4& n) { + double nx = n.xx; double ny = n.yy; double nz = n.zz; + double norm = 1. / sqrt(nx*nx + ny*ny + nz*nz); + nx *= norm; ny *=norm; nz *=norm; + double v1s = v1.xx * v1.xx + v1.yy * v1.yy + v1.zz * v1.zz; + double v2s = v2.xx * v2.xx + v2.yy * v2.yy + v2.zz * v2.zz; + double v1v2 = v1.xx * v2.xx + v1.yy * v2.yy + v1.zz * v2.zz; + double v1n = v1.xx * nx + v1.yy * ny + v1.zz * nz; + double v2n = v2.xx * nx + v2.yy * ny + v2.zz * nz; + double cphi = (v1v2 - v1n * v2n) / sqrt( max( Vec4::TINY, + (v1s - v1n*v1n) * (v2s - v2n*v2n) )); + cphi = max(-1., min(1., cphi)); + return acos(cphi); +} + +//********* + +// Cosine of the azimuthal angle between two three-vectors around a third. + +double cosphi(const Vec4& v1, const Vec4& v2, const Vec4& n) { + double nx = n.xx; double ny = n.yy; double nz = n.zz; + double norm = 1. / sqrt(nx*nx + ny*ny + nz*nz); + nx *= norm; ny *=norm; nz *=norm; + double v1s = v1.xx * v1.xx + v1.yy * v1.yy + v1.zz * v1.zz; + double v2s = v2.xx * v2.xx + v2.yy * v2.yy + v2.zz * v2.zz; + double v1v2 = v1.xx * v2.xx + v1.yy * v2.yy + v1.zz * v2.zz; + double v1n = v1.xx * nx + v1.yy * ny + v1.zz * nz; + double v2n = v2.xx * nx + v2.yy * ny + v2.zz * nz; + double cphi = (v1v2 - v1n * v2n) / sqrt( max( Vec4::TINY, + (v1s - v1n*v1n) * (v2s - v2n*v2n) )); + cphi = max(-1., min(1., cphi)); + return cphi; +} + +//********* + +// Print a four-vector: also operator overloading with friend. + +ostream& operator<<(ostream& os, const Vec4& v) { + os << fixed << setprecision(3) << setw(10) << v.xx << setw(10) << v.yy + << setw(10) << v.zz << setw(10) << v.tt << "\n"; + return os; +} + +//************************************************************************** + +// RotBstMatrix class. +// This class implements 4 * 4 matrices that encode an arbitrary combination +// of rotations and boosts, that can be applied to Vec4 four-vectors. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Small number to avoid division by zero. +const double RotBstMatrix::TINY = 1e-20; + +//********* + +// Rotate by polar angle theta and azimuthal angle phi. + +void RotBstMatrix::rot(double theta, double phi) { + + // Set up rotation matrix. + double cthe = cos(theta); double sthe = sin(theta); + double cphi = cos(phi); double sphi = sin(phi); + double Mrot[4][4] = { + {1., 0., 0., 0.}, + {0., cthe * cphi, - sphi, sthe * cphi}, + {0., cthe * sphi, cphi, sthe * sphi}, + {0., -sthe, 0., cthe } }; + + // Rotate current matrix accordingly. + double Mtmp[4][4]; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + Mtmp[i][j] = M[i][j]; + } + } + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + M[i][j] = Mrot[i][0] * Mtmp[0][j] + Mrot[i][1] * Mtmp[1][j] + + Mrot[i][2] * Mtmp[2][j] + Mrot[i][3] * Mtmp[3][j]; + } + } + +} + +//********* + +// Rotate so that vector originally along z axis becomes parallel with p. + +void RotBstMatrix::rot(const Vec4& p) { + + double theta = p.theta(); + double phi = p.phi(); + rot(0., -phi); + rot(theta, phi); + +} + +//********* + +// Boost with velocity vector (betaX, betaY, betaZ). + +void RotBstMatrix::bst(double betaX, double betaY, double betaZ) { + + // Set up boost matrix. + double gm = 1. / sqrt( max( TINY, 1. - betaX*betaX - betaY*betaY + - betaZ*betaZ ) ); + double gf = gm*gm / (1. + gm); + double Mbst[4][4] = { + { gm, gm*betaX, gm*betaY, gm*betaZ }, + { gm*betaX, 1. + gf*betaX*betaX, gf*betaX*betaY, gf*betaX*betaZ }, + { gm*betaY, gf*betaY*betaX, 1. + gf*betaY*betaY, gf*betaY*betaZ }, + { gm*betaZ, gf*betaZ*betaX, gf*betaZ*betaY, 1. + gf*betaZ*betaZ } }; + + // Boost current matrix correspondingly. + double Mtmp[4][4]; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + Mtmp[i][j] = M[i][j]; + } + } + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + M[i][j] = Mbst[i][0] * Mtmp[0][j] + Mbst[i][1] * Mtmp[1][j] + + Mbst[i][2] * Mtmp[2][j] + Mbst[i][3] * Mtmp[3][j]; + } + } + +} + +//********* + +// Boost so that vector originally at rest obtains same velocity as p. + +void RotBstMatrix::bst(const Vec4& p) { + double betaX = p.px() / p.e(); + double betaY = p.py() / p.e(); + double betaZ = p.pz() / p.e(); + bst(betaX, betaY, betaZ); +} + +//********* + +// Boost so vector originally with same velocity as p is brought to rest. + +void RotBstMatrix::bstback(const Vec4& p) { + double betaX = -p.px() / p.e(); + double betaY = -p.py() / p.e(); + double betaZ = -p.pz() / p.e(); + bst(betaX, betaY, betaZ); +} + +//********* + +// Boost that transforms p1 to p2, where p1^2 = p2^2 is assumed. + +void RotBstMatrix::bst(const Vec4& p1, const Vec4& p2) { + double eSum = p1.e() + p2.e(); + double betaX = (p2.px() - p1.px()) / eSum; + double betaY = (p2.py() - p1.py()) / eSum; + double betaZ = (p2.pz() - p1.pz()) / eSum; + double fac = 2. / (1. + betaX*betaX + betaY*betaY + betaZ*betaZ); + betaX *= fac; betaY *= fac; betaZ *= fac; + bst(betaX, betaY, betaZ); +} + +//********* + +// Boost and rotation that transforms from p1 and p2 +// to their rest frame with p1 along +z axis. + +void RotBstMatrix::toCMframe(const Vec4& p1, const Vec4& p2) { + Vec4 pSum = p1 + p2; + Vec4 dir = p1; + dir.bstback(pSum); + double theta = dir.theta(); + double phi = dir.phi(); + bstback(pSum); + rot(0., -phi); + rot(-theta, phi); +} + +//********* + +// Rotation and boost that transforms from rest frame of p1 and p2 +// with p1 along +z axis to actual frame of p1 and p2. (Inverse of above.) + +void RotBstMatrix::fromCMframe(const Vec4& p1, const Vec4& p2) { + Vec4 pSum = p1 + p2; + Vec4 dir = p1; + dir.bstback(pSum); + double theta = dir.theta(); + double phi = dir.phi(); + rot(0., -phi); + rot(theta, phi); + bst(pSum); +} + +//********* + +// Combine existing rotation/boost matrix with another one. + +void RotBstMatrix::rotbst(const RotBstMatrix& Mrb) { + double Mtmp[4][4]; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + Mtmp[i][j] = M[i][j]; + } + } + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + M[i][j] = Mrb.M[i][0] * Mtmp[0][j] + Mrb.M[i][1] * Mtmp[1][j] + + Mrb.M[i][2] * Mtmp[2][j] + Mrb.M[i][3] * Mtmp[3][j]; + } + } +} + +//********* + +// Invert the rotation and boost. + +void RotBstMatrix::invert() { + double Mtmp[4][4]; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + Mtmp[i][j] = M[i][j]; + } + } + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + M[i][j] = ( (i == 0 && j > 0) || (i > 0 && j == 0) ) + ? - Mtmp[j][i] : Mtmp[j][i]; + } + } +} + +//********* + +// Reset to diagonal matrix. + +void RotBstMatrix::reset() { + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + M[i][j] = (i==j) ? 1. : 0.; + } + } +} + +//********* + +// Crude estimate deviation from unit matrix. + +double RotBstMatrix::deviation() const { + double devSum = 0.; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + devSum += (i==j) ? abs(M[i][j] - 1.) : abs(M[i][j]); + } + } + return devSum; +} + +//********* + +// Print a rotation and boost matrix: operator overloading with friend. + +ostream& operator<<(ostream& os, const RotBstMatrix& M) { + os << fixed << setprecision(5) << " Rotation/boost matrix: \n"; + for (int i = 0; i <4; ++i) { + os << setw(10) << M.M[i][0] << setw(10) << M.M[i][1] + << setw(10) << M.M[i][2] << setw(10) << M.M[i][3] << "\n"; + } + return os; +} + +//************************************************************************** + +// Hist class. +// This class handles a single histogram at a time +// (or a vector of histograms). + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Maximum number of bins in a histogram. +const int Hist::NBINMAX = 100; + +// Maximum number of lines a histogram can use at output. +const int Hist::NLINES = 30; + +// Tolerance in deviation of xMin and xMax between two histograms. +const double Hist::TOLERANCE = 0.001; + +// Small number to avoid division by zero. +const double Hist::TINY = 1e-20; + +// When minbin/maxbin < SMALLFRAC the y scale goes down to zero. +const double Hist::SMALLFRAC = 0.1; + +// Constants for printout: fixed steps on y scale; filling characters. +const double DYAC[] = {0.04, 0.05, 0.06, 0.08, 0.10, + 0.12, 0.15, 0.20, 0.25, 0.30}; +const char NUMBER[] = {'0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', 'X' }; + +//********* + +// Book a histogram. + +void Hist::book(string titleIn, int nBinIn, double xMinIn, + double xMaxIn) { + + title = titleIn; + nBin = nBinIn; + if (nBinIn < 1) nBin = 1; + if (nBinIn > NBINMAX) nBin = NBINMAX; + xMin = xMinIn; + xMax = xMaxIn; + dx = (xMax - xMin)/nBin; + res.resize(nBin); + null(); + +} + +//********* + +// Reset bin contents. + +void Hist::null() { + + nFill = 0; + under = 0.; + inside = 0.; + over = 0.; + for (int ix = 0; ix < nBin; ++ix) {res[ix] = 0.;} + +} + +//********* + +// Fill bin with weight. + +void Hist::fill(double x, double w) { + + ++nFill; + int iBin = int(floor((x - xMin)/dx)); + if (iBin < 0) {under += w; } + else if (iBin >= nBin) {over += w; } + else {inside += w; res[iBin] += w; } + +} + +//********* + +// Get content of specific bin. +// Special values are bin 0 for underflow and bin nBin+1 for overflow. +// All other bins outside proper histogram range return 0. + +double Hist::getBinContent(int iBin) { + + if (iBin > 0 && iBin <= nBin) return res[iBin - 1]; + else if (iBin == 0) return under; + else if (iBin == nBin + 1) return over; + else return 0.; + +} + +//********* + +// Print histogram contents as a table (e.g. for Gnuplot). + +void Hist::table(ostream& os) const { + + // Print histogram vector bin by bin, with mean x as first column. + os << scientific << setprecision(4); + for (int ix = 0; ix < nBin; ++ix) { + os << setw(12) << xMin + (ix + 0.5) * dx + << setw(12) << res[ix] << "\n"; + + } +} + +//********* + +// Check whether another histogram has same size and limits. + +bool Hist::sameSize(const Hist& h) const { + + if (nBin == h.nBin && abs(xMin - h.xMin) < TOLERANCE * dx && + abs(xMax - h.xMax) < TOLERANCE * dx) {return true;} + else {return false;} + +} + +//********* + +// Take 10-logarithm or natural logarithm of contents bin by bin. + +void Hist::takeLog(bool tenLog) { + + // Find smallest positive bin content, and put min a bit below. + double yMin = 1e20; + for (int ix = 0; ix < nBin; ++ix) + if (res[ix] > 1e-20 && res[ix] < yMin ) yMin = res[ix]; + yMin *= 0.8; + + // Take 10-logarithm bin by bin, but ensure positivity. + if (tenLog) { + for (int ix = 0; ix < nBin; ++ix) res[ix] = log10( max( yMin, res[ix]) ); + under = log10( max( yMin, under) ); + inside = log10( max( yMin, inside) ); + over = log10( max( yMin, over) ); + + // Take natural logarithm bin by bin, but ensure positivity. + } else { + for (int ix = 0; ix < nBin; ++ix) res[ix] = log( max( yMin, res[ix]) ); + under = log( max( yMin, under) ); + inside = log( max( yMin, inside) ); + over = log( max( yMin, over) ); + } + +} + +//********* + +// Add histogram to existing one. + +Hist& Hist::operator+=(const Hist& h) { + if (!sameSize(h)) return *this; + nFill += h.nFill; + under += h.under; + inside += h.inside; + over += h.over; + for (int ix = 0; ix < nBin; ++ix) {res[ix] += h.res[ix];} + return *this; +} + +//********* + +// Subtract histogram from existing one. + +Hist& Hist::operator-=(const Hist& h) { + if (!sameSize(h)) return *this; + nFill += h.nFill; + under -= h.under; + inside -= h.inside; + over -= h.over; + for (int ix = 0; ix < nBin; ++ix) {res[ix] -= h.res[ix];} + return *this; +} + +//********* + +// Multiply existing histogram by another one. + +Hist& Hist::operator*=(const Hist& h) { + if (!sameSize(h)) return *this; + nFill += h.nFill; + under *= h.under; + inside *= h.inside; + over *= h.over; + for (int ix = 0; ix < nBin; ++ix) {res[ix] *= h.res[ix];} + return *this; +} + +//********* + +// Divide existing histogram by another one. + +Hist& Hist::operator/=(const Hist& h) { + if (!sameSize(h)) return *this; + nFill += h.nFill; + under = (abs(h.under) < Hist::TINY) ? 0. : under/h.under; + inside = (abs(h.inside) < Hist::TINY) ? 0. : inside/h.inside; + over = (abs(h.over) < Hist::TINY) ? 0. : over/h.over; + for (int ix = 0; ix < nBin; ++ix) { + res[ix] = (abs(h.res[ix]) < Hist::TINY) ? 0. : res[ix]/h.res[ix]; + } + return *this; +} + +//********* + +// Add constant offset to histogram. + +Hist& Hist::operator+=(double f) { + under += f; + inside += nBin * f; + over -= f; + for (int ix = 0; ix < nBin; ++ix) {res[ix] += f;} + return *this; +} + +//********* + +// Subtract constant offset from histogram. + +Hist& Hist::operator-=(double f) { + under -= f; + inside -= nBin * f; + over -= f; + for (int ix = 0; ix < nBin; ++ix) {res[ix] -= f;} + return *this; +} + +//********* + +// Multiply histogram by constant + +Hist& Hist::operator*=(double f) { + under *= f; + inside *= f; + over *= f; + for (int ix = 0; ix < nBin; ++ix) {res[ix] *= f;} + return *this; +} + +//********* + +// Divide histogram by constant + +Hist& Hist::operator/=(double f) { + under /= f; + inside /= f; + over /= f; + for (int ix = 0; ix < nBin; ++ix) {res[ix] /= f;} + return *this; +} + +//********* + +// Implementation of operator overloading with friends. + +Hist operator+(double f, const Hist& h1) + {Hist h = h1; return h += f;} + +Hist operator+(const Hist& h1, double f) + {Hist h = h1; return h += f;} + +Hist operator+(const Hist& h1, const Hist& h2) + {Hist h = h1; return h += h2;} + +Hist operator-(double f, const Hist& h1) + {Hist h = h1; + h.under = f - h1.under; + h.inside = h1.nBin * f - h1.inside; + h.over = f - h1.over; + for (int ix = 0; ix < h1.nBin; ++ix) {h.res[ix] = f - h1.res[ix];} + return h;} + +Hist operator-(const Hist& h1, double f) + {Hist h = h1; return h -= f;} + +Hist operator-(const Hist& h1, const Hist& h2) + {Hist h = h1; return h -= h2;} + +Hist operator*(double f, const Hist& h1) + {Hist h = h1; return h *= f;} + +Hist operator*(const Hist& h1, double f) + {Hist h = h1; return h *= f;} + +Hist operator*(const Hist& h1, const Hist& h2) + {Hist h = h1; return h *= h2;} + +Hist operator/(double f, const Hist& h1) {Hist h = h1; + h.under = (abs(h1.under) < Hist::TINY) ? 0. : f/h1.under; + h.inside = (abs(h1.inside) < Hist::TINY) ? 0. : f/h1.inside; + h.over = (abs(h1.over) < Hist::TINY) ? 0. : f/h1.over; + for (int ix = 0; ix < h1.nBin; ++ix) { + h.res[ix] = (abs(h1.res[ix]) < Hist::TINY) ? 0. : f/h1.res[ix]; + } + return h; +} + +Hist operator/(const Hist& h1, double f) + {Hist h = h1; return h /= f;} + +Hist operator/(const Hist& h1, const Hist& h2) + {Hist h = h1; return h /= h2;} + +//********* + +// Print a histogram: also operator overloading with friend. + +ostream& operator<<(ostream& os, const Hist& h) { + + // Do not print empty histograms. + if (h.nFill <= 0) return os; + + // Write time and title. + time_t t = time(0); + char date[18]; + strftime(date,18,"%Y-%m-%d %H:%M",localtime(&t)); + os << "\n\n " << date << " " << h.title << "\n\n"; + + // Find minimum and maximum bin content + double yMin = h.res[0]; + double yMax = h.res[0]; + for (int i = 1; i < h.nBin; ++i) { + if (h.res[i] < yMin) yMin = h.res[i]; + if (h.res[i] > yMax) yMax = h.res[i]; + } + + // Determine scale and step size for y axis. + if (yMax - yMin > Hist::NLINES * DYAC[0] * 1e-9) { + if (yMin > 0. && yMin < Hist::SMALLFRAC * yMax) yMin = 0.; + if (yMax < 0. && yMax > Hist::SMALLFRAC * yMin) yMax = 0.; + int iPowY = int(floor( log10(yMax - yMin) )); + if (yMax - yMin < Hist::NLINES * DYAC[0] * pow(10.,iPowY)) + iPowY = iPowY - 1; + if (yMax - yMin > Hist::NLINES * DYAC[9] * pow(10.,iPowY)) + iPowY = iPowY + 1; + double nLinePow = Hist::NLINES * pow(10.,iPowY); + double delY = DYAC[0]; + for (int idel = 0; idel < 9; ++idel) { + if (yMax - yMin >= nLinePow * DYAC[idel]) delY = DYAC[idel+1]; + } + double dy = delY * pow(10.,iPowY); + + // Convert bin contents to integer form; fractional fill in top row. + vector row(h.nBin); + vector frac(h.nBin); + for (int ix = 0; ix < h.nBin ; ++ix) { + double cta = abs(h.res[ix]) / dy; + row[ix] = int(cta + 0.95); + if(h.res[ix] < 0.) row[ix] = - row[ix]; + frac[ix] = int(10. * (cta + 1.05 - floor(cta + 0.95))); + } + int rowMin = int(abs(yMin)/dy + 0.95); + if ( yMin < 0) rowMin = - rowMin; + int rowMax = int(abs(yMax)/dy + 0.95); + if ( yMax < 0) rowMax = - rowMax; + + // Print histogram row by row. + os << fixed << setprecision(2); + for (int iRow = rowMax; iRow >= rowMin; iRow--) { + if (iRow != 0) { + os << " " << setw(10) << iRow*delY << "*10^" + << setw(2) << iPowY << " "; + for (int ix = 0; ix < h.nBin ; ++ix) { + if (iRow == row[ix]) {os << NUMBER[frac[ix]];} + else if (iRow * (row[ix] - iRow) > 0) {os << NUMBER[10];} + else {os << " ";} + } os << "\n"; + } + } os << "\n"; + + // Print sign and value of bin contents + double maxim = log10(max(yMax, -yMin)); + int iPowBin = int(floor(maxim + 0.0001)); + os << " Contents "; + for (int ix = 0; ix < h.nBin ; ++ix) { + if (h.res[ix] < - pow(10., iPowBin-4)) {os << "-";} + else {os << " ";} + row[ix] = int(abs(h.res[ix]) * pow(10.,3-iPowBin) + 0.5); + } os << "\n"; + for (int iRow = 3; iRow >= 0; iRow--) { + os << " *10^" << setw(2) << iPowBin+iRow-3 << " "; + int mask = int( pow(10., iRow) + 0.5); + for (int ix = 0; ix < h.nBin ; ++ix) { + os << NUMBER[(row[ix] / mask) % 10]; + } os << "\n"; + } os << "\n"; + + // Print sign and value of lower bin edge. + maxim = log10(max(-h.xMin, h.xMax - h.dx)); + int iPowExp = int(floor(maxim + 0.0001)); + os << " Low edge "; + for (int ix = 0; ix < h.nBin ; ++ix) { + if (h.xMin + ix * h.dx < - pow(10., iPowExp-3)) {os << "-";} + else {os << " ";} + row[ix] = int(abs(h.xMin + ix * h.dx) * pow(10.,2-iPowExp) + 0.5); + } os << "\n"; + for (int iRow = 2; iRow >= 0; iRow--) { + os << " *10^" << setw(2) << iPowExp+iRow-2 << " "; + int mask = int( pow(10., iRow) + 0.5); + for (int ix = 0; ix < h.nBin ; ++ix) { + os << NUMBER[(row[ix] / mask) % 10]; + } os << "\n"; + } os << "\n"; + } + + // Calculate and print statistics. + double cSum = 0.; + double cxSum = 0.; + double cxxSum = 0.; + for (int ix = 0; ix < h.nBin ; ++ix) { + double cta = abs(h.res[ix]); + double x = h.xMin + (ix + 0.5) * h.dx; + cSum = cSum + cta; + cxSum = cxSum + cta * x; + cxxSum = cxxSum + cta * x * x; + } + double xmean = cxSum / max(cSum, Hist::TINY); + double rms = sqrtpos( cxxSum / max(cSum, Hist::TINY) - xmean*xmean ); + os << scientific << setprecision(4) + << " Entries =" << setw(12) << h.nFill + << " Mean =" << setw(12) << xmean + << " Underflow =" << setw(12) << h.under + << " Low edge =" << setw(12) << h.xMin << "\n" + << " All chan =" << setw(12) << h.inside + << " Rms =" << setw(12) << rms + << " Overflow =" << setw(12) << h.over + << " High edge =" << setw(12) << h.xMax << endl; + return os; +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/BeamParticle.cxx b/PYTHIA8/pythia8130/src/BeamParticle.cxx new file mode 100644 index 00000000000..2c033550fad --- /dev/null +++ b/PYTHIA8/pythia8130/src/BeamParticle.cxx @@ -0,0 +1,862 @@ +// BeamParticle.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// BeamParticle class. + +#include "BeamParticle.h" + +namespace Pythia8 { + +//************************************************************************** + +// The BeamParticle class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// A lepton that takes (almost) the full beam energy does not leave a remnant. +const double BeamParticle::XMINUNRESOLVED = 1. - 1e-10; + +//********* + +// Initialize data on a beam particle and save pointers. + +void BeamParticle::init( int idIn, double pzIn, double eIn, double mIn, + Info* infoPtrIn, PDF* pdfInPtr, PDF* pdfHardInPtr, + bool isUnresolvedIn, StringFlav* flavSelPtrIn) { + + // Store input pointers (and one bool) for future use. + infoPtr = infoPtrIn; + pdfBeamPtr = pdfInPtr; + pdfHardBeamPtr = pdfHardInPtr; + isUnresolvedBeam = isUnresolvedIn; + flavSelPtr = flavSelPtrIn; + + // Maximum quark kind in allowed incoming beam hadrons. + maxValQuark = Settings::mode("BeamRemnants:maxValQuark"); + + // Power of (1-x)^power/sqrt(x) for remnant valence quark distribution. + valencePowerMeson = Settings::parm("BeamRemnants:valencePowerMeson"); + valencePowerUinP = Settings::parm("BeamRemnants:valencePowerUinP"); + valencePowerDinP = Settings::parm("BeamRemnants:valencePowerDinP"); + + // Enhancement factor of x of diquark. + valenceDiqEnhance = Settings::parm("BeamRemnants:valenceDiqEnhance"); + + // Assume g(x) ~ (1-x)^power/x to constrain companion to sea quark. + companionPower = Settings::mode("BeamRemnants:companionPower"); + + // Assume g(x) ~ (1-x)^power/x to constrain companion to sea quark. + companionPower = Settings::mode("BeamRemnants:companionPower"); + + // Allow or not more than one valence quark to be kicked out. + allowJunction = Settings::flag("BeamRemnants:allowJunction"); + + // For diffractive system kick out q/g = norm / mass^power. + pickQuarkNorm = Settings::parm("BeamRemnants:pickQuarkNorm"); + pickQuarkPower = Settings::parm("BeamRemnants:pickQuarkPower"); + + // Width of primordial kT distribution in diffractive systems. + diffPrimKTwidth = Settings::parm("BeamRemnants:diffPrimKTwidth"); + + // Suppress large masses of beam remnant in diffractive systems. + diffLargeMassSuppress = Settings::parm("BeamRemnants:diffLargeMassSuppress"); + + // Store info on the incoming beam. + idBeam = idIn; + initBeamKind(); + pBeam = Vec4( 0., 0., pzIn, eIn); + mBeam = mIn; + +} + +//********* + +// Initialize kind and valence flavour content of incoming beam. +// For recognized hadrons one can generate multiple interactions. +// So far we do not handle diagonal mesons or K0S/K0L (or photons), +// for which flavour content is only known after first interaction. + +void BeamParticle::initBeamKind() { + + // Reset. + idBeamAbs = abs(idBeam); + isLeptonBeam = false; + isHadronBeam = false; + isMesonBeam = false; + isBaryonBeam = false; + nValKinds = 0; + + // Check for leptons. + if (idBeamAbs > 10 && idBeamAbs < 17) { + nValKinds = 1; + nVal[0] = 1; + idVal[0] = idBeam; + isLeptonBeam = true; + } + + // Done if cannot be lowest-lying hadron state. + if (idBeamAbs < 101 || idBeamAbs > 9999) return; + + // Resolve valence content for assumed meson. Flunk unallowed codes. + if (idBeamAbs < 1000) { + int id1 = idBeamAbs/100; + int id2 = (idBeamAbs/10)%10; + if ( id1 < 1 || id1 > maxValQuark + || id2 < 1 || id2 > maxValQuark ) return; + if (id2 == id1 || idBeamAbs == 130 || idBeamAbs == 310) return; + isMesonBeam = true; + + // Store valence content of a confirmed meson. + nValKinds = 2; + nVal[0] = 1 ; + nVal[1] = 1; + if (id1%2 == 0) { + idVal[0] = id1; + idVal[1] = -id2; + } else { + idVal[0] = id2; + idVal[1] = -id1; + } + + // Resolve valence content for assumed baryon. Flunk unallowed codes. + } else { + int id1 = idBeamAbs/1000; + int id2 = (idBeamAbs/100)%10; + int id3 = (idBeamAbs/10)%10; + if ( id1 < 1 || id1 > maxValQuark || id2 < 1 || id2 > maxValQuark + || id3 < 1 || id3 > maxValQuark) return; + if (id2 > id1 || id3 > id1) return; + isBaryonBeam = true; + + // Store valence content of a confirmed baryon. + nValKinds = 1; idVal[0] = id1; nVal[0] = 1; + if (id2 == id1) ++nVal[0]; + else { + nValKinds = 2; + idVal[1] = id2; + nVal[1] = 1; + } + if (id3 == id1) ++nVal[0]; + else if (id3 == id2) ++nVal[1]; + else { + idVal[nValKinds] = id3; + nVal[nValKinds] = 1; + ++nValKinds; + } + } + + // Flip flavours for antimeson or antibaryon, and then done. + if (idBeam < 0) for (int i = 0; i < nValKinds; ++i) idVal[i] = -idVal[i]; + isHadronBeam = true; + Q2ValFracSav = -1.; + +} + +//********* + +double BeamParticle::xMax(int iSkip) { + + // Minimum requirement on remaining energy > nominal mass for hadron. + double xLeft = 1.; + if (isHadron()) xLeft -= m() / e(); + if (size() == 0) return xLeft; + + // Subtract what was carried away by initiators (to date). + for (int i = 0; i < size(); ++i) + if (i != iSkip) xLeft -= resolved[i].x(); + return xLeft; + +} + +//********* + +// Parton distributions, reshaped to take into account previous +// multiple interactions. By picking a non-negative iSkip value, +// one particular interaction is skipped, as needed for ISR + +double BeamParticle::xfModified(int iSkip, int idIn, double x, double Q2) { + + // Initial values. + idSave = idIn; + iSkipSave = iSkip; + xqVal = 0.; + xqgSea = 0.; + xqCompSum = 0.; + + // Fast procedure for first interaction. + if (size() == 0) { + if (x >= 1.) return 0.; + bool canBeVal = false; + for (int i = 0; i < nValKinds; ++i) + if (idIn == idVal[i]) canBeVal = true; + if (canBeVal) { + xqVal = xfVal( idIn, x, Q2); + xqgSea = xfSea( idIn, x, Q2); + } + else xqgSea = xf( idIn, x, Q2); + + // More complicated procedure for non-first interaction. + } else { + + // Sum up the x already removed, and check that remaining x is enough. + double xUsed = 0.; + for (int i = 0; i < size(); ++i) + if (i != iSkip) xUsed += resolved[i].x(); + double xLeft = 1. - xUsed; + if (x >= xLeft) return 0.; + double xRescaled = x / xLeft; + + // Calculate total and remaining amount of x carried by valence quarks. + double xValTot = 0.; + double xValLeft = 0.; + for (int i = 0; i < nValKinds; ++i) { + nValLeft[i] = nVal[i]; + for (int j = 0; j < size(); ++j) + if (j != iSkip && resolved[j].isValence() + && resolved[j].id() == idVal[i]) --nValLeft[i]; + double xValNow = xValFrac(i, Q2); + xValTot += nVal[i] * xValNow; + xValLeft += nValLeft[i] * xValNow; + } + + // Calculate total amount of x carried by unmatched companion quarks. + double xCompAdded = 0.; + for (int i = 0; i < size(); ++i) + if (i != iSkip && resolved[i].isUnmatched()) xCompAdded + += xCompFrac( resolved[i].x() / (xLeft + resolved[i].x()) ) + // Typo warning: extrafactor missing in Skands&Sjostrand article; + // for companion refers to fraction of x left INCLUDING sea quark. + // To be modified further?? + * (1. + resolved[i].x() / xLeft); + + // Calculate total rescaling factor and pdf for sea and gluon. + double rescaleGS = max( 0., (1. - xValLeft - xCompAdded) + / (1. - xValTot) ); + xqgSea = rescaleGS * xfSea( idIn, xRescaled, Q2); + + // Find valence part and rescale it to remaining number of quarks. + for (int i = 0; i < nValKinds; ++i) + if (idIn == idVal[i] && nValLeft[i] > 0) + xqVal = xfVal( idIn, xRescaled, Q2) + * double(nValLeft[i]) / double(nVal[i]); + + // Find companion part, by adding all companion contributions. + for (int i = 0; i < size(); ++i) + if (i != iSkip && resolved[i].id() == -idIn + && resolved[i].isUnmatched()) { + double xsRescaled = resolved[i].x() / (xLeft + resolved[i].x()); + double xcRescaled = x / (xLeft + resolved[i].x()); + double xqCompNow = xCompDist( xcRescaled, xsRescaled); + resolved[i].xqCompanion( xqCompNow); + xqCompSum += xqCompNow; + } + } + + // Add total, but only return relevant part for ISR. More cases?? + // Watch out, e.g. g can come from either kind of quark.?? + xqgTot = xqVal + xqgSea + xqCompSum; + if (iSkip >= 0) { + if (resolved[iSkip].isValence()) return xqVal; + if (resolved[iSkip].isUnmatched()) return xqgSea + xqCompSum; + } + return xqgTot; + +} + +//********* + +// Decide whether a quark extracted from the beam is of valence, sea or +// companion kind; in the latter case also pick its companion. +// Assumes xfModified has already been called. + + int BeamParticle::pickValSeaComp() { + + // If parton already has a companion than reset code for this. + int oldCompanion = resolved[iSkipSave].companion(); + if (oldCompanion >= 0) resolved[oldCompanion].companion(-2); + + // Default assignment is sea. + int vsc = -2; + + // For gluons or photons no sense of valence or sea. + if (idSave == 21 || idSave == 22) vsc = -1; + + // For lepton beam assume same-kind lepton inside is valence. + else if (isLeptonBeam && idSave == idBeam) vsc = -3; + + // Decide if valence or sea quark. + else { + double xqRndm = xqgTot * Rndm::flat(); + if (xqRndm < xqVal) vsc = -3; + else if (xqRndm < xqVal + xqgSea) vsc = -2; + + // If not either, loop over all possible companion quarks. + else { + xqRndm -= xqVal + xqgSea; + for (int i = 0; i < size(); ++i) + if (i != iSkipSave && resolved[i].id() == -idSave + && resolved[i].isUnmatched()) { + xqRndm -= resolved[i].xqCompanion(); + if (xqRndm < 0.) vsc = i; + break; + } + } + } + + // Bookkeep assignment; for sea--companion pair both ways. + resolved[iSkipSave].companion(vsc); + if (vsc >= 0) resolved[vsc].companion(iSkipSave); + + // Done; return code for choice (to distinguish valence/sea in Info). + return vsc; + +} + +//********* + +// Fraction of hadron momentum sitting in a valence quark distribution. +// Based on hardcoded parametrizations of CTEQ 5L numbers. + +double BeamParticle::xValFrac(int j, double Q2) { + + // Only recalculate when required. + if (Q2 != Q2ValFracSav) { + Q2ValFracSav = Q2; + + // Q2-dependence of log-log form; assume fixed Lambda = 0.2. + double llQ2 = log( log( max( 1., Q2) / 0.04 )); + + // Fractions carried by u and d in proton. + uValInt = 0.48 / (1. + 1.56 * llQ2); + dValInt = 0.385 / (1. + 1.60 * llQ2); + } + + // Baryon with three different quark kinds: (2 * u + d) / 3 of proton. + if (isBaryonBeam && nValKinds == 3) return (2. * uValInt + dValInt) / 3.; + + // Baryon with one or two identical: like d or u of proton. + if (isBaryonBeam && nVal[j] == 1) return dValInt; + if (isBaryonBeam && nVal[j] == 2) return uValInt; + + // Meson: (2 * u + d) / 2 of proton so same total valence quark fraction. + return 0.5 * (2. * uValInt + dValInt); + +} + +//********* + +// The momentum integral of a companion quark, with its partner at x_s, +// using an approximate gluon density like (1 - x_g)^power / x_g. +// The value corresponds to an unrescaled range between 0 and 1 - x_s. + +double BeamParticle::xCompFrac(double xs) { + + // Select case by power of gluon (1-x_g) shape. + switch (companionPower) { + + case 0: + return xs * ( 5. + xs * (-9. - 2. * xs * (-3. + xs)) + 3. * log(xs) ) + / ( (-1. + xs) * (2. + xs * (-1. + 2. * xs)) ); + + case 1: + return -1. -3. * xs + ( 2. * pow2(-1. + xs) * (1. + xs + xs*xs)) + / ( 2. + xs*xs * (xs - 3.) + 3. * xs * log(xs) ); + + case 2: + return xs * ( (1. - xs) * (19. + xs * (43. + 4. * xs)) + + 6. * log(xs) * (1. + 6. * xs + 4.*xs*xs) ) / + ( 4. * ( (xs - 1.) * (1. + xs * (4. + xs) ) + - 3. * xs * log(xs) * (1 + xs) ) ); + + case 3: + return 3. * xs * ( (xs - 1.) * (7. + xs * (28. + 13. * xs)) + - 2. * log(xs) * (1. + xs * (9. + 2. * xs * (6. + xs))) ) + / ( 4. + 27. * xs - 31. * pow3(xs) + + 6. * xs * log(xs) * (3. + 2. * xs * (3.+xs)) ); + + default: + return ( -9. * xs * (xs*xs - 1.) * (5. + xs * (24. + xs)) + 12. * xs + * log(xs) * (1. + 2. * xs) * (1. + 2. * xs * (5. + 2. * xs)) ) + / ( 8. * (1. + 2. * xs) * ((xs - 1.) * (1. + xs * (10. + xs)) + - 6. * xs * log(xs) * (1. + xs)) ); + + } +} + +//********* + +// The x*f pdf of a companion quark at x_c, with its sea partner at x_s, +// using an approximate gluon density like (1 - x_g)^power / x_g. +// The value corresponds to an unrescaled range between 0 and 1 - x_s. + +double BeamParticle::xCompDist(double xc, double xs) { + + // Mother gluon momentum fraction. Check physical limit. + double xg = xc + xs; + if (xg > 1.) return 0.; + + // Common factor, including splitting kernel and part of gluon density + // (and that it is x_c * f that is coded). + double fac = 3. * xc * xs * (xc*xc + xs*xs) / pow4(xg); + + // Select case by power of gluon (1-x_g) shape. + switch (companionPower) { + + case 0: + return fac / ( 2. - xs * (3. - xs * (3. - 2. * xs)) ); + + case 1: + return fac * (1. - xg) / ( 2. + xs*xs * (-3. + xs) + 3. * xs * log(xs) ); + + case 2: + return fac * pow2(1. - xg) / ( 2. * ((1. - xs) * (1. + xs * (4. + xs)) + + 3. * xs * (1. + xs) * log(xs)) ); + + case 3: + return fac * pow3(1. - xg) * 2. / ( 4. + 27. * xs - 31. * pow3(xs) + + 6. * xs * log(xs) * (3. + 2. * xs * (3. + xs)) ); + + default: + return fac * pow4(1. - xg) / ( 2. * (1. + 2. * xs) * ((1. - xs) + * (1. + xs * (10. + xs)) + 6. * xs * log(xs) * (1. + xs)) ); + + } +} + +//********* + +// Add required extra remnant flavour content. Also initial colours. + +bool BeamParticle::remnantFlavours(Event& event) { + + // A baryon will have a junction, unless a diquark is formed later. + hasJunctionBeam = (isBaryon()); + + // Store how many hard-scattering partons were removed from beam. + nInit = size(); + + // Find remaining valence quarks. + for (int i = 0; i < nValKinds; ++i) { + nValLeft[i] = nVal[i]; + for (int j = 0; j < nInit; ++j) if (resolved[j].isValence() + && resolved[j].id() == idVal[i]) --nValLeft[i]; + // Add remaining valence quarks to record. Partly temporary values. + for (int k = 0; k < nValLeft[i]; ++k) append(0, idVal[i], 0., -3); + } + + // If at least two valence quarks left in baryon remnant then form diquark. + int nInitPlusVal = size(); + if (isBaryon() && nInitPlusVal - nInit >= 2) { + + // If three, pick two at random to form diquark, else trivial. + int iQ1 = nInit; + int iQ2 = nInit + 1; + if (nInitPlusVal - nInit == 3) { + double pickDq = 3. * Rndm::flat(); + if (pickDq > 1.) iQ2 = nInit + 2; + if (pickDq > 2.) iQ1 = nInit + 1; + } + + // Pick spin 0 or 1 according to SU(6) wave function factors. + int idDq = flavSelPtr->makeDiquark( resolved[iQ1].id(), + resolved[iQ2].id(), idBeam); + + // Overwrite with diquark flavour and remove one slot. No more junction. + resolved[iQ1].id(idDq); + if (nInitPlusVal - nInit == 3 && iQ2 == nInit + 1) + resolved[nInit + 1].id( resolved[nInit + 2].id() ); + resolved.pop_back(); + hasJunctionBeam = false; + } + + // Find companion quarks to unmatched sea quarks. + for (int i = 0; i < nInit; ++i) + if (resolved[i].isUnmatched()) { + + // Add companion quark to record; and bookkeep both ways. + append(0, -resolved[i].id(), 0., i); + resolved[i].companion(size() - 1); + } + + // If no other remnants found, add a gluon or photon to carry momentum. + if (size() == nInit) { + int idRemnant = (isHadronBeam) ? 21 : 22; + append(0, idRemnant, 1., -1); + } + + // Set initiator and remnant masses. + for (int i = 0; i < size(); ++i) { + if (i < nInit) resolved[i].m(0.); + else resolved[i].m( ParticleDataTable::m0( resolved[i].id() ) ); + } + + // For debug purposes: reject beams with resolved junction topology. + if (hasJunctionBeam && !allowJunction) return false; + + // Pick initial colours for remnants. + for (int i = nInit; i < size(); ++i) { + int colType = ParticleDataTable::colType( resolved[i].id() ); + int col = (colType == 1 || colType == 2) ? event.nextColTag() : 0; + int acol = (colType == -1 || colType == 2) ? event.nextColTag() : 0; + resolved[i].cols( col, acol); + } + + // Done. + return true; + +} + +//********* + +// Correlate all initiators and remnants to make a colour singlet. + +bool BeamParticle::remnantColours(Event& event, vector& colFrom, + vector& colTo) { + + // No colours in lepton beams so no need to do anything. + if (isLeptonBeam) return true; + + // Copy initiator colour info from the event record to the beam. + for (int i = 0; i < size(); ++i) { + int j = resolved[i].iPos(); + resolved[i].cols( event[j].col(), event[j].acol()); + } + + // Find number and position of valence quarks, of gluons, and + // of sea-companion pairs (counted as gluons) in the beam remnants. + // Skip gluons with same colour as anticolour. + vector iVal; + vector iGlu; + for (int i = 0; i < size(); ++i) { + if ( resolved[i].isValence() ) iVal.push_back(i); + else if ( resolved[i].isCompanion() && resolved[i].companion() > i ) + iGlu.push_back(i); + else if ( resolved[i].id() == 21 + && resolved[i].col() != resolved[i].acol() ) iGlu.push_back(i); + } + + // Pick a valence quark to which gluons are attached. + // Do not resolve quarks in diquark. (More sophisticated??) + int iValSel= iVal[0]; + if (iVal.size() == 2) { + if ( abs(resolved[iValSel].id()) > 10 ) iValSel = iVal[1]; + } else { + double rndmValSel = 3. * Rndm::flat(); + if (rndmValSel > 1.) iValSel= iVal[1]; + if (rndmValSel > 2.) iValSel= iVal[2]; + } + + // This valence quark defines initial (anti)colour. + int iBeg = iValSel; + bool hasCol = (resolved[iBeg].col() > 0); + int begCol = (hasCol) ? resolved[iBeg].col() : resolved[iBeg].acol(); + + // Do random stepping through gluon/(sea+companion) list. + vector iGluRndm; + for (int i = 0; i < int(iGlu.size()); ++i) + iGluRndm.push_back( iGlu[i] ); + for (int iOrder = 0; iOrder < int(iGlu.size()); ++iOrder) { + int iRndm = int( double(iGluRndm.size()) * Rndm::flat()); + int iGluSel = iGluRndm[iRndm]; + iGluRndm[iRndm] = iGluRndm[iGluRndm.size() - 1]; + iGluRndm.pop_back(); + + // Find matching anticolour/colour to current colour/anticolour. + int iEnd = iGluSel; + int endCol = (hasCol) ? resolved[iEnd].acol() : resolved[iEnd].col(); + // Not gluon but sea+companion pair: go to other. + if (endCol == 0) { + iEnd = resolved[iEnd].companion(); + endCol = (hasCol) ? resolved[iEnd].acol() : resolved[iEnd].col(); + } + + // Collapse this colour-anticolour pair to the lowest one. + if (begCol < endCol) { + if (hasCol) resolved[iEnd].acol(begCol); + else resolved[iEnd].col(begCol); + colFrom.push_back(endCol); + colTo.push_back(begCol); + } else { + if (hasCol) resolved[iBeg].col(endCol); + else resolved[iBeg].acol(endCol); + colFrom.push_back(begCol); + colTo.push_back(endCol); + } + + // Pick up the other colour of the recent gluon and repeat. + iBeg = iEnd; + begCol = (hasCol) ? resolved[iBeg].col() : resolved[iBeg].acol(); + // Not gluon but sea+companion pair: go to other. + if (begCol == 0) { + iBeg = resolved[iBeg].companion(); + begCol = (hasCol) ? resolved[iBeg].col() : resolved[iBeg].acol(); + } + + // At end of gluon/(sea+companion) list. + } + + // Now begin checks, and also finding junction information. + // Loop through remnant partons; isolate all colours and anticolours. + vector colList; + vector acolList; + for (int i = 0; i < size(); ++i) + if ( resolved[i].col() != resolved[i].acol() ) { + if (resolved[i].col() > 0) colList.push_back( resolved[i].col() ); + if (resolved[i].acol() > 0) acolList.push_back( resolved[i].acol() ); + } + + // Remove all matching colour-anticolour pairs. + bool foundPair = true; + while (foundPair && colList.size() > 0 && acolList.size() > 0) { + foundPair = false; + for (int iCol = 0; iCol < int(colList.size()); ++iCol) { + for (int iAcol = 0; iAcol < int(acolList.size()); ++iAcol) { + if (acolList[iAcol] == colList[iCol]) { + colList[iCol] = colList.back(); colList.pop_back(); + acolList[iAcol] = acolList.back(); acolList.pop_back(); + foundPair = true; break; + } + } if (foundPair) break; + } + } + + // Usually one unmatched pair left to collapse. + if (colList.size() == 1 && acolList.size() == 1) { + int finalFrom = max( colList[0], acolList[0]); + int finalTo = min( colList[0], acolList[0]); + for (int i = 0; i < size(); ++i) { + if (resolved[i].col() == finalFrom) resolved[i].col(finalTo); + if (resolved[i].acol() == finalFrom) resolved[i].acol(finalTo); + } + colFrom.push_back(finalFrom); + colTo.push_back(finalTo); + + // Store an (anti)junction when three (anti)coloured daughters. + } else if (hasJunctionBeam && colList.size() == 3 + && acolList.size() == 0) { + event.appendJunction( 1, colList[0], colList[1], colList[2]); + junCol[0] = colList[0]; + junCol[1] = colList[1]; + junCol[2] = colList[2]; + } else if (hasJunctionBeam && acolList.size() == 3 + && colList.size() == 0) { + event.appendJunction( 2, acolList[0], acolList[1], acolList[2]); + junCol[0] = acolList[0]; + junCol[1] = acolList[1]; + junCol[2] = acolList[2]; + + // Any other nonvanishing values indicate failure. + } else if (colList.size() > 0 || acolList.size() > 0) { + infoPtr->errorMsg("Error in BeamParticle::remnantColours: " + "leftover unmatched colours"); + return false; + } + + // Store colour assignment of beam particles. + for (int i = nInit; i < size(); ++i) + event[resolved[i].iPos()].cols( resolved[i].col(), resolved[i].acol() ); + + // Done. + return true; +} + + +//********* + +// Pick unrescaled x values for beam remnant sharing. + +double BeamParticle::xRemnant( int i) { + + double x = 0.; + + // Calculation of x of valence quark or diquark, for latter as sum. + if (resolved[i].isValence()) { + + // Resolve diquark into sum of two quarks. + int id1 = resolved[i].id(); + int id2 = 0; + if (abs(id1) > 10) { + id2 = (id1 > 0) ? (id1/100)%10 : -(((-id1)/100)%10); + id1 = (id1 > 0) ? id1/1000 : -((-id1)/1000); + } + + // Loop over (up to) two quarks; add their contributions. + for (int iId = 0; iId < 2; ++iId) { + int idNow = (iId == 0) ? id1 : id2; + if (idNow == 0) break; + double xPart = 0.; + + // Assume form (1-x)^a / sqrt(x). + double xPow = valencePowerMeson; + if (isBaryonBeam) { + if (nValKinds == 3 || nValKinds == 1) + xPow = (3. * Rndm::flat() < 2.) + ? valencePowerUinP : valencePowerDinP ; + else if (nValence(idNow) == 2) xPow = valencePowerUinP; + else xPow = valencePowerDinP; + } + do xPart = pow2( Rndm::flat() ); + while ( pow(1. - xPart, xPow) < Rndm::flat() ); + + // End loop over (up to) two quarks. Possibly enhancement for diquarks. + x += xPart; + } + if (id2 != 0) x *= valenceDiqEnhance; + + // Calculation of x of sea quark, based on companion association. + } else if (resolved[i].isCompanion()) { + + // Find rescaled x value of companion. + double xLeft = 1.; + for (int iInit = 0; iInit < nInit; ++iInit) + xLeft -= resolved[iInit].x(); + double xCompanion = resolved[ resolved[i].companion() ].x(); + xCompanion /= (xLeft + xCompanion); + + // Now use ansatz q(x; x_c) < N/(x +x_c) to pick x. + do x = pow( xCompanion, Rndm::flat()) - xCompanion; + while ( pow( (1. - x - xCompanion) / (1. - xCompanion), companionPower) + * (pow2(x) + pow2(xCompanion)) / pow2(x + xCompanion) < Rndm::flat() ); + + // Else, rarely, a single gluon remnant, so value does not matter. + } else x = 1.; + return x; + +} + +//********* + +// Print the list of resolved partons in a beam. + +void BeamParticle::list(ostream& os) { + + // Header. + os << "\n -------- PYTHIA Partons resolved in beam ------------" + << "--------------------------------------------------------\n" + << "\n i iPos id x comp xqcomp colours" + << " p_x p_y p_z e m \n"; + + // Loop over list of removed partons and print it. + double xSum = 0.; + Vec4 pSum; + for (int i = 0; i < size(); ++i) { + ResolvedParton res = resolved[i]; + os << fixed << setprecision(6) << setw(5) << i << setw(6) << res.iPos() + << setw(8) << res.id() << setw(10) << res.x() << setw(6) + << res.companion() << setw(10) << res.xqCompanion() + << setprecision(3) << setw(6) << res.col() << setw(6) << res.acol() + << setw(11) << res.px() << setw(11) << res.py() << setw(11) + << res.pz() << setw(11) << res.e() << setw(11) << res.m() << "\n"; + + // Also find and print sum of x and p values. Endline. + xSum += res.x(); + pSum += res.p(); + } + os << setprecision(6) << " x sum:" << setw(10) << xSum + << setprecision(3) << " p sum:" << setw(11) + << pSum.px() << setw(11) << pSum.py() << setw(11) << pSum.pz() + << setw(11) << pSum.e() + << "\n\n -------- End PYTHIA Partons resolved in beam ------" + << "----------------------------------------------------------" + << endl; +} + +//********* + +// Test whether a lepton is to be considered as unresolved. + +bool BeamParticle::isUnresolvedLepton() { + + // Require record to consist of lepton with full energy plus a photon. + if (!isLeptonBeam || resolved.size() > 2 || resolved[1].id() != 22 + || resolved[0].x() < XMINUNRESOLVED) return false; + return true; + +} + +//********* + +// For a diffractive system, decide whether to kick out gluon or quark. + +bool BeamParticle::pickGluon(double mDiff) { + + // Relative weight to pick a quark, assumed falling with energy. + double probPickQuark = pickQuarkNorm / pow( mDiff, pickQuarkPower); + return ( (1. + probPickQuark) * Rndm::flat() < 1. ); + +} + +//********* + +// Pick a valence quark at random. (Used for diffractive systems.) + +int BeamParticle::pickValence() { + + // Pick one valence quark at random. + int nTotVal = (isBaryonBeam) ? 3 : 2; + double rnVal = Rndm::flat() * nTotVal; + int iVal = (rnVal < 1.) ? 1 : ( (rnVal < 2.) ? 2 : 3 ); + + // This valence in slot 1, the rest thereafter. + idVal1 = 0; + idVal2 = 0; + idVal3 = 0; + int iNow = 0; + for (int i = 0; i < nValKinds; ++i) + for (int j = 0; j < nVal[i]; ++j) { + ++iNow; + if (iNow == iVal) idVal1 = idVal[i]; + else if ( idVal2 == 0) idVal2 = idVal[i]; + else idVal3 = idVal[i]; + } + + // Construct diquark if baryon. + if (idVal3 != 0) idVal2 = flavSelPtr->makeDiquark( idVal2, idVal3); + + // Done. + return idVal1; + +} + +//********* + +// Share lightcone momentum between two remnants in a diffractive system. + +double BeamParticle::zShare( double mDiff, double m1, double m2) { + + // Set up as valence in normal beam so can use xRemnant code. + append(0, idVal1, 0., -3); + append(0, idVal2, 0., -3); + double m2Diff = mDiff*mDiff; + + // Begin to generate z and pT until acceptable solution. + double wtAcc = 0.; + do { + double x1 = xRemnant(0); + double x2 = xRemnant(0); + zRel = x1 / (x1 + x2); + pxRel = diffPrimKTwidth * Rndm::gauss(); + pyRel = diffPrimKTwidth * Rndm::gauss(); + + // Suppress large invariant masses of remnant system. + double mTS1 = m1*m1 + pxRel*pxRel + pyRel*pyRel; + double mTS2 = m2*m2 + pxRel*pxRel + pyRel*pyRel; + double m2Sys = mTS1 / zRel + mTS2 / (1. - zRel); + wtAcc = (m2Sys < m2Diff) + ? pow( 1. - m2Sys / m2Diff, diffLargeMassSuppress) : 0.; + } while (wtAcc < Rndm::flat()); + + // Done. + return zRel; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/BeamRemnants.cxx b/PYTHIA8/pythia8130/src/BeamRemnants.cxx new file mode 100644 index 00000000000..de42357b82a --- /dev/null +++ b/PYTHIA8/pythia8130/src/BeamRemnants.cxx @@ -0,0 +1,809 @@ +// BeamRemnants.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// BeamRemnants class. + +#include "BeamRemnants.h" + +namespace Pythia8 { + +//************************************************************************** + +// The BeamDipole class is purely internal to reconnectColours. + +class BeamDipole { + +public: + + // Constructor. + BeamDipole( int colIn = 0, int iColIn = 0, int iAcolIn = 0) + : col(colIn), iCol(iColIn), iAcol(iAcolIn) {} + + // Members. + int col, iCol, iAcol; + double p1p2; + +}; + +//************************************************************************** + +// The BeamRemnants class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Maximum number of tries to match colours and kinematics in the event. +const int BeamRemnants::NTRYCOLMATCH = 10; +const int BeamRemnants::NTRYKINMATCH = 10; + +//********* + +// Initialization. + +bool BeamRemnants::init( Info* infoPtrIn, BeamParticle* beamAPtrIn, + BeamParticle* beamBPtrIn) { + + // Save pointers. + infoPtr = infoPtrIn; + beamAPtr = beamAPtrIn; + beamBPtr = beamBPtrIn; + + // Width of primordial kT distribution. + doPrimordialKT = Settings::flag("BeamRemnants:primordialKT"); + primordialKTsoft = Settings::parm("BeamRemnants:primordialKTsoft"); + primordialKThard = Settings::parm("BeamRemnants:primordialKThard"); + primordialKTremnant = Settings::parm("BeamRemnants:primordialKTremnant"); + halfScaleForKT = Settings::parm("BeamRemnants:halfScaleForKT"); + halfMassForKT = Settings::parm("BeamRemnants:halfMassForKT"); + + // Parameters for colour reconnection scenario, partly borrowed from + // multiple interactions not to introduce too many new ones. + doReconnect = Settings::flag("BeamRemnants:reconnectColours"); + reconnectRange = Settings::parm("BeamRemnants:reconnectRange"); + pT0Ref = Settings::parm("MultipleInteractions:pT0Ref"); + ecmRef = Settings::parm("MultipleInteractions:ecmRef"); + ecmPow = Settings::parm("MultipleInteractions:ecmPow"); + + // Total and squared CM energy at nominal energy. + eCM = infoPtr->eCM(); + sCM = eCM * eCM; + + // The MI pT0 smoothening scale and its reconnection-strength combination. + pT0 = pT0Ref * pow(eCM / ecmRef, ecmPow); + pT20Rec = pow2(reconnectRange * pT0); + + // Done. + return true; + +} + +//********* + +// Select the flavours/kinematics/colours of the two beam remnants. +// Notation: iPar = all partons, iSys = matched systems of two beams, +// iRem = additional partons in remnants. + +bool BeamRemnants::add( Event& event) { + + // Update to current CM energy. + eCM = infoPtr->eCM(); + sCM = eCM * eCM; + + // Number of scattering subsystems. Size of event record before treatment. + nSys = event.sizeSystems(); + oldSize = event.size(); + + // Add required extra remnant flavour content. + // Start all over if fails (in option where junctions not allowed). + if ( !beamAPtr->remnantFlavours(event) + || !beamBPtr->remnantFlavours(event) ) { + infoPtr->errorMsg("Error in BeamRemnants::add:" + " remnant flavour setup failed"); + return false; + } + + // Do the kinematics of the collision subsystems and two beam remnants + if (!setKinematics(event)) return false; + + // Allow colour reconnections. + if (doReconnect) reconnectColours(event); + + // Save current modifiable colour configuration for fast restoration. + vector colSave; + vector acolSave; + for (int i = oldSize; i < event.size(); ++i) { + colSave.push_back( event[i].col() ); + acolSave.push_back( event[i].acol() ); + } + event.saveJunctionSize(); + + // Allow several tries to match colours of initiators and remnants. + // Frequent "failures" since shortcutting colours separately on + // the two event sides may give "colour singlet gluons" etc. + bool physical = true; + for (int iTry = 0; iTry < NTRYCOLMATCH; ++iTry) { + physical = true; + + // Reset list of colour "collapses" (transformations). + colFrom.resize(0); + colTo.resize(0); + + // First process each set of beam colours on its own. + if (!beamAPtr->remnantColours(event, colFrom, colTo)) + physical = false; + if (!beamBPtr->remnantColours(event, colFrom, colTo)) + physical = false; + + // Then check that colours and anticolours are matched in whole event. + if ( physical && !checkColours(event) ) physical = false; + + // If no problems then done, else restore and loop. + if (physical) break; + for (int i = oldSize; i < event.size(); ++i) + event[i].cols( colSave[i - oldSize], acolSave[i - oldSize] ); + event.restoreJunctionSize(); + } + + // If no solution after several tries then failed. + if (!physical) { + infoPtr->errorMsg("Error in BeamRemnants::add:" + " colour tracing failed"); + return false; + } + + // Done. + return true; + +} + +//********* + +// Set up trial transverse and longitudinal kinematics for each beam +// separately. Final decisions involve comparing the two beams. + +bool BeamRemnants::setKinematics( Event& event) { + + // References to beams to simplify indexing. + BeamParticle& beamA = *beamAPtr; + BeamParticle& beamB = *beamBPtr; + + // Nothing to do for lepton-lepton scattering with all energy already used. + if ( beamA.isUnresolvedLepton() && beamB.isUnresolvedLepton() ) + return true; + + // Allow primordial kT reduction for small-mass and small-pT systems + // (for hardest interaction pT -> renormalization scale so also 2 -> 1). + vector kTwidth; + vector kTcomp; + double kTcompSumSys = 0.; + for (int iSys = 0; iSys < nSys; ++iSys) { + double kTwidthNow = 0.; + double mHatDamp = 1.; + if (doPrimordialKT) { + double mHat = sqrtpos( beamA[iSys].x() * beamB[iSys].x() * sCM ); + mHatDamp = mHat / (mHat + halfMassForKT); + double scale = (iSys == 0) ? infoPtr->QRen() : infoPtr->pTMI(iSys); + kTwidthNow = ( (halfScaleForKT * primordialKTsoft + + scale * primordialKThard) / (halfScaleForKT + scale) ) * mHatDamp; + } + kTwidth.push_back( kTwidthNow ); + kTcomp.push_back( mHatDamp ); + kTcompSumSys += mHatDamp; + } + double kTwidthNow = (doPrimordialKT) ? primordialKTremnant : 0.; + for (int iRem = nSys; iRem < max( beamA.size(), beamB.size() ); ++iRem) { + kTwidth.push_back( kTwidthNow ); + kTcomp.push_back( 1. ); + } + + // Allow ten tries to construct kinematics (but normally works first). + bool physical; + double xSum[2], xInvM[2], w2Beam[2], wPosRem, wNegRem, w2Rem; + for (int iTry = 0; iTry < NTRYKINMATCH; ++iTry) { + physical = true; + + // Loop over the two beams. Sum px and py separately within each. + for (int iBeam = 0; iBeam < 2; ++iBeam) { + BeamParticle& beam = (iBeam == 0) ? beamA : beamB; + int nPar = beam.size(); + double pxSum = 0.; + double pySum = 0.; + + // Loop over the partons in a beam. Generate Gaussian pT for hadrons. + for (int iPar = 0; iPar < nPar; ++iPar) { + double px = 0.; + double py = 0.; + if (beam.isHadron() && doPrimordialKT) { + px = kTwidth[iPar] * Rndm::gauss(); + py = kTwidth[iPar] * Rndm::gauss(); + } + beam[iPar].px(px); + beam[iPar].py(py); + pxSum += px; + pySum += py; + } + + // Share recoil between all partons. + if (doPrimordialKT) { + double kTcompSum = kTcompSumSys + (nPar - nSys); + for (int iPar = 0; iPar < nPar; ++iPar) { + beam[iPar].px( beam[iPar].px() - pxSum * kTcomp[iPar] / kTcompSum ); + beam[iPar].py( beam[iPar].py() - pySum * kTcomp[iPar] / kTcompSum ); + } + } + + // Pick unrescaled x values for remnants. Sum up (unscaled) p+ and p-. + xSum[iBeam] = 0.; + xInvM[iBeam] = 0.; + for (int iRem = nSys; iRem < nPar; ++iRem) { + double xPrel = beam.xRemnant( iRem); + beam[iRem].x(xPrel); + xSum[iBeam] += xPrel; + xInvM[iBeam] += beam[iRem].mT2()/xPrel; + } + + // Squared transverse mass for each beam, using lightcone x. + w2Beam[iBeam] = xSum[iBeam] * xInvM[iBeam]; + + // End separate treatment of the two beams. + } + + // Recalculate kinematics of initiator systems with primordial kT. + wPosRem = eCM; + wNegRem = eCM; + for (int iSys = 0; iSys < nSys; ++iSys) { + double sHat = beamA[iSys].x() * beamB[iSys].x() * sCM; + double sHatT = sHat + + pow2( beamA[iSys].px() + beamB[iSys].px()) + + pow2( beamA[iSys].py() + beamB[iSys].py()); + double rescale = sqrt( sHatT / sHat); + wPosRem -= rescale * beamA[iSys].x() * eCM; + wNegRem -= rescale * beamB[iSys].x() * eCM; + + // Kinematics forbids too large primordial kT. + if (sqrt(sHatT) < beamA[iSys].pT() + beamB[iSys].pT()) + physical = false; + } + + // Check that remaining momentum is enough for remnants. + if (wPosRem < 0. || wNegRem < 0.) physical = false; + w2Rem = wPosRem * wNegRem; + if (sqrtpos(w2Rem) < sqrt(w2Beam[0]) + sqrt(w2Beam[1])) + physical = false; + + // End of loop over ten tries. Do not loop when solution found. + if (physical) break; + } + + // If no solution after ten tries then failed. + if (!physical) { + infoPtr->errorMsg("Error in BeamRemnants::add:" + " kinematics construction failed"); + return false; + } + + // Construct energy and pz for each initiator pair. + for (int iSys = 0; iSys < nSys; ++iSys) { + double sHat = beamA[iSys].x() * beamB[iSys].x() * sCM; + double sHatT = sHat + pow2( beamA[iSys].px() + beamB[iSys].px()) + + pow2( beamA[iSys].py() + beamB[iSys].py()); + double rescale = sqrt( sHatT / sHat); + double wPos = rescale * beamA[iSys].x() * eCM; + double wNeg = rescale * beamB[iSys].x() * eCM; + double w2A = beamA[iSys].mT2(); + double w2B = beamB[iSys].mT2(); + double lambdaRoot = sqrtpos( pow2( sHatT - w2A - w2B) - 4. * w2A * w2B ); + double pPosA = 0.5 * (sHatT + w2A - w2B + lambdaRoot) / sHatT * wPos; + beamA[iSys].e( 0.5 * (pPosA + w2A / pPosA) ); + beamA[iSys].pz( 0.5 * (pPosA - w2A / pPosA) ); + double pNegB = 0.5 * (sHatT + w2B - w2A + lambdaRoot) / sHatT * wNeg; + beamB[iSys].e( 0.5 * (pNegB + w2B / pNegB) ); + beamB[iSys].pz( 0.5 * (w2B / pNegB - pNegB) ); + + // Construct rotations and boosts caused by primordial kT. + int iA = beamA[iSys].iPos(); + int iB = beamB[iSys].iPos(); + RotBstMatrix M; + M.toCMframe( event[iA].p(), event[iB].p() ); + M.fromCMframe( beamA[iSys].p(), beamB[iSys].p() ); + + // Copy initiators and their systems and boost them accordingly. + // Update subsystem and beams info on new positions of partons. + int iAcopy = event.copy(iA, -61); + event[iAcopy].rotbst(M); + event.setInSystem(iSys, 0, iAcopy); + beamA[iSys].iPos( iAcopy); + int iBcopy = event.copy(iB, -61); + event[iBcopy].rotbst(M); + event.setInSystem(iSys, 1, iBcopy); + beamB[iSys].iPos( iBcopy); + for (int iABsys = 2; iABsys < event.sizeSystem(iSys); ++iABsys) { + int iAB = event.getInSystem(iSys, iABsys); + int iABcopy = event.copy(iAB, 62); + event[iABcopy].rotbst(M); + event.setInSystem(iSys, iABsys, iABcopy); + } + + // Update daughter info of mothers, i.e. of beams, for hardest interaction. + if (iSys == 0) { + int mother = event[iAcopy].mother1(); + event[mother].daughter1(iAcopy); + mother = event[iBcopy].mother1(); + event[mother].daughter1(iBcopy); + } + } + + // Construct x rescaling factors for the two remants. + double lambdaRoot = sqrtpos( pow2(w2Rem - w2Beam[0] - w2Beam[1]) + - 4. * w2Beam[0] * w2Beam[1] ); + double rescaleA = (w2Rem + w2Beam[0] - w2Beam[1] + lambdaRoot) + / (2. * w2Rem * xSum[0]) ; + double rescaleB = (w2Rem + w2Beam[1] - w2Beam[0] + lambdaRoot) + / (2. * w2Rem * xSum[1]) ; + + // Construct energy and pz for remnants in first beam. + for (int iRem = nSys; iRem < beamA.size(); ++iRem) { + double pPos = rescaleA * beamA[iRem].x() * wPosRem; + double pNeg = beamA[iRem].mT2() / pPos; + beamA[iRem].e( 0.5 * (pPos + pNeg) ); + beamA[iRem].pz( 0.5 * (pPos - pNeg) ); + + // Add these partons to the normal event record. + int iNew = event.append( beamA[iRem].id(), 63, 1, 0, 0, 0, + beamA[iRem].col(), beamA[iRem].acol(), beamA[iRem].p(), + beamA[iRem].m() ); + beamA[iRem].iPos( iNew); + } + + // Construct energy and pz for remnants in second beam. + for (int iRem = nSys; iRem < beamB.size(); ++iRem) { + double pNeg = rescaleB * beamB[iRem].x() * wNegRem; + double pPos = beamB[iRem].mT2() / pNeg; + beamB[iRem].e( 0.5 * (pPos + pNeg) ); + beamB[iRem].pz( 0.5 * (pPos - pNeg) ); + + // Add these partons to the normal event record. + int iNew = event.append( beamB[iRem].id(), 63, 2, 0, 0, 0, + beamB[iRem].col(), beamB[iRem].acol(), beamB[iRem].p(), + beamB[iRem].m() ); + beamB[iRem].iPos( iNew); + } + + // Done. + return true; + +} + +//********* + +// Allow colour reconnections by mergings of collision subsystems. +// iRec is system that may be reconnected, by moving its gluons to iSys, +// where minimal pT (or equivalently Lambda) is used to pick location. +// Therefore all dipoles in iSys have to be found, and all gluons in iRec. +// Matching q-qbar pairs are treated by analogy with gluons. + +bool BeamRemnants::reconnectColours( Event& event) { + + // Prepare record of which systems should be merged onto another. + // The iSys system must have colour in final state to attach to it. + vector iMerge; + vector hasColour; + for (int iSys = 0; iSys < nSys; ++iSys) { + iMerge.push_back( iSys ); + bool hasCol = false; + for (int iMem = 2; iMem < event.sizeSystem( iSys); ++iMem) { + int iNow = event.getInSystem( iSys, iMem); + if (event[iNow].col() > 0 || event[iNow].acol() > 0) { + hasCol = true; + break; + } + } + hasColour.push_back( hasCol ); + } + + // Loop over system that may be reconnected. + for (int iRec = nSys - 1; iRec > 0; --iRec) { + + // Determine reconnection strength from pT scale of system. + double pT2Rec = pow2( infoPtr->pTMI(iRec) ); + double probRec = pT20Rec / (pT20Rec + pT2Rec); + + // Loop over other systems iSys at higher pT scale and + // decide whether to reconnect the iRec gluons onto one of them. + for (int iSys = iRec - 1; iSys >= 0; --iSys) + if (hasColour[iSys] && probRec > Rndm::flat()) { + + // The iRec system and all merged with it to be merged with iSys. + iMerge[iRec] = iSys; + for (int iRec2 = iRec + 1; iRec2 < nSys; ++iRec2) + if (iMerge[iRec2] == iRec) iMerge[iRec2] = iSys; + + // Once a system has been merged do not test it anymore. + break; + } + } + + // Loop over systems. Check whether other systems to be merged with it. + for (int iSys = 0; iSys < nSys; ++iSys) { + + int nMerge = 0; + for (int iRec = iSys + 1; iRec < nSys; ++iRec) + if (iMerge[iRec] == iSys) ++nMerge; + if (nMerge == 0) continue; + + // Begin find dipoles in iSys system. + vector dipoles; + int sizeSys = event.sizeSystem( iSys); + int iInASys = event.getInSystem( iSys, 0); + int iInBSys = event.getInSystem( iSys, 1); + for (int iMem = 2; iMem < sizeSys; ++iMem) { + + // Find colour dipoles to beam remnant. + int iNow = event.getInSystem( iSys, iMem); + int col = event[iNow].col(); + if (col > 0) { + if (event[iInASys].col() == col) + dipoles.push_back( BeamDipole( col, iNow, iInASys ) ); + else if (event[iInBSys].col() == col) + dipoles.push_back( BeamDipole( col, iNow, iInBSys ) ); + + // Find colour dipole between final-state partons. + else for (int iMem2 = 2; iMem2 < sizeSys; ++iMem2) + if (iMem2 != iMem) { + int iNow2 = event.getInSystem( iSys, iMem2); + if (event[iNow2].acol() == col) { + dipoles.push_back( BeamDipole( col, iNow, iNow2) ); + break; + } + } + } + + // Find anticolour dipoles to beam remnant. + int acol = event[iNow].acol(); + if (acol > 0) { + if (event[iInASys].acol() == acol) + dipoles.push_back( BeamDipole( acol, iInASys, iNow ) ); + else if (event[iInBSys].acol() == acol) + dipoles.push_back( BeamDipole( acol, iInBSys, iNow ) ); + } + } + + // Find dipole sizes. + for (int iDip = 0; iDip < int(dipoles.size()); ++iDip) + dipoles[iDip].p1p2 = event[dipoles[iDip].iCol].p() + * event[dipoles[iDip].iAcol].p(); + + // Loop over systems iRec to be merged with iSys. + for (int iRec = iSys + 1; iRec < nSys; ++iRec) { + if (iMerge[iRec] != iSys) continue; + + // Information on iRec. Vectors for gluons and anything else. + int sizeRec = event.sizeSystem( iRec); + int iInARec = event.getInSystem( iRec, 0); + int iInBRec = event.getInSystem( iRec, 1); + int nGluRec = 0; + vector iGluRec; + vector pT2GluRec; + int nAnyRec = 0; + vector iAnyRec; + vector freeAnyRec; + + // Copy of gluon positions in descending order. + for (int iMem = 2; iMem < sizeRec; ++iMem) { + int iNow = event.getInSystem( iRec, iMem); + if (event[iNow].isGluon()) { + ++nGluRec; + iGluRec.push_back( iNow ); + pT2GluRec.push_back( event[iNow].pT2() ); + for (int i = nGluRec - 1; i > 1; --i) { + if (pT2GluRec[i - 1] > pT2GluRec[i]) break; + swap( iGluRec[i - 1], iGluRec[i] ); + swap( pT2GluRec[i - 1], pT2GluRec[i] ); + } + // Copy of anything else, mainly quarks, in no particular order. + } else { + ++nAnyRec; + iAnyRec.push_back( iNow ); + freeAnyRec.push_back( true ); + } + } + + // For each gluon in iRec now find the dipole that gives the smallest + // (pGlu * pI) (pGlu * pJ) / (pI * pJ), i.e. minimal pT (and Lambda). + for (int iGRec = 0; iGRec < nGluRec; ++iGRec) { + int iGlu = iGluRec[iGRec]; + Vec4 pGlu = event[iGlu].p(); + int iDipMin = 0; + double pT2DipMin = sCM; + for (int iDip = 0; iDip < int(dipoles.size()); ++iDip) { + double pT2Dip = (pGlu * event[dipoles[iDip].iCol].p()) + * (pGlu * event[dipoles[iDip].iAcol].p()) / dipoles[iDip].p1p2; + if (pT2Dip < pT2DipMin) { + iDipMin = iDip; + pT2DipMin = pT2Dip; + } + } + + // Attach the gluon to the dipole, i.e. split the dipole in two. + int colGlu = event[iGlu].col(); + int acolGlu = event[iGlu].acol(); + int colDip = dipoles[iDipMin].col; + int iColDip = dipoles[iDipMin].iCol; + int iAcolDip = dipoles[iDipMin].iAcol; + event[iGlu].acol( colDip ); + if (event[iAcolDip].acol() == colDip) + event[iAcolDip].acol( colGlu ); + else event[iAcolDip].col( colGlu ); + dipoles[iDipMin].iAcol = iGlu; + dipoles[iDipMin].p1p2 = event[iColDip].p() * pGlu; + dipoles.push_back( BeamDipole( colGlu, iGlu, iAcolDip ) ); + dipoles.back().p1p2 = pGlu * event[iAcolDip].p(); + + // Remove gluon from old system: reconnect colours. + if (event[iInARec].col() == colGlu) + event[iInARec].col( acolGlu ); + else if (event[iInBRec].col() == colGlu) + event[iInBRec].col( acolGlu ); + else for (int i = iGRec + 1; i < nGluRec; ++i) + if (event[iGluRec[i]].acol() == colGlu) { + event[iGluRec[i]].acol( acolGlu ); + break; + } + for (int i = 0; i < nAnyRec; ++i) + if (event[iAnyRec[i]].acol() == colGlu) { + event[iAnyRec[i]].acol( acolGlu ); + break; + } + } + + // See if any matching quark-antiquark pairs among the rest. + for (int iQRec = 0; iQRec < nAnyRec; ++iQRec) { + int iQ = iAnyRec[iQRec]; + int idQ = event[iQ].id(); + if (freeAnyRec[iQRec] && idQ > 0 && idQ < 6) + for (int iQbarRec = 0; iQbarRec < nAnyRec; ++iQbarRec) { + int iQbar = iAnyRec[iQbarRec]; + if (freeAnyRec[iQbarRec] && event[iQbar].id() == -idQ) { + + // Check that these can be traced back to same gluon splitting. + int iTopQ = event.iTopCopyId(iQ); + int iTopQbar = event.iTopCopyId(iQbar); + int iMother = event[iTopQ].mother1(); + if (event[iTopQbar].mother1() == iMother + && event[iMother].isGluon()) { + + // Now find the dipole that gives the smallest + // ((pQ + pQbar) * pI) ((pQ + pQbar) * pJ) / (pI * pJ). + Vec4 pGlu = event[iQ].p() + event[iQbar].p(); + int iDipMin = 0; + double pT2DipMin = sCM; + for (int iDip = 0; iDip < int(dipoles.size()); ++iDip) { + double pT2Dip = (pGlu * event[dipoles[iDip].iCol].p()) + * (pGlu * event[dipoles[iDip].iAcol].p()) + / dipoles[iDip].p1p2; + if (pT2Dip < pT2DipMin) { + iDipMin = iDip; + pT2DipMin = pT2Dip; + } + } + + // Attach the q-qbar pair to the dipole, i.e. split the dipole. + int colGlu = event[iQ].col(); + int acolGlu = event[iQbar].acol(); + int colDip = dipoles[iDipMin].col; + int iColDip = dipoles[iDipMin].iCol; + int iAcolDip = dipoles[iDipMin].iAcol; + event[iQbar].acol( colDip ); + if (event[iAcolDip].acol() == colDip) + event[iAcolDip].acol( colGlu ); + else event[iAcolDip].col( colGlu ); + dipoles[iDipMin].iAcol = iQbar; + dipoles[iDipMin].p1p2 = event[iColDip].p() * event[iQbar].p(); + dipoles.push_back( BeamDipole( colGlu, iQ, iAcolDip ) ); + dipoles.back().p1p2 = event[iQ].p() * event[iAcolDip].p(); + + // Remove q-qbar pair from old system: reconnect colours. + freeAnyRec[iQRec] = false; + freeAnyRec[iQbarRec] = false; + if (event[iInARec].col() == colGlu) + event[iInARec].col( acolGlu ); + else if (event[iInBRec].col() == colGlu) + event[iInBRec].col( acolGlu ); + else for (int i = 0; i < nAnyRec; ++i) + if (freeAnyRec[i] && event[iAnyRec[i]].acol() == colGlu) { + event[iAnyRec[i]].acol( acolGlu ); + break; + } + + // Done with processing of q-qbar pairs. + } + } + } + } + + // If only two beam gluons left of system, set their colour = anticolour. + // Used by BeamParticle::remnantColours to skip irrelevant gluons. + if ( event[iInARec].isGluon() && event[iInBRec].isGluon() + && event[iInARec].col() == event[iInBRec].acol() + && event[iInARec].acol() == event[iInBRec].col() ) { + event[iInARec].acol( event[iInARec].col() ); + event[iInBRec].acol( event[iInBRec].col() ); + } + + // End of loops over iRec and iSys systems. + } + } + + // Done. + return true; + +} + +//********* + +// Collapse colours and check that they are consistent. + +bool BeamRemnants::checkColours( Event& event) { + + // No colours in lepton beams so no need to do anything. + if (beamAPtr->isLepton() && beamBPtr->isLepton()) return true; + + // Remove ambiguities when one colour collapses two ways. + // Resolve chains where one colour is mapped to another. + for (int iCol = 1; iCol < int(colFrom.size()); ++iCol) + for (int iColRef = 0; iColRef < iCol; ++iColRef) { + if (colFrom[iCol] == colFrom[iColRef]) { + colFrom[iCol] = colTo[iCol]; + colTo[iCol] = colTo[iColRef]; + } + if (colTo[iCol] == colFrom[iColRef]) colTo[iCol] = colTo[iColRef]; + } + + // Transform event record colours from beam remnant colour collapses. + for (int i = oldSize; i < event.size(); ++i) { + int col = event[i].col(); + int acol = event[i].acol(); + for (int iCol = 0; iCol < int(colFrom.size()); ++iCol) { + if (col == colFrom[iCol]) {col = colTo[iCol]; event[i].col(col);} + if (acol == colFrom[iCol]) {acol = colTo[iCol]; event[i].acol(acol);} + } + } + + // Transform junction colours from beam remnant colour collapses. + for (int iJun = 0; iJun < event.sizeJunction(); ++iJun) + for (int leg = 0; leg < 3; ++leg) { + int col = event.colJunction(iJun, leg); + for (int iCol = 0; iCol < int(colFrom.size()); ++iCol) + if (col == colFrom[iCol]) { + col = colTo[iCol]; + event.colJunction(iJun, leg, col); + } + } + + // Arrays for current colours and anticolours, and for singlet gluons. + vector colList; + vector acolList; + vector iSingletGluon; + + // Find current colours and anticolours in the event record. + for (int i = oldSize; i < event.size(); ++i) + if (event[i].status() > 0) { + int id = event[i].id(); + int col = event[i].col(); + int acol = event[i].acol(); + + // Quarks must have colour set, antiquarks anticolour, gluons both. + if ( (id > 0 && id < 9 && (col <= 0 || acol != 0) ) + || (id < 0 && id > -9 && (col != 0 || acol <= 0) ) + || (id == 21 && (col <= 0 || acol <= 0) ) ) { + infoPtr->errorMsg("Error in BeamRemnants::checkColours: " + "q/qbar/g has wrong colour slots set"); + return false; + } + + // Save colours/anticolours, and position of colour singlet gluons. + if ( col > 0) colList.push_back( col ); + if (acol > 0) acolList.push_back( acol ); + if (col > 0 && acol == col) iSingletGluon.push_back(i); + } + + // Run though list of singlet gluons and put them on final-state dipole + // (i,j) that offers smallest (p_g p_i) * (p_g p_j) / (p_i p_j). + for (int iS = 0; iS < int(iSingletGluon.size()); ++iS) { + int iGlu = iSingletGluon[iS]; + int iAcolDip = 0; + double pT2DipMin = sCM; + for (int iC = oldSize; iC < event.size(); ++iC) + if (iC != iGlu && event[iC].status() > 0) { + int colDip = event[iC].col(); + if (colDip > 0 && event[iC].acol() !=colDip) + for (int iA = oldSize; iA < event.size(); ++iA) + if (iA != iGlu && iA != iC && event[iA].status() > 0 + && event[iA].acol() == colDip && event[iA].col() !=colDip) { + double pT2Dip = (event[iGlu].p() * event[iC].p()) + * (event[iGlu].p() * event[iA].p()) + / (event[iC].p() * event[iA].p()); + if (pT2Dip < pT2DipMin) { + iAcolDip = iA; + pT2DipMin = pT2Dip; + } + } + } + event[iGlu].acol( event[iAcolDip].acol() ); + event[iAcolDip].acol( event[iGlu].col() ); + } + + // Check that not the same colour or anticolour appears twice. + for (int iCol = 0; iCol < int(colList.size()) - 1; ++iCol) { + int col = colList[iCol]; + for (int iCol2 = iCol + 1; iCol2 < int(colList.size()); ++iCol2) + if (colList[iCol2] == col) return false; + } + for (int iAcol = 0; iAcol < int(acolList.size()) - 1; ++iAcol) { + int acol = acolList[iAcol]; + for (int iAcol2 = iAcol + 1; iAcol2 < int(acolList.size()); ++iAcol2) + if (acolList[iAcol2] == acol) return false; + } + + // Remove all matching colour-anticolour pairs. + bool foundPair = true; + while (foundPair && colList.size() > 0 && acolList.size() > 0) { + foundPair = false; + for (int iCol = 0; iCol < int(colList.size()); ++iCol) { + for (int iAcol = 0; iAcol < int(acolList.size()); ++iAcol) { + if (acolList[iAcol] == colList[iCol]) { + colList[iCol] = colList.back(); colList.pop_back(); + acolList[iAcol] = acolList.back(); acolList.pop_back(); + foundPair = true; break; + } + } if (foundPair) break; + } + } + + // Check that remaining (anti)colours are accounted for by junctions. + for (int iJun = 0; iJun < event.sizeJunction(); ++iJun) { + int kindJun = event.kindJunction(iJun); + for (int leg = 0; leg < 3; ++leg) { + int colEnd = event.colJunction(iJun, leg); + + // Junction connected to three colours. + if (kindJun == 1) { + bool foundCol = false; + for (int iCol = 0; iCol < int(colList.size()); ++iCol) + if (colList[iCol] == colEnd) { + colList[iCol] = colList.back(); + colList.pop_back(); + foundCol = true; + break; + } + } + + // Junction connected to three anticolours. + else if (kindJun == 2) { + bool foundCol = false; + for (int iAcol = 0; iAcol < int(acolList.size()); ++iAcol) + if (acolList[iAcol] == colEnd) { + acolList[iAcol] = acolList.back(); + acolList.pop_back(); + foundCol = true; + break; + } + } + + // End junction check. More junction cases to come?? + } + } + + // Done. + return (colList.size() == 0 && acolList.size() == 0); + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/BeamShape.cxx b/PYTHIA8/pythia8130/src/BeamShape.cxx new file mode 100644 index 00000000000..77a1bb27bdd --- /dev/null +++ b/PYTHIA8/pythia8130/src/BeamShape.cxx @@ -0,0 +1,148 @@ +// BeamShape.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the BeamShape class. + +#include "BeamShape.h" + +namespace Pythia8 { + +//************************************************************************** + +// The BeamShape class. + +//********* + +// Initialize beam parameters. + +void BeamShape::init() { + + // Main flags. + allowMomentumSpread = Settings::flag("Beams:allowMomentumSpread"); + allowVertexSpread = Settings::flag("Beams:allowVertexSpread"); + + // Parameters for beam A momentum spread. + sigmaPxA = Settings::parm("Beams:sigmaPxA"); + sigmaPyA = Settings::parm("Beams:sigmaPyA"); + sigmaPzA = Settings::parm("Beams:sigmaPzA"); + maxDevA = Settings::parm("Beams:maxDevA"); + + // Parameters for beam B momentum spread. + sigmaPxB = Settings::parm("Beams:sigmaPxB"); + sigmaPyB = Settings::parm("Beams:sigmaPyB"); + sigmaPzB = Settings::parm("Beams:sigmaPzB"); + maxDevB = Settings::parm("Beams:maxDevB"); + + // Parameters for beam vertex spread. + sigmaVertexX = Settings::parm("Beams:sigmaVertexX"); + sigmaVertexY = Settings::parm("Beams:sigmaVertexY"); + sigmaVertexZ = Settings::parm("Beams:sigmaVertexZ"); + maxDevVertex = Settings::parm("Beams:maxDevVertex"); + sigmaTime = Settings::parm("Beams:sigmaTime"); + maxDevTime = Settings::parm("Beams:maxDevTime"); + + // Parameters for beam vertex offset. + offsetX = Settings::parm("Beams:offsetVertexX"); + offsetY = Settings::parm("Beams:offsetVertexY"); + offsetZ = Settings::parm("Beams:offsetVertexZ"); + offsetT = Settings::parm("Beams:offsetTime"); + +} + +//********* + +// Set the two beam momentum deviations and the beam vertex. + +void BeamShape::pick() { + + // Reset all values. + deltaPxA = deltaPyA = deltaPzA = deltaPxB = deltaPyB = deltaPzB + = vertexX = vertexY = vertexZ = vertexT = 0.; + + // Set beam A momentum deviation by a three-dimensional Gaussian. + if (allowMomentumSpread) { + double totalDev, gauss; + do { + totalDev = 0.; + if (sigmaPxA > 0.) { + gauss = Rndm::gauss(); + deltaPxA = sigmaPxA * gauss; + totalDev += gauss * gauss; + } + if (sigmaPyA > 0.) { + gauss = Rndm::gauss(); + deltaPyA = sigmaPyA * gauss; + totalDev += gauss * gauss; + } + if (sigmaPzA > 0.) { + gauss = Rndm::gauss(); + deltaPzA = sigmaPzA * gauss; + totalDev += gauss * gauss; + } + } while (totalDev > maxDevA * maxDevA); + + // Set beam B momentum deviation by a three-dimensional Gaussian. + do { + totalDev = 0.; + if (sigmaPxB > 0.) { + gauss = Rndm::gauss(); + deltaPxB = sigmaPxB * gauss; + totalDev += gauss * gauss; + } + if (sigmaPyB > 0.) { + gauss = Rndm::gauss(); + deltaPyB = sigmaPyB * gauss; + totalDev += gauss * gauss; + } + if (sigmaPzB > 0.) { + gauss = Rndm::gauss(); + deltaPzB = sigmaPzB * gauss; + totalDev += gauss * gauss; + } + } while (totalDev > maxDevB * maxDevB); + } + + // Set beam vertex location by a three-dimensional Gaussian. + if (allowVertexSpread) { + double totalDev, gauss; + do { + totalDev = 0.; + if (sigmaVertexX > 0.) { + gauss = Rndm::gauss(); + vertexX = sigmaVertexX * gauss; + totalDev += gauss * gauss; + } + if (sigmaVertexY > 0.) { + gauss = Rndm::gauss(); + vertexY = sigmaVertexY * gauss; + totalDev += gauss * gauss; + } + if (sigmaVertexZ > 0.) { + gauss = Rndm::gauss(); + vertexZ = sigmaVertexZ * gauss; + totalDev += gauss * gauss; + } + } while (totalDev > maxDevVertex * maxDevVertex); + + // Set beam collision time by a Gaussian. + if (sigmaTime > 0.) { + do gauss = Rndm::gauss(); + while (abs(gauss) > maxDevTime); + vertexT = sigmaTime * gauss; + } + + // Add offset to beam vertex. + vertexX += offsetX; + vertexY += offsetY; + vertexZ += offsetZ; + vertexT += offsetT; + } + +} + +//************************************************************************** + +} // end namespace Pythia8 + diff --git a/PYTHIA8/pythia8130/src/BoseEinstein.cxx b/PYTHIA8/pythia8130/src/BoseEinstein.cxx new file mode 100644 index 00000000000..2c7c20a78e3 --- /dev/null +++ b/PYTHIA8/pythia8130/src/BoseEinstein.cxx @@ -0,0 +1,280 @@ +// BoseEinstein.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the BoseEinsten class. + +#include "BoseEinstein.h" + +namespace Pythia8 { + +//************************************************************************** + +// The BoseEinstein class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Enumeration of id codes and table for particle species considered. +const int BoseEinstein::IDHADRON[9] = { 211, -211, 111, 321, -321, + 130, 310, 221, 331 }; +const int BoseEinstein::ITABLE[9] = { 0, 0, 0, 1, 1, 1, 1, 2, 3 }; + +// Distance between table entries, normalized to min( 2*mass, QRef). +const double BoseEinstein::STEPSIZE = 0.05; + +// Skip shift for two extremely close particles, to avoid instabilities. +const double BoseEinstein::Q2MIN = 1e-8; + +// Parameters of energy compensation procedure: maximally allowed +// relative energy error, iterative stepsize, and number of iterations. +const double BoseEinstein::COMPRELERR = 1e-10; +const double BoseEinstein::COMPFACMAX = 1000.; +const int BoseEinstein::NCOMPSTEP = 10; + +//********* + +// Find settings. Precalculate table used to find momentum shifts. + +bool BoseEinstein::init(Info* infoPtrIn) { + + // Save pointer. + infoPtr = infoPtrIn; + + // Main flags. + doPion = Settings::flag("BoseEinstein:Pion"); + doKaon = Settings::flag("BoseEinstein:Kaon"); + doEta = Settings::flag("BoseEinstein:Eta"); + + // Shape of Bose-Einstein enhancement/suppression. + lambda = Settings::parm("BoseEinstein:lambda"); + QRef = Settings::parm("BoseEinstein:QRef"); + + // Multiples and inverses (= "radii") of distance parameters in Q-space. + QRef2 = 2. * QRef; + QRef3 = 3. * QRef; + R2Ref = 1. / (QRef * QRef); + R2Ref2 = 1. / (QRef2 * QRef2); + R2Ref3 = 1. / (QRef3 * QRef3); + + // Masses of particles with Bose-Einstein implemented. + for (int iSpecies = 0; iSpecies < 9; ++iSpecies) + mHadron[iSpecies] = ParticleDataTable::m0( IDHADRON[iSpecies] ); + + // Pair pi, K, eta and eta' masses for use in tables. + mPair[0] = 2. * mHadron[0]; + mPair[1] = 2. * mHadron[3]; + mPair[2] = 2. * mHadron[7]; + mPair[3] = 2. * mHadron[8]; + + // Loop over the four required tables. Local variables. + double Qnow, Q2now, centerCorr; + for (int iTab = 0; iTab < 4; ++iTab) { + m2Pair[iTab] = mPair[iTab] * mPair[iTab]; + + // Step size and number of steps in normal table. + deltaQ[iTab] = STEPSIZE * min(mPair[iTab], QRef); + nStep[iTab] = min( 199, 1 + int(3. * QRef / deltaQ[iTab]) ); + maxQ[iTab] = (nStep[iTab] - 0.1) * deltaQ[iTab]; + centerCorr = deltaQ[iTab] * deltaQ[iTab] / 12.; + + // Construct normal table recursively in Q space. + shift[iTab][0] = 0.; + for (int i = 1; i <= nStep[iTab]; ++i) { + Qnow = deltaQ[iTab] * (i - 0.5); + Q2now = Qnow * Qnow; + shift[iTab][i] = shift[iTab][i - 1] + exp(-Q2now * R2Ref) + * deltaQ[iTab] * (Q2now + centerCorr) / sqrt(Q2now + m2Pair[iTab]); + } + + // Step size and number of steps in compensation table. + deltaQ3[iTab] = STEPSIZE * min(mPair[iTab], QRef3); + nStep3[iTab] = min( 199, 1 + int(9. * QRef / deltaQ3[iTab]) ); + maxQ3[iTab] = (nStep3[iTab] - 0.1) * deltaQ3[iTab]; + centerCorr = deltaQ3[iTab] * deltaQ3[iTab] / 12.; + + // Construct compensation table recursively in Q space. + shift3[iTab][0] = 0.; + for (int i = 1; i <= nStep3[iTab]; ++i) { + Qnow = deltaQ3[iTab] * (i - 0.5); + Q2now = Qnow * Qnow; + shift3[iTab][i] = shift3[iTab][i - 1] + exp(-Q2now * R2Ref3) + * deltaQ3[iTab] * (Q2now + centerCorr) / sqrt(Q2now + m2Pair[iTab]); + } + + } + + // Done. + return true; + +} + +//********* + +// Perform Bose-Einstein corrections on an event. + +bool BoseEinstein::shiftEvent( Event& event) { + + // Reset list of identical particles. + hadronBE.resize(0); + + // Loop over all hadron species with BE effects. + nStored[0] = 0; + for (int iSpecies = 0; iSpecies < 9; ++iSpecies) { + nStored[iSpecies + 1] = nStored[iSpecies]; + if (!doPion && iSpecies <= 2) continue; + if (!doKaon && iSpecies >= 3 && iSpecies <= 6) continue; + if (!doEta && iSpecies >= 7) continue; + + // Properties of current hadron species. + int idNow = IDHADRON[ iSpecies ]; + int iTab = ITABLE[ iSpecies ]; + + // Loop through event record to store copies of current species. + for (int i = 0; i < event.size(); ++i) + if ( event[i].id() == idNow && event[i].isFinal() ) + hadronBE.push_back( + BoseEinsteinHadron( idNow, i, event[i].p(), event[i].m() ) ); + nStored[iSpecies + 1] = hadronBE.size(); + + // Loop through pairs of identical particles and find shifts. + for (int i1 = nStored[iSpecies]; i1 < nStored[iSpecies+1] - 1; ++i1) + for (int i2 = i1 + 1; i2 < nStored[iSpecies+1]; ++i2) + shiftPair( i1, i2, iTab); + } + + // Must have at least two pairs to carry out compensation. + if (nStored[9] < 2) return true; + + // Shift momenta and recalculate energies. + double eSumOriginal = 0.; + double eSumShifted = 0.; + double eDiffByComp = 0.; + for (int i = 0; i < nStored[9]; ++i) { + eSumOriginal += hadronBE[i].p.e(); + hadronBE[i].p += hadronBE[i].pShift; + hadronBE[i].p.e( sqrt( hadronBE[i].p.pAbs2() + hadronBE[i].m2 ) ); + eSumShifted += hadronBE[i].p.e(); + eDiffByComp += dot3( hadronBE[i].pComp, hadronBE[i].p) + / hadronBE[i].p.e(); + } + + // Iterate compensation shift until convergence. + int iStep = 0; + while ( abs(eSumShifted - eSumOriginal) > COMPRELERR * eSumOriginal + && abs(eSumShifted - eSumOriginal) < COMPFACMAX * abs(eDiffByComp) + && iStep < NCOMPSTEP ) { + ++iStep; + double compFac = (eSumOriginal - eSumShifted) / eDiffByComp; + eSumShifted = 0.; + eDiffByComp = 0.; + for (int i = 0; i < nStored[9]; ++i) { + hadronBE[i].p += compFac * hadronBE[i].pComp; + hadronBE[i].p.e( sqrt( hadronBE[i].p.pAbs2() + hadronBE[i].m2 ) ); + eSumShifted += hadronBE[i].p.e(); + eDiffByComp += dot3( hadronBE[i].pComp, hadronBE[i].p) + / hadronBE[i].p.e(); + } + } + + // Error if no convergence, and then return without doing BE shift. + // However, not grave enough to kill event, so return true. + if ( abs(eSumShifted - eSumOriginal) > COMPRELERR * eSumOriginal ) { + infoPtr->errorMsg("Warning in BoseEinstein::shiftEvent: " + "no consistent BE shift topology found, so skip BE"); + return true; + } + + // Store new particle copies with shifted momenta. + for (int i = 0; i < nStored[9]; ++i) { + int iNew = event.copy( hadronBE[i].iPos, 99); + event[ iNew ].p( hadronBE[i].p ); + } + + // Done. + return true; + +} + +//********* + +// Calculate shift and (unnormalized) compensation for pair. + +void BoseEinstein::shiftPair( int i1, int i2, int iTab) { + + // Calculate old relative momentum. + double Q2old = m2(hadronBE[i1].p, hadronBE[i2].p) - m2Pair[iTab]; + if (Q2old < Q2MIN) return; + double Qold = sqrt(Q2old); + double psFac = sqrt(Q2old + m2Pair[iTab]) / Q2old; + + // Calculate new relative momentum for normal shift. + double Qmove = 0.; + if (Qold < deltaQ[iTab]) Qmove = Qold / 3.; + else if (Qold < maxQ[iTab]) { + double realQbin = Qold / deltaQ[iTab]; + int intQbin = int( realQbin ); + double inter = (pow3(realQbin) - pow3(intQbin)) + / (3 * intQbin * (intQbin + 1) + 1); + Qmove = ( shift[iTab][intQbin] + inter * (shift[iTab][intQbin + 1] + - shift[iTab][intQbin]) ) * psFac; + } + else Qmove = shift[iTab][nStep[iTab]] * psFac; + double Q2new = Q2old * pow( Qold / (Qold + 3. * lambda * Qmove), 2. / 3.); + + // Calculate corresponding three-momentum shift. + double Q2Diff = Q2new - Q2old; + double p2DiffAbs = (hadronBE[i1].p - hadronBE[i2].p).pAbs2(); + double p2AbsDiff = hadronBE[i1].p.pAbs2() - hadronBE[i2].p.pAbs2(); + double eSum = hadronBE[i1].p.e() + hadronBE[i2].p.e(); + double eDiff = hadronBE[i1].p.e() - hadronBE[i2].p.e(); + double sumQ2E = Q2Diff + eSum * eSum; + double rootA = eSum * eDiff * p2AbsDiff - p2DiffAbs * sumQ2E; + double rootB = p2DiffAbs * sumQ2E - p2AbsDiff * p2AbsDiff; + double factor = 0.5 * ( rootA + sqrtpos(rootA * rootA + + Q2Diff * (sumQ2E - eDiff * eDiff) * rootB) ) / rootB; + + // Add shifts to sum. (Energy component dummy.) + Vec4 pDiff = factor * (hadronBE[i1].p - hadronBE[i2].p); + hadronBE[i1].pShift += pDiff; + hadronBE[i2].pShift -= pDiff; + + // Calculate new relative momentum for compensation shift. + double Qmove3 = 0.; + if (Qold < deltaQ3[iTab]) Qmove3 = Qold / 3.; + else if (Qold < maxQ3[iTab]) { + double realQbin = Qold / deltaQ3[iTab]; + int intQbin = int( realQbin ); + double inter = (pow3(realQbin) - pow3(intQbin)) + / (3 * intQbin * (intQbin + 1) + 1); + Qmove3 = ( shift3[iTab][intQbin] + inter * (shift3[iTab][intQbin + 1] + - shift3[iTab][intQbin]) ) * psFac; + } + else Qmove3 = shift3[iTab][nStep3[iTab]] *psFac; + double Q2new3 = Q2old * pow( Qold / (Qold + 3. * lambda * Qmove3), 2. / 3.); + + // Calculate corresponding three-momentum shift. + Q2Diff = Q2new3 - Q2old; + sumQ2E = Q2Diff + eSum * eSum; + rootA = eSum * eDiff * p2AbsDiff - p2DiffAbs * sumQ2E; + rootB = p2DiffAbs * sumQ2E - p2AbsDiff * p2AbsDiff; + factor = 0.5 * ( rootA + sqrtpos(rootA * rootA + + Q2Diff * (sumQ2E - eDiff * eDiff) * rootB) ) / rootB; + + // Extra dampening factor to go from BE_3 to BE_32. + factor *= 1. - exp(-Q2old * R2Ref2); + + // Add shifts to sum. (Energy component dummy.) + pDiff = factor * (hadronBE[i1].p - hadronBE[i2].p); + hadronBE[i1].pComp += pDiff; + hadronBE[i2].pComp -= pDiff; + +} + +//************************************************************************** + +} // end namespace Pythia8 + diff --git a/PYTHIA8/pythia8130/src/Event.cxx b/PYTHIA8/pythia8130/src/Event.cxx new file mode 100644 index 00000000000..b3936c11bcc --- /dev/null +++ b/PYTHIA8/pythia8130/src/Event.cxx @@ -0,0 +1,752 @@ +// Event.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// Particle and Event classes, and some related global functions. + +#include "Event.h" + +namespace Pythia8 { + +//************************************************************************** + +// Particle class. +// This class holds info on a particle in general. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Small number to avoid division by zero. +const double Particle::TINY = 1e-20; + +//********* + +// Functions for rapidity and pseudorapidity. + +double Particle::y() const { + double temp = log( ( pSave.e() + abs(pSave.pz()) ) / max( TINY, mT() ) ); + return (pSave.pz() > 0) ? temp : -temp; +} + +double Particle::eta() const { + double temp = log( ( pSave.pAbs() + abs(pSave.pz()) ) / max( TINY, pT() ) ); + return (pSave.pz() > 0) ? temp : -temp; +} + +//********* + +// Particle name, with status but imposed maximum length -> may truncate. + +string Particle::nameWithStatus(int maxLen) const { + + string temp = (statusSave > 0) ? particlePtr->name(idSave) + : "(" + particlePtr->name(idSave) + ")"; + while (int(temp.length()) > maxLen) { + // Remove from end, excluding closing bracket and charge. + int iRem = temp.find_last_not_of(")+-0"); + temp.erase(iRem, 1); + } + return temp; +} + +//********* + +// Add offsets to mother and daughter pointers (must be non-negative). + +void Particle::offsetHistory( int minMother, int addMother, int minDaughter, + int addDaughter) { + + if (addMother < 0 || addDaughter < 0) return; + if ( mother1Save > minMother ) mother1Save += addMother; + if ( mother2Save > minMother ) mother2Save += addMother; + if (daughter1Save > minDaughter) daughter1Save += addDaughter; + if (daughter2Save > minDaughter) daughter2Save += addDaughter; + +} + +//********* + +// Add offsets to colour and anticolour (must be positive). + +void Particle::offsetCol( int addCol) { + + if (addCol < 0) return; + if ( colSave > 0) colSave += addCol; + if (acolSave > 0) acolSave += addCol; + +} + +//********* + +// Set the ParticleDataEntry pointer, using the stored idSave value. + +void Particle::setParticlePtr() { + + particlePtr = ParticleDataTable::particleDataPtr(idSave); + +} + +//********* + +// Invariant mass of a pair and its square. +// (Not part of class proper, but tightly linked.) + +double m(const Particle& pp1, const Particle& pp2) { + double m2 = pow2(pp1.e() + pp2.e()) - pow2(pp1.px() + pp2.px()) + - pow2(pp1.py() + pp2.py()) - pow2(pp1.pz() + pp2.pz()); + return (m2 > 0. ? sqrt(m2) : 0.); +} + +double m2(const Particle& pp1, const Particle& pp2) { + double m2 = pow2(pp1.e() + pp2.e()) - pow2(pp1.px() + pp2.px()) + - pow2(pp1.py() + pp2.py()) - pow2(pp1.pz() + pp2.pz()); + return m2; +} + +//************************************************************************** + +// Event class. +// This class holds info on the complete event record. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Maxmimum number of mothers or daughter indices per line in listing. +const int Event::IPERLINE = 20; + +//********* + +// Copy all information from one event record to another. + +Event& Event::operator=( const Event& oldEvent) { + + // Do not copy if same. + if (this != &oldEvent) { + + // Reset all current info in the event. + clear(); + + // Copy all the particles one by one. + for (int i = 0; i < oldEvent.size(); ++i) append( oldEvent[i] ); + + // Copy all the junctions one by one. + for (int i = 0; i < oldEvent.sizeJunction(); ++i) + appendJunction( oldEvent.getJunction(i) ); + + // Copy values in the system arrays. + for (int i = 0; i < int(oldEvent.beginSys.size()); ++i) + beginSys.push_back( oldEvent.beginSys[i] ); + for (int i = 0; i < int(oldEvent.sizeSys.size()); ++i) + sizeSys.push_back( oldEvent.sizeSys[i] ); + for (int i = 0; i < int(oldEvent.memberSys.size()); ++i) + memberSys.push_back( oldEvent.memberSys[i] ); + + // Copy all other values. + startColTag = oldEvent.startColTag; + maxColTag = oldEvent.maxColTag; + savedSize = oldEvent.savedSize; + savedJunctionSize = oldEvent.savedJunctionSize; + scaleSave = oldEvent.scaleSave; + scaleSecondSave = oldEvent.scaleSecondSave; + headerList = oldEvent.headerList; + + // Done. + } + return *this; + +} + +//********* + +// Initialize colour and header specification for event listing. + +void Event::init( string headerIn) { + + // The starting colour tag for the event. + startColTag = Settings::mode("Event:startColTag"); + + // Set header specification for event listing. + headerList.replace(0, headerIn.length() + 2, headerIn + " "); + +} + +//********* + +// Add a copy of an existing particle at the end of the event record; +// return index. Three cases, depending on sign of new status code: +// Positive: copy is viewed as daughter, status of original is negated. +// Negative: copy is viewed as mother, status of original is unchanged. +// Zero: the new is a perfect carbon copy (maybe to be changed later). + +int Event::copy(int iCopy, int newStatus) { + + // Simple carbon copy. + entry.push_back(entry[iCopy]); + int iNew = entry.size() - 1; + + // Set up to make new daughter of old. + if (newStatus > 0) { + entry[iCopy].daughters(iNew,iNew); + entry[iCopy].statusNeg(); + entry[iNew].mothers(iCopy, iCopy); + entry[iNew].status(newStatus); + + // Set up to make new mother of old. + } else if (newStatus < 0) { + entry[iCopy].mothers(iNew,iNew); + entry[iNew].daughters(iCopy, iCopy); + entry[iNew].status(newStatus); + } + + // Done. + return iNew; + +} + +//********* + +// Print an event. + +void Event::list(bool showScaleAndVertex, bool showMothersAndDaughters, + ostream& os) { + + // Header. + os << "\n -------- PYTHIA Event Listing " << headerList << "----------" + << "------------------------------------------------- \n \n no " + << " id name status mothers daughters colou" + << "rs p_x p_y p_z e m \n"; + if (showScaleAndVertex) + os << " scale " + << " xProd yProd zProd tProd " + << " tau\n"; + + // At high energy switch to scientific format for momenta. + bool useFixed = (entry[0].e() < 1e5); + + // Listing of complete event. + Vec4 pSum; + double chargeSum = 0.; + for (int i = 0; i < int(entry.size()); ++i) { + const Particle& pt = entry[i]; + + // Basic line for a particle, always printed. + os << setw(6) << i << setw(10) << pt.id() << " " << left + << setw(18) << pt.nameWithStatus(18) << right << setw(4) + << pt.status() << setw(6) << pt.mother1() << setw(6) + << pt.mother2() << setw(6) << pt.daughter1() << setw(6) + << pt.daughter2() << setw(6) << pt.col() << setw(6) << pt.acol() + << ( (useFixed) ? fixed : scientific ) << setprecision(3) + << setw(11) << pt.px() << setw(11) << pt.py() << setw(11) + << pt.pz() << setw(11) << pt.e() << setw(11) << pt.m() << "\n"; + + // Optional extra line for scale value and production vertex. + if (showScaleAndVertex) + os << " " << setw(11) << pt.scale() + << " " << scientific + << setprecision(3) << setw(11) << pt.xProd() << setw(11) + << pt.yProd() << setw(11) << pt.zProd() << setw(11) + << pt.tProd() << setw(11) << pt.tau() << "\n"; + + // Optional extra line, giving a complete list of mothers and daughters. + if (showMothersAndDaughters) { + int linefill = 2; + os << " mothers:"; + vector allMothers = motherList(i); + for (int j = 0; j < int(allMothers.size()); ++j) { + os << " " << allMothers[j]; + if (++linefill == IPERLINE) {os << "\n "; linefill = 0;} + } + os << "; daughters:"; + vector allDaughters = daughterList(i); + for (int j = 0; j < int(allDaughters.size()); ++j) { + os << " " << allDaughters[j]; + if (++linefill == IPERLINE) {os << "\n "; linefill = 0;} + } + if (linefill !=0) os << "\n"; + } + + // Statistics on momentum and charge. + if (entry[i].status() > 0) { + pSum += entry[i].p(); + chargeSum += entry[i].charge(); + } + } + + // Line with sum charge, momentum, energy and invariant mass. + os << fixed << setprecision(3) << " " + << "Charge sum:" << setw(7) << chargeSum << " Momentum sum:" + << ( (useFixed) ? fixed : scientific ) << setprecision(3) + << setw(11) << pSum.px() << setw(11) << pSum.py() << setw(11) + << pSum.pz() << setw(11) << pSum.e() << setw(11) << pSum.mCalc() + << "\n"; + + // Listing finished. + os << "\n -------- End PYTHIA Event Listing ----------------------------" + << "-------------------------------------------------------------------" + << endl; +} + +//********* + +// Find complete list of mothers. + +vector Event::motherList(int i) const { + + // Vector of all the mothers; created empty. + vector mothers; + + // Read out the two official mother indices and status code. + int mother1 = entry[i].mother1(); + int mother2 = entry[i].mother2(); + int statusAbs = entry[i].statusAbs(); + + // Special cases in the beginning, where the meaning of zero is unclear. + if (statusAbs == 11 || statusAbs == 12) ; + else if (mother1 == 0 && mother2 == 0) mothers.push_back(0); + + // One mother or a carbon copy + else if (mother2 == 0 || mother2 == mother1) mothers.push_back(mother1); + + // A range of mothers from string fragmentation. + else if ( statusAbs > 80 && statusAbs < 90) + for (int iRange = mother1; iRange <= mother2; ++iRange) + mothers.push_back(iRange); + + // Two separate mothers. + else { + mothers.push_back( min(mother1, mother2) ); + mothers.push_back( max(mother1, mother2) ); + } + + // Done. + return mothers; + +} + +//********* + +// Find complete list of daughters. + +vector Event::daughterList(int i) const { + + // Vector of all the daughters; created empty. + vector daughters; + + // Read out the two official daughter indices. + int daughter1 = entry[i].daughter1(); + int daughter2 = entry[i].daughter2(); + + // Simple cases: no or one daughter. + if (daughter1 == 0 && daughter2 == 0) ; + else if (daughter2 == 0 || daughter2 == daughter1) + daughters.push_back(daughter1); + + // A range of daughters. + else if (daughter2 > daughter1) + for (int iRange = daughter1; iRange <= daughter2; ++iRange) + daughters.push_back(iRange); + + // Two separated daughters. + else { + daughters.push_back(daughter2); + daughters.push_back(daughter1); + } + + // Special case for two incoming beams: attach further + // initiators and remnants that have beam as mother. + if (entry[i].statusAbs() == 12 || entry[i].statusAbs() == 13) + for (int iDau = 3; iDau < size(); ++iDau) + if (entry[iDau].mother1() == i) { + bool isIn = false; + for (int iIn = 0; iIn < int(daughters.size()); ++iIn) + if (iDau == daughters[iIn]) isIn = true; + if (!isIn) daughters.push_back(iDau); + } + + // Done. + return daughters; + +} + +//********* + +// Trace the first and last copy of one and the same particle. + +int Event::iTopCopy( int i) const { + + int iUp = i; + while ( iUp > 0 && entry[iUp].mother2() == entry[iUp].mother1() + && entry[iUp].mother1() > 0) iUp = entry[iUp].mother1(); + return iUp; + +} + +int Event::iBotCopy( int i) const { + + int iDn = i; + while ( iDn > 0 && entry[iDn].daughter2() == entry[iDn].daughter1() + && entry[iDn].daughter1() > 0) iDn = entry[iDn].daughter1(); + return iDn; + +} + +//********* + +// Trace the first and last copy of one and the same particle, +// also through shower branchings, making use of flavour matches. +// Stops tracing when this gives ambiguities. + +int Event::iTopCopyId( int i) const { + + int id = entry[i].id(); + int iUp = i; + for ( ; ; ) { + int mother1 = entry[iUp].mother1(); + int id1 = (mother1 > 0) ? entry[mother1].id() : 0; + int mother2 = entry[iUp].mother2(); + int id2 = (mother2 > 0) ? entry[mother2].id() : 0; + if (mother2 != mother1 && id2 == id1) break; + if (id1 == id) { + iUp = mother1; + continue; + } + if (id2 == id) { + iUp = mother2; + continue; + } + break; + } + return iUp; + +} + +int Event::iBotCopyId( int i) const { + + int id = entry[i].id(); + int iDn = i; + for ( ; ; ) { + int daughter1 = entry[iDn].daughter1(); + int id1 = (daughter1 > 0) ? entry[daughter1].id() : 0; + int daughter2 = entry[iDn].daughter2(); + int id2 = (daughter2 > 0) ? entry[daughter2].id() : 0; + if (daughter2 != daughter1 && id2 == id1) break; + if (id1 == id) { + iDn = daughter1; + continue; + } + if (id2 == id) { + iDn = daughter2; + continue; + } + break; + } + return iDn; + +} + +//********* + +// Find complete list of sisters. + +vector Event::sisterList(int i) const { + + // Vector of all the sisters; created empty. + vector sisters; + if (entry[i].statusAbs() == 11) return sisters; + + // Find mother and all its daughters. + int iMother = entry[i].mother1(); + vector daughters = daughterList(iMother); + + // Copy all daughters, excepting the input particle itself. + for (int j = 0; j < int(daughters.size()); ++j) + if (daughters[j] != i) sisters.push_back( daughters[j] ); + + // Done. + return sisters; + +} + +//********* + +// Find complete list of sisters. Traces up with iTopCopy and +// down with iBotCopy to give sisters at same level of evolution. +// Should this not give any final particles, the search is widened. + +vector Event::sisterListTopBot(int i, bool widenSearch) const { + + // Vector of all the sisters; created empty. + vector sisters; + if (entry[i].statusAbs() == 11) return sisters; + + // Trace up to first copy of current particle. + int iUp = iTopCopy(i); + + // Find mother and all its daughters. + int iMother = entry[iUp].mother1(); + vector daughters = daughterList(iMother); + + // Trace all daughters down, excepting the input particle itself. + for (int jD = 0; jD < int(daughters.size()); ++jD) + if (daughters[jD] != iUp) + sisters.push_back( iBotCopy( daughters[jD] ) ); + + // Prune any non-final particles from list. + int jP = 0; + while (jP < int(sisters.size())) { + if (entry[sisters[jP]].status() > 0) ++jP; + else { + sisters[jP] = sisters.back(); + sisters.pop_back(); + } + } + + // If empty list then restore immediate daughters. + if (sisters.size() == 0 && widenSearch) { + for (int jR = 0; jR < int(daughters.size()); ++jR) + if (daughters[jR] != iUp) + sisters.push_back( iBotCopy( daughters[jR] ) ); + + // Then trace all daughters, not only bottom copy. + for (int jT = 0; jT < int(sisters.size()); ++jT) { + daughters = daughterList( sisters[jT] ); + for (int k = 0; k < int(daughters.size()); ++k) + sisters.push_back( daughters[k] ); + } + + // And then prune any non-final particles from list. + int jN = 0; + while (jN < int(sisters.size())) { + if (entry[sisters[jN]].status() > 0) ++jN; + else { + sisters[jN] = sisters.back(); + sisters.pop_back(); + } + } + } + + // Done. + return sisters; + +} + +//********* + +// Check whether a given particle is an arbitrarily-steps-removed +// mother to another. For the parton -> hadron transition, only +// first-rank hadrons are associated with the respective end quark. + +bool Event::isAncestor(int i, int iAncestor) const { + + // Begin loop to trace upwards from the daughter. + int iUp = i; + for ( ; ; ) { + + // If positive match then done. + if (iUp == iAncestor) return true; + + // If out of range then failed to find match. + if (iUp <= 0 || iUp > size()) return false; + + // If unique mother then keep on moving up the chain. + int mother1 = entry[iUp].mother1(); + int mother2 = entry[iUp].mother2(); + if (mother2 == mother1 || mother2 == 0) {iUp = mother1; continue;} + + // If many mothers, except hadronization, then fail tracing. + int status = entry[iUp].statusAbs(); + if (status < 81 || status > 86) return false; + + // For hadronization step, fail if not first rank, else move up. + if (status == 82) { + iUp = (iUp + 1 < size() && entry[iUp + 1].mother1() == mother1) + ? mother1 : mother2; continue; + } + if (status == 83) { + if (entry[iUp - 1].mother1() == mother1) return false; + iUp = mother1; continue; + } + if (status == 84) { + if (iUp + 1 < size() && entry[iUp + 1].mother1() == mother1) + return false; + iUp = mother1; continue; + } + + // Fail for ministring -> one hadron and for junctions. + return false; + + } + // End of loop. Should never reach beyond here. + return false; + +} + +//********* + +// Erase junction stored in specified slot and move up the ones under. + +void Event::eraseJunction(int i) { + + for (int j = i; j < int(junction.size()) - 1; ++j) + junction[j] = junction[j + 1]; + junction.pop_back(); + +} + +//********* + +// Print the junctions in an event. + +void Event::listJunctions(ostream& os) const { + + // Header. + os << "\n -------- PYTHIA Junction Listing " + << headerList.substr(0,30) << "\n \n no kind col0 col1 col2 " + << "endc0 endc1 endc2 stat0 stat1 stat2\n"; + + // Loop through junctions in event and list them. + for (int i = 0; i < sizeJunction(); ++i) + os << setw(6) << i << setw(6) << kindJunction(i) << setw(6) + << colJunction(i, 0) << setw(6) << colJunction(i, 1) << setw(6) + << colJunction(i, 2) << setw(6) << endColJunction(i, 0) << setw(6) + << endColJunction(i, 1) << setw(6) << endColJunction(i, 2) << setw(6) + << statusJunction(i, 0) << setw(6) << statusJunction(i, 1) << setw(6) + << statusJunction(i, 2) << "\n"; + + // Alternative if no junctions. Listing finished. + if (sizeJunction() == 0) os << " no junctions present \n"; + os << "\n -------- End PYTHIA Junction Listing --------------------" + << "------" << endl; +} + +//********* + +// Add parton to system, by shifting everything below to make room. + +void Event::addToSystem(int iSys, int iPos) { + + int newPos = beginSys[iSys] + sizeSys[iSys]; + memberSys.push_back(0); + for (int i = int(memberSys.size()) - 2; i >= newPos; --i) + memberSys[i+1] = memberSys[i]; + memberSys[newPos] = iPos; + ++sizeSys[iSys]; + for (int i = iSys + 1; i < int(beginSys.size()); ++i) ++beginSys[i]; + +} + +//********* + +// Replace existing value by new one in given system but unknown member. + +void Event::replaceInSystem(int iSys, int iPosOld, int iPosNew) { + + for (int i = beginSys[iSys]; i < beginSys[iSys] + sizeSys[iSys]; ++i) + if (memberSys[i] == iPosOld) memberSys[i] = iPosNew; + +} + +//********* + +// Print members in systems; for debug mainly. + +void Event::listSystems(ostream& os) const { + + + // Header. + os << "\n -------- PYTHIA Systems Listing " << headerList + << "------------ \n \n no members \n"; + + // Loop over system list and over members in each system. + for (int iSys = 0; iSys < int(beginSys.size()); ++iSys) { + os << " " << setw(5) << iSys << " "; + for (int iMem = 0; iMem < sizeSys[iSys]; ++iMem) { + if (iMem%16 == 0 && iMem > 0) os << "\n "; + os << " " << setw(4) << memberSys[beginSys[iSys] + iMem]; + } + os << "\n"; + } + + // Alternative if no systems. Done. + if (beginSys.size() == 0) os << " no systems defined \n"; + os << "\n -------- End PYTHIA Systems Listing ----------------------" + << "--------------------------" << endl; + +} + +//********* + +// Operator overloading allows to append one event to an existing one. + +Event& Event::operator+=( const Event& addEvent) { + + // Find offsets. One less since won't copy line 0. + int offsetIdx = entry.size() - 1; + int offsetCol = maxColTag; + + // Add energy to zeroth line and calculate new invariant mass. + entry[0].p( entry[0].p() + addEvent[0].p() ); + entry[0].m( entry[0].mCalc() ); + + // Read out particles from line 1 (not 0) onwards. + Particle temp; + for (int i = 1; i < addEvent.size(); ++i) { + temp = addEvent[i]; + + // Add offset to nonzero mother, daughter and colour indices. + if (temp.mother1() > 0) temp.mother1( temp.mother1() + offsetIdx ); + if (temp.mother2() > 0) temp.mother2( temp.mother2() + offsetIdx ); + if (temp.daughter1() > 0) temp.daughter1( temp.daughter1() + offsetIdx ); + if (temp.daughter2() > 0) temp.daughter2( temp.daughter2() + offsetIdx ); + if (temp.col() > 0) temp.col( temp.col() + offsetCol ); + if (temp.acol() > 0) temp.acol( temp.acol() + offsetCol ); + + // Append particle to summed event. + append( temp ); + } + + // Read out junctions one by one. + Junction tempJ; + int begCol, endCol; + for (int i = 0; i < addEvent.sizeJunction(); ++i) { + tempJ = addEvent.getJunction(i); + + // Add colour offsets to all three legs. + for (int j = 0; j < 3; ++j) { + begCol = tempJ.col(j); + endCol = tempJ.endCol(j); + if (begCol > 0) begCol += offsetCol; + if (endCol > 0) endCol += offsetCol; + tempJ.cols( j, begCol, endCol); + } + + // Append junction to summed event. + appendJunction( tempJ ); + } + + // Read out systems one by one. Append new system to event. + for (int i = 0; i < addEvent.sizeSystems(); ++i) { + int iNew = newSystem(); + + // Append members in system, with offset. + for (int j = 0; j < addEvent.sizeSystem(i); ++j) + addToSystem( iNew, addEvent.getInSystem( i, j) + offsetIdx ); + } + + // Set header that indicates character as sum of events. + headerList = "(combination of several events) -------"; + + // Done. + return *this; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/FragmentationFlavZpT.cxx b/PYTHIA8/pythia8130/src/FragmentationFlavZpT.cxx new file mode 100644 index 00000000000..cddb51fc586 --- /dev/null +++ b/PYTHIA8/pythia8130/src/FragmentationFlavZpT.cxx @@ -0,0 +1,748 @@ +// FragmentationFlavZpT.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// StringFlav, StringZ and StringPT classes. + +#include "FragmentationFlavZpT.h" + +namespace Pythia8 { + +//************************************************************************** + +// The StringFlav class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Offset for different meson multiplet id values. +const int StringFlav::mesonMultipletCode[6] + = { 1, 3, 10003, 10001, 20003, 5}; + +// Clebsch-Gordan coefficients for baryon octet and decuplet are +// fixed once and for all, so only weighted sum needs to be edited. +// Order: ud0 + u, ud0 + s, uu1 + u, uu1 + d, ud1 + u, ud1 + s. +const double StringFlav::baryonCGOct[6] + = { 0.75, 0.5, 0., 0.1667, 0.0833, 0.1667}; +const double StringFlav::baryonCGDec[6] + = { 0., 0., 1., 0.3333, 0.6667, 0.3333}; + +//********* + +// Initialize data members of the flavour generation. + +void StringFlav::init() { + + // Basic parameters for generation of new flavour. + probQQtoQ = Settings::parm("StringFlav:probQQtoQ"); + probStoUD = Settings::parm("StringFlav:probStoUD"); + probSQtoQQ = Settings::parm("StringFlav:probSQtoQQ"); + probQQ1toQQ0 = Settings::parm("StringFlav:probQQ1toQQ0"); + + // Parameters derived from above. + probQandQQ = 1. + probQQtoQ; + probQandS = 2. + probStoUD; + probQandSinQQ = 2. + probSQtoQQ * probStoUD; + probQQ1corr = 3. * probQQ1toQQ0; + probQQ1corrInv = 1. / probQQ1corr; + probQQ1norm = probQQ1corr / (1. + probQQ1corr); + + // Parameters for normal meson production. + for (int i = 0; i < 4; ++i) mesonRate[i][0] = 1.; + mesonRate[0][1] = Settings::parm("StringFlav:mesonUDvector"); + mesonRate[1][1] = Settings::parm("StringFlav:mesonSvector"); + mesonRate[2][1] = Settings::parm("StringFlav:mesonCvector"); + mesonRate[3][1] = Settings::parm("StringFlav:mesonBvector"); + + // Parameters for L=1 excited-meson production. + mesonRate[0][2] = Settings::parm("StringFlav:mesonUDL1S0J1"); + mesonRate[1][2] = Settings::parm("StringFlav:mesonSL1S0J1"); + mesonRate[2][2] = Settings::parm("StringFlav:mesonCL1S0J1"); + mesonRate[3][2] = Settings::parm("StringFlav:mesonBL1S0J1"); + mesonRate[0][3] = Settings::parm("StringFlav:mesonUDL1S1J0"); + mesonRate[1][3] = Settings::parm("StringFlav:mesonSL1S1J0"); + mesonRate[2][3] = Settings::parm("StringFlav:mesonCL1S1J0"); + mesonRate[3][3] = Settings::parm("StringFlav:mesonBL1S1J0"); + mesonRate[0][4] = Settings::parm("StringFlav:mesonUDL1S1J1"); + mesonRate[1][4] = Settings::parm("StringFlav:mesonSL1S1J1"); + mesonRate[2][4] = Settings::parm("StringFlav:mesonCL1S1J1"); + mesonRate[3][4] = Settings::parm("StringFlav:mesonBL1S1J1"); + mesonRate[0][5] = Settings::parm("StringFlav:mesonUDL1S1J2"); + mesonRate[1][5] = Settings::parm("StringFlav:mesonSL1S1J2"); + mesonRate[2][5] = Settings::parm("StringFlav:mesonCL1S1J2"); + mesonRate[3][5] = Settings::parm("StringFlav:mesonBL1S1J2"); + + // Store sum over multiplets for Monte Carlo generation. + for (int i = 0; i < 4; ++i) mesonRateSum[i] + = mesonRate[i][0] + mesonRate[i][1] + mesonRate[i][2] + + mesonRate[i][3] + mesonRate[i][4] + mesonRate[i][5]; + + // Parameters for uubar - ddbar - ssbar meson mixing. + for (int spin = 0; spin < 6; ++spin) { + double theta; + if (spin == 0) theta = Settings::parm("StringFlav:thetaPS"); + else if (spin == 1) theta = Settings::parm("StringFlav:thetaV"); + else if (spin == 2) theta = Settings::parm("StringFlav:thetaL1S0J1"); + else if (spin == 3) theta = Settings::parm("StringFlav:thetaL1S1J0"); + else if (spin == 4) theta = Settings::parm("StringFlav:thetaL1S1J1"); + else theta = Settings::parm("StringFlav:thetaL1S1J2"); + double alpha = (spin == 0) ? 90. - (theta + 54.7) : theta + 54.7; + alpha *= M_PI / 180.; + // Fill in (flavour, spin)-dependent probability of producing + // the lightest or the lightest two mesons of the nonet. + mesonMix1[0][spin] = 0.5; + mesonMix2[0][spin] = 0.5 * (1. + pow2(sin(alpha))); + mesonMix1[1][spin] = 0.; + mesonMix2[1][spin] = pow2(cos(alpha)); + } + + // Additional suppression of eta and etaPrime. + etaSup = Settings::parm("StringFlav:etaSup"); + etaPrimeSup = Settings::parm("StringFlav:etaPrimeSup"); + + // Sum of baryon octet and decuplet weights. + decupletSup = Settings::parm("StringFlav:decupletSup"); + for (int i = 0; i < 6; ++i) baryonCGSum[i] + = baryonCGOct[i] + decupletSup * baryonCGDec[i]; + + // Maximum SU(6) weight for ud0, ud1, uu1 types. + baryonCGMax[0] = max( baryonCGSum[0], baryonCGSum[1]); + baryonCGMax[1] = baryonCGMax[0]; + baryonCGMax[2] = max( baryonCGSum[2], baryonCGSum[3]); + baryonCGMax[3] = baryonCGMax[2]; + baryonCGMax[4] = max( baryonCGSum[4], baryonCGSum[5]); + baryonCGMax[5] = baryonCGMax[4]; + + // Popcorn baryon parameters. + popcornRate = Settings::parm("StringFlav:popcornRate"); + popcornSpair = Settings::parm("StringFlav:popcornSpair"); + popcornSmeson = Settings::parm("StringFlav:popcornSmeson"); + + // Suppression of leading (= first-rank) baryons. + suppressLeadingB = Settings::flag("StringFlav:suppressLeadingB"); + lightLeadingBSup = Settings::parm("StringFlav:lightLeadingBSup"); + heavyLeadingBSup = Settings::parm("StringFlav:heavyLeadingBSup"); + + // Begin calculation of derived parameters for baryon production. + + // Enumerate distinguishable diquark types (in diquark first is popcorn q). + enum Diquark {ud0, ud1, uu1, us0, su0, us1, su1, ss1}; + + // Maximum SU(6) weight by diquark type. + double barCGMax[8]; + barCGMax[ud0] = baryonCGMax[0]; + barCGMax[ud1] = baryonCGMax[4]; + barCGMax[uu1] = baryonCGMax[2]; + barCGMax[us0] = baryonCGMax[0]; + barCGMax[su0] = baryonCGMax[0]; + barCGMax[us1] = baryonCGMax[4]; + barCGMax[su1] = baryonCGMax[4]; + barCGMax[ss1] = baryonCGMax[2]; + + // Diquark SU(6) survival = Sum_quark (quark tunnel weight) * SU(6). + double dMB[8]; + dMB[ud0] = 2. * baryonCGSum[0] + probStoUD * baryonCGSum[1]; + dMB[ud1] = 2. * baryonCGSum[4] + probStoUD * baryonCGSum[5]; + dMB[uu1] = baryonCGSum[2] + (1. + probStoUD) * baryonCGSum[3]; + dMB[us0] = (1. + probStoUD) * baryonCGSum[0] + baryonCGSum[1]; + dMB[su0] = dMB[us0]; + dMB[us1] = (1. + probStoUD) * baryonCGSum[4] + baryonCGSum[5]; + dMB[su1] = dMB[us1]; + dMB[ss1] = probStoUD * baryonCGSum[2] + 2. * baryonCGSum[3]; + for (int i = 1; i < 8; ++i) dMB[i] = dMB[i] / dMB[0]; + + // Tunneling factors for diquark production; only half a pair = sqrt. + double probStoUDroot = sqrt(probStoUD); + double probSQtoQQroot = sqrt(probSQtoQQ); + double probQQ1toQQ0root = sqrt(probQQ1toQQ0); + double qBB[8]; + qBB[ud1] = probQQ1toQQ0root; + qBB[uu1] = probQQ1toQQ0root; + qBB[us0] = probSQtoQQroot; + qBB[su0] = probStoUDroot * probSQtoQQroot; + qBB[us1] = probQQ1toQQ0root * qBB[us0]; + qBB[su1] = probQQ1toQQ0root * qBB[su0]; + qBB[ss1] = probStoUDroot * pow2(probSQtoQQroot) * probQQ1toQQ0root; + + // spin * (vertex factor) * (half-tunneling factor above). + double qBM[8]; + qBM[ud1] = 3. * qBB[ud1]; + qBM[uu1] = 6. * qBB[uu1]; + qBM[us0] = probStoUD * qBB[us0]; + qBM[su0] = qBB[su0]; + qBM[us1] = probStoUD * 3. * qBB[us1]; + qBM[su1] = 3. * qBB[su1]; + qBM[ss1] = probStoUD * 6. * qBB[ss1]; + + // Combine above two into total diquark weight for q -> B Bbar. + for (int i = 1; i < 8; ++i) qBB[i] = qBB[i] * qBM[i]; + + // Suppression from having strange popcorn meson. + qBM[us0] *= popcornSmeson; + qBM[us1] *= popcornSmeson; + qBM[ss1] *= popcornSmeson; + + // Suppression for a heavy quark of a diquark to fit into a baryon + // on the other side of popcorn meson: (0) s/u for q -> B M; + // (1) s/u for rank 0 diquark su -> M B; (2) ditto for s -> c/b. + double uNorm = 1. + qBM[ud1] + qBM[uu1] + qBM[us0] + qBM[us1]; + scbBM[0] = (2. * (qBM[su0] + qBM[su1]) + qBM[ss1]) / uNorm; + scbBM[1] = scbBM[0] * popcornSpair * qBM[su0] / qBM[us0]; + scbBM[2] = (1. + qBM[ud1]) * (2. + qBM[us0]) / uNorm; + + // Include maximum of Clebsch-Gordan coefficients. + for (int i = 1; i < 8; ++i) dMB[i] *= qBM[i]; + for (int i = 1; i < 8; ++i) qBM[i] *= barCGMax[i] / barCGMax[0]; + for (int i = 1; i < 8; ++i) qBB[i] *= barCGMax[i] / barCGMax[0]; + + // Popcorn fraction for normal diquark production. + double qNorm = uNorm * popcornRate / 3.; + double sNorm = scbBM[0] * popcornSpair; + popFrac = qNorm * (1. + qBM[ud1] + qBM[uu1] + qBM[us0] + qBM[us1] + + sNorm * (qBM[su0] + qBM[su1] + 0.5 * qBM[ss1])) / (1. + qBB[ud1] + + qBB[uu1] + 2. * (qBB[us0] + qBB[us1]) + 0.5 * qBB[ss1]); + + // Popcorn fraction for rank 0 diquarks, depending on number of s quarks. + popS[0] = qNorm * qBM[ud1] / qBB[ud1]; + popS[1] = qNorm * 0.5 * (qBM[us1] / qBB[us1] + + sNorm * qBM[su1] / qBB[su1]); + popS[2] = qNorm * sNorm * qBM[ss1] / qBB[ss1]; + + // Recombine diquark weights to flavour and spin ratios. Second index: + // 0 = s/u popcorn quark ratio. + // 1, 2 = s/u ratio for vertex quark if popcorn quark is u/d or s. + // 3 = q/q' vertex quark ratio if popcorn quark is light and = q. + // 4, 5, 6 = (spin 1)/(spin 0) ratio for su, us and ud. + + // Case 0: q -> B B. + dWT[0][0] = (2. * (qBB[su0] + qBB[su1]) + qBB[ss1]) + / (1. + qBB[ud1] + qBB[uu1] + qBB[us0] + qBB[us1]); + dWT[0][1] = 2. * (qBB[us0] + qBB[us1]) / (1. + qBB[ud1] + qBB[uu1]); + dWT[0][2] = qBB[ss1] / (qBB[su0] + qBB[su1]); + dWT[0][3] = qBB[uu1] / (1. + qBB[ud1] + qBB[uu1]); + dWT[0][4] = qBB[su1] / qBB[su0]; + dWT[0][5] = qBB[us1] / qBB[us0]; + dWT[0][6] = qBB[ud1]; + + // Case 1: q -> B M B. + dWT[1][0] = (2. * (qBM[su0] + qBM[su1]) + qBM[ss1]) + / (1. + qBM[ud1] + qBM[uu1] + qBM[us0] + qBM[us1]); + dWT[1][1] = 2. * (qBM[us0] + qBM[us1]) / (1. + qBM[ud1] + qBM[uu1]); + dWT[1][2] = qBM[ss1] / (qBM[su0] + qBM[su1]); + dWT[1][3] = qBM[uu1] / (1. + qBM[ud1] + qBM[uu1]); + dWT[1][4] = qBM[su1] / qBM[su0]; + dWT[1][5] = qBM[us1] / qBM[us0]; + dWT[1][6] = qBM[ud1]; + + // Case 2: qq -> M B; diquark inside chain. + dWT[2][0] = (2. * (dMB[su0] + dMB[su1]) + dMB[ss1]) + / (1. + dMB[ud1] + dMB[uu1] + dMB[us0] + dMB[us1]); + dWT[2][1] = 2. * (dMB[us0] + dMB[us1]) / (1. + dMB[ud1] + dMB[uu1]); + dWT[2][2] = dMB[ss1] / (dMB[su0] + dMB[su1]); + dWT[2][3] = dMB[uu1] / (1. + dMB[ud1] + dMB[uu1]); + dWT[2][4] = dMB[su1] / dMB[su0]; + dWT[2][5] = dMB[us1] / dMB[us0]; + dWT[2][6] = dMB[ud1]; + +} + +//********* + +// Pick a new flavour (including diquarks) given an incoming one. + +FlavContainer StringFlav::pick(FlavContainer& flavOld) { + + // Initial values for new flavour. + FlavContainer flavNew; + flavNew.rank = flavOld.rank + 1; + + // For original diquark assign popcorn quark and whether popcorn meson. + int idOld = abs(flavOld.id); + if (flavOld.rank == 0 && idOld > 1000) assignPopQ(flavOld); + + // Diquark exists, to be forced into baryon now. + bool doOldBaryon = (idOld > 1000 && flavOld.nPop == 0); + // Diquark exists, but do meson now. + bool doPopcornMeson = flavOld.nPop > 0; + // Newly created diquark gives baryon now, antibaryon later. + bool doNewBaryon = false; + + // Choose whether to generate a new meson or a new baryon. + if (!doOldBaryon && !doPopcornMeson && probQandQQ * Rndm::flat() > 1.) { + doNewBaryon = true; + if ((1. + popFrac) * Rndm::flat() > 1.) flavNew.nPop = 1; + } + + // Optional suppression of first-rank baryon. + if (flavOld.rank == 0 && doNewBaryon && suppressLeadingB) { + double leadingBSup = (idOld < 4) ? lightLeadingBSup : heavyLeadingBSup; + if (Rndm::flat() > leadingBSup) { + doNewBaryon = false; + flavNew.nPop = 0; + } + } + + // Single quark for new meson or for baryon where diquark already exists. + if (!doPopcornMeson && !doNewBaryon) { + flavNew.id = pickLightQ(); + if ( (flavOld.id > 0 && flavOld.id < 9) || flavOld.id < -1000 ) + flavNew.id = -flavNew.id; + + // Done for simple-quark case. + return flavNew; + } + + // Case: 0 = q -> B B, 1 = q -> B M B, 2 = qq -> M B. + int iCase = flavNew.nPop; + if (flavOld.nPop == 1) iCase = 2; + + // Flavour of popcorn quark (= q shared between B and Bbar). + if (doNewBaryon) { + double sPopWT = dWT[iCase][0]; + if (iCase == 1) sPopWT *= scbBM[0] * popcornSpair; + double rndmFlav = (2. + sPopWT) * Rndm::flat(); + flavNew.idPop = 1; + if (rndmFlav > 1.) flavNew.idPop = 2; + if (rndmFlav > 2.) flavNew.idPop = 3; + } else flavNew.idPop = flavOld.idPop; + + // Flavour of vertex quark. + double sVtxWT = dWT[iCase][1]; + if (flavNew.idPop >= 3) sVtxWT = dWT[iCase][2]; + if (flavNew.idPop > 3) sVtxWT *= 0.5 * (1. + 1./dWT[iCase][4]); + double rndmFlav = (2. + sVtxWT) * Rndm::flat(); + flavNew.idVtx = 1; + if (rndmFlav > 1.) flavNew.idVtx = 2; + if (rndmFlav > 2.) flavNew.idVtx = 3; + + // Special case for light flavours, possibly identical. + if (flavNew.idPop < 3 && flavNew.idVtx < 3) { + flavNew.idVtx = flavNew.idPop; + if (Rndm::flat() > dWT[iCase][3]) flavNew.idVtx = 3 - flavNew.idPop; + } + + // Pick 2 * spin + 1. + int spin = 3; + if (flavNew.idVtx != flavNew.idPop) { + double spinWT = dWT[iCase][6]; + if (flavNew.idVtx == 3) spinWT = dWT[iCase][5]; + if (flavNew.idPop >= 3) spinWT = dWT[iCase][4]; + if ((1. + spinWT) * Rndm::flat() < 1.) spin = 1; + } + + // Form outgoing diquark. Done. + flavNew.id = 1000 * max(flavNew.idVtx, flavNew.idPop) + + 100 * min(flavNew.idVtx, flavNew.idPop) + spin; + if ( (flavOld.id < 0 && flavOld.id > -9) || flavOld.id > 1000 ) + flavNew.id = -flavNew.id; + return flavNew; + +} + +//********* + +// Combine two flavours (including diquarks) to produce a hadron. +// The weighting of the combination may fail, giving output 0. + +int StringFlav::combine(FlavContainer& flav1, FlavContainer& flav2) { + + // Recognize largest and smallest flavour. + int id1Abs = abs(flav1.id); + int id2Abs = abs(flav2.id); + int idMax = max(id1Abs, id2Abs); + int idMin = min(id1Abs, id2Abs); + + // Construct a meson. + if (idMax < 9 || idMin > 1000) { + + // Popcorn meson: use only vertex quarks. + if (idMin > 1000) { + id1Abs = flav1.idVtx; + id2Abs = flav2.idVtx; + idMax = max(id1Abs, id2Abs); + idMin = min(id1Abs, id2Abs); + } + + // Pick spin state and preliminary code. + int flav = (idMax < 3) ? 0 : idMax - 2; + double rndmSpin = mesonRateSum[flav] * Rndm::flat(); + int spin = -1; + do rndmSpin -= mesonRate[flav][++spin]; + while (rndmSpin > 0.); + int idMeson = 100 * idMax + 10 * idMin + mesonMultipletCode[spin]; + + // For nondiagonal mesons distinguish particle/antiparticle. + if (idMax != idMin) { + int sign = (idMax%2 == 0) ? 1 : -1; + if ( (idMax == id1Abs && flav1.id < 0) + || (idMax == id2Abs && flav2.id < 0) ) sign = -sign; + idMeson *= sign; + + // For light diagonal mesons include uubar - ddbar - ssbar mixing. + } else if (flav < 2) { + double rMix = Rndm::flat(); + if (rMix < mesonMix1[flav][spin]) idMeson = 110; + else if (rMix < mesonMix2[flav][spin]) idMeson = 220; + else idMeson = 330; + idMeson += mesonMultipletCode[spin]; + + // Additional suppression of eta and eta' may give failure. + if (idMeson == 221 && etaSup < Rndm::flat()) return 0; + if (idMeson == 331 && etaPrimeSup < Rndm::flat()) return 0; + } + + // Finished for mesons. + return idMeson; + } + + // SU(6) factors for baryon production may give failure. + int idQQ1 = idMax / 1000; + int idQQ2 = (idMax / 100) % 10; + int spinQQ = idMax % 10; + int spinFlav = spinQQ - 1; + if (spinFlav == 2 && idQQ1 != idQQ2) spinFlav = 4; + if (idMin != idQQ1 && idMin != idQQ2) spinFlav++; + if (baryonCGSum[spinFlav] < Rndm::flat() * baryonCGMax[spinFlav]) + return 0; + + // Order quarks to form baryon. Pick spin. + int idOrd1 = max( idMin, max( idQQ1, idQQ2) ); + int idOrd3 = min( idMin, min( idQQ1, idQQ2) ); + int idOrd2 = idMin + idQQ1 + idQQ2 - idOrd1 - idOrd3; + int spinBar = (baryonCGSum[spinFlav] * Rndm::flat() + < baryonCGOct[spinFlav]) ? 2 : 4; + + // Distinguish Lambda- and Sigma-like. + bool LambdaLike = false; + if (spinBar == 2 && idOrd1 > idOrd2 && idOrd2 > idOrd3) { + LambdaLike = (spinQQ == 1); + if (idOrd1 != idMin && spinQQ == 1) LambdaLike = (Rndm::flat() < 0.25); + else if (idOrd1 != idMin) LambdaLike = (Rndm::flat() < 0.75); + } + + // Form baryon code and return with sign. + int idBaryon = (LambdaLike) + ? 1000 * idOrd1 + 100 * idOrd3 + 10 * idOrd2 + spinBar + : 1000 * idOrd1 + 100 * idOrd2 + 10 * idOrd3 + spinBar; + return (flav1.id > 0) ? idBaryon : -idBaryon; + +} + +//********* + +// Assign popcorn quark inside an original (= rank 0) diquark. + +void StringFlav::assignPopQ(FlavContainer& flav) { + + // Safety check that intended to do something. + int idAbs = abs(flav.id); + if (flav.rank > 0 || idAbs < 1000) return; + + // Make choice of popcorn quark. + int id1 = (idAbs/1000)%10; + int id2 = (idAbs/100)%10; + double pop2WT = 1.; + if (id1 == 3) pop2WT = scbBM[1]; + else if (id1 > 3) pop2WT = scbBM[2]; + if (id2 == 3) pop2WT /= scbBM[1]; + else if (id2 > 3) pop2WT /= scbBM[2]; + // Agrees with Patrik code, but opposite to intention?? + flav.idPop = ((1. + pop2WT) * Rndm::flat() > 1.) ? id2 : id1; + flav.idVtx = id1 + id2 - flav.idPop; + + // Also determine if to produce popcorn meson. + flav.nPop = 0; + double popWT = popS[0]; + if (id1 == 3) popWT = popS[1]; + if (id2 == 3) popWT = popS[2]; + if (idAbs%10 == 1) popWT *= sqrt(probQQ1toQQ0); + if ((1. + popWT) * Rndm::flat() > 1.) flav.nPop = 1; + +} + +//********* + +// Combine two quarks to produce a diquark. +// Normally according to production composition, but nonvanishing idHad +// means diquark from known hadron content, so use SU(6) wave fucntion. + +int StringFlav::makeDiquark(int id1, int id2, int idHad) { + + // Initial values. + int idMin = min( abs(id1), abs(id2)); + int idMax = max( abs(id1), abs(id2)); + int spin = 1; + + // Select spin of diquark formed from two valence quarks in proton. + // (More hadron cases??) + if (abs(idHad) == 2212) { + if (idMin == 1 && idMax == 2 && Rndm::flat() < 0.75) spin = 0; + + // Else select spin of diquark according to production composition. + } else { + if (idMin != idMax && Rndm::flat() > probQQ1norm) spin = 0; + } + + // Combined diquark code. + int idNewAbs = 1000 * idMax + 100 * idMin + 2 * spin + 1; + return (id1 > 0) ? idNewAbs : -idNewAbs; + +} + +//************************************************************************** + +// The StringZ class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// When a or c are close to special cases, default to these. +const double StringZ::CFROMUNITY = 0.01; +const double StringZ::AFROMZERO = 0.02; +const double StringZ::AFROMC = 0.01; + +// Do not take exponent of too large or small number. +const double StringZ::EXPMAX = 50.; + +//********* + +// Initialize data members of the string z selection. + +void StringZ::init() { + + // c and b quark masses. + mc2 = pow2( ParticleDataTable::m0(4)); + mb2 = pow2( ParticleDataTable::m0(5)); + + // Paramaters of Lund/Bowler symmetric fragmentation function. + aLund = Settings::parm("StringZ:aLund"); + bLund = Settings::parm("StringZ:bLund"); + aExtraDiquark = Settings::parm("StringZ:aExtraDiquark"); + rFactC = Settings::parm("StringZ:rFactC"); + rFactB = Settings::parm("StringZ:rFactB"); + rFactH = Settings::parm("StringZ:rFactH"); + + // Flags and parameters of Peterson/SLAC fragmentation function. + usePetersonC = Settings::flag("StringZ:usePetersonC"); + usePetersonB = Settings::flag("StringZ:usePetersonB"); + usePetersonH = Settings::flag("StringZ:usePetersonH"); + epsilonC = Settings::parm("StringZ:epsilonC"); + epsilonB = Settings::parm("StringZ:epsilonB"); + epsilonH = Settings::parm("StringZ:epsilonH"); + +} + +//********* + +// Generate the fraction z that the next hadron will take, +// using either Lund/Bowler or, for heavy, Peterson/SLAC functions. +// Note: for a heavy new coloured particle we assume pT negligible. + +double StringZ::zFrag( int idOld, int idNew, double mT2) { + + // Find if old or new flavours correspond to diquarks. + int idOldAbs = abs(idOld); + int idNewAbs = abs(idNew); + bool isOldDiquark = (idOldAbs > 1000 && idOldAbs < 10000); + bool isNewDiquark = (idNewAbs > 1000 && idNewAbs < 10000); + + // Find heaviest quark in fragmenting parton/diquark. + int idFrag = idOldAbs; + if (isOldDiquark) idFrag = max( idOldAbs / 1000, (idOldAbs / 100) % 10); + + // Use Peterson where explicitly requested for heavy flavours. + if (idFrag == 4 && usePetersonC) return zPeterson( epsilonC); + if (idFrag == 5 && usePetersonB) return zPeterson( epsilonB); + if (idFrag > 5 && usePetersonH) { + double epsilon = epsilonH * mb2 / mT2; + return zPeterson( epsilon); + } + + // Shape parameters of Lund symmetric fragmentation function. + double aShape = aLund; + if (isOldDiquark) aShape += aExtraDiquark; + double bShape = bLund * mT2; + double cShape = 1.; + if (isOldDiquark) cShape -= aExtraDiquark; + if (isNewDiquark) cShape += aExtraDiquark; + if (idFrag == 4) cShape += rFactC * bLund * mc2; + if (idFrag == 5) cShape += rFactB * bLund * mb2; + if (idFrag > 5) cShape += rFactH * bLund * mT2; + return zLund( aShape, bShape, cShape); + +} + +//********* + +// Generate a random z according to the Lund/Bowler symmetric +// fragmentation function f(z) = (1 -z)^a * exp(-b/z) / z^c. +// Normalized so that f(z_max) = 1 it can also be written as +// f(z) = exp( a * ln( (1 - z) / (1 - z_max) ) + b * (1/z_max - 1/z) +// + c * ln(z_max/z) ). + +double StringZ::zLund( double a, double b, double c) { + + // Special cases for c = 1, a = 0 and a = c. + bool cIsUnity = (abs( c - 1.) < CFROMUNITY); + bool aIsZero = (a < AFROMZERO); + bool aIsC = (abs(a - c) < AFROMC); + + // Determine position of maximum. + double zMax; + if (aIsZero) zMax = (c > b) ? b / c : 1.; + else if (aIsC) zMax = b / (b + c); + else { zMax = 0.5 * (b + c - sqrt( pow2(b - c) + 4. * a * b)) / (c - a); + if (zMax > 0.9999 && b > 100.) zMax = min(zMax, 1. - a / b); } + + // Subdivide z range if distribution very peaked near either endpoint. + bool peakedNearZero = (zMax < 0.1); + bool peakedNearUnity = (zMax > 0.85 && b > 1.); + + // Find integral of trial function everywhere bigger than f. + // (Dummy start values.) + double fIntLow = 1.; + double fIntHigh = 1.; + double fInt = 2.; + double zDiv = 0.5; + double zDivC = 0.5; + // When z_max is small use that f(z) + // < 1 for z < z_div = 2.75 * z_max, + // < (z_div/z)^c for z > z_div (=> logarithm for c = 1, else power). + if (peakedNearZero) { + zDiv = 2.75 * zMax; + fIntLow = zDiv; + if (cIsUnity) fIntHigh = -zDiv * log(zDiv); + else { zDivC = pow( zDiv, 1. - c); + fIntHigh = zDiv * (1. - 1./zDivC) / (c - 1.);} + fInt = fIntLow + fIntHigh; + // When z_max large use that f(z) + // < exp( b * (z - z_div) ) for z < z_div with z_div messy expression, + // < 1 for z > z_div. + // To simplify expressions the integral is extended to z = -infinity. + } else if (peakedNearUnity) { + double rcb = sqrt(4. + pow2(c / b)); + zDiv = rcb - 1./zMax - (c / b) * log( zMax * 0.5 * (rcb + c / b) ); + if (!aIsZero) zDiv += (a/b) * log(1. - zMax); + zDiv = min( zMax, max(0., zDiv)); + fIntLow = 1. / b; + fIntHigh = 1. - zDiv; + fInt = fIntLow + fIntHigh; + } + + // Choice of z, preweighted for peaks at low or high z. (Dummy start values.) + double z = 0.5; + double fPrel = 1.; + double fVal = 1.; + do { + // Choice of z flat good enough for distribution peaked in the middle; + // if not this z can be reused as a random number in general. + z = Rndm::flat(); + fPrel = 1.; + // When z_max small use flat below z_div and 1/z^c above z_div. + if (peakedNearZero) { + if (fInt * Rndm::flat() < fIntLow) z = zDiv * z; + else if (cIsUnity) {z = pow( zDiv, z); fPrel = zDiv / z;} + else { z = pow( zDivC + (1. - zDivC) * z, 1. / (1. - c) ); + fPrel = pow( zDiv / z, c); } + // When z_max large use exp( b * (z -z_div) ) below z_div and flat above it. + } else if (peakedNearUnity) { + if (fInt * Rndm::flat() < fIntLow) { + z = zDiv + log(z) / b; + fPrel = exp( b * (z - zDiv) ); + } else z = zDiv + (1. - zDiv) * z; + } + + // Evaluate actual f(z) (if in physical range) and correct. + if (z > 0 && z < 1) { + double fExp = b * (1. / zMax - 1. / z)+ c * log(zMax / z); + if (!aIsZero) fExp += a * log( (1. - z) / (1. - zMax) ); + fVal = exp( max( -EXPMAX, min( EXPMAX, fExp) ) ) ; + } else fVal = 0.; + } while (fVal < Rndm::flat() * fPrel); + + // Done. + return z; + +} + +//********* + +// Generate a random z according to the Peterson/SLAC formula +// f(z) = 1 / ( z * (1 - 1/z - epsilon/(1-z))^2 ) +// = z * (1-z)^2 / ((1-z)^2 + epsilon * z)^2. + +double StringZ::zPeterson( double epsilon) { + + double z, fVal; + + // For large epsilon pick z flat and reject, + // knowing that 4 * epsilon * f(z) < 1 everywhere. + if (epsilon > 0.01) { + do { + z = Rndm::flat(); + fVal = 4. * epsilon * z * pow2(1. - z) + / pow2( pow2(1. - z) + epsilon * z); + } while (fVal < Rndm::flat()); + return z; + } + + // Else split range, using that 4 * epsilon * f(z) + // < 4 * epsilon / (1 - z)^2 for 0 < z < 1 - 2 * sqrt(epsilon) + // < 1 for 1 - 2 * sqrt(epsilon) < z < 1 + double epsRoot = sqrt(epsilon); + double epsComb = 0.5 / epsRoot - 1.; + double fIntLow = 4. * epsilon * epsComb; + double fInt = fIntLow + 2. * epsRoot; + do { + if (Rndm::flat() * fInt < fIntLow) { + z = 1. - 1. / (1. + Rndm::flat() * epsComb); + fVal = z * pow2( pow2(1. - z) / (pow2(1. - z) + epsilon * z) ); + } else { + z = 1. - 2. * epsRoot * Rndm::flat(); + fVal = 4. * epsilon * z * pow2(1. - z) + / pow2( pow2(1. - z) + epsilon * z); + } + } while (fVal < Rndm::flat()); + return z; + +} + +//************************************************************************** + +// The StringPT class. + +//********* + +// Initialize data members of the string pT selection. + +void StringPT::init() { + + // Parameters of the pT width and enhancement. + sigmaQ = Settings::parm("StringPT:sigma") / sqrt(2.); + enhancedFraction = Settings::parm("StringPT:enhancedFraction"); + enhancedWidth = Settings::parm("StringPT:enhancedWidth"); + +} + +//********* + +// Generate Gaussian pT such that = = sigma^2 = width^2/2, +// but with small fraction multiplied up to a broader spectrum. + +double StringPT::pxy() { + + double pxyNow = sigmaQ * Rndm::gauss(); + if (Rndm::flat() < enhancedFraction) pxyNow *= enhancedWidth; + return pxyNow; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/FragmentationSystems.cxx b/PYTHIA8/pythia8130/src/FragmentationSystems.cxx new file mode 100644 index 00000000000..755d89d7bd9 --- /dev/null +++ b/PYTHIA8/pythia8130/src/FragmentationSystems.cxx @@ -0,0 +1,471 @@ +// FragmentationSystems.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// ColConfig, StringRegion and StringSystem classes. + +#include "FragmentationSystems.h" + +namespace Pythia8 { + +//************************************************************************** + +// The ColConfig class. + +//********* + +// Initialize and save pointers. + +void ColConfig::init(StringFlav* flavSelPtrIn) { + + // Save pointer. + flavSelPtr = flavSelPtrIn; + + // Joining of nearby partons along the string. + mJoin = Settings::parm("FragmentationSystems:mJoin"); + + // For consistency ensure that mJoin is bigger than in StringRegion. + mJoin = max( mJoin, 2. * StringRegion::MJOIN); + + // Simplification of q q q junction topology to quark - diquark one. + mJoinJunction = Settings::parm("FragmentationSystems:mJoinJunction"); + mStringMin = Settings::parm("HadronLevel:mStringMin"); + +} + +//********* + +// Insert a new colour singlet system in ascending mass order. +// Calculate its properties. Join nearby partons. + +void ColConfig::insert( vector& iPartonIn, Event& event) { + + // Find momentum and invariant mass of system, minus endpoint masses. + Vec4 pSumIn; + double mSumIn = 0.; + bool hasJunctionIn = false; + for (int i = 0; i < int(iPartonIn.size()); ++i) { + if (iPartonIn[i] < 0) { + hasJunctionIn = true; + continue; + } + pSumIn += event[ iPartonIn[i] ].p(); + if (!event[ iPartonIn[i] ].isGluon()) + mSumIn += event[ iPartonIn[i] ].constituentMass(); + } + double massIn = pSumIn.mCalc(); + double massExcessIn = massIn - mSumIn; + + // Identify closed gluon loop. Assign "endpoint" masses as light quarks. + bool isClosedIn = (iPartonIn[0] >= 0 && event[ iPartonIn[0] ].isGluon()); + if (isClosedIn) massExcessIn -= 2. * ParticleDataTable::constituentMass(1); + + // For junction topology: join two nearby legs into a diquark. + if (hasJunctionIn && joinJunction( iPartonIn, event, massExcessIn)) + hasJunctionIn = false; + + // Loop while > 2 partons left and hope of finding joining pair. + bool hasJoined = true; + while (hasJoined && iPartonIn.size() > 2) { + + // Look for the pair of neighbour partons (along string) with + // the smallest invariant mass (subtracting quark masses). + int iJoinMin = -1; + double mJoinMin = 2. * mJoin; + int nSize = iPartonIn.size(); + int nPair = (isClosedIn) ? nSize : nSize - 1; + for (int i = 0; i < nPair; ++i) { + // Keep three legs of junction separate. + if (iPartonIn[i] < 0 || iPartonIn[(i + 1)%nSize] < 0) continue; + Particle& parton1 = event[ iPartonIn[i] ]; + Particle& parton2 = event[ iPartonIn[(i + 1)%nSize] ]; + Vec4 pSumNow; + pSumNow += (parton1.isGluon()) ? 0.5 * parton1.p() : parton1.p(); + pSumNow += (parton2.isGluon()) ? 0.5 * parton2.p() : parton2.p(); + double mJoinNow = pSumNow.mCalc(); + if (!parton1.isGluon()) mJoinNow -= parton1.m(); + if (!parton2.isGluon()) mJoinNow -= parton2.m(); + if (mJoinNow < mJoinMin) { iJoinMin = i; mJoinMin = mJoinNow; } + } + + // If sufficiently nearby then join into one new parton. + // Note: error sensitivity to mJoin indicates unstable precedure?? + hasJoined = false; + if (mJoinMin < mJoin) { + int iJoin1 = iPartonIn[iJoinMin]; + int iJoin2 = iPartonIn[(iJoinMin + 1)%nSize]; + int idNew = (event[iJoin1].isGluon()) ? event[iJoin2].id() + : event[iJoin1].id(); + int colNew = event[iJoin1].col(); + int acolNew = event[iJoin2].acol(); + if (colNew == acolNew) { + colNew = event[iJoin2].col(); + acolNew = event[iJoin1].acol(); + } + Vec4 pNew = event[iJoin1].p() + event[iJoin2].p(); + + // Append joined parton to event record. + int iNew = event.append( idNew, 73, min(iJoin1, iJoin2), + max(iJoin1, iJoin2), 0, 0, colNew, acolNew, pNew, pNew.mCalc() ); + + // Mark joined partons and reduce remaining system. + event[iJoin1].statusNeg(); + event[iJoin2].statusNeg(); + event[iJoin1].daughter1(iNew); + event[iJoin2].daughter1(iNew); + if (iJoinMin == nSize - 1) iPartonIn[0] = iNew; + else { + iPartonIn[iJoinMin] = iNew; + for (int i = iJoinMin + 1; i < nSize - 1; ++i) + iPartonIn[i] = iPartonIn[i + 1]; + } + iPartonIn.pop_back(); + + // If joined,then loopback to look for more. + hasJoined = true; + } + } + + // Store new colour singlet system at the end. + singlets.push_back( ColSinglet(iPartonIn, pSumIn, massIn, + massExcessIn, hasJunctionIn, isClosedIn) ); + + // Now move around, so that smallest mass excesses come first. + int iInsert = singlets.size() - 1; + for (int iSub = singlets.size() - 2; iSub >= 0; --iSub) { + if (massExcessIn > singlets[iSub].massExcess) break; + singlets[iSub + 1] = singlets[iSub]; + iInsert = iSub; + } + if (iInsert < int(singlets.size()) - 1) singlets[iInsert] = + ColSinglet(iPartonIn, pSumIn, massIn, massExcessIn, + hasJunctionIn, isClosedIn); + +} + +//********* + +// Join two legs of junction to a diquark for small invariant masses. +// Note: for junction system, iPartonIn points to structure +// (-code0) g...g.q0 (-code1) g...g.q1 (-code2) g...g.q2 + +bool ColConfig::joinJunction( vector& iPartonIn, Event& event, + double massExcessIn) { + + // Find four-momentum and endpoint quarks and masses on the three legs. + Vec4 pLeg[3]; + double mLeg[3]; + int idAbsLeg[3]; + int leg = -1; + for (int i = 0; i < int(iPartonIn.size()); ++ i) { + if (iPartonIn[i] < 0) ++leg; + else { + pLeg[leg] += event[ iPartonIn[i] ].p(); + mLeg[leg] = event[ iPartonIn[i] ].m(); + idAbsLeg[leg] = event[ iPartonIn[i] ].idAbs(); + } + } + + // Calculate invariant mass of three pairs, minus endpoint masses. + double m01 = (pLeg[0] + pLeg[1]).mCalc() - mLeg[0] - mLeg[1]; + double m02 = (pLeg[0] + pLeg[2]).mCalc() - mLeg[0] - mLeg[2]; + double m12 = (pLeg[1] + pLeg[2]).mCalc() - mLeg[1] - mLeg[2]; + + // Find lowest-mass pair not involving diquark. + double mMin = mJoinJunction + 1.; + int legA = -1; + int legB = -1; + if (m01 < mMin && idAbsLeg[0] < 9 && idAbsLeg[1] < 9) { + mMin = m01; + legA = 0; + legB = 1; + } + if (m02 < mMin && idAbsLeg[0] < 9 && idAbsLeg[2] < 9) { + mMin = m02; + legA = 0; + legB = 2; + } + if (m12 < mMin && idAbsLeg[1] < 9 && idAbsLeg[2] < 9) { + mMin = m12; + legA = 1; + legB = 2; + } + int legC = 3 - legA - legB; + + // Nothing to do if no two legs have small invariant mass, and + // system as a whole is above MiniStringFragmentation threshold. + if (mMin > mJoinJunction && massExcessIn > mStringMin) return false; + + // Construct separate index arrays for the three legs. + vector iLegA, iLegB, iLegC; + leg = -1; + for (int i = 0; i < int(iPartonIn.size()); ++ i) { + if (iPartonIn[i] < 0) ++leg; + else if( leg == legA) iLegA.push_back( iPartonIn[i] ); + else if( leg == legB) iLegB.push_back( iPartonIn[i] ); + else if( leg == legC) iLegC.push_back( iPartonIn[i] ); + } + + // First step: successively combine any gluons on the two legs. + // (Presumably overkill; not likely to be (m)any extra gluons.) + // (Do as successive binary joinings, so only need two mothers.) + for (leg = 0; leg < 2; ++leg) { + vector& iLegNow = (leg == 0) ? iLegA : iLegB; + int sizeNow = iLegNow.size(); + for (int i = sizeNow - 2; i >= 0; --i) { + int iQ = iLegNow.back(); + int iG = iLegNow[i]; + int colNew = (event[iQ].id() > 0) ? event[iG].col() : 0; + int acolNew = (event[iQ].id() < 0) ? event[iG].acol() : 0; + Vec4 pNew = event[iQ].p() + event[iG].p(); + int iNew = event.append( event[iQ].id(), 74, min(iQ, iG), + max(iQ, iG), 0, 0, colNew, acolNew, pNew, pNew.mCalc() ); + + // Mark joined partons and update iLeg end. + event[iQ].statusNeg(); + event[iG].statusNeg(); + event[iQ].daughter1(iNew); + event[iG].daughter1(iNew); + iLegNow.back() = iNew; + } + } + + // Second step: combine two quarks into a diquark. + int iQA = iLegA.back(); + int iQB = iLegB.back(); + int idQA = event[iQA].id(); + int idQB = event[iQB].id(); + int idNew = flavSelPtr->makeDiquark( idQA, idQB ); + // Diquark colour is opposite to parton closest to junction on third leg. + int colNew = (idNew > 0) ? 0 : event[ iLegC[0] ].acol(); + int acolNew = (idNew > 0) ? event[ iLegC[0] ].col() : 0; + Vec4 pNew = pLeg[legA] + pLeg[legB]; + int iNew = event.append( idNew, 74, min(iQA, iQB), max( iQA, iQB), + 0, 0, colNew, acolNew, pNew, pNew.mCalc() ); + + // Mark joined partons and reduce remaining system. + event[iQA].statusNeg(); + event[iQB].statusNeg(); + event[iQA].daughter1(iNew); + event[iQB].daughter1(iNew); + iPartonIn.resize(0); + iPartonIn.push_back( iNew); + for (int i = 0; i < int(iLegC.size()) ; ++i) + iPartonIn.push_back( iLegC[i]); + + // Remove junction from event record list, identifying by colour. + int iJun = -1; + for (int i = 0; i < event.sizeJunction(); ++i) + for (int j = 0; j < 3; ++ j) + if ( event.colJunction(i,j) == max(colNew, acolNew) ) iJun = i; + if (iJun >= 0) event.eraseJunction(iJun); + + // Done, having eliminated junction. + return true; + +} + +//********* + +// Collect all partons of singlet to be consecutively ordered. + +void ColConfig::collect(int iSub, Event& event) { + + // Partons may already have been collected, e.g. at ministring collapse. + if (singlets[iSub].isCollected) return; + singlets[iSub].isCollected = true; + + // Check if partons already "by chance" happen to be ordered. + bool inOrder = true; + for (int i = 0; i < singlets[iSub].size() - 1; ++i) { + int iFirst = singlets[iSub].iParton[i]; + if (iFirst < 0) continue; + int iSecond = singlets[iSub].iParton[i + 1]; + if (iSecond < 0) iSecond = singlets[iSub].iParton[i + 2]; + if (iSecond != iFirst + 1) { inOrder = false; break;} + } + if (inOrder) return; + + // Copy down system. Update current partons. + for (int i = 0; i < singlets[iSub].size(); ++i) { + int iOld = singlets[iSub].iParton[i]; + if (iOld < 0) continue; + int iNew = event.copy(iOld, 71); + singlets[iSub].iParton[i] = iNew; + } + + // Done. +} + +//********* + +// List all currently identified singlets. + +void ColConfig::list(ostream& os) { + + // Header. Loop over all individual singlets. + os << "\n -------- Colour Singlet Systems Listing -------------------\n"; + for (int iSub = 0; iSub < int(singlets.size()); ++iSub) { + + // List all partons belonging to each singlet. + os << " singlet " << iSub << " contains " ; + for (int i = 0; i < singlets[iSub].size(); ++i) + os << singlets[iSub].iParton[i] << " "; + os << "\n"; + + // Done. + } +} + +//************************************************************************** + +// The StringRegion class. + +// Currently a number of simplifications, in particular ?? +// 1) No popcorn baryon production. +// 2) Simplified treatment of pT in stepping and joining. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// If a string region is smaller thsan this it is assumed empty. +const double StringRegion::MJOIN = 0.1; + +// Avoid division by zero. +const double StringRegion::TINY = 1e-20; + +//********* + +// Set up four-vectors for longitudinal and transverse directions. + +void StringRegion::setUp(Vec4 p1, Vec4 p2, bool isMassless) { + + // Simple case: the two incoming four-vectors guaranteed massless. + if (isMassless) { + + // Calculate w2, minimum value. Lightcone directions = input. + w2 = 2. * (p1 * p2); + if (w2 < MJOIN*MJOIN) {isSetUp = true; isEmpty = true; return;} + pPos = p1; + pNeg = p2; + + // Else allow possibility of masses for incoming partons (also gluons!). + } else { + + // Generic four-momentum combinations. + double m1Sq = p1 * p1; + double m2Sq = p2 * p2; + double p1p2 = p1 * p2; + w2 = m1Sq + 2. * p1p2 + m2Sq; + double rootSq = pow2(p1p2) - m1Sq * m2Sq; + + // If crazy kinematics (should not happen!) modify energies. + if (w2 <= 0. || rootSq <= 0.) { + if (m1Sq < 0.) m1Sq = 0.; + p1.e( sqrt(m1Sq + p1.pAbs2()) ); + if (m2Sq < 0.) m2Sq = 0.; + p2.e( sqrt(m2Sq + p2.pAbs2()) ); + p1p2 = p1 * p2; + w2 = m1Sq + 2. * p1p2 + m2Sq; + rootSq = pow2(p1p2) - m1Sq * m2Sq; + } + + // If still small invariant mass then empty region (e.g. in gg system). + if (w2 < MJOIN*MJOIN) {isSetUp = true; isEmpty = true; return;} + + // Find two lightconelike longitudinal four-vector directions. + double root = sqrt( max(TINY, rootSq) ); + double k1 = 0.5 * ( (m2Sq + p1p2) / root - 1.); + double k2 = 0.5 * ( (m1Sq + p1p2) / root - 1.); + pPos = (1. + k1) * p1 - k2 * p2; + pNeg = (1. + k2) * p2 - k1 * p1; + } + + // Find two spacelike transverse four-vector directions. + // Begin by picking two sensible trial directions. + Vec4 eDiff = pPos / pPos.e() - pNeg / pNeg.e(); + double eDx = pow2( eDiff.px() ); + double eDy = pow2( eDiff.py() ); + double eDz = pow2( eDiff.pz() ); + if (eDx < min(eDy, eDz)) { + eX = Vec4( 1., 0., 0., 0.); + eY = (eDy < eDz) ? Vec4( 0., 1., 0., 0.) : Vec4( 0., 0., 1., 0.); + } else if (eDy < eDz) { + eX = Vec4( 0., 1., 0., 0.); + eY = (eDx < eDz) ? Vec4( 1., 0., 0., 0.) : Vec4( 0., 0., 1., 0.); + } else { + eX = Vec4( 0., 0., 1., 0.); + eY = (eDx < eDy) ? Vec4( 1., 0., 0., 0.) : Vec4( 0., 1., 0., 0.); + } + + // Then construct orthogonal linear combinations. + double pPosNeg = pPos * pNeg; + double kXPos = eX * pPos / pPosNeg; + double kXNeg = eX * pNeg / pPosNeg; + double kXX = 1. / sqrt( 1. + 2. * kXPos * kXNeg * pPosNeg ); + double kYPos = eY * pPos / pPosNeg; + double kYNeg = eY * pNeg / pPosNeg; + double kYX = kXX * (kXPos * kYNeg + kXNeg * kYPos) * pPosNeg; + double kYY = 1. / sqrt(1. + 2. * kYPos * kYNeg * pPosNeg - pow2(kYX)); + eX = kXX * (eX - kXNeg * pPos - kXPos * pNeg); + eY = kYY * (eY - kYNeg * pPos - kYPos * pNeg - kYX * eX); + + // Done. + isSetUp = true; + isEmpty = false; + +} + +//********* + +// Project a four-momentum onto (x+, x-, px, py). + +void StringRegion::project(Vec4 pIn) { + + // Perform projections by four-vector multiplication. + xPosProj = 2. * (pIn * pNeg) / w2; + xNegProj = 2. * (pIn * pPos) / w2; + pxProj = - (pIn * eX); + pyProj = - (pIn * eY); + +} + +//************************************************************************** + +// The StringSystem class. + +//********* + +// Set up system from parton list. + +void StringSystem::setUp(vector& iSys, Event& event) { + + // Figure out how big the system is. (Closed gluon loops?) + sizePartons = iSys.size(); + sizeStrings = sizePartons - 1; + sizeRegions = (sizeStrings * (sizeStrings + 1)) / 2; + indxReg = 2 * sizeStrings + 1; + iMax = sizeStrings - 1; + + // Reserve space for the required number of regions. + system.clear(); + system.resize(sizeRegions); + + // Set up the lowest-lying regions. + for (int i = 0; i < sizeStrings; ++i) { + Vec4 p1 = event[ iSys[i] ].p(); + if ( event[ iSys[i] ].isGluon() ) p1 *= 0.5; + Vec4 p2 = event[ iSys[i+1] ].p(); + if ( event[ iSys[i+1] ].isGluon() ) p2 *= 0.5; + system[ iReg(i, iMax - i) ].setUp( p1, p2, false); + } + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/HadronLevel.cxx b/PYTHIA8/pythia8130/src/HadronLevel.cxx new file mode 100644 index 00000000000..9963c5e7b21 --- /dev/null +++ b/PYTHIA8/pythia8130/src/HadronLevel.cxx @@ -0,0 +1,904 @@ +// HadronLevel.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the HadronLevel class. + +#include "HadronLevel.h" + +namespace Pythia8 { + +//************************************************************************** + +// The HadronLevel class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// For breaking J-J string, pick a Gamma by taking a step with fictitious mass. +const double HadronLevel::JJSTRINGM2MAX = 25.; +const double HadronLevel::JJSTRINGM2FRAC = 0.1; + +// Iterate junction rest frame boost until convergence or too many tries. +const double HadronLevel::CONVJNREST = 1e-5; +const int HadronLevel::NTRYJNREST = 20; + +// Typical average transvere primary hadron mass . +const double HadronLevel::MTHAD = 0.9; + +//********* + +// Find settings. Initialize HadronLevel classes as required. + +bool HadronLevel::init(Info* infoPtrIn, TimeShower* timesDecPtr, + DecayHandler* decayHandlePtr, vector handledParticles) { + + // Save pointer. + infoPtr = infoPtrIn; + + // Main flags. + doHadronize = Settings::flag("HadronLevel:Hadronize"); + doDecay = Settings::flag("HadronLevel:Decay"); + doBoseEinstein = Settings::flag("HadronLevel:BoseEinstein"); + + // Boundary mass between string and ministring handling. + mStringMin = Settings::parm("HadronLevel:mStringMin"); + + // For junction processing. + eNormJunction = Settings::parm("StringFragmentation:eNormJunction"); + + // Particles that should decay or not before Bose-Einstein stage. + widthSepBE = Settings::parm("BoseEinstein:widthSep"); + + // Initialize string and ministring fragmentation. + stringFrag.init(infoPtr, &flavSel, &pTSel, &zSel); + ministringFrag.init(infoPtr, &flavSel); + + // Initialize particle decays. + decays.init(infoPtr, timesDecPtr, &flavSel, decayHandlePtr, + handledParticles); + + // Initialize BoseEinstein. + boseEinstein.init(infoPtr); + + // Initialize auxiliary administrative classes. + colConfig.init( &flavSel); + + // Initialize auxiliary fragmentation classes. + flavSel.init(); + pTSel.init(); + zSel.init(); + + // Done. + return true; + +} + +//********* + +// Hadronize and decay the next parton-level. + +bool HadronLevel::next( Event& event) { + + // Colour-octet onia states must be decayed to singlet + gluon. + if (!decayOctetOnia(event)) return false; + + // Possibility of hadronization inside decay, but then no BE second time. + bool moreToDo; + bool doBoseEinsteinNow = doBoseEinstein; + do { + moreToDo = false; + + // First part: string fragmentation. + if (doHadronize) { + + // Find the complete colour singlet configuration of the event. + if (!findSinglets( event)) return false; + + // Process all colour singlet (sub)system + for (int iSub = 0; iSub < colConfig.size(); ++iSub) { + + // Collect sequentially all partons in a colour singlet subsystem. + colConfig.collect(iSub, event); + + // String fragmentation of each colour singlet (sub)system. + if ( colConfig[iSub].massExcess > mStringMin ) { + if (!stringFrag.fragment( iSub, colConfig, event)) return false; + + // Low-mass string treated separately. Tell if diffractive system. + } else { + bool isDiff = infoPtr->isDiffractiveA() + || infoPtr->isDiffractiveB(); + if (!ministringFrag.fragment( iSub, colConfig, event, isDiff)) + return false; + } + } + } + + // Second part: sequential decays of short-lived particles (incl. K0). + if (doDecay) { + + // Loop through all entries to find those that should decay. + int iDec = 0; + do { + if ( event[iDec].isFinal() && event[iDec].canDecay() + && event[iDec].mayDecay() && (event[iDec].idAbs() == 311 + || event[iDec].mWidth() > widthSepBE) ) { + decays.decay( iDec, event); + if (decays.moreToDo()) moreToDo = true; + } + } while (++iDec < event.size()); + } + + // Third part: include Bose-Einstein effects among current particles. + if (doBoseEinsteinNow) { + if (!boseEinstein.shiftEvent(event)) return false; + doBoseEinsteinNow = false; + } + + // Fourth part: sequential decays also of long-lived particles. + if (doDecay) { + + // Loop through all entries to find those that should decay. + int iDec = 0; + do { + if ( event[iDec].isFinal() && event[iDec].canDecay() + && event[iDec].mayDecay() ) { + decays.decay( iDec, event); + if (decays.moreToDo()) moreToDo = true; + } + } while (++iDec < event.size()); + } + + + // Normally done first time around, but sometimes not (e.g. Upsilon). + } while (moreToDo); + + // Done. + return true; + +} + +//********* + +// Allow more decays if on/off switches changed. +// Note: does not do sequential hadronization, e.g. for Upsilon. + +bool HadronLevel::moreDecays( Event& event) { + + // Colour-octet onia states must be decayed to singlet + gluon. + if (!decayOctetOnia(event)) return false; + + // Loop through all entries to find those that should decay. + int iDec = 0; + do { + if ( event[iDec].isFinal() && event[iDec].canDecay() + && event[iDec].mayDecay() ) decays.decay( iDec, event); + } while (++iDec < event.size()); + + // Done. + return true; + +} + +//********* + +// Decay colour-octet onium states. + +bool HadronLevel::decayOctetOnia(Event& event) { + + // Onium states to be decayed. + int idOnium[6] = { 9900443, 9900441, 9910441, + 9900553, 9900551, 9910551 }; + + // Loop over particles and identify onia. + for (int iDec = 0; iDec < event.size(); ++iDec) + if (event[iDec].isFinal()) { + int id = event[iDec].id(); + bool isOnium = false; + for (int j = 0; j < 6; ++j) if (id == idOnium[j]) isOnium = true; + + // Decay any onia encountered. + if (isOnium) { + if (!decays.decay( iDec, event)) return false; + + // Set colour flow by hand: gluon inherits octet-onium state. + int iGlu = event.size() - 1; + event[iGlu].cols( event[iDec].col(), event[iDec].acol() ); + } + } + + // Done. + return true; + +} + +//********* + +// Trace colour flow in the event to form colour singlet subsystems. + +bool HadronLevel::findSinglets(Event& event) { + + // Find a list of final partons and of all colour ends and gluons. + iColEnd.resize(0); + iAcolEnd.resize(0); + iColAndAcol.resize(0); + for (int i = 0; i < event.size(); ++ i) if (event[i].isFinal()) { + if (event[i].col() > 0 && event[i].acol() > 0) iColAndAcol.push_back(i); + else if (event[i].col() > 0) iColEnd.push_back(i); + else if (event[i].acol() > 0) iAcolEnd.push_back(i); + } + + // Begin arrange the partons into separate colour singlets. + colConfig.clear(); + iPartonJun.resize(0); + iPartonAntiJun.resize(0); + + // Junctions: loop over them, and identify kind. + for (int iJun = 0; iJun < event.sizeJunction(); ++iJun) + if (event.remainsJunction(iJun)) { + event.remainsJunction(iJun, false); + int kindJun = event.kindJunction(iJun); + iParton.resize(0); + + // First kind: three (anti)colours out from junction. + if (kindJun == 1 || kindJun == 2) { + for (int iCol = 0; iCol < 3; ++iCol) { + int indxCol = event.colJunction(iJun, iCol); + iParton.push_back( -(10 + 10 * iJun + iCol) ); + if (kindJun == 1 && !traceFromAcol(indxCol, event, iJun, iCol)) + return false; + if (kindJun == 2 && !traceFromCol(indxCol, event, iJun, iCol)) + return false; + } + } + + // Keep in memory a junction hooked up with an antijunction, + // else store found single-junction system. + int nNeg = 0; + for (int i = 0; i < int(iParton.size()); ++i) if (iParton[i] < 0) + ++nNeg; + if (nNeg > 3 && kindJun == 1) { + for (int i = 0; i < int(iParton.size()); ++i) + iPartonJun.push_back(iParton[i]); + } else if (nNeg > 3 && kindJun == 2) { + for (int i = 0; i < int(iParton.size()); ++i) + iPartonAntiJun.push_back(iParton[i]); + } else { + // A junction may be eliminated by insert if two quarks are nearby. + int nJunOld = event.sizeJunction(); + colConfig.insert(iParton, event); + if (event.sizeJunction() < nJunOld) --iJun; + } + } + + // Split junction-antijunction system into two, and store those. + // (Only one system in extreme cases, and then second empty.) + if (iPartonJun.size() > 0 && iPartonAntiJun.size() > 0) { + if (!splitJunctionPair(event)) return false; + colConfig.insert(iPartonJun, event); + if (iPartonAntiJun.size() > 0) + colConfig.insert(iPartonAntiJun, event); + // Error if only one of junction and antijuction left here. + } else if (iPartonJun.size() > 0 || iPartonAntiJun.size() > 0) { + infoPtr->errorMsg("Error in HadronLevel::findSinglets: " + "unmatched (anti)junction"); + return false; + } + + // Open strings: pick up each colour end and trace to its anticolor end. + for (int iEnd = 0; iEnd < int(iColEnd.size()); ++iEnd) { + iParton.resize(0); + iParton.push_back( iColEnd[iEnd] ); + int indxCol = event[ iColEnd[iEnd] ].col(); + if (!traceFromCol(indxCol, event)) return false; + + // Store found open string system. Analyze its properties. + colConfig.insert(iParton, event); + } + + // Closed strings : begin at any gluon and trace until back at it. + while (iColAndAcol.size() > 0) { + iParton.resize(0); + iParton.push_back( iColAndAcol[0] ); + int indxCol = event[ iColAndAcol[0] ].col(); + int indxAcol = event[ iColAndAcol[0] ].acol(); + iColAndAcol[0] = iColAndAcol.back(); + iColAndAcol.pop_back(); + if (!traceInLoop(indxCol, indxAcol, event)) return false; + + // Store found closed string system. Analyze its properties. + colConfig.insert(iParton, event); + } + + // Done. + return true; + +} + +//********* + +// Trace a colour line, from a colour to an anticolour. + +bool HadronLevel::traceFromCol(int indxCol, Event& event, int iJun, + int iCol) { + + // Junction kind, if any. + int kindJun = (iJun >= 0) ? event.kindJunction(iJun) : 0; + + // Begin to look for a matching anticolour. + int loop = 0; + int loopMax = iColAndAcol.size() + 2; + bool hasFound = false; + do { + ++loop; + hasFound= false; + + // First check list of matching anticolour ends. + for (int i = 0; i < int(iAcolEnd.size()); ++i) + if (event[ iAcolEnd[i] ].acol() == indxCol) { + iParton.push_back( iAcolEnd[i] ); + indxCol = 0; + iAcolEnd[i] = iAcolEnd.back(); + iAcolEnd.pop_back(); + hasFound = true; + break; + } + + // Then check list of intermediate gluons. + if (!hasFound) + for (int i = 0; i < int(iColAndAcol.size()); ++i) + if (event[ iColAndAcol[i] ].acol() == indxCol) { + iParton.push_back( iColAndAcol[i] ); + + // Update to new colour. Remove gluon. + indxCol = event[ iColAndAcol[i] ].col(); + if (kindJun > 0) event.endColJunction(iJun, iCol, indxCol); + iColAndAcol[i] = iColAndAcol.back(); + iColAndAcol.pop_back(); + hasFound = true; + break; + } + + // In a pinch, check list of end colours on other (anti)junction. + if (!hasFound && kindJun == 2 && event.sizeJunction() > 1) + for (int iAntiJun = 0; iAntiJun < event.sizeJunction(); ++iAntiJun) + if (iAntiJun != iJun && event.kindJunction(iAntiJun) == 1) + for (int iColAnti = 0; iColAnti < 3; ++iColAnti) + if (event.endColJunction(iAntiJun, iColAnti) == indxCol) { + iParton.push_back( -(10 + 10 * iAntiJun + iColAnti) ); + indxCol = 0; + hasFound = true; + break; + } + + // Keep on tracing via gluons until reached end of leg. + } while (hasFound && indxCol > 0 && loop < loopMax); + + // Something went wrong in colour tracing. + if (!hasFound || loop == loopMax) { + infoPtr->errorMsg("Error in HadronLevel::traceFromCol: " + "colour tracing failed"); + return false; + } + + // Done. + return true; + +} + +//********* + +// Trace a colour line, from an anticolour to a colour. + +bool HadronLevel::traceFromAcol(int indxCol, Event& event, int iJun, + int iCol) { + + // Junction kind, if any. + int kindJun = (iJun >= 0) ? event.kindJunction(iJun) : 0; + + // Begin to look for a matching colour. + int loop = 0; + int loopMax = iColAndAcol.size() + 2; + bool hasFound = false; + do { + ++loop; + hasFound= false; + + // First check list of matching colour ends. + for (int i = 0; i < int(iColEnd.size()); ++i) + if (event[ iColEnd[i] ].col() == indxCol) { + iParton.push_back( iColEnd[i] ); + indxCol = 0; + iColEnd[i] = iColEnd.back(); + iColEnd.pop_back(); + hasFound = true; + break; + } + + // Then check list of intermediate gluons. + if (!hasFound) + for (int i = 0; i < int(iColAndAcol.size()); ++i) + if (event[ iColAndAcol[i] ].col() == indxCol) { + iParton.push_back( iColAndAcol[i] ); + + // Update to new colour. Remove gluon. + indxCol = event[ iColAndAcol[i] ].acol(); + if (kindJun > 0) event.endColJunction(iJun, iCol, indxCol); + iColAndAcol[i] = iColAndAcol.back(); + iColAndAcol.pop_back(); + hasFound = true; + break; + } + + // In a pinch, check list of colours on other (anti)junction. + if (!hasFound && kindJun == 1 && event.sizeJunction() > 1) + for (int iAntiJun = 0; iAntiJun < event.sizeJunction(); ++iAntiJun) + if (iAntiJun != iJun && event.kindJunction(iAntiJun) == 2) + for (int iColAnti = 0; iColAnti < 3; ++iColAnti) + if (event.endColJunction(iAntiJun, iColAnti) == indxCol) { + iParton.push_back( -(10 + 10 * iAntiJun + iColAnti) ); + indxCol = 0; + hasFound = true; + break; + } + + // Keep on tracing via gluons until reached end of leg. + } while (hasFound && indxCol > 0 && loop < loopMax); + + // Something went wrong in colour tracing. + if (!hasFound || loop == loopMax) { + infoPtr->errorMsg("Error in HadronLevel::traceFromAcol: " + "colour tracing failed"); + return false; + } + + // Done. + return true; + +} + +//********* + +// Trace a colour loop, from a colour back to the anticolour of the same. + +bool HadronLevel::traceInLoop(int indxCol, int indxAcol, Event& event) { + + // Move around until back where begun. + int loop = 0; + int loopMax = iColAndAcol.size() + 2; + bool hasFound = false; + do { + ++loop; + hasFound= false; + + // Check list of gluons. + for (int i = 0; i < int(iColAndAcol.size()); ++i) + if (event[ iColAndAcol[i] ].acol() == indxCol) { + iParton.push_back( iColAndAcol[i] ); + indxCol = event[ iColAndAcol[i] ].col(); + iColAndAcol[i] = iColAndAcol.back(); + iColAndAcol.pop_back(); + hasFound = true; + break; + } + } while (hasFound && indxCol != indxAcol && loop < loopMax); + + // Something went wrong in colour tracing. + if (!hasFound || loop == loopMax) { + infoPtr->errorMsg("Error in HadronLevel::traceInLoop: " + "colour tracing failed"); + return false; + } + + // Done. + return true; + +} + +//********* + +// Split junction-antijunction system into two, or simplify other way. + +bool HadronLevel::splitJunctionPair(Event& event) { + + // Construct separate index arrays for the three junction legs. + int identJun = (-iPartonJun[0])/10; + iJunLegA.resize(0); + iJunLegB.resize(0); + iJunLegC.resize(0); + int leg = -1; + for (int i = 0; i < int(iPartonJun.size()); ++ i) { + if ( (-iPartonJun[i])/10 == identJun) ++leg; + if (leg == 0) iJunLegA.push_back( iPartonJun[i] ); + else if (leg == 1) iJunLegB.push_back( iPartonJun[i] ); + else iJunLegC.push_back( iPartonJun[i] ); + } + + // Construct separate index arrays for the three antijunction legs. + int identAnti = (-iPartonAntiJun[0])/10; + iAntiLegA.resize(0); + iAntiLegB.resize(0); + iAntiLegC.resize(0); + leg = -1; + for (int i = 0; i < int(iPartonAntiJun.size()); ++ i) { + if ( (-iPartonAntiJun[i])/10 == identAnti) ++leg; + if (leg == 0) iAntiLegA.push_back( iPartonAntiJun[i] ); + else if (leg == 1) iAntiLegB.push_back( iPartonAntiJun[i] ); + else iAntiLegC.push_back( iPartonAntiJun[i] ); + } + + // Find interjunction legs, i.e. between junction and antijunction. + int nMatch = 0; + int legJun[3], legAnti[3], nGluLeg[3]; + if (iJunLegA.back() < 0) { legJun[nMatch] = 0; + legAnti[nMatch] = (-iJunLegA.back())%10; ++nMatch;} + if (iJunLegB.back() < 0) { legJun[nMatch] = 1; + legAnti[nMatch] = (-iJunLegB.back())%10; ++nMatch;} + if (iJunLegC.back() < 0) { legJun[nMatch] = 2; + legAnti[nMatch] = (-iJunLegC.back())%10; ++nMatch;} + + // Loop over interjunction legs. + for (int iMatch = 0; iMatch < nMatch; ++iMatch) { + vector& iJunLeg = (legJun[iMatch] == 0) ? iJunLegA + : ( (legJun[iMatch] == 1) ? iJunLegB : iJunLegC ); + vector& iAntiLeg = (legAnti[iMatch] == 0) ? iAntiLegA + : ( (legAnti[iMatch] == 1) ? iAntiLegB : iAntiLegC ); + + // Find number of gluons on each. Do nothing for now if none. + nGluLeg[iMatch] = iJunLeg.size() + iAntiLeg.size() - 4; + if (nGluLeg[iMatch] == 0) continue; + + // Else pick up the gluons on the interjunction leg in order. + iGluLeg.resize(0); + for (int i = 1; i < int(iJunLeg.size()) - 1; ++i) + iGluLeg.push_back( iJunLeg[i] ); + for (int i = int(iAntiLeg.size()) - 2; i > 0; --i) + iGluLeg.push_back( iAntiLeg[i] ); + + // Remove those gluons from the junction/antijunction leg lists. + iJunLeg.resize(1); + iAntiLeg.resize(1); + + // Pick a new quark at random; for simplicity no diquarks. + int idQ = flavSel.pickLightQ(); + int colQ, acolQ; + + // If one gluon on leg, split it into a collinear q-qbar pair. + if (iGluLeg.size() == 1) { + + // Store the new q qbar pair, sharing gluon colour and momentum. + colQ = event[ iGluLeg[0] ].col(); + acolQ = event[ iGluLeg[0] ].acol(); + Vec4 pQ = 0.5 * event[ iGluLeg[0] ].p(); + double mQ = 0.5 * event[ iGluLeg[0] ].m(); + int iQ = event.append( idQ, 75, iGluLeg[0], 0, 0, 0, colQ, 0, pQ, mQ ); + int iQbar = event.append( -idQ, 75, iGluLeg[0], 0, 0, 0, 0, acolQ, + pQ, mQ ); + + // Mark split gluon and update junction and antijunction legs. + event[ iGluLeg[0] ].statusNeg(); + event[ iGluLeg[0] ].daughters( iQ, iQbar); + iJunLeg.push_back(iQ); + iAntiLeg.push_back(iQbar); + + // If several gluons on the string, decide which g-g region to split up. + } else { + + // Evaluate mass-squared for all adjacent gluon pairs. + m2Pair.resize(0); + double m2Sum = 0.; + for (int i = 0; i < int(iGluLeg.size()) - 1; ++i) { + double m2Now = 0.5 * event[ iGluLeg[i] ].p() + * event[ iGluLeg[i + 1] ].p(); + m2Pair.push_back(m2Now); + m2Sum += m2Now; + } + + // Pick breakup region with probability proportional to mass-squared. + double m2Reg = m2Sum * Rndm::flat(); + int iReg = -1; + do m2Reg -= m2Pair[++iReg]; + while (m2Reg > 0. && iReg < int(iGluLeg.size()) - 1); + m2Reg = m2Pair[iReg]; + + // Pick breaking point of string in chosen region (symmetrically). + double m2Temp = min( JJSTRINGM2MAX, JJSTRINGM2FRAC * m2Reg); + double xPos = 0.5; + double xNeg = 0.5; + do { + double zTemp = zSel.zFrag( idQ, 0, m2Temp); + xPos = 1. - zTemp; + xNeg = m2Temp / (zTemp * m2Reg); + } while (xNeg > 1.); + if (Rndm::flat() > 0.5) swap(xPos, xNeg); + + // Pick up two "mother" gluons of breakup. Mark them decayed. + Particle& gJun = event[ iGluLeg[iReg] ]; + Particle& gAnti = event[ iGluLeg[iReg + 1] ]; + gJun.statusNeg(); + gAnti.statusNeg(); + int dau1 = event.size(); + gJun.daughters(dau1, dau1 + 3); + gAnti.daughters(dau1, dau1 + 3); + int mother1 = min( iGluLeg[iReg], iGluLeg[iReg + 1]); + int mother2 = max( iGluLeg[iReg], iGluLeg[iReg + 1]); + + // Can keep one of old colours but need one new so unambiguous. + colQ = gJun.acol(); + acolQ = event.nextColTag(); + + // Store copied gluons with reduced momenta. + int iGjun = event.append( 21, 75, mother1, mother2, 0, 0, + gJun.col(), gJun.acol(), (1. - 0.5 * xPos) * gJun.p(), + (1. - 0.5 * xPos) * gJun.m()); + int iGanti = event.append( 21, 75, mother1, mother2, 0, 0, + acolQ, gAnti.acol(), (1. - 0.5 * xNeg) * gAnti.p(), + (1. - 0.5 * xNeg) * gAnti.m()); + + // Store the new q qbar pair with remaining momenta. + int iQ = event.append( idQ, 75, mother1, mother2, 0, 0, + colQ, 0, 0.5 * xNeg * gAnti.p(), 0.5 * xNeg * gAnti.m() ); + int iQbar = event.append( -idQ, 75, mother1, mother2, 0, 0, + 0, acolQ, 0.5 * xPos * gJun.p(), 0.5 * xPos * gJun.m() ); + + // Update junction and antijunction legs with gluons and quarks. + for (int i = 0; i < iReg; ++i) + iJunLeg.push_back( iGluLeg[i] ); + iJunLeg.push_back(iGjun); + iJunLeg.push_back(iQ); + for (int i = int(iGluLeg.size()) - 1; i > iReg + 1; --i) + iAntiLeg.push_back( iGluLeg[i] ); + iAntiLeg.push_back(iGanti); + iAntiLeg.push_back(iQbar); + } + + // Update end colours for both g -> q qbar and g g -> g g q qbar. + event.endColJunction(identJun - 1, legJun[iMatch], colQ); + event.endColJunction(identAnti - 1, legAnti[iMatch], acolQ); + } + + // Update list of interjunction legs after splittings above. + int iMatchUp = 0; + while (iMatchUp < nMatch) { + if (nGluLeg[iMatchUp] > 0) { + for (int i = iMatchUp; i < nMatch - 1; ++i) { + legJun[i] = legJun[i + 1]; + legAnti[i] = legAnti[i + 1]; + nGluLeg[i] = nGluLeg[i + 1]; + } --nMatch; + } else ++iMatchUp; + } + + // Should not ever have three empty interjunction legs. + if (nMatch == 3) { + infoPtr->errorMsg("Error in HadronLevel::splitJunctionPair: " + "three empty junction-junction legs"); + return false; + } + + // If two legs are empty, then collapse system to a single string. + if (nMatch == 2) { + int legJunLeft = 3 - legJun[0] - legJun[1]; + int legAntiLeft = 3 - legAnti[0] - legAnti[1]; + vector& iJunLeg = (legJunLeft == 0) ? iJunLegA + : ( (legJunLeft == 1) ? iJunLegB : iJunLegC ); + vector& iAntiLeg = (legAntiLeft == 0) ? iAntiLegA + : ( (legAntiLeft == 1) ? iAntiLegB : iAntiLegC ); + iPartonJun.resize(0); + for (int i = int(iJunLeg.size()) - 1; i > 0; --i) + iPartonJun.push_back( iJunLeg[i] ); + for (int i = 1; i < int(iAntiLeg.size()); ++i) + iPartonJun.push_back( iAntiLeg[i] ); + + // Other string system empty. Remove junctions from their list. Done. + iPartonAntiJun.resize(0); + event.eraseJunction( max(identJun, identAnti) - 1); + event.eraseJunction( min(identJun, identAnti) - 1); + return true; + } + + // If one leg is empty then, depending on string length, either + // (a) annihilate junction and antijunction into two simple strings, or + // (b) split the empty leg by borrowing energy from nearby legs. + if (nMatch == 1) { + + // Identify the two external legs of either junction. + vector& iJunLeg0 = (legJun[0] == 0) ? iJunLegB : iJunLegA; + vector& iJunLeg1 = (legJun[0] == 2) ? iJunLegB : iJunLegC; + vector& iAntiLeg0 = (legAnti[0] == 0) ? iAntiLegB : iAntiLegA; + vector& iAntiLeg1 = (legAnti[0] == 2) ? iAntiLegB : iAntiLegC; + + // Simplified procedure: mainly study first parton on each leg. + Vec4 pJunLeg0 = event[ iJunLeg0[1] ].p(); + Vec4 pJunLeg1 = event[ iJunLeg1[1] ].p(); + Vec4 pAntiLeg0 = event[ iAntiLeg0[1] ].p(); + Vec4 pAntiLeg1 = event[ iAntiLeg1[1] ].p(); + + // Starting frame hopefully intermediate to two junction directions. + Vec4 pStart = pJunLeg0 / pJunLeg0.e() + pJunLeg1 / pJunLeg1.e() + + pAntiLeg0 / pAntiLeg0.e() + pAntiLeg1 / pAntiLeg1.e(); + + // Loop over iteration to junction/antijunction rest frames (JRF/ARF). + RotBstMatrix MtoJRF, MtoARF; + Vec4 pInJRF[3], pInARF[3]; + for (int iJun = 0; iJun < 2; ++iJun) { + int offset = (iJun == 0) ? 0 : 2; + + // Iterate from system rest frame towards the junction rest frame. + RotBstMatrix MtoRF, Mstep; + MtoRF.bstback(pStart); + Vec4 pInRF[4]; + int iter = 0; + do { + ++iter; + + // Find rest-frame momenta on the three sides of the junction. + // Only consider first parton on each leg, for simplicity. + pInRF[0 + offset] = pJunLeg0; + pInRF[1 + offset] = pJunLeg1; + pInRF[2 - offset] = pAntiLeg0; + pInRF[3 - offset] = pAntiLeg1; + for (int i = 0; i < 4; ++i) pInRF[i].rotbst(MtoRF); + + // For third side add both legs beyond other junction, weighted. + double wt2 = 1. - exp( -pInRF[2].e() / eNormJunction); + double wt3 = 1. - exp( -pInRF[3].e() / eNormJunction); + pInRF[2] = wt2 * pInRF[2] + wt3 * pInRF[3]; + + // Find new junction rest frame from the set of momenta. + Mstep = stringFrag.junctionRestFrame( pInRF[0], pInRF[1], pInRF[2]); + MtoRF.rotbst( Mstep ); + } while (iter < 3 || (Mstep.deviation() > CONVJNREST + && iter < NTRYJNREST) ); + + // Store final boost and rest-frame (weighted) momenta. + if (iJun == 0) { + MtoJRF = MtoRF; + for (int i = 0; i < 3; ++i) pInJRF[i] = pInRF[i]; + } else { + MtoARF = MtoRF; + for (int i = 0; i < 3; ++i) pInARF[i] = pInRF[i]; + } + } + + // Opposite operations: boost from JRF/ARF to original system. + RotBstMatrix MfromJRF = MtoJRF; + MfromJRF.invert(); + RotBstMatrix MfromARF = MtoARF; + MfromARF.invert(); + + // Velocity vectors of junctions and momentum of legs in lab frame. + Vec4 vJun(0., 0., 0., 1.); + vJun.rotbst(MfromJRF); + Vec4 vAnti(0., 0., 0., 1.); + vAnti.rotbst(MfromARF); + Vec4 pLabJ[3], pLabA[3]; + for (int i = 0; i < 3; ++i) { + pLabJ[i] = pInJRF[i]; + pLabJ[i].rotbst(MfromJRF); + pLabA[i] = pInARF[i]; + pLabA[i].rotbst(MfromARF); + } + + // Calculate Lambda-measure length of three possible topologies. + double vJvA = vJun * vAnti; + double vJvAe2y = vJvA + sqrt(vJvA*vJvA - 1.); + double LambdaJA = (2. * pInJRF[0].e()) * (2. * pInJRF[1].e()) + * (2. * pInARF[0].e()) * (2. * pInARF[1].e()) * vJvAe2y; + double Lambda00 = (2. * pLabJ[0] * pLabA[0]) + * (2. * pLabJ[1] * pLabA[1]); + double Lambda01 = (2. * pLabJ[0] * pLabA[1]) + * (2. * pLabJ[1] * pLabA[0]); + + // Case when either topology without junctions is the shorter one. + if (LambdaJA > min( Lambda00, Lambda01)) { + vector& iAntiMatch0 = (Lambda00 < Lambda01) + ? iAntiLeg0 : iAntiLeg1; + vector& iAntiMatch1 = (Lambda00 < Lambda01) + ? iAntiLeg1 : iAntiLeg0; + + // Define two quark-antiquark strings. + iPartonJun.resize(0); + for (int i = int(iJunLeg0.size()) - 1; i > 0; --i) + iPartonJun.push_back( iJunLeg0[i] ); + for (int i = 1; i < int(iAntiMatch0.size()); ++i) + iPartonJun.push_back( iAntiMatch0[i] ); + iPartonAntiJun.resize(0); + for (int i = int(iJunLeg1.size()) - 1; i > 0; --i) + iPartonAntiJun.push_back( iJunLeg1[i] ); + for (int i = 1; i < int(iAntiMatch1.size()); ++i) + iPartonAntiJun.push_back( iAntiMatch1[i] ); + + // Remove junctions from their list. Done. + event.eraseJunction( max(identJun, identAnti) - 1); + event.eraseJunction( min(identJun, identAnti) - 1); + return true; + } + + // Case where junction and antijunction to be separated. + // Shuffle (p+/p-) momentum of order between systems, + // times 2/3 for 120 degree in JRF, times 1/2 for two legs, + // but not more than half of what nearest parton carries. + double eShift = MTHAD / (3. * sqrt(vJvAe2y)); + double fracJ0 = min(0.5, eShift / pInJRF[0].e()); + double fracJ1 = min(0.5, eShift / pInJRF[0].e()); + Vec4 pFromJun = fracJ0 * pJunLeg0 + fracJ1 * pJunLeg1; + double fracA0 = min(0.5, eShift / pInARF[0].e()); + double fracA1 = min(0.5, eShift / pInARF[0].e()); + Vec4 pFromAnti = fracA0 * pAntiLeg0 + fracA1 * pAntiLeg1; + + // Copy partons with scaled-down momenta and update legs. + int iNew = event.copy(iJunLeg0[1], 76); + event[iNew].rescale5(1. - fracJ0); + iJunLeg0[1] = iNew; + iNew = event.copy(iJunLeg1[1], 76); + event[iNew].rescale5(1. - fracJ1); + iJunLeg1[1] = iNew; + iNew = event.copy(iAntiLeg0[1], 76); + event[iNew].rescale5(1. - fracA0); + iAntiLeg0[1] = iNew; + iNew = event.copy(iAntiLeg1[1], 76); + event[iNew].rescale5(1. - fracA1); + iAntiLeg1[1] = iNew; + + // Pick a new quark at random; for simplicity no diquarks. + int idQ = flavSel.pickLightQ(); + + // Update junction colours for new quark and antiquark. + int colQ = event.nextColTag(); + int acolQ = event.nextColTag(); + event.endColJunction(identJun - 1, legJun[0], colQ); + event.endColJunction(identAnti - 1, legAnti[0], acolQ); + + // Store new quark and antiquark with momentum from other junction. + int mother1 = min(iJunLeg0[1], iJunLeg1[1]); + int mother2 = max(iJunLeg0[1], iJunLeg1[1]); + int iNewJ = event.append( idQ, 76, mother1, mother2, 0, 0, + colQ, 0, pFromAnti, pFromAnti.mCalc() ); + mother1 = min(iAntiLeg0[1], iAntiLeg1[1]); + mother2 = max(iAntiLeg0[1], iAntiLeg1[1]); + int iNewA = event.append( -idQ, 76, mother1, mother2, 0, 0, + 0, acolQ, pFromJun, pFromJun.mCalc() ); + + // Bookkeep new quark and antiquark on third legs. + if (legJun[0] == 0) iJunLegA[1] = iNewJ; + else if (legJun[0] == 1) iJunLegB[1] = iNewJ; + else iJunLegC[1] = iNewJ; + if (legAnti[0] == 0) iAntiLegA[1] = iNewA; + else if (legAnti[0] == 1) iAntiLegB[1] = iNewA; + else iAntiLegC[1] = iNewA; + + // Done with splitting junction from antijunction. + } + + // Put together new junction parton list. + iPartonJun.resize(0); + for (int i = 0; i < int(iJunLegA.size()); ++i) + iPartonJun.push_back( iJunLegA[i] ); + for (int i = 0; i < int(iJunLegB.size()); ++i) + iPartonJun.push_back( iJunLegB[i] ); + for (int i = 0; i < int(iJunLegC.size()); ++i) + iPartonJun.push_back( iJunLegC[i] ); + + // Put together new antijunction parton list. + iPartonAntiJun.resize(0); + for (int i = 0; i < int(iAntiLegA.size()); ++i) + iPartonAntiJun.push_back( iAntiLegA[i] ); + for (int i = 0; i < int(iAntiLegB.size()); ++i) + iPartonAntiJun.push_back( iAntiLegB[i] ); + for (int i = 0; i < int(iAntiLegC.size()); ++i) + iPartonAntiJun.push_back( iAntiLegC[i] ); + + // Now the two junction systems are separated and can be stored. + return true; + +} + +//************************************************************************** + +} // end namespace Pythia8 + diff --git a/PYTHIA8/pythia8130/src/Info.cxx b/PYTHIA8/pythia8130/src/Info.cxx new file mode 100644 index 00000000000..c94e7cfeab3 --- /dev/null +++ b/PYTHIA8/pythia8130/src/Info.cxx @@ -0,0 +1,186 @@ +// Info.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the Info class. + +#include "Info.h" + +namespace Pythia8 { + +//************************************************************************** + +// Info class. +// This class contains a mixed bag of information on the event generation +// activity, especially on the current subprocess properties. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Number of times the same error message will be repeated at most. +const int Info::TIMESTOPRINT = 1; + +//********* + +// List (almost) all information currently set. + +void Info::list(ostream& os) { + + // Header and beam info. + os << "\n -------- PYTHIA Info Listing ------------------------" + << "---------------- \n \n" + << scientific << setprecision(3) + << " Beam A: id = " << setw(6) << idASave << ", pz = " << setw(10) + << pzASave << ", e = " << setw(10) << eASave << ", m = " << setw(10) + << mASave << ".\n" + << " Beam B: id = " << setw(6) << idBSave << ", pz = " << setw(10) + << pzBSave << ", e = " << setw(10) << eBSave << ", m = " << setw(10) + << mBSave << ".\n\n"; + + // Done if no subprocess has been defined. + if (codeSave == 0 && nFinalSave == 0) { + os << " No process has been set; something must have gone wrong! \n" + << "\n -------- End PYTHIA Info Listing --------------------" + << "----------------" << endl; + return; + } + + // Colliding parton info. + if (isRes) + os << " In 1: id = " << setw(4) << id1Save << ", x = " << setw(10) + << x1Save << ", pdf = " << setw(10) << pdf1Save << " at Q2 = " + << setw(10) << Q2FacSave << ".\n" + << " In 2: id = " << setw(4) << id2Save << ", x = " << setw(10) + << x2Save << ", pdf = " << setw(10) << pdf2Save << " at same Q2.\n\n"; + + // Process name and code. + os << ((isRes && !hasSubSave) ? " Subprocess " : " Process ") << nameSave + << " with code " << codeSave << " is 2 -> " << nFinalSave << ".\n"; + + // Subprocess name and code for minimum bias processes. + if (hasSubSave) + os << " Subprocess " << nameSubSave << " with code " << codeSubSave + << " is 2 -> " << nFinalSubSave << ".\n"; + + // Process-type-specific kinematics information. + if (isRes && nFinalSave == 1) + os << " It has sHat = " << setw(10) << sH << ".\n"; + else if ( isRes && nFinalSave == 2) + os << " It has sHat = " << setw(10) << sH << ", tHat = " + << setw(10) << tH << ", uHat = " << setw(10) << uH << ",\n" + << " pTHat = " << setw(10) << pTH << ", m3Hat = " + << setw(10) << m3H << ", m4Hat = " << setw(10) << m4H << ",\n" + << " thetaHat = " << setw(10) << thetaH << ", phiHat = " + << setw(10) << phiH << ".\n"; + else if ( nFinalSave == 2) + os << " It has s = " << setw(10) << sH << ", t = " << setw(10) + << tH << ", u = " << setw(10) << uH << ",\n" + << " pT = " << setw(10) << pTH << ", m3 = " << setw(10) + << m3H << ", m4 = " << setw(10) << m4H << ",\n" + << " theta = " << setw(10) << thetaH << ", phi = " << setw(10) + << phiH << ".\n"; + else if ( isRes && nFinalSave == 3) + os << " It has sHat = " << setw(10) << sH << ", = " + << setw(10) << pTH << ".\n"; + + // Couplings. + if (isRes) os << " alphaEM = " << setw(10) << alphaEMSave + << ", alphaS = " << setw(10) << alphaSSave << " at Q2 = " + << setw(10) << Q2RenSave << ".\n"; + + // Impact parameter. + if (bIsSet) os << "\n Impact parameter b =" << setw(10) << bMISave + << " gives enhancement factor = " << setw(10) << enhanceMISave + << ".\n"; + + // Multiple interactions and shower evolution. + if (evolIsSet) os << " Max pT scale for MI = " << setw(10) << pTmaxMISave + << ", ISR = " << setw(10) << pTmaxISRSave << ", FSR = " << setw(10) + << pTmaxISRSave << ".\n Number of MI = " << setw(5) << nMISave + << ", ISR = " << setw(5) << nISRSave << ", FSRproc = " << setw(5) + << nFSRinProcSave << ", FSRreson = " << setw(5) << nFSRinResSave + << ".\n"; + + // Listing finished. + os << "\n -------- End PYTHIA Info Listing --------------------" + << "----------------" << endl; + +} + +//********* + +// Print a message the first few times. Insert in database. + +void Info::errorMsg(string messageIn, string extraIn, ostream& os) { + + // Recover number of times message occured. Also inserts new string. + int times = messages[messageIn]; + ++messages[messageIn]; + + // Print message the first few times. + if (times < TIMESTOPRINT) os << " PYTHIA " << messageIn << " " + << extraIn << endl; + +} + +//********* + +// Provide total number of errors/aborts/warnings experienced to date. + +int Info::errorTotalNumber() { + + int nTot = 0; + for ( map::iterator messageEntry = messages.begin(); + messageEntry != messages.end(); ++messageEntry) + nTot += messageEntry->second; + return nTot; + +} + +//********* + +// Print statistics on errors/aborts/warnings. + +void Info::errorStatistics(ostream& os) { + + // Header. + os << "\n *------- PYTHIA Error and Warning Messages Statistics " + << "----------------------------------------------------------* \n" + << " | " + << " | \n" + << " | times message " + << " | \n" + << " | " + << " | \n"; + + // Loop over all messages + map::iterator messageEntry = messages.begin(); + if (messageEntry == messages.end()) + os << " | 0 no errors or warnings to report " + << " | \n"; + while (messageEntry != messages.end()) { + // Debug printout. + string temp = messageEntry->first; + int len = temp.length(); + temp.insert( len, max(0, 102 - len), ' '); + os << " | " << setw(6) << messageEntry->second << " " + << temp << " | \n"; + ++messageEntry; + } + + // Done. + os << " | " + << " | \n" + << " *------- End PYTHIA Error and Warning Messages Statistics" + << " ------------------------------------------------------* " + << endl; + +} + +//************************************************************************** + +} // end namespace Pythia8 + diff --git a/PYTHIA8/pythia8130/src/LesHouches.cxx b/PYTHIA8/pythia8130/src/LesHouches.cxx new file mode 100644 index 00000000000..296355629eb --- /dev/null +++ b/PYTHIA8/pythia8130/src/LesHouches.cxx @@ -0,0 +1,503 @@ +// LesHouches.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the LHAup and +// LHAupLHEF classes. + +#include "LesHouches.h" + +// Access time information. +#include + +namespace Pythia8 { + +//************************************************************************** + +// LHAup class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// LHA convention with cross section in pb may require conversion from mb. +const double LHAup::CONVERTMB2PB = 1e9; + +//********* + +// Print the initialization info; to check it worked. + +void LHAup::listInit(ostream& os) { + + // Header. + os << "\n -------- LHA initialization information ------------ \n"; + + // Beam info. + os << fixed << setprecision(3) + << "\n beam kind energy pdfgrp pdfset \n" + << " A " << setw(6) << idBeamASave + << setw(12) << eBeamASave + << setw(8) << pdfGroupBeamASave + << setw(8) << pdfSetBeamASave << "\n" + << " B " << setw(6) << idBeamBSave + << setw(12) << eBeamBSave + << setw(8) << pdfGroupBeamBSave + << setw(8) << pdfSetBeamBSave << "\n"; + + // Event weighting strategy. + os << "\n Event weighting strategy = " << setw(2) + << strategySave << "\n" ; + + // Process list. + os << scientific << setprecision(4) + << "\n Processes, with strategy-dependent cross section info \n" + << " number xsec (pb) xerr (pb) xmax (pb) \n" ; + for (int ip = 0; ip < int(processes.size()); ++ip) { + os << setw(8) << processes[ip].idProc + << setw(15) << processes[ip].xSecProc + << setw(15) << processes[ip].xErrProc + << setw(15) << processes[ip].xMaxProc << "\n"; + } + + // Finished. + os << "\n -------- End LHA initialization information -------- \n"; + +} + +//********* + +// Print the event info; to check it worked. + +void LHAup::listEvent(ostream& os) { + + // Header. + os << "\n -------- LHA event information and listing -------------" + << "--------------------------------------------------------- \n"; + + // Basic event info. + os << scientific << setprecision(4) + << "\n process = " << setw(8) << idProc + << " weight = " << setw(12) << weightProc + << " scale = " << setw(12) << scaleProc << " (GeV) \n" + << " " + << " alpha_em = " << setw(12) << alphaQEDProc + << " alpha_strong = " << setw(12) << alphaQCDProc << "\n"; + + // Particle list + os << fixed << setprecision(3) + << "\n Participating Particles \n" + << " no id stat mothers colours p_x " + << "p_y p_z e m tau spin \n" ; + for (int ip = 1; ip < int(particles.size()); ++ip) { + os << setw(6) << ip + << setw(10) << particles[ip].idPart + << setw(5) << particles[ip].statusPart + << setw(6) << particles[ip].mother1Part + << setw(6) << particles[ip].mother2Part + << setw(6) << particles[ip].col1Part + << setw(6) << particles[ip].col2Part + << setw(11) << particles[ip].pxPart + << setw(11) << particles[ip].pyPart + << setw(11) << particles[ip].pzPart + << setw(11) << particles[ip].ePart + << setw(11) << particles[ip].mPart + << setw(8) << particles[ip].tauPart + << setw(8) << particles[ip].spinPart << "\n"; + } + + // PDF info - optional. + if (pdfIsSetSave) os << "\n pdf: id1 =" << setw(5) << id1Save + << " id2 =" << setw(5) << id2Save + << " x1 =" << scientific << setw(10) << x1Save + << " x2 =" << setw(10) << x2Save + << " scalePDF =" << setw(10) << scalePDFSave + << " xpdf1 =" << setw(10) << xpdf1Save + << " xpdf2 =" << setw(10) << xpdf2Save << "\n"; + + // Finished. + os << "\n -------- End LHA event information and listing ---------" + << "--------------------------------------------------------- \n"; + +} + +//********* + +// Open and write header to a Les Houches Event File. + +bool LHAup::openLHEF(string fileNameIn) { + + // Open file for writing. Reset it to be empty. + fileName = fileNameIn; + const char* cstring = fileName.c_str(); + osLHEF.open(cstring, ios::out | ios::trunc); + if (!osLHEF) { + infoPtr->errorMsg("Error in LHAup::openLHEF:" + " could not open file", fileName); + return false; + } + + // Read out current date and time. + time_t t = time(0); + strftime(dateNow,12,"%d %b %Y",localtime(&t)); + strftime(timeNow,9,"%H:%M:%S",localtime(&t)); + + // Write header. + osLHEF << "\n" + << "" << endl; + + // Done. + return true; + +} + +//********* + +// Write initialization information to a Les Houches Event File. + +bool LHAup::initLHEF() { + + // Write information on beams. + osLHEF << "\n" << scientific << setprecision(6) + << " " << idBeamASave << " " << idBeamBSave + << " " << eBeamASave << " " << eBeamBSave + << " " << pdfGroupBeamASave << " " << pdfGroupBeamBSave + << " " << pdfSetBeamASave << " " << pdfSetBeamBSave + << " " << strategySave << " " << processes.size() << "\n"; + + // Write information on all the subprocesses. + for (int ip = 0; ip < int(processes.size()); ++ip) + osLHEF << " " << setw(13) << processes[ip].xSecProc + << " " << setw(13) << processes[ip].xErrProc + << " " << setw(13) << processes[ip].xMaxProc + << " " << setw(6) << processes[ip].idProc << "\n"; + + // Done. + osLHEF << "" << endl; + return true; + +} + +//********* + +// Write event information to a Les Houches Event File. + +bool LHAup::eventLHEF() { + + // Write information on process as such. + osLHEF << "\n" << scientific << setprecision(6) + << " " << setw(5) << particles.size() - 1 + << " " << setw(5) << idProc + << " " << setw(13) << weightProc + << " " << setw(13) << scaleProc + << " " << setw(13) << alphaQEDProc + << " " << setw(13) << alphaQCDProc << "\n"; + + // Write information on the particles, excluding zeroth. + for (int ip = 1; ip < int(particles.size()); ++ip) { + osLHEF << " " << setw(8) << particles[ip].idPart + << " " << setw(5) << particles[ip].statusPart + << " " << setw(5) << particles[ip].mother1Part + << " " << setw(5) << particles[ip].mother2Part + << " " << setw(5) << particles[ip].col1Part + << " " << setw(5) << particles[ip].col2Part << setprecision(10) + << " " << setw(17) << particles[ip].pxPart + << " " << setw(17) << particles[ip].pyPart + << " " << setw(17) << particles[ip].pzPart + << " " << setw(17) << particles[ip].ePart + << " " << setw(17) << particles[ip].mPart << setprecision(6); + if (particles[ip].tauPart == 0.) osLHEF << " 0."; + else osLHEF << " " << setw(13) << particles[ip].tauPart; + if (particles[ip].spinPart == 9.) osLHEF << " 9."; + else osLHEF << " " << setw(13) << particles[ip].spinPart; + osLHEF << "\n"; + } + + // Optionally write information on PDF values at hard interaction. + if (pdfIsSetSave) osLHEF << "#pdf" + << " " << setw(4) << id1Save + << " " << setw(4) << id2Save + << " " << setw(13) << x1Save + << " " << setw(13) << x2Save + << " " << setw(13) << scalePDFSave + << " " << setw(13) << xpdf1Save + << " " << setw(13) << xpdf2Save << "\n"; + + // Done. + osLHEF << "" << endl; + return true; + +} + +//********* + +// Write end of a Les Houches Event File and close it. + +bool LHAup::closeLHEF(bool updateInit) { + + // Write an end to the file. + osLHEF << "" << endl; + osLHEF.close(); + + // Optionally update the cross section information. + if (updateInit) { + const char* cstring = fileName.c_str(); + osLHEF.open(cstring, ios::in | ios::out); + + // Rewrite header; identically with what openLHEF did. + osLHEF << "\n" + << "" << endl; + + // Redo initialization information. + initLHEF(); + osLHEF.close(); + } + + // Done. + return true; + +} + +//************************************************************************** + +// LHAupLHEF class. + +//********* + +// Read in initialization information from a Les Houches Event File. + +bool LHAupLHEF::setInit() { + + // Check that first line is consistent with proper LHEF file. + string line; + if (!getline(is, line)) return false; + if (line.find("> tag; + if (!getfirst) return false; + } + } while (tag != "" && tag != "> idbmupA >> idbmupB >> ebmupA >> ebmupB >> pdfgupA + >> pdfgupB >> pdfsupA >> pdfsupB >> idwtup >> nprup; + if (!getbms) return false; + setBeamA(idbmupA, ebmupA, pdfgupA, pdfsupA); + setBeamB(idbmupB, ebmupB, pdfgupB, pdfsupB); + setStrategy(idwtup); + + // Read in process info, one process at a time, and store it. + double xsecup, xerrup, xmaxup; + int lprup; + for (int ip = 0; ip < nprup; ++ip) { + if (!getline(is, line)) return false; + istringstream getpro(line); + getpro >> xsecup >> xerrup >> xmaxup >> lprup ; + if (!getpro) return false; + addProcess(lprup, xsecup, xerrup, xmaxup); + } + + // Reading worked. + return true; + +} + +//********* + +// Read in event information from a Les Houches Event File. + +bool LHAupLHEF::setEvent( int ) { + + // Loop over lines until an > tag; + if (!getfirst) return false; + } + } while (tag != "" && tag != "> nup >> idprup >> xwgtup >> scalup >> aqedup >> aqcdup; + if (!getpro) return false; + setProcess(idprup, xwgtup, scalup, aqedup, aqcdup); + + // Read in particle info one by one, and store it. + // Note unusual C++ loop range, to better reflect LHA/Fortran standard. + // (Recall that process(...) above added empty particle at index 0.) + int idup, istup, mothup1, mothup2, icolup1, icolup2; + double pup1, pup2, pup3, pup4, pup5, vtimup, spinup; + for (int ip = 1; ip <= nup; ++ip) { + if (!getline(is, line)) return false; + istringstream getall(line); + getall >> idup >> istup >> mothup1 >> mothup2 >> icolup1 >> icolup2 + >> pup1 >> pup2 >> pup3 >> pup4 >> pup5 >> vtimup >> spinup; + if (!getall) return false; + addParticle(idup, istup, mothup1, mothup2, icolup1, icolup2, + pup1, pup2, pup3, pup4, pup5, vtimup, spinup) ; + } + + // Continue parsing till . Extract pdf info if present. + do { + if (!getline(is, line)) return false; + istringstream getpdf(line); + getpdf >> tag; + if (!getpdf) return false; + if (tag == "#pdf") { + int id1In, id2In; + double x1In, x2In, scalePDFIn, xpdf1In, xpdf2In; + getpdf >> id1In >> id2In >> x1In >> x2In >> scalePDFIn + >> xpdf1In >> xpdf2In; + if (!getpdf) return false; + setPdf(id1In, id2In, x1In, x2In, scalePDFIn, xpdf1In, xpdf2In); + } + } while (tag != "" && tag != "idA(); + int idbmupB = infoPtr->idB(); + double ebmupA = infoPtr->eA(); + double ebmupB = infoPtr->eB(); + int pdfgupA = 0; + int pdfgupB = 0; + int pdfsupA = 0; + int pdfsupB = 0; + setBeamA(idbmupA, ebmupA, pdfgupA, pdfsupA); + setBeamB(idbmupB, ebmupB, pdfgupB, pdfsupB); + + // Currently only one allowed strategy. + int idwtup = 3; + setStrategy(idwtup); + + // Only one process with dummy information. (Can overwrite at the end.) + int lprup = 9999; + double xsecup = 1.; + double xerrup = 0.; + double xmaxup = 1.; + addProcess(lprup, xsecup, xerrup, xmaxup); + + // Done. + return true; + +} + +//********* + +// Read in event information from PYTHIA 8. + +bool LHAupFromPYTHIA8::setEvent( int ) { + + // Read process information from Info class, and store it. + // Note: renormalization scale here, factorization further down. + int idprup = infoPtr->code(); + // For now always convert to process 9999. + idprup = 9999; + double xwgtup = infoPtr->weight(); + double scalup = infoPtr->QRen(); + double aqedup = infoPtr->alphaEM(); + double aqcdup = infoPtr->alphaS(); + setProcess(idprup, xwgtup, scalup, aqedup, aqcdup); + + // Read in particle info one by one, excluding zero and beams, and store it. + // Note unusual C++ loop range, to better reflect LHA/Fortran standard. + int nup = processPtr->size() - 3; + int idup, statusup, istup, mothup1, mothup2, icolup1, icolup2; + double pup1, pup2, pup3, pup4, pup5, vtimup, spinup; + for (int ip = 1; ip <= nup; ++ip) { + Particle& particle = (*processPtr)[ip + 2]; + idup = particle.id(); + // Convert from PYTHIA8 to LHA status codes. + statusup = particle.status(); + if (ip < 3) istup = -1; + else if (statusup < 0) istup = 2; + else istup = 1; + mothup1 = max(0, particle.mother1() - 2); + mothup2 = max(0, particle.mother2() - 2); + icolup1 = particle.col(); + icolup2 = particle.acol(); + pup1 = particle.px(); + pup2 = particle.py(); + pup3 = particle.pz(); + pup4 = particle.e(); + pup5 = particle.m(); + vtimup = particle.tau(); + spinup = 9.; + addParticle(idup, istup, mothup1, mothup2, icolup1, icolup2, + pup1, pup2, pup3, pup4, pup5, vtimup, spinup) ; + } + + // Also extract pdf information from Info class, and store it. + int id1up = infoPtr->id1(); + int id2up = infoPtr->id2(); + double x1up = infoPtr->x1(); + double x2up = infoPtr->x2(); + double scalePDFup = infoPtr->QFac(); + double xpdf1up = infoPtr->pdf1(); + double xpdf2up = infoPtr->pdf2(); + setPdf(id1up, id2up, x1up, x2up, scalePDFup, xpdf1up, xpdf2up); + + // Done. + return true; + +} + +//********* + +// Update cross-section information at the end of the run. + +bool LHAupFromPYTHIA8::updateSigma() { + + // Read out information from PYTHIA 8 and send it in to LHA. + double sigGen = CONVERTMB2PB * infoPtr->sigmaGen(); + double sigErr = CONVERTMB2PB * infoPtr->sigmaErr(); + setXSec(0, sigGen); + setXErr(0, sigErr); + + // Done. + return true; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/MiniStringFragmentation.cxx b/PYTHIA8/pythia8130/src/MiniStringFragmentation.cxx new file mode 100644 index 00000000000..93e4ce05e5d --- /dev/null +++ b/PYTHIA8/pythia8130/src/MiniStringFragmentation.cxx @@ -0,0 +1,317 @@ +// MiniStringFragmentation.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the . +// MiniStringFragmentation class + +#include "MiniStringFragmentation.h" + +namespace Pythia8 { + +//************************************************************************** + +// The MiniStringFragmentation class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Since diffractive by definition is > 1 particle, try hard. +const int MiniStringFragmentation::NTRYDIFFRACTIVE = 200; + +// After one-body fragmentation failed, try two-body once more. +const int MiniStringFragmentation::NTRYLASTRESORT = 100; + +// To avoid division by zero one must have sigma > 0. +const double MiniStringFragmentation::SIGMAMIN = 0.01; + +// Loop try to combine available endquarks to valid hadron. +const int MiniStringFragmentation::NTRYFLAV = 10; + +//********* + +// Initialize and save pointers. + +void MiniStringFragmentation::init(Info* infoPtrIn, + StringFlav* flavSelPtrIn) { + + // Save pointers. + infoPtr = infoPtrIn; + flavSelPtr = flavSelPtrIn; + + // Initialize the MiniStringFragmentation class proper. + nTryMass = Settings::mode("MiniStringFragmentation:nTry"); + sigma = Settings::parm("StringPT:sigma"); + sigma2Had = 2. * pow2( max( SIGMAMIN, sigma) ); + + // Initialize the b parameter of the z spectrum, used when joining jets. + bLund = Settings::parm("StringZ:bLund"); + +} + +//********* + +// Do the fragmentation: driver routine. + +bool MiniStringFragmentation::fragment(int iSub, ColConfig& colConfig, + Event& event, bool isDiff) { + + // Read in info on system to be treated. + iParton = colConfig[iSub].iParton; + flav1.id = event[ iParton.front() ].id(); + flav2.id = event[ iParton.back() ].id(); + pSum = colConfig[iSub].pSum; + mSum = colConfig[iSub].mass; + m2Sum = mSum*mSum; + isClosed = colConfig[iSub].isClosed; + + // Do not want diffractive systems to easily collapse to one particle. + int nTryFirst = (isDiff) ? NTRYDIFFRACTIVE : nTryMass; + + // First try to produce two particles from the system. + if (ministring2two( nTryFirst, event)) return true; + + // If this fails, then form one hadron and shuffle momentum. + if (ministring2one( iSub, colConfig, event)) return true; + + // If also this fails, then try harder to produce two particles. + if (ministring2two( NTRYLASTRESORT, event)) return true; + + // Else complete failure. + infoPtr->errorMsg("Error in MiniStringFragmentation::fragment: " + "no 1- or 2-body state found above mass threshold"); + return false; + +} + +//********* + + // Attempt to produce two particles from the ministring. + +bool MiniStringFragmentation::ministring2two( int nTry, Event& event) { + + // Properties of the produced hadrons. + int idHad1 = 0; + int idHad2 = 0; + double mHad1 = 0.; + double mHad2 = 0.; + double mHadSum = 0.; + + // Allow a few attempts to find a particle pair with low enough masses. + for (int iTry = 0; iTry < nTry; ++iTry) { + + // For closed gluon loop need to pick an initial flavour. + if (isClosed) do { + int idStart = flavSelPtr->pickLightQ(); + FlavContainer flavStart(idStart, 1); + flavStart = flavSelPtr->pick( flavStart); + flav1 = flavSelPtr->pick( flavStart); + flav2.anti(flav1); + } while (flav1.id == 0 || flav1.nPop > 0); + + // Create a new q qbar flavour to form two hadrons. + // Start from a diquark, if any. + do { + FlavContainer flav3 = + (abs(flav1.id) > 8 || (abs(flav2.id) < 9 && Rndm::flat() < 0.5) ) + ? flavSelPtr->pick( flav1) : flavSelPtr->pick( flav2).anti(); + idHad1 = flavSelPtr->combine( flav1, flav3); + idHad2 = flavSelPtr->combine( flav2, flav3.anti()); + } while (idHad1 == 0 || idHad2 == 0); + + // Check whether the mass sum fits inside the available phase space. + mHad1 = ParticleDataTable::mass(idHad1); + mHad2 = ParticleDataTable::mass(idHad2); + mHadSum = mHad1 + mHad2; + if (mHadSum < mSum) break; + } + if (mHadSum >= mSum) return false; + + // Define an effective two-parton string, by splitting intermediate + // gluon momenta in proportion to their closeness to either endpoint. + Vec4 pSum1 = event[ iParton.front() ].p(); + Vec4 pSum2 = event[ iParton.back() ].p(); + if (iParton.size() > 2) { + Vec4 pEnd1 = pSum1; + Vec4 pEnd2 = pSum2; + Vec4 pEndSum = pEnd1 + pEnd2; + for (int i = 1; i < int(iParton.size()) - 1 ; ++i) { + Vec4 pNow = event[ iParton[i] ].p(); + double ratio = (pEnd2 * pNow) / (pEndSum * pNow); + pSum1 += ratio * pNow; + pSum2 += (1. - ratio) * pNow; + } + } + + // Set up a string region based on the two effective endpoints. + StringRegion region; + region.setUp( pSum1, pSum2); + + // Generate an isotropic decay in the ministring rest frame, + // suppressed at large pT by a fragmentation pT Gaussian. + double pAbs2 = 0.25 * ( pow2(m2Sum - mHad1*mHad1 - mHad2*mHad2) + - pow2(2. * mHad1 * mHad2) ) / m2Sum; + double pT2 = 0.; + do { + double cosTheta = Rndm::flat(); + if (sigma < SIGMAMIN) cosTheta = 1.; + pT2 = (1. - pow2(cosTheta)) * pAbs2; + } while ( exp( -pT2 / sigma2Had) < Rndm::flat() ); + + // Construct the forward-backward asymmetry of the two particles. + double mT21 = mHad1*mHad1 + pT2; + double mT22 = mHad2*mHad2 + pT2; + double lambda = sqrtpos( pow2(m2Sum - mT21 - mT22) - 4. * mT21 * mT22 ); + double probReverse = 1. / (1. + exp( min( 50., bLund * lambda) ) ); + + // Construct kinematics, as viewed in the transverse rest frame. + double xpz1 = 0.5 * lambda/ m2Sum; + if (probReverse > Rndm::flat()) xpz1 = -xpz1; + double xmDiff = (mT21 - mT22) / m2Sum; + double xe1 = 0.5 * (1. + xmDiff); + double xe2 = 0.5 * (1. - xmDiff ); + + // Distribute pT isotropically in angle. + double phi = 2. * M_PI * Rndm::flat(); + double pT = sqrt(pT2); + double px = pT * cos(phi); + double py = pT * sin(phi); + + // Translate this into kinematics in the string frame. + Vec4 pHad1 = region.pHad( xe1 + xpz1, xe1 - xpz1, px, py); + Vec4 pHad2 = region.pHad( xe2 - xpz1, xe2 + xpz1, -px, -py); + + // Add produced particles to the event record. + int iFirst = event.append( idHad1, 82, iParton.front(), iParton.back(), + 0, 0, 0, 0, pHad1, mHad1); + int iLast = event.append( idHad2, 82, iParton.front(), iParton.back(), + 0, 0, 0, 0, pHad2, mHad2); + + // Set decay vertex when this is displaced. + if (event[iParton.front()].hasVertex()) { + Vec4 vDec = event[iParton.front()].vDec(); + event[iFirst].vProd( vDec ); + event[iLast].vProd( vDec ); + } + + // Set lifetime of hadrons. + event[iFirst].tau( event[iFirst].tau0() * Rndm::exp() ); + event[iLast].tau( event[iLast].tau0() * Rndm::exp() ); + + // Mark original partons as hadronized and set their daughter range. + for (int i = 0; i < int(iParton.size()); ++i) { + event[ iParton[i] ].statusNeg(); + event[ iParton[i] ].daughters(iFirst, iLast); + } + + // Successfully done. + return true; + +} + +//********* + +// Attempt to produce one particle from a ministring. +// Current algorithm: find the system with largest invariant mass +// relative to the existing one, and boost that system appropriately. +// Try more sophisticated alternatives later?? (Z0 mass shifted??) +// Also, if problems, attempt several times to obtain closer mass match?? + +bool MiniStringFragmentation::ministring2one( int iSub, + ColConfig& colConfig, Event& event) { + + // Cannot handle qq + qbarqbar system. + if (abs(flav1.id) > 100 && abs(flav2.id) > 100) return false; + + // For closed gluon loop need to pick an initial flavour. + if (isClosed) do { + int idStart = flavSelPtr->pickLightQ(); + FlavContainer flavStart(idStart, 1); + flav1 = flavSelPtr->pick( flavStart); + flav2 = flav1.anti(); + } while (abs(flav1.id) > 100); + + // Select hadron flavour from available quark flavours. + int idHad = 0; + for (int iTryFlav = 0; iTryFlav < NTRYFLAV; ++iTryFlav) { + idHad = flavSelPtr->combine( flav1, flav2); + if (idHad != 0) break; + } + if (idHad == 0) return false; + + // Find mass. + double mHad = ParticleDataTable::mass(idHad); + + // Find the untreated parton system which combines to the largest + // squared mass above mimimum required. + int iMax = -1; + double deltaM2 = mHad*mHad - mSum*mSum; + double delta2Max = 0.; + for (int iRec = iSub + 1; iRec < colConfig.size(); ++iRec) { + double delta2Rec = 2. * (pSum * colConfig[iRec].pSum) - deltaM2 + - 2. * mHad * colConfig[iRec].mass; + if (delta2Rec > delta2Max) { iMax = iRec; delta2Max = delta2Rec;} + } + if (iMax == -1) return false; + + // Construct kinematics of the hadron and recoiling system. + Vec4& pRec = colConfig[iMax].pSum; + double mRec = colConfig[iMax].mass; + double vecProd = pSum * pRec; + double coefOld = mSum*mSum + vecProd; + double coefNew = mHad*mHad + vecProd; + double coefRec = mRec*mRec + vecProd; + double coefSum = coefOld + coefNew; + double sHat = coefOld + coefRec; + double root = sqrtpos( (pow2(coefSum) - 4. * sHat * mHad*mHad) + / (pow2(vecProd) - pow2(mSum * mRec)) ); + double k2 = 0.5 * (coefOld * root - coefSum) / sHat; + double k1 = (coefRec * k2 + 0.5 * deltaM2) / coefOld; + Vec4 pHad = (1. + k1) * pSum - k2 * pRec; + Vec4 pRecNew = (1. + k2) * pRec - k1 * pSum; + + // Add the produced particle to the event record. + int iHad = event.append( idHad, 81, iParton.front(), iParton.back(), + 0, 0, 0, 0, pHad, mHad); + + // Set decay vertex when this is displaced. + if (event[iParton.front()].hasVertex()) { + Vec4 vDec = event[iParton.front()].vDec(); + event[iHad].vProd( vDec ); + } + + // Set lifetime of hadron. + event[iHad].tau( event[iHad].tau0() * Rndm::exp() ); + + // Mark original partons as hadronized and set their daughter range. + for (int i = 0; i < int(iParton.size()); ++i) { + event[ iParton[i] ].statusNeg(); + event[ iParton[i] ].daughters(iHad, iHad); + } + + // Copy down recoiling system, with boosted momentum. Update current partons. + RotBstMatrix M; + M.bst(pRec, pRecNew); + for (int i = 0; i < colConfig[iMax].size(); ++i) { + int iOld = colConfig[iMax].iParton[i]; + // Do not touch negative iOld = beginning of new junction leg. + if (iOld >= 0) { + int iNew = event.copy(iOld, 72); + event[iNew].rotbst(M); + colConfig[iMax].iParton[i] = iNew; + } + } + colConfig[iMax].pSum = pRecNew; + colConfig[iMax].isCollected = true; + + // Successfully done. + return true; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/MultipleInteractions.cxx b/PYTHIA8/pythia8130/src/MultipleInteractions.cxx new file mode 100644 index 00000000000..762e09f17b0 --- /dev/null +++ b/PYTHIA8/pythia8130/src/MultipleInteractions.cxx @@ -0,0 +1,1353 @@ +// MultipleInteractions.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// SigmaMultiple and MultipleInteractions classes. + +#include "MultipleInteractions.h" + +// Internal headers for special processes. +#include "SigmaQCD.h" +#include "SigmaEW.h" +#include "SigmaOnia.h" + +namespace Pythia8 { + +//************************************************************************** + +// The SigmaMultiple class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// The sum of outgoing masses must not be too close to the cm energy. +const double SigmaMultiple::MASSMARGIN = 0.1; + +// Fraction of time not the dominant "gluon t-channel" process is picked. +const double SigmaMultiple::OTHERFRAC = 0.2; + +//********* + +// Initialize the generation process for given beams. + +bool SigmaMultiple::init(int inState, int processLevel) { + + // Reset vector sizes (necessary in case of re-initialization). + if (sigmaT.size() > 0) { + for (int i = 0; i < int(sigmaT.size()); ++i) delete sigmaT[i]; + sigmaT.resize(0); + } + if (sigmaU.size() > 0) { + for (int i = 0; i < int(sigmaU.size()); ++i) delete sigmaU[i]; + sigmaU.resize(0); + } + + // Always store mimimal set of processes:QCD 2 -> 2 t-channel. + + // Gluon-gluon instate. + if (inState == 0) { + sigmaT.push_back( new Sigma2gg2gg() ); + sigmaU.push_back( new Sigma2gg2gg() ); + + // Quark-gluon instate. + } else if (inState == 1) { + sigmaT.push_back( new Sigma2qg2qg() ); + sigmaU.push_back( new Sigma2qg2qg() ); + + // Quark-(anti)quark instate. + } else { + sigmaT.push_back( new Sigma2qq2qq() ); + sigmaU.push_back( new Sigma2qq2qq() ); + } + + // Normally store QCD processes to new flavour. + if (processLevel > 0) { + if (inState == 0) { + sigmaT.push_back( new Sigma2gg2qqbar() ); + sigmaU.push_back( new Sigma2gg2qqbar() ); + sigmaT.push_back( new Sigma2gg2QQbar(4, 121) ); + sigmaU.push_back( new Sigma2gg2QQbar(4, 121) ); + sigmaT.push_back( new Sigma2gg2QQbar(5, 123) ); + sigmaU.push_back( new Sigma2gg2QQbar(5, 123) ); + } else if (inState == 2) { + sigmaT.push_back( new Sigma2qqbar2gg() ); + sigmaU.push_back( new Sigma2qqbar2gg() ); + sigmaT.push_back( new Sigma2qqbar2qqbarNew() ); + sigmaU.push_back( new Sigma2qqbar2qqbarNew() ); + sigmaT.push_back( new Sigma2qqbar2QQbar(4, 122) ); + sigmaU.push_back( new Sigma2qqbar2QQbar(4, 122) ); + sigmaT.push_back( new Sigma2qqbar2QQbar(5, 124) ); + sigmaU.push_back( new Sigma2qqbar2QQbar(5, 124) ); + } + } + + // Optionally store electroweak processes, mainly photon production. + if (processLevel > 1) { + if (inState == 0) { + sigmaT.push_back( new Sigma2gg2ggamma() ); + sigmaU.push_back( new Sigma2gg2ggamma() ); + sigmaT.push_back( new Sigma2gg2gammagamma() ); + sigmaU.push_back( new Sigma2gg2gammagamma() ); + } else if (inState == 1) { + sigmaT.push_back( new Sigma2qg2qgamma() ); + sigmaU.push_back( new Sigma2qg2qgamma() ); + } else if (inState == 2) { + sigmaT.push_back( new Sigma2qqbar2ggamma() ); + sigmaU.push_back( new Sigma2qqbar2ggamma() ); + sigmaT.push_back( new Sigma2ffbar2gammagamma() ); + sigmaU.push_back( new Sigma2ffbar2gammagamma() ); + sigmaT.push_back( new Sigma2ffbar2ffbarsgm() ); + sigmaU.push_back( new Sigma2ffbar2ffbarsgm() ); + } + if (inState >= 2) { + sigmaT.push_back( new Sigma2ff2fftgmZ() ); + sigmaU.push_back( new Sigma2ff2fftgmZ() ); + sigmaT.push_back( new Sigma2ff2fftW() ); + sigmaU.push_back( new Sigma2ff2fftW() ); + } + } + + // Optionally store charmonium and bottomonium production. + if (processLevel > 2) { + if (inState == 0) { + sigmaT.push_back( new Sigma2gg2QQbar3S11g(4, 401) ); + sigmaU.push_back( new Sigma2gg2QQbar3S11g(4, 401) ); + sigmaT.push_back( new Sigma2gg2QQbar3PJ1g(4, 0, 402) ); + sigmaU.push_back( new Sigma2gg2QQbar3PJ1g(4, 0, 402) ); + sigmaT.push_back( new Sigma2gg2QQbar3PJ1g(4, 1, 403) ); + sigmaU.push_back( new Sigma2gg2QQbar3PJ1g(4, 1, 403) ); + sigmaT.push_back( new Sigma2gg2QQbar3PJ1g(4, 2, 404) ); + sigmaU.push_back( new Sigma2gg2QQbar3PJ1g(4, 2, 404) ); + sigmaT.push_back( new Sigma2gg2QQbarX8g(4, 0, 411) ); + sigmaU.push_back( new Sigma2gg2QQbarX8g(4, 0, 411) ); + sigmaT.push_back( new Sigma2gg2QQbarX8g(4, 1, 412) ); + sigmaU.push_back( new Sigma2gg2QQbarX8g(4, 1, 412) ); + sigmaT.push_back( new Sigma2gg2QQbarX8g(4, 2, 413) ); + sigmaU.push_back( new Sigma2gg2QQbarX8g(4, 2, 413) ); + sigmaT.push_back( new Sigma2gg2QQbar3S11g(5, 501) ); + sigmaU.push_back( new Sigma2gg2QQbar3S11g(5, 501) ); + sigmaT.push_back( new Sigma2gg2QQbar3PJ1g(5, 0, 502) ); + sigmaU.push_back( new Sigma2gg2QQbar3PJ1g(5, 0, 502) ); + sigmaT.push_back( new Sigma2gg2QQbar3PJ1g(5, 1, 503) ); + sigmaU.push_back( new Sigma2gg2QQbar3PJ1g(5, 1, 503) ); + sigmaT.push_back( new Sigma2gg2QQbar3PJ1g(5, 2, 504) ); + sigmaU.push_back( new Sigma2gg2QQbar3PJ1g(5, 2, 504) ); + sigmaT.push_back( new Sigma2gg2QQbarX8g(5, 0, 511) ); + sigmaU.push_back( new Sigma2gg2QQbarX8g(5, 0, 511) ); + sigmaT.push_back( new Sigma2gg2QQbarX8g(5, 1, 512) ); + sigmaU.push_back( new Sigma2gg2QQbarX8g(5, 1, 512) ); + sigmaT.push_back( new Sigma2gg2QQbarX8g(5, 2, 513) ); + sigmaU.push_back( new Sigma2gg2QQbarX8g(5, 2, 513) ); + } else if (inState == 1) { + sigmaT.push_back( new Sigma2qg2QQbar3PJ1q(4, 0, 405) ); + sigmaU.push_back( new Sigma2qg2QQbar3PJ1q(4, 0, 405) ); + sigmaT.push_back( new Sigma2qg2QQbar3PJ1q(4, 1, 406) ); + sigmaU.push_back( new Sigma2qg2QQbar3PJ1q(4, 1, 406) ); + sigmaT.push_back( new Sigma2qg2QQbar3PJ1q(4, 2, 407) ); + sigmaU.push_back( new Sigma2qg2QQbar3PJ1q(4, 2, 407) ); + sigmaT.push_back( new Sigma2qg2QQbarX8q(4, 0, 414) ); + sigmaU.push_back( new Sigma2qg2QQbarX8q(4, 0, 414) ); + sigmaT.push_back( new Sigma2qg2QQbarX8q(4, 1, 415) ); + sigmaU.push_back( new Sigma2qg2QQbarX8q(4, 1, 415) ); + sigmaT.push_back( new Sigma2qg2QQbarX8q(4, 2, 416) ); + sigmaU.push_back( new Sigma2qg2QQbarX8q(4, 2, 416) ); + sigmaT.push_back( new Sigma2qg2QQbar3PJ1q(5, 0, 505) ); + sigmaU.push_back( new Sigma2qg2QQbar3PJ1q(5, 0, 505) ); + sigmaT.push_back( new Sigma2qg2QQbar3PJ1q(5, 1, 506) ); + sigmaU.push_back( new Sigma2qg2QQbar3PJ1q(5, 1, 506) ); + sigmaT.push_back( new Sigma2qg2QQbar3PJ1q(5, 2, 507) ); + sigmaU.push_back( new Sigma2qg2QQbar3PJ1q(5, 2, 507) ); + sigmaT.push_back( new Sigma2qg2QQbarX8q(5, 0, 514) ); + sigmaU.push_back( new Sigma2qg2QQbarX8q(5, 0, 514) ); + sigmaT.push_back( new Sigma2qg2QQbarX8q(5, 1, 515) ); + sigmaU.push_back( new Sigma2qg2QQbarX8q(5, 1, 515) ); + sigmaT.push_back( new Sigma2qg2QQbarX8q(5, 2, 516) ); + sigmaU.push_back( new Sigma2qg2QQbarX8q(5, 2, 516) ); + } else if (inState == 2) { + sigmaT.push_back( new Sigma2qqbar2QQbar3PJ1g(4, 0, 408) ); + sigmaU.push_back( new Sigma2qqbar2QQbar3PJ1g(4, 0, 408) ); + sigmaT.push_back( new Sigma2qqbar2QQbar3PJ1g(4, 1, 409) ); + sigmaU.push_back( new Sigma2qqbar2QQbar3PJ1g(4, 1, 409) ); + sigmaT.push_back( new Sigma2qqbar2QQbar3PJ1g(4, 2, 410) ); + sigmaU.push_back( new Sigma2qqbar2QQbar3PJ1g(4, 2, 410) ); + sigmaT.push_back( new Sigma2qqbar2QQbarX8g(4, 0, 417) ); + sigmaU.push_back( new Sigma2qqbar2QQbarX8g(4, 0, 417) ); + sigmaT.push_back( new Sigma2qqbar2QQbarX8g(4, 1, 418) ); + sigmaU.push_back( new Sigma2qqbar2QQbarX8g(4, 1, 418) ); + sigmaT.push_back( new Sigma2qqbar2QQbarX8g(4, 2, 419) ); + sigmaU.push_back( new Sigma2qqbar2QQbarX8g(4, 2, 419) ); + sigmaT.push_back( new Sigma2qqbar2QQbar3PJ1g(5, 0, 508) ); + sigmaU.push_back( new Sigma2qqbar2QQbar3PJ1g(5, 0, 508) ); + sigmaT.push_back( new Sigma2qqbar2QQbar3PJ1g(5, 1, 509) ); + sigmaU.push_back( new Sigma2qqbar2QQbar3PJ1g(5, 1, 509) ); + sigmaT.push_back( new Sigma2qqbar2QQbar3PJ1g(5, 2, 510) ); + sigmaU.push_back( new Sigma2qqbar2QQbar3PJ1g(5, 2, 510) ); + sigmaT.push_back( new Sigma2qqbar2QQbarX8g(5, 0, 517) ); + sigmaU.push_back( new Sigma2qqbar2QQbarX8g(5, 0, 517) ); + sigmaT.push_back( new Sigma2qqbar2QQbarX8g(5, 1, 518) ); + sigmaU.push_back( new Sigma2qqbar2QQbarX8g(5, 1, 518) ); + sigmaT.push_back( new Sigma2qqbar2QQbarX8g(5, 2, 519) ); + sigmaU.push_back( new Sigma2qqbar2QQbarX8g(5, 2, 519) ); + } + } + + // Resize arrays to match sizes above. + nChan = sigmaT.size(); + needMasses.resize(nChan); + m3Fix.resize(nChan); + m4Fix.resize(nChan); + sHatMin.resize(nChan); + sigmaTval.resize(nChan); + sigmaUval.resize(nChan); + + // Initialize the processes. + for (int i = 0; i < nChan; ++i) { + sigmaT[i]->initProc(); + sigmaU[i]->initProc(); + + // Prepare for massive kinematics (but fixed masses!) where required. + needMasses[i] = false; + int id3Mass = sigmaT[i]->id3Mass(); + int id4Mass = sigmaT[i]->id4Mass(); + m3Fix[i] = 0.; + m4Fix[i] = 0.; + if (id3Mass > 0 || id4Mass > 0) { + needMasses[i] = true; + m3Fix[i] = ParticleDataTable::m0(id3Mass); + m4Fix[i] = ParticleDataTable::m0(id4Mass); + } + sHatMin[i] = pow2( m3Fix[i] + m4Fix[i] + MASSMARGIN); + } + + // Done. + return true; + +} + +//********* + +// Calculate cross section summed over possibilities. + +double SigmaMultiple::sigma( int id1, int id2, double x1, double x2, + double sHat, double tHat, double uHat, double alpS, double alpEM) { + + // Choose either the dominant process (in slot 0) or the rest of them. + bool pickOther = (Rndm::flat() < OTHERFRAC); + + // Iterate over all subprocesses. + sigmaTsum = 0.; + sigmaUsum = 0.; + for (int i = 0; i < nChan; ++i) { + sigmaTval[i] = 0.; + sigmaUval[i] = 0.; + + // Skip the not chosen processes. + if (i == 0 && pickOther) continue; + if (i > 0 && !pickOther) continue; + + // t-channel-sampling contribution. + if (sHat > sHatMin[i]) { + sigmaT[i]->set2KinMI( x1, x2, sHat, tHat, uHat, + alpS, alpEM, needMasses[i], m3Fix[i], m4Fix[i]); + sigmaTval[i] = sigmaT[i]->sigmaHatWrap(id1, id2); + sigmaT[i]->pickInState(id1, id2); + // Correction factor for tHat rescaling in massive kinematics. + if (needMasses[i]) sigmaTval[i] *= sigmaT[i]->sHBetaMI() / sHat; + sigmaTsum += sigmaTval[i]; + } + + // u-channel-sampling contribution. + if (sHat > sHatMin[i]) { + sigmaU[i]->set2KinMI( x1, x2, sHat, uHat, tHat, + alpS, alpEM, needMasses[i], m3Fix[i], m4Fix[i]); + sigmaUval[i] = sigmaU[i]->sigmaHatWrap( id1, id2); + sigmaU[i]->pickInState(id1, id2); + // Correction factor for tHat rescaling in massive kinematics. + if (needMasses[i]) sigmaUval[i] *= sigmaU[i]->sHBetaMI() / sHat; + sigmaUsum += sigmaUval[i]; + } + + // Average of t- and u-channel sampling; corrected for not selected channels. + } + double sigmaAvg = 0.5 * (sigmaTsum + sigmaUsum); + if (pickOther) sigmaAvg /= OTHERFRAC; + if (!pickOther) sigmaAvg /= (1. - OTHERFRAC); + return sigmaAvg; + +} + +//********* + +// Return one subprocess, picked according to relative cross sections. + +SigmaProcess* SigmaMultiple::sigmaSel() { + + // Decide between t- and u-channel-sampled kinematics. + pickedU = (Rndm::flat() * (sigmaTsum + sigmaUsum) < sigmaUsum); + + // Pick one of t-channel-sampled processes. + if (!pickedU) { + double sigmaRndm = sigmaTsum * Rndm::flat(); + int iPick = -1; + do sigmaRndm -= sigmaTval[++iPick]; + while (sigmaRndm > 0.); + return sigmaT[iPick]; + + // Pick one of u-channel-sampled processes. + } else { + double sigmaRndm = sigmaUsum * Rndm::flat(); + int iPick = -1; + do sigmaRndm -= sigmaUval[++iPick]; + while (sigmaRndm > 0.); + return sigmaU[iPick]; + } + +} + +//************************************************************************** + +// The MultipleInteractions class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Factorization scale pT2 by default, but could be shifted to pT2 + pT02. +// (A priori possible, but problems for flavour threshold interpretation.) +const bool MultipleInteractions::SHIFTFACSCALE = false; + +// Naive upper estimate of cross section too pessimistic, so reduce by this. +const double MultipleInteractions::SIGMAFUDGE = 0.7; + +// Number of bins that the dpT2 / (pT2 + r * pT20)^2 range is split into. +const int MultipleInteractions::NBINS = 100; + +// The r value above, picked to allow a flatter correct/trial cross section. +const double MultipleInteractions::RPT20 = 0.25; + +// Reduce pT0 by factor pT0STEP if sigmaInt < SIGMASTEP * sigmaND. +const double MultipleInteractions::PT0STEP = 0.9; +const double MultipleInteractions::SIGMASTEP = 1.1; + +// Refuse too low expPow in impact parameter profile. +const double MultipleInteractions::EXPPOWMIN = 0.4; + +// Define low-b region by interaction rate above given number. +const double MultipleInteractions::PROBATLOWB = 0.6; + +// Basic step size for b integration; sometimes modified. +const double MultipleInteractions::BSTEP = 0.01; + +// Stop b integration when integrand dropped enough. +const double MultipleInteractions::BMAX = 1e-8; + +// Do not allow too large argument to exp function. +const double MultipleInteractions::EXPMAX = 50.; + +// Convergence criterion for k iteration. +const double MultipleInteractions::KCONVERGE = 1e-7; + +// Conversion of GeV^{-2} to mb for cross section. +const double MultipleInteractions::CONVERT2MB = 0.389380; + +//********* + +// Initialize the generation process for given beams. + +bool MultipleInteractions::init( bool doMIinit, Info* infoPtrIn, + BeamParticle* beamAPtrIn, BeamParticle* beamBPtrIn, + SigmaTotal* sigmaTotPtrIn, ostream& os) { + + // Store input pointers for future use. Done if no initialization. + infoPtr = infoPtrIn; + beamAPtr = beamAPtrIn; + beamBPtr = beamBPtrIn; + sigmaTotPtr = sigmaTotPtrIn; + if (!doMIinit) return false; + + // Matching in pT of hard interaction to further interactions. + pTmaxMatch = Settings::mode("MultipleInteractions:pTmaxMatch"); + + // Parameters of alphaStrong generation. + alphaSvalue = Settings::parm("MultipleInteractions:alphaSvalue"); + alphaSorder = Settings::mode("MultipleInteractions:alphaSorder"); + + // Parameters of alphaEM generation. + alphaEMorder = Settings::mode("MultipleInteractions:alphaEMorder"); + + // Parameters of cross section generation. + Kfactor = Settings::parm("MultipleInteractions:Kfactor"); + + // Regularization of QCD evolution for pT -> 0. + pT0Ref = Settings::parm("MultipleInteractions:pT0Ref"); + ecmRef = Settings::parm("MultipleInteractions:ecmRef"); + ecmPow = Settings::parm("MultipleInteractions:ecmPow"); + pTmin = Settings::parm("MultipleInteractions:pTmin"); + + // Impact parameter profile. + bProfile = Settings::mode("MultipleInteractions:bProfile"); + coreRadius = Settings::parm("MultipleInteractions:coreRadius"); + coreFraction = Settings::parm("MultipleInteractions:coreFraction"); + expPow = Settings::parm("MultipleInteractions:expPow"); + expPow = max(EXPPOWMIN, expPow); + + // Process sets to include in machinery. + processLevel = Settings::mode("MultipleInteractions:processLevel"); + + // Various other parameters. + nQuarkIn = Settings::mode("MultipleInteractions:nQuarkIn"); + nSample = Settings::mode("MultipleInteractions:nSample"); + + // Some common combinations for double Gaussian, as shorthand. + if (bProfile == 2) { + fracA = pow2(1. - coreFraction); + fracB = 2. * coreFraction * (1. - coreFraction); + fracC = pow2(coreFraction); + radius2B = 0.5 * (1. + pow2(coreRadius)); + radius2C = pow2(coreRadius); + + // Some common combinations for exp(b^pow), as shorthand. + } else if (bProfile == 3) { + hasLowPow = (expPow < 2.); + expRev = 2. / expPow - 1.; + } + + // Initialize alpha_strong generation. + alphaS.init( alphaSvalue, alphaSorder); + + // Initialize alphaEM generation. + alphaEM.init( alphaEMorder); + + // Attach matrix-element calculation objects. + sigma2gg.init( 0, processLevel); + sigma2qg.init( 1, processLevel); + sigma2qqbarSame.init( 2, processLevel); + sigma2qq.init( 3, processLevel); + + // Calculate invariant mass of system. Set current pT0 scale. + eCM = infoPtr->eCM(); + sCM = eCM * eCM; + pT0 = pT0Ref * pow(eCM / ecmRef, ecmPow); + + // Get the total inelastic and nondiffractive cross section. Output. + if (!sigmaTotPtr->hasSigmaTot()) return false; + sigmaND = sigmaTotPtr->sigmaND(); + os << "\n *------- PYTHIA Multiple Interactions Initialization --" + << "-----* \n" + << " | " + << " | \n" + << " | sigmaNonDiffractive = " << fixed + << setprecision(2) << setw(7) << sigmaND << " mb | \n" + << " | " + << " | \n"; + + // The pT0 value may need to be decreased, if sigmaInt < sigmaND. + double pT4dSigmaMaxBeg = 0.; + for ( ; ; ) { + + // Derived pT kinematics combinations. + pT20 = pT0*pT0; + pT2min = pTmin*pTmin; + pTmax = 0.5*eCM; + pT2max = pTmax*pTmax; + pT20R = RPT20 * pT20; + pT20minR = pT2min + pT20R; + pT20maxR = pT2max + pT20R; + pT20min0maxR = pT20minR * pT20maxR; + pT2maxmin = pT2max - pT2min; + + // Provide upper estimate of interaction rate d(Prob)/d(pT2). + upperEnvelope(); + + // Integrate the parton-parton interaction cross section. + pT4dSigmaMaxBeg = pT4dSigmaMax; + jetCrossSection(); + + // Sufficiently big SigmaInt or reduce pT0. Output. + if (sigmaInt > SIGMASTEP * sigmaND) break; + os << " | pT0 = " << setw(5) << pT0 << " gives sigmaInteraction = " + << setw(7) << sigmaInt << " mb: rejected | \n"; + pT0 *= PT0STEP; + } + os << " | pT0 = " << setw(5) << pT0 << " gives sigmaInteraction = " + << setw(7) << sigmaInt << " mb: accepted | \n" + << " | " + << " | \n" + << " *------- End PYTHIA Multiple Interactions Initialization" + << " ---* " << endl; + + // Amount of violation from upperEnvelope to jetCrossSection. + if (pT4dSigmaMax > pT4dSigmaMaxBeg) { + ostringstream osWarn; + osWarn << "by factor " << fixed << setprecision(3) + << pT4dSigmaMax/pT4dSigmaMaxBeg; + infoPtr->errorMsg("Warning in MultipleInteractions::init:" + " maximum increased", osWarn.str()); + } + + // Calculate factor relating matter overlap and interaction rate. + overlapInit(); + + // Reset statistics. + SigmaMultiple* dSigma; + for (int i = 0; i < 4; ++i) { + if (i == 0) dSigma = &sigma2gg; + else if (i == 1) dSigma = &sigma2qg; + else if (i == 2) dSigma = &sigma2qqbarSame; + else dSigma = &sigma2qq; + int nProc = dSigma->nProc(); + for (int iProc = 0; iProc < nProc; ++iProc) + nGen[ dSigma->codeProc(iProc) ] = 0; + } + + // Done. + return true; +} + +//********* + +// Select first = hardest pT in minbias process. +// Requires separate treatment at low and high b values + +void MultipleInteractions::pTfirst() { + + // Pick impact parameter and thereby interaction rate enhancement. + overlapFirst(); + bSetInFirst = true; + double WTacc; + + // At low b values evolve downwards with Sudakov. + if (isAtLowB) { + pT2 = pT2max; + do { + + // Pick a pT using a quick-and-dirty cross section estimate. + pT2 = fastPT2(pT2); + + // If fallen below lower cutoff then need to restart at top. + if (pT2 < pT2min) { + pT2 = pT2max; + WTacc = 0.; + + // Else pick complete kinematics and evaluate cross-section correction. + } else WTacc = sigmaPT2(true) / dSigmaApprox; + + // Loop until acceptable pT and acceptable kinematics. + } while (WTacc < Rndm::flat() || !dSigmaDtSel->final2KinMI()); + + // At high b values make preliminary pT choice without Sudakov factor. + } else { + do { + pT2 = pT20min0maxR / (pT20minR + Rndm::flat() * pT2maxmin) - pT20R; + + // Evaluate upper estimate of cross section for this pT2 choice. + dSigmaApprox = pT4dSigmaMax / pow2(pT2 + pT20R); + + // Pick complete kinematics and evaluate cross-section correction. + WTacc = sigmaPT2(true) / dSigmaApprox; + + // Evaluate and include Sudakov factor. + WTacc *= sudakov( pT2, enhanceB); + + // Loop until acceptable pT and acceptable kinematics. + } while (WTacc < Rndm::flat() || !dSigmaDtSel->final2KinMI()); + } + +} + +//********* + +// Set up kinematics for first = hardest pT in minbias process. + +void MultipleInteractions::setupFirstSys( Event& process) { + + // Remove any partons of previous failed interactions. + if (process.size() > 3) { + process.popBack( process.size() - 3); + process.initColTag(); + } + + // Loop over four partons and offset info relative to subprocess itself. + int colOffset = process.lastColTag(); + double pTMI= 0.; + for (int i = 1; i <= 4; ++i) { + Particle parton = dSigmaDtSel->getParton(i); + if (i <= 2 ) parton.mothers( i, 0); + else parton.mothers( 3, 4); + if (i <= 2 ) parton.daughters( 5, 6); + else parton.daughters( 0, 0); + int col = parton.col(); + if (col > 0) parton.col( col + colOffset); + int acol = parton.acol(); + if (acol > 0) parton.acol( acol + colOffset); + + // Put the partons into the event record. + process.append(parton); + if (i == 3) pTMI = parton.pT(); + } + + // Set scale from which to begin evolution. + process.scale( sqrt(pT2Fac) ); + + // Info on subprocess - specific to mimimum-bias events. + string nameSub = dSigmaDtSel->name(); + int codeSub = dSigmaDtSel->code(); + int nFinalSub = dSigmaDtSel->nFinal(); + infoPtr->setSubType( nameSub, codeSub, nFinalSub); + infoPtr->setTypeMI( codeSub, pTMI); + + // Further standard info on process. + infoPtr->setPDFalpha( id1, id2, xPDF1now, xPDF2now, pT2Fac, alpEM, alpS, + pT2Ren); + double m3 = dSigmaDtSel->m(3); + double m4 = dSigmaDtSel->m(4); + double theta = dSigmaDtSel->thetaMI(); + double phi = dSigmaDtSel->phiMI(); + infoPtr->setKin( x1, x2, sHat, tHat, uHat, sqrt(pT2), m3, m4, theta, phi); + +} + +//********* + +// Find whether to limit maximum scale of emissions. + +bool MultipleInteractions::limitPTmax( Event& event) { + + // User-set cases. + if (pTmaxMatch == 1) return true; + if (pTmaxMatch == 2) return false; + + // Look if only quarks (u, d, s, c, b), gluons and photons in final state. + bool onlyQGP = true; + for (int i = 5; i < event.size(); ++i) + if (event[i].status() != -21) { + int idAbs = event[i].idAbs(); + if (idAbs > 5 && idAbs != 21 && idAbs != 22) onlyQGP = false; + } + return (onlyQGP); + +} + +//********* + +// Select next pT in downwards evolution. + +double MultipleInteractions::pTnext( double pTbegAll, double pTendAll) { + + // Pick a pT using a quick-and-dirty cross section estimate. + double WTacc; + double pT2end = pow2( max(pTmin, pTendAll) ); + pT2 = pow2(pTbegAll); + do { + pT2 = fastPT2(pT2); + if (pT2 < pT2end) return 0.; + + // Pick complete kinematics and evaluate cross-section correction. + // Note: dSigmaApprox was set in fastPT2 above. + WTacc = sigmaPT2(false) / dSigmaApprox; + if (WTacc > 1.) infoPtr->errorMsg("Warning in MultipleInteractions::" + "pTnext: weight above unity"); + + // Decide whether to keep the event. + } while (WTacc < Rndm::flat() || !dSigmaDtSel->final2KinMI()); + + // Done. + return sqrt(pT2); + +} + +//********* + +// Set up the kinematics of the 2 -> 2 scattering process, +// and store the scattering in the event record. + +void MultipleInteractions::scatter( Event& event) { + + // Loop over four partons and offset info relative to subprocess itself. + int motherOffset = event.size(); + int colOffset = event.lastColTag(); + double pTMI= 0.; + for (int i = 1; i <= 4; ++i) { + Particle parton = dSigmaDtSel->getParton(i); + if (i <= 2 ) parton.mothers( i, 0); + else parton.mothers( motherOffset, motherOffset + 1); + if (i <= 2 ) parton.daughters( motherOffset + 2, motherOffset + 3); + else parton.daughters( 0, 0); + int col = parton.col(); + if (col > 0) parton.col( col + colOffset); + int acol = parton.acol(); + if (acol > 0) parton.acol( acol + colOffset); + + // Put the partons into the event record. + event.append(parton); + if (i == 3) pTMI = parton.pT(); + } + + // Store participating partons as a new set in list of all systems. + int iSys = event.newSystem(); + for (int i = 0; i < 4; ++i) event.addToSystem(iSys, motherOffset + i); + + // Add scattered partons to list in beam remnants. + int iA = beamAPtr->append( motherOffset, id1, x1); + int iB = beamBPtr->append( motherOffset + 1, id2, x2); + + // Find whether incoming partons are valence or sea, so prepared for ISR. + beamAPtr->xfISR( iA, id1, x1, pT2); + beamAPtr->pickValSeaComp(); + beamBPtr->xfISR( iB, id2, x2, pT2); + beamBPtr->pickValSeaComp(); + + // Store info on subprocess code. + int codeMI = dSigmaDtSel->code(); + infoPtr->setTypeMI( codeMI, pTMI); + + // Done. +} + +//********* + +// Determine constant in d(Prob)/d(pT2) < const / (pT2 + r * pT20)^2. + +void MultipleInteractions::upperEnvelope() { + + // Initially determine constant in jet cross section upper estimate + // d(sigma_approx)/d(pT2) < const / (pT2 + r * pT20)^2. + pT4dSigmaMax = 0.; + + // Loop thorough allowed pT range logarithmically evenly. + for (int iPT = 0; iPT < NBINS; ++iPT) { + double pT = pTmin * pow( pTmax/pTmin, (iPT + 0.5) / NBINS); + pT2 = pT*pT; + pT2shift = pT2 + pT20; + pT2Ren = pT2shift; + pT2Fac = (SHIFTFACSCALE) ? pT2shift : pT2; + xT = 2. * pT / eCM; + + // Evaluate parton density sums at x1 = x2 = xT. + double xPDF1sumMax = (9./4.) * beamAPtr->xf(21, xT, pT2Fac); + for (int id = 1; id <= nQuarkIn; ++id) + xPDF1sumMax += beamAPtr->xf( id, xT, pT2Fac) + + beamAPtr->xf(-id, xT, pT2Fac); + double xPDF2sumMax = (9./4.) * beamBPtr->xf(21, xT, pT2Fac); + for (int id = 1; id <= nQuarkIn; ++id) + xPDF2sumMax += beamBPtr->xf( id, xT, pT2Fac) + + beamBPtr->xf(-id, xT, pT2Fac); + + // Evaluate alpha_strong and _EM, matrix element and phase space volume. + alpS = alphaS.alphaS(pT2Ren); + alpEM = alphaEM.alphaEM(pT2Ren); + double dSigmaPartonApprox = CONVERT2MB * Kfactor * 0.5 * M_PI + * pow2(alpS / pT2shift); + double yMax = log(1./xT + sqrt(1./(xT*xT) - 1.)); + double volumePhSp = pow2(2. * yMax); + + // Final comparison to determine upper estimate. + double dSigmaApproxNow = SIGMAFUDGE * xPDF1sumMax * xPDF2sumMax + * dSigmaPartonApprox * volumePhSp; + double pT4dSigmaNow = pow2(pT2 + pT20R) * dSigmaApproxNow; + if ( pT4dSigmaNow > pT4dSigmaMax) pT4dSigmaMax = pT4dSigmaNow; + } + + // Get wanted constant by dividing by the nondiffractive cross section. + pT4dProbMax = pT4dSigmaMax / sigmaND; + +} + +//********* + +// Integrate the parton-parton interaction cross section, +// using stratified Monte Carlo sampling. +// Store result in pT bins for use as Sudakov form factors. + +void MultipleInteractions::jetCrossSection() { + + // Common factor from bin size in dpT2 / (pT2 + r * pT20)^2 and statistics. + double sigmaFactor = (1. / pT20minR - 1. / pT20maxR) / (NBINS * nSample); + + // Loop through allowed pT range evenly in dpT2 / (pT2 + r * pT20)^2. + sigmaInt = 0.; + double dSigmaMax = 0.; + sudExpPT[NBINS] = 0.; + for (int iPT = NBINS - 1; iPT >= 0; --iPT) { + double sigmaSum = 0.; + + // In each pT bin sample a number of random pT values. + for (int iSample = 0; iSample < nSample; ++iSample) { + double mappedPT2 = 1. - (iPT + Rndm::flat()) / NBINS; + pT2 = pT20min0maxR / (pT20minR + mappedPT2 * pT2maxmin) - pT20R; + + // Evaluate cross section dSigma/dpT2 in phase space point. + double dSigma = sigmaPT2(true); + + // Multiply by (pT2 + r * pT20)^2 to compensate for pT sampling. Sum. + dSigma *= pow2(pT2 + pT20R); + sigmaSum += dSigma; + if (dSigma > dSigmaMax) dSigmaMax = dSigma; + } + + // Store total cross section and exponent of Sudakov. + sigmaSum *= sigmaFactor; + sigmaInt += sigmaSum; + sudExpPT[iPT] = sudExpPT[iPT + 1] + sigmaSum / sigmaND; + + // End of loop over pT values. + } + + // Update upper estimate of differential cross section. Done. + if (dSigmaMax > pT4dSigmaMax) { + pT4dSigmaMax = dSigmaMax; + pT4dProbMax = dSigmaMax / sigmaND; + } + +} + +//********* + +// Evaluate "Sudakov form factor" for not having a harder interaction +// at the selected b value, given the pT scale of the event. + +double MultipleInteractions::sudakov(double pT2sud, double enhance) { + + // Find bin the pT2 scale falls in. + double xBin = (pT2sud - pT2min) * pT20maxR + / (pT2maxmin * (pT2sud + pT20R)); + xBin = max(1e-6, min(NBINS - 1e-6, NBINS * xBin) ); + int iBin = int(xBin); + + // Interpolate inside bin. Optionally include enhancement factor. + double sudExp = sudExpPT[iBin] + (xBin - iBin) + * (sudExpPT[iBin + 1] - sudExpPT[iBin]); + return exp( -enhance * sudExp); + +} + +//********* + +// Pick a trial next pT, based on a simple upper estimate of the +// d(sigma)/d(pT2) spectrum. + +double MultipleInteractions::fastPT2( double pT2beg) { + + // Use d(Prob)/d(pT2) < pT4dProbMax / (pT2 + r * pT20)^2. + double pT20begR = pT2beg + pT20R; + double pT4dProbMaxNow = pT4dProbMax * enhanceB; + double pT2try = pT4dProbMaxNow * pT20begR + / (pT4dProbMaxNow - pT20begR * log(Rndm::flat())) - pT20R; + + // Save cross section associated with ansatz above. Done. + dSigmaApprox = pT4dSigmaMax / pow2(pT2try + pT20R); + return pT2try; + +} + +//********* + +// Calculate the actual cross section to decide whether fast choice is OK. +// Select flavours and kinematics for interaction at given pT. +// Slightly different treatment for first interaction and subsequent ones. + +double MultipleInteractions::sigmaPT2(bool isFirst) { + + // Derive shifted pT2 and rapidity limits from chosen pT2. + pT2shift = pT2 + pT20; + pT2Ren = pT2shift; + pT2Fac = (SHIFTFACSCALE) ? pT2shift : pT2; + xT = 2. * sqrt(pT2) / eCM; + if (xT >= 1.) return 0.; + xT2 = xT*xT; + double yMax = log(1./xT + sqrt(1./xT2 - 1.)); + + // Select rapidities y3 and y4 of the two produced partons. + double y3 = yMax * (2. * Rndm::flat() - 1.); + double y4 = yMax * (2. * Rndm::flat() - 1.); + y = 0.5 * (y3 + y4); + + // Reject some events at large rapidities to improve efficiency. + // (Don't have to evaluate PDF's and ME's.) + double WTy = (1. - pow2(y3/yMax)) * (1. - pow2(y4/yMax)); + if (WTy < Rndm::flat()) return 0.; + + // Failure if x1 or x2 exceed what is left in respective beam. + x1 = 0.5 * xT * (exp(y3) + exp(y4)); + x2 = 0.5 * xT * (exp(-y3) + exp(-y4)); + if (isFirst) { + if (x1 > 1. || x2 > 1.) return 0.; + } else { + if (x1 > beamAPtr->xMax() || x2 > beamBPtr->xMax()) return 0.; + } + tau = x1 * x2; + + // Begin evaluate parton densities at actual x1 and x2. + double xPDF1[21]; + double xPDF1sum = 0.; + double xPDF2[21]; + double xPDF2sum = 0.; + + // For first interaction use normal densities. + if (isFirst) { + for (int id = -nQuarkIn; id <= nQuarkIn; ++id) { + if (id == 0) xPDF1[10] = (9./4.) * beamAPtr->xf(21, x1, pT2Fac); + else xPDF1[id+10] = beamAPtr->xf(id, x1, pT2Fac); + xPDF1sum += xPDF1[id+10]; + } + for (int id = -nQuarkIn; id <= nQuarkIn; ++id) { + if (id == 0) xPDF2[10] = (9./4.) * beamBPtr->xf(21, x2, pT2Fac); + else xPDF2[id+10] = beamBPtr->xf(id, x2, pT2Fac); + xPDF2sum += xPDF2[id+10]; + } + + // For subsequent interactions use rescaled densities. + } else { + for (int id = -nQuarkIn; id <= nQuarkIn; ++id) { + if (id == 0) xPDF1[10] = (9./4.) * beamAPtr->xfMI(21, x1, pT2Fac); + else xPDF1[id+10] = beamAPtr->xfMI(id, x1, pT2Fac); + xPDF1sum += xPDF1[id+10]; + } + for (int id = -nQuarkIn; id <= nQuarkIn; ++id) { + if (id == 0) xPDF2[10] = (9./4.) * beamBPtr->xfMI(21, x2, pT2Fac); + else xPDF2[id+10] = beamBPtr->xfMI(id, x2, pT2Fac); + xPDF2sum += xPDF2[id+10]; + } + } + + // Select incoming flavours according to actual PDF's. + id1 = -nQuarkIn - 1; + double temp = xPDF1sum * Rndm::flat(); + do { xPDF1now = xPDF1[(++id1) + 10]; temp -= xPDF1now; } + while (temp > 0. && id1 < nQuarkIn); + if (id1 == 0) id1 = 21; + id2 = -nQuarkIn-1; + temp = xPDF2sum * Rndm::flat(); + do { xPDF2now = xPDF2[(++id2) + 10]; temp -= xPDF2now;} + while (temp > 0. && id2 < nQuarkIn); + if (id2 == 0) id2 = 21; + + // Assign pointers to processes relevant for incoming flavour choice: + // g + g, q + g, q + qbar (same flavour), q + q(bar) (the rest). + // Factor 4./9. per incoming gluon to compensate for preweighting. + SigmaMultiple* dSigma; + double gluFac = 1.; + if (id1 == 21 && id2 == 21) { + dSigma = &sigma2gg; + gluFac = 16. / 81.; + } else if (id1 == 21 || id2 == 21) { + dSigma = &sigma2qg; + gluFac = 4. / 9.; + } else if (id1 == -id2) dSigma = &sigma2qqbarSame; + else dSigma = &sigma2qq; + + // Prepare to generate differential cross sections. + alpS = alphaS.alphaS(pT2Ren); + alpEM = alphaEM.alphaEM(pT2Ren); + sHat = tau * sCM; + double root = sqrtpos(1. - xT2 / tau); + tHat = -0.5 * sHat * (1. - root); + uHat = -0.5 * sHat * (1. + root); + + // Evaluate cross sections, include possibility of K factor. + // Use kinematics for two symmetrical configurations (tHat <-> uHat). + // (Not necessary, but makes for better MC efficiency.) + double dSigmaPartonCorr = Kfactor * gluFac + * dSigma->sigma( id1, id2, x1, x2, sHat, tHat, uHat, alpS, alpEM); + + // Pick one of the possible channels summed above. + dSigmaDtSel = dSigma->sigmaSel(); + if (dSigma->swapTU()) swap( tHat, uHat); + + // Combine cross section, pdf's and phase space integral. + double volumePhSp = pow2(2. * yMax) / WTy; + double dSigmaCorr = dSigmaPartonCorr * xPDF1sum * xPDF2sum * volumePhSp; + + // Dampen cross section at small pT values; part of formalism. + // Use pT2 corrected for massive kinematics at this step. + double pT2massive = dSigmaDtSel->pT2MI(); + dSigmaCorr *= pow2( pT2massive / (pT2massive + pT20) ); + + // Done. + return dSigmaCorr; +} + + +//********* + +// Calculate factor relating matter overlap and interaction rate, +// i.e. k in = k * overlap(b) (neglecting +// n_int = 0 corrections and energy-momentum conservation effects). + +void MultipleInteractions::overlapInit() { + + // Initial values for iteration. Step size of b integration. + nAvg = sigmaInt / sigmaND; + kNow = 0.5; + int stepDir = 1; + double deltaB = BSTEP; + if (bProfile == 2) deltaB *= min( 0.5, 2.5 * coreRadius); + if (bProfile == 3) deltaB *= max(1., pow(2. / expPow, 1. / expPow)); + + // Further variables, with dummy initial values. + double nNow = 0.; + double kLow = 0.; + double nLow = 0.; + double kHigh = 0.; + double nHigh = 0.; + double overlapNow = 0.; + double probNow = 0.; + double overlapInt = 0.5; + double probInt = 0.; + double probOverlapInt = 0.; + double bProbInt = 0.; + normPi = 1. / (2. * M_PI); + + // Subdivision into low-b and high-b region by interaction rate. + bool pastBDiv = false; + double overlapHighB = 0.; + + // First close k into an interval by binary steps, + // then find k by successive interpolation. + do { + if (stepDir == 1) kNow *= 2.; + else if (stepDir == -1) kNow *= 0.5; + else kNow = kLow + (nAvg - nLow) * (kHigh - kLow) / (nHigh - nLow); + + // Overlap trivial if no impact parameter dependence. + if (bProfile <= 0 || bProfile > 3) { + probInt = 0.5 * M_PI * (1. - exp(-kNow)); + probOverlapInt = probInt / M_PI; + bProbInt = probInt; + + // Else integrate overlap over impact parameter. + } else { + + // Reset integrals. + overlapInt = (bProfile == 3) ? 0. : 0.5; + probInt = 0.; + probOverlapInt = 0.; + bProbInt = 0.; + pastBDiv = false; + overlapHighB = 0.; + + // Step in b space. + double b = -0.5 * deltaB; + double bArea = 0.; + do { + b += deltaB; + bArea = 2. * M_PI * b * deltaB; + + // Evaluate overlap at current b value. + if (bProfile == 1) { + overlapNow = normPi * exp( -b*b); + } else if (bProfile == 2) { + overlapNow = normPi * ( fracA * exp( -min(EXPMAX, b*b)) + + fracB * exp( -min(EXPMAX, b*b / radius2B)) / radius2B + + fracC * exp( -min(EXPMAX, b*b / radius2C)) / radius2C ); + } else { + overlapNow = normPi * exp( -pow( b, expPow)); + overlapInt += bArea * overlapNow; + } + if (pastBDiv) overlapHighB += bArea * overlapNow; + + // Calculate interaction probability and integrate. + probNow = 1. - exp( -min(EXPMAX, M_PI * kNow * overlapNow)); + probInt += bArea * probNow; + probOverlapInt += bArea * overlapNow * probNow; + bProbInt += b * bArea * probNow; + + // Check when interaction probability has dropped sufficiently. + if (!pastBDiv && probNow < PROBATLOWB) { + bDiv = b + 0.5 * deltaB; + pastBDiv = true; + } + + // Continue out in b until overlap too small. + } while (b < 1. || b * probNow > BMAX); + } + + // Ratio of b-integrated k * overlap / (1 - exp( - k * overlap)). + nNow = M_PI * kNow * overlapInt / probInt; + + // Replace lower or upper limit of k. + if (nNow < nAvg) { + kLow = kNow; + nLow = nNow; + if (stepDir == -1) stepDir = 0; + } else { + kHigh = kNow; + nHigh = nNow; + if (stepDir == 1) stepDir = -1; + } + + // Continue iteration until convergence. + } while (abs(nNow - nAvg) > KCONVERGE * nAvg); + + // Save relevant final numbers for overlap values. + double avgOverlap = probOverlapInt / probInt; + zeroIntCorr = probOverlapInt / overlapInt; + normOverlap = normPi * zeroIntCorr / avgOverlap; + bAvg = bProbInt / probInt; + + // Relative rates for preselection of low-b and high-b region. + // Other useful combinations for subsequent selection. + if (bProfile > 0 && bProfile <= 3) { + probLowB = M_PI * bDiv*bDiv; + double probHighB = M_PI * kNow * overlapHighB; + if (bProfile == 1) probHighB = M_PI * kNow * 0.5 * exp( -bDiv*bDiv); + else if (bProfile == 2) { + fracAhigh = fracA * exp( -bDiv*bDiv); + fracBhigh = fracB * exp( -bDiv*bDiv / radius2B); + fracChigh = fracC * exp( -bDiv*bDiv / radius2C); + fracABChigh = fracAhigh + fracBhigh + fracChigh; + probHighB = M_PI * kNow * 0.5 * fracABChigh; + } else { + cDiv = pow( bDiv, expPow); + cMax = max(2. * expRev, cDiv); + } + probLowB /= (probLowB + probHighB); + } + +} + +//********* + +// Pick impact parameter and interaction rate enhancement beforehand, +// i.e. before even the hardest interaction for minimum-bias events. + +void MultipleInteractions::overlapFirst() { + + // Trivial values if no impact parameter dependence. + if (bProfile <= 0 || bProfile > 3) { + bNow = bAvg; + enhanceB = zeroIntCorr; + bIsSet = true; + isAtLowB = true; + return; + } + + // Preliminary choice between and inside low-b and high-b regions. + double overlapNow = 0.; + double probAccept = 0.; + do { + + // Treatment in low-b region: pick b flat in area. + if (Rndm::flat() < probLowB) { + isAtLowB = true; + bNow = bDiv * sqrt(Rndm::flat()); + if (bProfile == 1) overlapNow = normPi * exp( -bNow*bNow); + else if (bProfile == 2) overlapNow = normPi * + ( fracA * exp( -bNow*bNow) + + fracB * exp( -bNow*bNow / radius2B) / radius2B + + fracC * exp( -bNow*bNow / radius2C) / radius2C ); + else overlapNow = normPi * exp( -pow( bNow, expPow)); + probAccept = 1. - exp( -min(EXPMAX, M_PI * kNow * overlapNow)); + + // Treatment in high-b region: pick b according to overlap. + } else { + + // For simple and double Gaussian pick b according to exp(-b^2 / r^2). + if (bProfile == 1) { + bNow = sqrt(bDiv*bDiv - log(Rndm::flat())); + overlapNow = normPi * exp( -min(EXPMAX, bNow*bNow)); + } else if (bProfile == 2) { + double pickFrac = Rndm::flat() * fracABChigh; + if (pickFrac < fracAhigh) bNow = sqrt(bDiv*bDiv - log(Rndm::flat())); + else if (pickFrac < fracAhigh + fracBhigh) + bNow = sqrt(bDiv*bDiv - radius2B * log(Rndm::flat())); + else bNow = sqrt(bDiv*bDiv - radius2C * log(Rndm::flat())); + overlapNow = normPi * ( fracA * exp( -min(EXPMAX, bNow*bNow)) + + fracB * exp( -min(EXPMAX, bNow*bNow / radius2B)) / radius2B + + fracC * exp( -min(EXPMAX, bNow*bNow / radius2C)) / radius2C ); + + // For exp( - b^expPow) transform to variable c = b^expPow so that + // f(b) = b * exp( - b^expPow) -> f(c) = c^r * exp(-c) with r = expRev. + // case hasLowPow: expPow < 2 <=> r > 0: preselect according to + // f(c) < N exp(-c/2) and then accept with N' * c^r * exp(-c/2). + } else if (hasLowPow) { + double cNow, acceptC; + do { + cNow = cDiv - 2. * log(Rndm::flat()); + acceptC = pow(cNow / cMax, expRev) * exp( -0.5 * (cNow - cMax)); + } while (acceptC < Rndm::flat()); + bNow = pow( cNow, 1. / expPow); + overlapNow = normPi * exp( -cNow); + + // case !hasLowPow: expPow >= 2 <=> - 1 < r < 0: preselect according to + // f(c) < N exp(-c) and then accept with N' * c^r. + } else { + double cNow, acceptC; + do { + cNow = cDiv - log(Rndm::flat()); + acceptC = pow(cNow / cDiv, expRev); + } while (acceptC < Rndm::flat()); + bNow = pow( cNow, 1. / expPow); + overlapNow = normPi * exp( -cNow); + } + double temp = M_PI * kNow *overlapNow; + probAccept = (1. - exp( -min(EXPMAX, temp))) / temp; + } + + // Confirm choice of b value. Derive enhancement factor. + } while (probAccept < Rndm::flat()); + enhanceB = (normOverlap / normPi) * overlapNow ; + + // Done. + bIsSet = true; + +} + +//********* + +// Pick impact parameter and interaction rate enhancement afterwards, +// i.e. after a hard interaction is known but before rest of MI treatment. + +void MultipleInteractions::overlapNext(double pTscale) { + + // Default, valid for bProfile = 0. Also initial Sudakov. + enhanceB = zeroIntCorr; + if (bProfile <= 0 || bProfile > 3) return; + double pT2scale = pTscale*pTscale; + + // Begin loop over pT-dependent rejection of b value. + do { + + // Flat enhancement distribution for simple Gaussian. + if (bProfile == 1) { + double expb2 = Rndm::flat(); + enhanceB = normOverlap * expb2; + bNow = sqrt( -log(expb2)); + + // For double Gaussian go the way via b, according to each Gaussian. + } else if (bProfile == 2) { + double bType = Rndm::flat(); + double b2 = -log( Rndm::flat() ); + if (bType < fracA) ; + else if (bType < fracA + fracB) b2 *= radius2B; + else b2 *= radius2C; + enhanceB = normOverlap * ( fracA * exp( -min(EXPMAX, b2)) + + fracB * exp( -min(EXPMAX, b2 / radius2B)) / radius2B + + fracC * exp( -min(EXPMAX, b2 / radius2C)) / radius2C ); + bNow = sqrt(b2); + + // For exp( - b^expPow) transform to variable c = b^expPow so that + // f(b) = b * exp( - b^expPow) -> f(c) = c^r * exp(-c) with r = expRev. + // case hasLowPow: expPow < 2 <=> r > 0: + // f(c) < r^r exp(-r) for c < 2r, < (2r)^r exp(-r-c/2) for c > 2r. + } else if (hasLowPow) { + double cNow, acceptC; + double probLowC = expRev / (expRev + pow(2., expRev) * exp( - expRev)); + do { + if (Rndm::flat() < probLowC) { + cNow = 2. * expRev * Rndm::flat(); + acceptC = pow( cNow / expRev, expRev) * exp(expRev - cNow); + } else { + cNow = 2. * (expRev - log( Rndm::flat() )); + acceptC = pow(0.5 * cNow / expRev, expRev) * exp(expRev - 0.5 * cNow); + } + } while (acceptC < Rndm::flat()); + enhanceB = normOverlap *exp(-cNow); + bNow = pow( cNow, 1. / expPow); + + // case !hasLowPow: expPow >= 2 <=> - 1 < r < 0: + // f(c) < c^r for c < 1, f(c) < exp(-c) for c > 1. + } else { + double cNow, acceptC; + double probLowC = expPow / (2. * exp(-1.) + expPow); + do { + if (Rndm::flat() < probLowC) { + cNow = pow( Rndm::flat(), 0.5 * expPow); + acceptC = exp(-cNow); + } else { + cNow = 1. - log( Rndm::flat() ); + acceptC = pow( cNow, expRev); + } + } while (acceptC < Rndm::flat()); + enhanceB = normOverlap * exp(-cNow); + bNow = pow( cNow, 1. / expPow); + } + + // Evaluate "Sudakov form factor" for not having a harder interaction. + } while (sudakov(pT2scale, enhanceB) < Rndm::flat()); + + // Done. + bIsSet = true; +} + +//********* + +// Printe statistics on number of multiple-interactions processes. + +void MultipleInteractions::statistics(bool reset, ostream& os) { + + // Header. + os << "\n *------- PYTHIA Multiple Interactions Statistics --------" + << "---*\n" + << " | " + << " |\n" + << " | Note: excludes hardest subprocess if already listed above " + << " |\n" + << " | " + << " |\n" + << " | Subprocess Code | Times" + << " |\n" + << " | | " + << " |\n" + << " |------------------------------------------------------------" + << "-|\n" + << " | | " + << " |\n"; + + // Loop over existing processes. Sum of all subprocesses. + int numberSum = 0; + for ( map::iterator iter = nGen.begin(); iter != nGen.end(); + ++iter) { + int code = iter -> first; + int number = iter->second; + numberSum += number; + + // Find process name that matches code. + string name = " "; + bool foundName = false; + SigmaMultiple* dSigma; + for (int i = 0; i < 4; ++i) { + if (i == 0) dSigma = &sigma2gg; + else if (i == 1) dSigma = &sigma2qg; + else if (i == 2) dSigma = &sigma2qqbarSame; + else dSigma = &sigma2qq; + int nProc = dSigma->nProc(); + for (int iProc = 0; iProc < nProc; ++iProc) + if (dSigma->codeProc(iProc) == code) { + name = dSigma->nameProc(iProc); + foundName = true; + } + if (foundName) break; + } + + // Print individual process info. + os << " | " << left << setw(40) << name << right << setw(5) << code + << " | " << setw(11) << number << " |\n"; + } + + // Print summed process info. + os << " | " + << " |\n" + << " | " << left << setw(45) << "sum" << right << " | " << setw(11) + << numberSum << " |\n"; + + // Listing finished. + os << " | | " + << " |\n" + << " *------- End PYTHIA Multiple Interactions Statistics -------" + << "-*" << endl; + + // Optionally reset statistics contants. + if (reset) for ( map::iterator iter = nGen.begin(); + iter != nGen.end(); ++iter) iter->second = 0; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/ParticleData.cxx b/PYTHIA8/pythia8130/src/ParticleData.cxx new file mode 100644 index 00000000000..46dc27c1ba2 --- /dev/null +++ b/PYTHIA8/pythia8130/src/ParticleData.cxx @@ -0,0 +1,2027 @@ +// ParticleData.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// DecayChannel, ParticleDataEntry and ParticleDataTable classes. + +#include "ParticleData.h" +#include "StandardModel.h" + +// Allow string and character manipulation. +#include + +namespace Pythia8 { + +//************************************************************************** + +// DecayChannel class. +// This class holds info on a single decay channel. + +//********* + +// Check whether id1 occurs anywhere in product list. + +bool DecayChannel::contains(int id1) const { + + bool found1 = false; + for (int i = 0; i < nProd; ++i) if (prod[i] == id1) found1 = true; + return found1; + +} + +//********* + +// Check whether id1 and id2 occur anywhere in product list. +// iF ID1 == ID2 then two copies of this particle must be present. + +bool DecayChannel::contains(int id1, int id2) const { + + bool found1 = false; + bool found2 = false; + for (int i = 0; i < nProd; ++i) { + if (!found1 && prod[i] == id1) {found1 = true; continue;} + if (!found2 && prod[i] == id2) {found2 = true; continue;} + } + return found1 && found2; + +} + +//********* + +// Check whether id1, id2 and id3 occur anywhere in product list. +// iF ID1 == ID2 then two copies of this particle must be present, etc. + +bool DecayChannel::contains(int id1, int id2, int id3) const { + + bool found1 = false; + bool found2 = false; + bool found3 = false; + for (int i = 0; i < nProd; ++i) { + if (!found1 && prod[i] == id1) {found1 = true; continue;} + if (!found2 && prod[i] == id2) {found2 = true; continue;} + if (!found3 && prod[i] == id3) {found3 = true; continue;} + } + return found1 && found2 && found3; + +} + +//************************************************************************** + +// DecayTable class. +// This class holds info on all decay channels of a particle. + +//********* + +// Rescale all branching ratios to assure normalization to unity. + +void DecayTable::rescaleBR(double newSumBR) { + + // Sum up branching ratios. Find rescaling factor. Rescale. + double oldSumBR = 0.; + for ( int i = 0; i < size(); ++ i) + oldSumBR += channel[i].bRatio(); + double rescaleFactor = newSumBR / oldSumBR; + for ( int i = 0; i < size(); ++ i) channel[i].rescaleBR(rescaleFactor); + +} + +//************************************************************************** + +// ParticleDataEntry class. +// This class holds info on a single particle species. + +//********* + +// Definitions of static variables. +// (Values will be overwritten in initStatic call, so are purely dummy.) + +int ParticleDataEntry::modeBreitWigner = 1; +double ParticleDataEntry::maxEnhanceBW = 2.5; +double ParticleDataEntry::mQRun[7] + = {0., 0.006, 0.003, 0.095, 1.25, 4.20, 165.}; +double ParticleDataEntry::Lambda5Run = 0.2; + +// Static copy of Info - not optimal solution?? +Info* ParticleDataEntry::infoPtr = 0; + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// A particle is invisible if it has neither strong nor electric charge, +// and is not made up of constituents that have it. Only relevant for +// long-lived particles. This list may need to be extended. +const int ParticleDataEntry::INVISIBLENUMBER = 29; +const int ParticleDataEntry::INVISIBLETABLE[29] = { 12, 14, 16, 18, 23, 25, + 32, 33, 35, 36, 39, 41, 1000012, 1000014, 1000016, 1000018, 1000022, + 1000023, 1000025, 1000035, 1000039, 2000012, 2000014, 2000016, 2000018, + 9900012, 9900014, 9900016, 9900023}; + +// Particles with a read-in tau0 (in mm/c) below this mayDecay by default. +const double ParticleDataEntry::MAXTAU0FORDECAY = 1000.; + +// Particles with a read-in m0 above this isResonance by default. +const double ParticleDataEntry::MINMASSRESONANCE = 20.; + +// Narrow states are assigned nominal mass. +const double ParticleDataEntry::NARROWMASS = 1e-6; + +// Constituent quark masses (d, u, s, c, b). +const double ParticleDataEntry::CONSTITUENTMASSTABLE[6] + = {0., 0.325, 0.325, 0.50, 1.60, 5.00}; + +//********* + +// Destructor: delete any ResonanceWidths object. + +ParticleDataEntry::~ParticleDataEntry() { + if (resonancePtr != 0) delete resonancePtr; +} + +//********* + +// Initialize static data members. + +void ParticleDataEntry::initStatic() { + + // Mass generation: fixed mass or linear/quadratic Breit-Wigner. + modeBreitWigner = Settings::mode("ParticleData:modeBreitWigner"); + + // Maximum tail enhancement when adding threshold factor to Breit-Wigner. + maxEnhanceBW = Settings::parm("ParticleData:maxEnhanceBW"); + + // Find initial MSbar masses for five light flavours. + mQRun[1] = Settings::parm("ParticleData:mdRun"); + mQRun[2] = Settings::parm("ParticleData:muRun"); + mQRun[3] = Settings::parm("ParticleData:msRun"); + mQRun[4] = Settings::parm("ParticleData:mcRun"); + mQRun[5] = Settings::parm("ParticleData:mbRun"); + mQRun[6] = Settings::parm("ParticleData:mtRun"); + + // Find Lambda5 value to use in running of MSbar masses. + double alphaSvalue = Settings::parm("ParticleData:alphaSvalueMRun"); + AlphaStrong alphaS; + alphaS.init( alphaSvalue, 1); + Lambda5Run = alphaS.Lambda5(); + +} + +//********* + +// Set initial default values for some quantities. + +void ParticleDataEntry::setDefaults() { + + // A particle is a resonance if it is heavy enough. + isResonanceSave = (m0Save > MINMASSRESONANCE); + + // A particle may decay if it is shortlived enough. + mayDecaySave = (tau0Save < MAXTAU0FORDECAY); + + // A particle by default has no external decays. + doExternalDecaySave = false; + + // A particle is invisible if in current table of such. + isVisibleSave = true; + for (int i = 0; i < INVISIBLENUMBER; ++i) + if (idSave == INVISIBLETABLE[i]) isVisibleSave = false; + + // Normally a resonance should not have width forced to fixed value. + doForceWidthSave = false; + + // Set up constituent masses. + setConstituentMass(); + + // No Breit-Wigner mass selection before initialized. + modeBWnow = 0; + +} + +//********* + +// Prepare the Breit-Wigner mass selection by precalculating +// frequently-used expressions. + +void ParticleDataEntry::initBWmass() { + + // Find Breit-Wigner mode for current particle. + modeBWnow = modeBreitWigner; + if ( mWidthSave < NARROWMASS || (mMaxSave > mMinSave + && mMaxSave - mMinSave < NARROWMASS) ) modeBWnow = 0; + if (modeBWnow == 0) return; + + // Find atan expressions to be used in random mass selection. + if (modeBWnow < 3) { + atanLow = atan( 2. * (mMinSave - m0Save) / mWidthSave ); + double atanHigh = (mMaxSave > mMinSave) + ? atan( 2. * (mMaxSave - m0Save) / mWidthSave ) : 0.5 * M_PI; + atanDif = atanHigh - atanLow; + } else { + atanLow = atan( (pow2(mMinSave) - pow2(m0Save)) + / (m0Save * mWidthSave) ); + double atanHigh = (mMaxSave > mMinSave) + ? atan( (pow2(mMaxSave) - pow2(m0Save)) / (m0Save * mWidthSave) ) + : 0.5 * M_PI; + atanDif = atanHigh - atanLow; + } + + // Done if no threshold factor. + if (modeBWnow%2 == 1) return; + + // Find average mass threshold for threshold-factor correction. + double bRatSum = 0.; + double mThrSum = 0; + for (int i = 0; i < decay.size(); ++i) + if (decay[i].onMode() >= 0) { + bRatSum += decay[i].bRatio(); + double mChannelSum = 0.; + for (int j = 0; j < decay[i].multiplicity(); ++j) + mChannelSum += ParticleDataTable::m0( decay[i].product(j) ); + mThrSum += decay[i].bRatio() * mChannelSum; + } + mThr = (bRatSum == 0.) ? 0. : mThrSum / bRatSum; + + // Switch off Breit-Wigner if very close to threshold. + if (mThr + NARROWMASS > m0Save) { + ostringstream osWarn; + osWarn << "for id = " << idSave; + infoPtr->errorMsg("Warning in ParticleDataEntry::initBWmass:" + " switching off width", osWarn.str()); + modeBWnow = 0; + } + +} + +//********* + +// Function to give mass of a particle, either at the nominal value +// or picked according to a (linear or quadratic) Breit-Wigner. + +double ParticleDataEntry::mass() { + + // Nominal value. + if (modeBWnow == 0) return m0Save; + double mNow, m2Now; + + // Mass according to a Breit-Wigner linear in m. + if (modeBWnow == 1) { + mNow = m0Save + 0.5 * mWidthSave + * tan( atanLow + atanDif * Rndm::flat() ); + + // Ditto, but make Gamma proportional to sqrt(m^2 - m_threshold^2). + } else if (modeBWnow == 2) { + double mWidthNow, fixBW, runBW; + double m0ThrS = m0Save*m0Save - mThr*mThr; + do { + mNow = m0Save + 0.5 * mWidthSave + * tan( atanLow + atanDif * Rndm::flat() ); + mWidthNow = mWidthSave * sqrtpos( (mNow*mNow - mThr*mThr) / m0ThrS ); + fixBW = mWidthSave / (pow2(mNow - m0Save) + pow2(0.5 * mWidthSave)); + runBW = mWidthNow / (pow2(mNow - m0Save) + pow2(0.5 * mWidthNow)); + } while (runBW < Rndm::flat() * maxEnhanceBW * fixBW); + + // Mass according to a Breit-Wigner quadratic in m. + } else if (modeBWnow == 3) { + m2Now = m0Save*m0Save + m0Save * mWidthSave + * tan( atanLow + atanDif * Rndm::flat() ); + mNow = sqrtpos( m2Now); + + // Ditto, but m_0 Gamma_0 -> m Gamma(m) with threshold factor as above. + } else { + double mwNow, fixBW, runBW; + double m2Ref = m0Save * m0Save; + double mwRef = m0Save * mWidthSave; + double m2Thr = mThr * mThr; + do { + m2Now = m2Ref + mwRef * tan( atanLow + atanDif * Rndm::flat() ); + mNow = sqrtpos( m2Now); + mwNow = mNow * mWidthSave + * sqrtpos( (m2Now - m2Thr) / (m2Ref - m2Thr) ); + fixBW = mwRef / (pow2(m2Now - m2Ref) + pow2(mwRef)); + runBW = mwNow / (pow2(m2Now - m2Ref) + pow2(mwNow)); + } while (runBW < Rndm::flat() * maxEnhanceBW * fixBW); + } + + // Done. + return mNow; +} + +//********* + +// Function to calculate running mass at given mass scale. + +double ParticleDataEntry::mRun(double mHat) { + + // Except for six quarks return nominal mass. + if (idSave > 6) return m0Save; + + // For d, u, s quarks start running at 2 GeV (RPP 2006 p. 505). + if (idSave < 4) return mQRun[idSave] * pow ( log(2. / Lambda5Run) + / log(max(2., mHat) / Lambda5Run), 12./23.); + + // For c, b and t quarks start running at respective mass. + return mQRun[idSave] * pow ( log(mQRun[idSave] / Lambda5Run) + / log(max(mQRun[idSave], mHat) / Lambda5Run), 12./23.); + +} + + +//********* + +// Prepare to pick a decay channel. + +bool ParticleDataEntry::preparePick(int idSgn, double mHat, int idInFlav) { + + // Reset sum of allowed widths/branching ratios. + currentBRSum = 0.; + + // For resonances the widths are calculated dynamically. + if (resonancePtr != 0) { + resonancePtr->widthStore(idSgn, mHat, idInFlav); + for (int i = 0; i < decay.size(); ++i) + currentBRSum += decay[i].currentBR(); + + // Else use normal fixed branching ratios. + } else { + int onMode; + double currentBRNow; + for (int i = 0; i < decay.size(); ++i) { + onMode = decay[i].onMode(); + currentBRNow = 0.; + if ( idSgn > 0 && (onMode == 1 || onMode == 2) ) + currentBRNow = decay[i].bRatio(); + else if ( idSgn < 0 && (onMode == 1 || onMode == 3) ) + currentBRNow = decay[i].bRatio(); + decay[i].currentBR(currentBRNow); + currentBRSum += currentBRNow; + } + } + + // Failure if no channels found with positive branching ratios. + return (currentBRSum > 0.); + +} + +//********* + +// Pick a decay channel according to branching ratios from preparePick. + +DecayChannel& ParticleDataEntry::pickChannel() { + + // Find channel in table. + int size = decay.size(); + double rndmBR = currentBRSum * Rndm::flat(); + int i = -1; + do rndmBR -= decay[++i].currentBR(); + while (rndmBR > 0. && i < size); + + // Emergency if no channel found. Done. + if (i == size) i = 0; + return decay[i]; + +} + +//********* + +// Find out if a particle is a hadron. +// Only covers normal hadrons, not e.g. R-hadrons. + +bool ParticleDataEntry::isHadron() const { + + if (idSave <= 100 || (idSave >= 1000000 && idSave <= 9000000) + || idSave >= 9900000) return false; + if (idSave == 130 || idSave == 310) return true; + if (idSave%10 == 0 || (idSave/10)%10 == 0 || (idSave/100)%10 == 0) + return false; + return true; + +} + +//********* + +// Find out if a particle is a meson. +// Only covers normal hadrons, not e.g. R-hadrons. + +bool ParticleDataEntry::isMeson() const { + + if (idSave <= 100 || (idSave >= 1000000 && idSave <= 9000000) + || idSave >= 9900000) return false; + if (idSave == 130 || idSave == 310) return true; + if (idSave%10 == 0 || (idSave/10)%10 == 0 || (idSave/100)%10 == 0 + || (idSave/1000)%10 != 0) return false; + return true; + +} + +//********* + +// Find out if a particle is a baryon. +// Only covers normal hadrons, not e.g. R-hadrons. + +bool ParticleDataEntry::isBaryon() const { + + if (idSave <= 1000 || (idSave >= 1000000 && idSave <= 9000000) + || idSave >= 9900000) return false; + if (idSave%10 == 0 || (idSave/10)%10 == 0 || (idSave/100)%10 == 0 + || (idSave/1000)%10 == 0) return false; + return true; + + +} + +//********* + +// Extract the heaviest (= largest id) quark in a hadron. + +int ParticleDataEntry::heaviestQuark(int idIn) const { + + if (!isHadron()) return 0; + int hQ = 0; + + // Meson. + if ( (idSave/1000)%10 == 0 ) { + hQ = (idSave/100)%10; + if (idSave == 130) hQ = 3; + if (hQ%2 == 1) hQ = -hQ; + + // Baryon. + } else hQ = (idSave/1000)%10; + + // Done. + return (idIn > 0) ? hQ : -hQ; + +} + +//********* + +// Calculate three times baryon number, i.e. net quark - antiquark number. + +int ParticleDataEntry::baryonNumberType(int idIn) const { + + // Quarks. + if (isQuark()) return (idIn > 0) ? 1 : -1; + + // Diquarks + if (isDiquark()) return (idIn > 0) ? 2 : -2; + + // Baryons. + if (isBaryon()) return (idIn > 0) ? 3 : -3; + + // Done. + return 0; + +} + +//********* + +// Access methods stored in ResonanceWidths. Could have been +// inline in .h, except for problems with forward declarations. + +void ParticleDataEntry::setResonancePtr( + ResonanceWidths* resonancePtrIn) { + if (resonancePtr == resonancePtrIn) return; + if (resonancePtr != 0) delete resonancePtr; + resonancePtr = resonancePtrIn; +} + +void ParticleDataEntry::resInit() { + if (resonancePtr != 0) resonancePtr->init(); +} + +double ParticleDataEntry::resWidth(int idSgn, double mHat, int idIn, + bool openOnly, bool setBR) { + return (resonancePtr != 0) ? resonancePtr->width( idSgn, mHat, + idIn, openOnly, setBR) : 0.; +} + +double ParticleDataEntry::resWidthOpen(int idSgn, double mHat, int idIn) { + return (resonancePtr != 0) ? resonancePtr->widthOpen( idSgn, mHat, idIn) + : 0.; +} + +double ParticleDataEntry::resWidthStore(int idSgn, double mHat, int idIn) { + return (resonancePtr != 0) ? resonancePtr->widthStore( idSgn, mHat, idIn) + : 0.; +} + +double ParticleDataEntry::resOpenFrac(int idSgn) { + return (resonancePtr != 0) ? resonancePtr->openFrac(idSgn) : 1.; +} + +double ParticleDataEntry::resWidthRescaleFactor() { + return (resonancePtr != 0) ? resonancePtr->widthRescaleFactor() : 1.; +} + +double ParticleDataEntry::resWidthChan(double mHat, int idAbs1, + int idAbs2) { + return (resonancePtr != 0) ? resonancePtr->widthChan( mHat, idAbs1, + idAbs2) : 0.; +} + +//********* + +// Constituent masses for (d, u, s, c, b) quarks and diquarks. +// Hardcoded in CONSTITUENTMASSTABLE so that they are not overwritten +// by mistake, and separated from the "normal" masses. +// Called both by setDefaults and setM0 so kept as separate method. + +void ParticleDataEntry::setConstituentMass() { + + // Equate with the normal masses as default guess. + constituentMassSave = m0Save; + + // Quark masses trivial. + if (idSave < 6) constituentMassSave = CONSTITUENTMASSTABLE[idSave]; + + // Diquarks as simple sum of constituent quarks. + if (idSave > 1000 && idSave < 10000 && (idSave/10)%10 == 0) { + int id1 = idSave/1000; + int id2 = (idSave/100)%10; + if (id1 <6 && id2 < 6) constituentMassSave + = CONSTITUENTMASSTABLE[id1] + CONSTITUENTMASSTABLE[id2]; + } + +} + +//********* + +// Convert string to lowercase for case-insensitive comparisons. + +string ParticleDataEntry::toLower(const string& name) { + + string temp(name); + for (int i = 0; i < int(temp.length()); ++i) + temp[i] = std::tolower(temp[i]); + return temp; + +} + +//************************************************************************** + +// ParticleDataTable class. +// This class holds a map of all ParticleDataEntries, +// each entry containing info on a particle species. + +//********* + +// Definitions of static variables. + +map ParticleDataTable::pdt; +bool ParticleDataTable::isInit = false; +ParticleDataEntry* ParticleDataTable::particlePtr = 0; + +// Static copy of Info - not optimal solution?? +Info* ParticleDataTable::infoPtr = 0; + +//********* + +// Initialize the special handling of resonances in ResonanceWidths. +// Note:order of initialization is essential to get secondary widths right. + +void ParticleDataTable::initResonances( + vector resonancePtrs, bool reInit) { + + // Initialize static resonance properties. + ResonanceWidths::initStatic(infoPtr); + + // Set up new resonance objects. Not necessary if already done. + if (!reInit) { + + // Z0, W+- and top are almost always needed. + new ResonanceGmZ(23); + new ResonanceW(24); + new ResonanceTop(6); + + // Higgs in SM. + if (!Settings::flag("Higgs:useBSM")) { + new ResonanceH(0, 25); + + // Higgses in BSM. + } else { + new ResonanceH(1, 25); + new ResonanceH(2, 35); + new ResonanceH(3, 36); + new ResonanceHchg(37); + } + + // A fourth generation: b', t', tau', nu'_tau. + new ResonanceFour(7); + new ResonanceFour(8); + new ResonanceFour(17); + new ResonanceFour(18); + + // New gauge bosons: Z', W', R. + new ResonanceZprime(32); + new ResonanceWprime(34); + new ResonanceRhorizontal(41); + + // A leptoquark. + new ResonanceLeptoquark(42); + + // Excited quarks and leptons. + for (int i = 1; i < 7; ++i) new ResonanceExcited(4000000 + i); + for (int i = 11; i < 17; ++i) new ResonanceExcited(4000000 + i); + + // An excited graviton in extra-dimensional scenarios. + new ResonanceGraviton(5000039); + + // A left-right-symmetric scenario with new righthanded neutrinos, + // righthanded gauge bosons and doubly charged Higgses. + new ResonanceNuRight(9900012); + new ResonanceNuRight(9900014); + new ResonanceNuRight(9900016); + new ResonanceZRight(9900023); + new ResonanceWRight(9900024); + new ResonanceHchgchgLeft(9900041); + new ResonanceHchgchgRight(9900042); + + // Attach user-defined external resonances and initialize them. + for (int i = 0; i < int(resonancePtrs.size()); ++i) + resonancePtrs[i]->initBasic(resonancePtrs[i]->id()); + } + + // Set up lists to order resonances in ascending mass. + vector idOrdered; + vector m0Ordered; + + // Put Z0 and W+- first, since known to be SM and often off-shell. + idOrdered.push_back(23); + m0Ordered.push_back(m0(23)); + idOrdered.push_back(24); + m0Ordered.push_back(m0(24)); + + // Loop through particle table to find resonances. + for (map::iterator pdtEntry = pdt.begin(); + pdtEntry != pdt.end(); ++pdtEntry) { + ParticleDataEntry& pdtNow = pdtEntry->second; + int idNow = pdtNow.id(); + + // Set up a simple default object for uninitialized resonances. + if (pdtNow.isResonance() && pdtNow.getResonancePtr() == 0) + new ResonanceGeneric(idNow); + + // Insert resonances in ascending mass, to respect decay hierarchies. + if (pdtNow.getResonancePtr() != 0 && idNow != 23 && idNow != 24) { + double m0Now = pdtNow.m0(); + idOrdered.push_back(idNow); + m0Ordered.push_back(m0Now); + for (int i = int(idOrdered.size()) - 2; i > 1; --i) { + if (m0Ordered[i] < m0Now) break; + swap( idOrdered[i], idOrdered[i + 1]); + swap( m0Ordered[i], m0Ordered[i + 1]); + } + } + } + + // Initialize the resonances in order. + for (int i = 0; i < int(idOrdered.size()); ++i) + resInit( idOrdered[i] ); + +} + +//********* + +// Read in database from specific XML file (which may refer to others). + +bool ParticleDataTable::readXML(string inFile, bool reset) { + + // Normally reset whole database before beginning. + if (reset) {pdt.clear(); isInit = false;} + + // List of files to be checked. + vector files; + files.push_back(inFile); + + // Loop over files. Open them for read. + for (int i = 0; i < int(files.size()); ++i) { + const char* cstring = files[i].c_str(); + ifstream is(cstring); + + // Check that instream is OK. + if (!is) { + infoPtr->errorMsg("Error in ParticleDataTable::readXML:" + " did not find file", files[i]); + return false; + } + + // Read in one line at a time. + particlePtr = 0; + string line; + while ( getline(is, line) ) { + + // Get first word of a line. + istringstream getfirst(line); + string word1; + getfirst >> word1; + + // Check for occurence of a particle. Add any continuation lines. + if (word1 == "") == string::npos) { + string addLine; + getline(is, addLine); + line += addLine; + } + + // Read in particle properties. + int id = intAttributeValue( line, "id"); + string name = attributeValue( line, "name"); + string antiName = attributeValue( line, "antiName"); + if (antiName == "") antiName = "void"; + int spinType = intAttributeValue( line, "spinType"); + int chargeType = intAttributeValue( line, "chargeType"); + int colType = intAttributeValue( line, "colType"); + double m0 = doubleAttributeValue( line, "m0"); + double mWidth = doubleAttributeValue( line, "mWidth"); + double mMin = doubleAttributeValue( line, "mMin"); + double mMax = doubleAttributeValue( line, "mMax"); + double tau0 = doubleAttributeValue( line, "tau0"); + + // Erase if particle already exists. + if (isParticle(id)) pdt.erase(id); + + // Store new particle. Save pointer, to be used for decay channels. + addParticle( id, name, antiName, spinType, chargeType, colType, + m0, mWidth, mMin, mMax, tau0); + particlePtr = particleDataPtr(id); + + // Check for occurence of a decay channel. Add any continuation lines. + } else if (word1 == "") == string::npos) { + string addLine; + getline(is, addLine); + line += addLine; + } + + // Read in channel properties - products so far only as a string. + int onMode = intAttributeValue( line, "onMode"); + double bRatio = doubleAttributeValue( line, "bRatio"); + int meMode = intAttributeValue( line, "meMode"); + string products = attributeValue( line, "products"); + + // Read in decay products from stream. Must have at least one. + istringstream prodStream(products); + int prod0 = 0; int prod1 = 0; int prod2 = 0; int prod3 = 0; + int prod4 = 0; int prod5 = 0; int prod6 = 0; int prod7 = 0; + prodStream >> prod0 >> prod1 >> prod2 >> prod3 >> prod4 >> prod5 + >> prod6 >> prod7; + if (prod0 == 0) { + infoPtr->errorMsg("Error in ParticleDataTable::readXML:" + " incomplete decay channel", line); + return false; + } + + // Store new channel (if particle already known). + if (particlePtr == 0) { + infoPtr->errorMsg("Error in ParticleDataTable::readXML:" + " orphan decay channel", line); + return false; + } + particlePtr->decay.addChannel(onMode, bRatio, meMode, prod0, prod1, + prod2, prod3, prod4, prod5, prod6, prod7); + + // Check for occurence of a file also to be read. + } else if (word1 == "errorMsg("Warning in ParticleDataTable::readXML:" + " skip unrecognized file name", line); + } else files.push_back(file); + } + + // End of loop over lines in input file and loop over files. + }; + }; + + // All particle data at this stage defines baseline original. + if (reset) for (map::iterator pdtEntry + = pdt.begin(); pdtEntry != pdt.end(); ++pdtEntry) { + particlePtr = &pdtEntry->second; + particlePtr->setHasChanged(false); + } + + // Done. + isInit = true; + return true; + +} + +//********* + +// Print out complete database in numerical order as an XML file. + +void ParticleDataTable::listXML(string outFile) { + + // Convert file name to ofstream. + const char* cstring = outFile.c_str(); + ofstream os(cstring); + + // Iterate through the particle data table. + for (map::iterator pdtEntry + = pdt.begin(); pdtEntry != pdt.end(); ++pdtEntry) { + particlePtr = &pdtEntry->second; + + // Print particle properties. + os << "id() << "\"" + << " name=\"" << particlePtr->name() << "\""; + if (particlePtr->hasAnti()) + os << " antiName=\"" << particlePtr->name(-1) << "\""; + os << " spinType=\"" << particlePtr->spinType() << "\"" + << " chargeType=\"" << particlePtr->chargeType() << "\"" + << " colType=\"" << particlePtr->colType() << "\"\n"; + // Pick format for mass and width based on mass value. + double m0Now = particlePtr->m0(); + if (m0Now == 0 || (m0Now > 0.1 && m0Now < 1000.)) + os << fixed << setprecision(5); + else os << scientific << setprecision(3); + os << " m0=\"" << m0Now << "\""; + if (particlePtr->mWidth() > 0.) + os << " mWidth=\"" << particlePtr->mWidth() << "\"" + << " mMin=\"" << particlePtr->mMin() << "\"" + << " mMax=\"" << particlePtr->mMax() << "\""; + if (particlePtr->tau0() > 0.) os << scientific << setprecision(5) + << " tau0=\"" << particlePtr->tau0() << "\""; + os << ">\n"; + + // Loop through the decay channel table for each particle. + if (particlePtr->decay.size() > 0) { + for (int i = 0; i < int(particlePtr->decay.size()); ++i) { + const DecayChannel& channel = particlePtr->decay[i]; + int mult = channel.multiplicity(); + + // Print decay channel properties. + os << " 0) + os << " meMode=\"" << channel.meMode() << "\""; + os << " products=\""; + for (int j = 0; j < mult; ++j) { + os << channel.product(j); + if (j < mult - 1) os << " "; + } + + // Finish off line and loop over allowed decay channels. + os << "\"/>\n"; + } + } + + // Finish off existing particle. + os << "\n\n"; + + } + +} + +//********* + +// Read in database from specific free format file. + +bool ParticleDataTable::readFF(string inFile, bool reset) { + + // Normally reset whole database before beginning. + if (reset) {pdt.clear(); isInit = false;} + + // Open file for read and check that instream is OK. + const char* cstring = inFile.c_str(); + ifstream is(cstring); + if (!is) { + infoPtr->errorMsg("Error in ParticleDataTable::readFF:" + " did not find file", inFile); + return false; + } + + // Read in one line at a time. + particlePtr = 0; + string line; + bool readParticle = false; + while ( getline(is, line) ) { + + // Empty lines begins new particle. + if (line.find_first_not_of(" ") == string::npos) { + readParticle = true; + continue; + } + + // Prepare to use standard read from line. + istringstream readLine(line); + + // Read in a line with particle information. + if (readParticle) { + + // Properties to be read. + int id; + string name, antiName; + int spinType, chargeType, colType; + double m0, mWidth, mMin, mMax, tau0; + string may; + + // Do the reading. + readLine >> id >> name >> antiName >> spinType >> chargeType + >> colType >> m0 >> mWidth >> mMin >> mMax >> tau0; + + // Error printout if something went wrong. + if (!readLine) { + infoPtr->errorMsg("Error in ParticleDataTable::readFF:" + " incomplete particle", line); + return false; + } + + // Erase if particle already exists. + if (isParticle(id)) pdt.erase(id); + + // Store new particle. Save pointer, to be used for decay channels. + addParticle( id, name, antiName, spinType, chargeType, colType, + m0, mWidth, mMin, mMax, tau0); + particlePtr = particleDataPtr(id); + readParticle = false; + + // Read in a line with decay channel information. + } else { + + // Properties to be read. + int onMode = 0; + double bRatio = 0.; + int meMode = 0; + int prod0 = 0; int prod1 = 0; int prod2 = 0; int prod3 = 0; + int prod4 = 0; int prod5 = 0; int prod6 = 0; int prod7 = 0; + + // Read in data from stream. Need at least one decay product. + readLine >> onMode >> bRatio >> meMode >> prod0; + if (!readLine) { + infoPtr->errorMsg("Error in ParticleDataTable::readFF:" + " incomplete decay channel", line); + return false; + } + readLine >> prod1 >> prod2 >> prod3 >> prod4 >> prod5 + >> prod6 >> prod7; + + // Store new channel. + if (particlePtr == 0) { + infoPtr->errorMsg("Error in ParticleDataTable::readFF:" + " orphan decay channel", line); + return false; + } + particlePtr->decay.addChannel(onMode, bRatio, meMode, prod0, prod1, + prod2, prod3, prod4, prod5, prod6, prod7); + + } + + // End of while loop over lines in the file. + } + + + // Done. + isInit = true; + return true; + +} + +//********* + +// Print out complete database in numerical order as a free format file. + +void ParticleDataTable::listFF(string outFile) { + + // Convert file name to ofstream. + const char* cstring = outFile.c_str(); + ofstream os(cstring); + + // Iterate through the particle data table. + for (map::iterator pdtEntry + = pdt.begin(); pdtEntry != pdt.end(); ++pdtEntry) { + particlePtr = &pdtEntry->second; + + // Pick format for mass and width based on mass value. + double m0Now = particlePtr->m0(); + if (m0Now == 0 || (m0Now > 0.1 && m0Now < 1000.)) + os << fixed << setprecision(5); + else os << scientific << setprecision(3); + + // Print particle properties. + os << "\n" << setw(8) << particlePtr->id() << " " + << left << setw(16) << particlePtr->name() << " " + << setw(16) << particlePtr->name(-1) << " " + << right << setw(2) << particlePtr->spinType() << " " + << setw(2) << particlePtr->chargeType() << " " + << setw(2) << particlePtr->colType() << " " + << setw(10) << particlePtr->m0() << " " + << setw(10) << particlePtr->mWidth() << " " + << setw(10) << particlePtr->mMin() << " " + << setw(10) << particlePtr->mMax() << " " + << scientific << setprecision(5) + << setw(12) << particlePtr->tau0() << "\n"; + + // Loop through the decay channel table for each particle. + if (particlePtr->decay.size() > 0) { + for (int i = 0; i < int(particlePtr->decay.size()); ++i) { + const DecayChannel& channel = particlePtr->decay[i]; + os << " " << setw(6) << channel.onMode() + << " " << fixed << setprecision(7) << setw(10) + << channel.bRatio() << " " + << setw(3) << channel.meMode() << " "; + for (int j = 0; j < channel.multiplicity(); ++j) + os << setw(8) << channel.product(j) << " "; + os << "\n"; + } + } + + } + +} + +//********* + +// Read in updates from a character string, like a line of a file. +// Is used by readString (and readFile) in Pythia. + +bool ParticleDataTable::readString(string lineIn, bool warn, + ostream& os) { + + // If empty line then done. + if (lineIn.find_first_not_of(" ") == string::npos) return true; + + // Take copy that will be modified. + string line = lineIn; + + // If first character is not a digit then taken to be a comment. + int firstChar = line.find_first_not_of(" "); + if (!isdigit(line[firstChar])) return true; + + // Replace colons and equal signs by blanks to make parsing simpler. + for ( int j = 0; j < int(line.size()); ++ j) + if (line[j] == ':' || line[j] == '=') line[j] = ' '; + + // Get particle id and property name. + int id; + string property; + istringstream getWord(line); + getWord >> id >> property; + property = toLower(property); + + // Check that valid particle. + if ( (!isParticle(id) && property != "all" && property != "new") + || id <= 0) { + if (warn) os << "\n Warning: input particle not found in Particle" + << " Data Table; skip:\n " << lineIn << "\n"; + return false; + } + + // Identify particle property and read + set its value, case by case. + if (property == "name") { + string name; + getWord >> name; + pdt[id].setName(name); + return true; + } + if (property == "antiname") { + string antiName; + getWord >> antiName; + pdt[id].setAntiName(antiName); + return true; + } + if (property == "names") { + string name, antiName; + getWord >> name >> antiName; + pdt[id].setNames(name, antiName); + return true; + } + if (property == "spintype") { + int spinType; + getWord >> spinType; + pdt[id].setSpinType(spinType); + return true; + } + if (property == "chargetype") { + int chargeType; + getWord >> chargeType; + pdt[id].setChargeType(chargeType); + return true; + } + if (property == "coltype") { + int colType; + getWord >> colType; + pdt[id].setColType(colType); + return true; + } + if (property == "m0") { + double m0; + getWord >> m0; + pdt[id].setM0(m0); + return true; + } + if (property == "mwidth") { + double mWidth; + getWord >> mWidth; + pdt[id].setMWidth(mWidth); + return true; + } + if (property == "mmin") { + double mMin; + getWord >> mMin; + pdt[id].setMMin(mMin); + return true; + } + if (property == "mmax") { + double mMax; + getWord >> mMax; + pdt[id].setMMax(mMax); + return true; + } + if (property == "tau0") { + double tau0; + getWord >> tau0; + pdt[id].setTau0(tau0); + return true; + } + if (property == "isresonance") { + string isres; + getWord >> isres; + bool isResonance = boolString(isres); + pdt[id].setIsResonance(isResonance); + return true; + } + if (property == "maydecay") { + string may; + getWord >> may; + bool mayDecay = boolString(may); + pdt[id].setMayDecay(mayDecay); + return true; + } + if (property == "doexternaldecay") { + string extdec; + getWord >> extdec; + bool doExternalDecay = boolString(extdec); + pdt[id].setDoExternalDecay(doExternalDecay); + return true; + } + if (property == "isvisible") { + string isvis; + getWord >> isvis; + bool isVisible = boolString(isvis); + pdt[id].setIsVisible(isVisible); + return true; + } + if (property == "doforcewidth") { + string doforce; + getWord >> doforce; + bool doForceWidth = boolString(doforce); + pdt[id].setDoForceWidth(doForceWidth); + return true; + } + + // Addition or complete replacement of a particle. + if (property == "all" || property == "new") { + + // Default values for properties to be read. + string name = "void"; + string antiName = "void"; + int spinType = 0; + int chargeType = 0; + int colType = 0; + double m0 = 0.; + double mWidth = 0.; + double mMin = 0.; + double mMax = 0.; + double tau0 = 0.; + + // Read in data from stream. + getWord >> name >> antiName >> spinType >> chargeType >> colType + >> m0 >> mWidth >> mMin >> mMax >> tau0; + + // To keep existing decay channels, only overwrite particle data. + if (property == "all" && isParticle(id)) { + setAll( id, name, antiName, spinType, chargeType, colType, + m0, mWidth, mMin, mMax, tau0); + + // Else start over completely from scratch. + } else { + if (isParticle(id)) pdt.erase(id); + addParticle( id, name, antiName, spinType, chargeType, colType, + m0, mWidth, mMin, mMax, tau0); + } + return true; + } + + // Set onMode of all decay channels in one go. + if (property == "onmode") { + int onMode = 0; + string onModeIn; + getWord >> onModeIn; + // For onMode allow the optional possibility of Bool input. + if (isdigit(onModeIn[0])) { + istringstream getOnMode(onModeIn); + getOnMode >> onMode; + } else onMode = (boolString(onModeIn)) ? 1 : 0; + for (int i = 0; i < pdt[id].decay.size(); ++i) + pdt[id].decay[i].onMode(onMode); + return true; + } + + // Selective search for matching decay channels. + int matchKind = 0; + if (property == "offifany" || property == "onifany" || + property == "onposifany" || property == "onnegifany") matchKind = 1; + if (property == "offifall" || property == "onifall" || + property == "onposifall" || property == "onnegifall") matchKind = 2; + if (property == "offifmatch" || property == "onifmatch" || + property == "onposifmatch" || property == "onnegifmatch") matchKind = 3; + if (matchKind > 0) { + int onMode = 0; + if (property == "onifany" || property == "onifall" + || property == "onifmatch") onMode = 1; + if (property == "onposifany" || property == "onposifall" + || property == "onposifmatch") onMode = 2; + if (property == "onnegifany" || property == "onnegifall" + || property == "onnegifmatch") onMode = 3; + + // Read in particles to match. + vector idToMatch; + int idRead; + for ( ; ; ) { + getWord >> idRead; + if (!getWord) break; + idToMatch.push_back(abs(idRead)); + } + int nToMatch = idToMatch.size(); + + // Loop over all decay channels. + for (int i = 0; i < pdt[id].decay.size(); ++i) { + int multi = pdt[id].decay[i].multiplicity(); + + // Look for any match at all. + if (matchKind == 1) { + bool foundMatch = false; + for (int j = 0; j < multi; ++j) { + int idNow = abs(pdt[id].decay[i].product(j)); + for (int k = 0; k < nToMatch; ++k) + if (idNow == idToMatch[k]) {foundMatch = true; break;} + if (foundMatch) break; + } + if (foundMatch) pdt[id].decay[i].onMode(onMode); + + // Look for match of all products provided. + } else { + int nUnmatched = nToMatch; + if (multi < nToMatch); + else if (multi > nToMatch && matchKind == 3); + else { + vector idUnmatched; + for (int k = 0; k < nToMatch; ++k) + idUnmatched.push_back(idToMatch[k]); + for (int j = 0; j < multi; ++j) { + int idNow = abs(pdt[id].decay[i].product(j)); + for (int k = 0; k < nUnmatched; ++k) + if (idNow == idUnmatched[k]) { + idUnmatched[k] = idUnmatched[--nUnmatched]; + break; + } + if (nUnmatched == 0) break; + } + } + if (nUnmatched == 0) pdt[id].decay[i].onMode(onMode); + } + } + return true; + } + + // Rescale all branching ratios by common factor. + if (property == "rescalebr") { + double factor; + getWord >> factor; + pdt[id].rescaleBR(factor); + return true; + } + + // Reset decay table in preparation for new input. + if (property == "onechannel") pdt[id].decay.clear(); + + // Add or change a decay channel: get channel number and new property. + if (property == "addchannel" || property == "onechannel" + || isdigit(property[0])) { + int channel; + if (property == "addchannel" || property == "onechannel") { + pdt[id].decay.addChannel(); + channel = pdt[id].decay.size() - 1; + property = "all"; + } else{ + istringstream getChannel(property); + getChannel >> channel; + getWord >> property; + property = toLower(property); + } + + // Check that channel exists. + if (channel < 0 || channel >= pdt[id].decay.size()) return false; + + // Find decay channel property and value, case by case. + // At same time also do case where all should be replaced. + if (property == "onmode" || property == "all") { + int onMode = 0; + string onModeIn; + getWord >> onModeIn; + // For onMode allow the optional possibility of Bool input. + if (isdigit(onModeIn[0])) { + istringstream getOnMode(onModeIn); + getOnMode >> onMode; + } else onMode = (boolString(onModeIn)) ? 1 : 0; + pdt[id].decay[channel].onMode(onMode); + if (property == "onmode") return true; + } + if (property == "bratio" || property == "all") { + double bRatio; + getWord >> bRatio; + pdt[id].decay[channel].bRatio(bRatio); + if (property == "bratio") return true; + } + if (property == "memode" || property == "all") { + int meMode; + getWord >> meMode; + pdt[id].decay[channel].meMode(meMode); + if (property == "memode") return true; + } + + // Scan for products until end of line. + if (property == "products" || property == "all") { + int nProd = 0; + for (int iProd = 0; iProd < 8; ++iProd) { + int idProd; + getWord >> idProd; + if (!getWord) break; + pdt[id].decay[channel].product(iProd, idProd); + ++nProd; + } + for (int iProd = nProd; iProd < 8; ++iProd) + pdt[id].decay[channel].product(iProd, 0); + pdt[id].decay[channel].multiplicity(nProd); + return true; + } + + // Rescale an existing branching ratio. + if (property == "rescalebr") { + double factor; + getWord >> factor; + pdt[id].decay[channel].rescaleBR(factor); + return true; + } + } + + // Return false if failed to recognize property. + if (warn) os << "\n Warning: input property not found in Particle" + << " Data Table; skip:\n " << lineIn << "\n"; + return false; + +} + +//********* + +// Print out complete or changed table of database in numerical order. + +void ParticleDataTable::list(bool changedOnly, bool changedRes, ostream& os) { + + // Table header; output for bool as off/on. + if (!changedOnly) { + os << "\n -------- PYTHIA Particle Data Table (complete) --------" + << "------------------------------------------------------------" + << "--------------\n \n"; + + } else { + os << "\n -------- PYTHIA Particle Data Table (changed only) ----" + << "------------------------------------------------------------" + << "--------------\n \n"; + } + os << " id name antiName spn chg col m0" + << " mWidth mMin mMax tau0 res dec ext " + << "vis wid\n no onMode bRatio meMode products \n"; + + // Iterate through the particle data table. Option to skip unchanged. + int nList = 0; + for (map::iterator pdtEntry + = pdt.begin(); pdtEntry != pdt.end(); ++pdtEntry) { + particlePtr = &pdtEntry->second; + if ( !changedOnly || particlePtr->hasChanged() || + ( changedRes && particlePtr->getResonancePtr() != 0 ) ) { + + // Pick format for mass and width based on mass value. + double m0Now = particlePtr->m0(); + if (m0Now == 0 || (m0Now > 0.1 && m0Now < 1000.)) + os << fixed << setprecision(5); + else os << scientific << setprecision(3); + + // Print particle properties. + ++nList; + string antiName = particlePtr->name(-1); + if (antiName == "void") antiName = " "; + os << "\n" << setw(8) << particlePtr->id() << " " + << left << setw(16) << particlePtr->name() << " " + << setw(16) << antiName << " " + << right << setw(2) << particlePtr->spinType() << " " + << setw(2) << particlePtr->chargeType() << " " + << setw(2) << particlePtr->colType() << " " + << setw(10) << particlePtr->m0() << " " + << setw(10) << particlePtr->mWidth() << " " + << setw(10) << particlePtr->mMin() << " " + << setw(10) << particlePtr->mMax() << " " + << scientific << setprecision(5) + << setw(12) << particlePtr->tau0() << " " << setw(2) + << particlePtr->isResonance() << " " << setw(2) + << (particlePtr->mayDecay() && particlePtr->canDecay()) + << " " << setw(2) << particlePtr->doExternalDecay() << " " + << setw(2) << particlePtr->isVisible()<< " " + << setw(2) << particlePtr->doForceWidth() << "\n"; + + // Loop through the decay channel table for each particle. + if (particlePtr->decay.size() > 0) { + for (int i = 0; i < int(particlePtr->decay.size()); ++i) { + const DecayChannel& channel = particlePtr->decay[i]; + os << " " << setprecision(7) + << setw(5) << i + << setw(6) << channel.onMode() + << fixed<< setw(12) << channel.bRatio() + << setw(5) << channel.meMode() << " "; + for (int j = 0; j < channel.multiplicity(); ++j) + os << setw(8) << channel.product(j) << " "; + os << "\n"; + } + } + } + + } + + // End of loop over database contents. + if (changedOnly && nList == 0) os << "\n no particle data has been " + << "changed from its default value \n"; + os << "\n -------- End PYTHIA Particle Data Table -----------------" + << "--------------------------------------------------------------" + << "----------\n" << endl; + +} + +//********* + +// Print out partial table of database in input order. + +void ParticleDataTable::list(vector idList, ostream& os) { + + // Table header; output for bool as off/on. + os << "\n -------- PYTHIA Particle Data Table (partial) ---------" + << "------------------------------------------------------------" + << "--------------\n \n"; + os << " id name antiName spn chg col m0" + << " mWidth mMin mMax tau0 res dec ext " + << "vis wid\n no onMode bRatio meMode products \n"; + + // Iterate through the given list of input particles. + for (int i = 0; i < int(idList.size()); ++i) { + particlePtr = particleDataPtr(idList[i]); + + // Pick format for mass and width based on mass value. + double m0Now = particlePtr->m0(); + if (m0Now == 0 || (m0Now > 0.1 && m0Now < 1000.)) + os << fixed << setprecision(5); + else os << scientific << setprecision(3); + + // Print particle properties. + string antiName = particlePtr->name(-1); + if (antiName == "void") antiName = " "; + os << "\n" << setw(8) << particlePtr->id() << " " + << left << setw(16) << particlePtr->name() << " " + << setw(16) << antiName << " " + << right << setw(2) << particlePtr->spinType() << " " + << setw(2) << particlePtr->chargeType() << " " + << setw(2) << particlePtr->colType() << " " + << setw(10) << particlePtr->m0() << " " + << setw(10) << particlePtr->mWidth() << " " + << setw(10) << particlePtr->mMin() << " " + << setw(10) << particlePtr->mMax() << " " + << scientific << setprecision(5) + << setw(12) << particlePtr->tau0() << " " << setw(2) + << particlePtr->isResonance() << " " << setw(2) + << (particlePtr->mayDecay() && particlePtr->canDecay()) + << " " << setw(2) << particlePtr->doExternalDecay() << " " + << setw(2) << particlePtr->isVisible() << " " + << setw(2) << particlePtr->doForceWidth() << "\n"; + + // Loop through the decay channel table for each particle. + if (particlePtr->decay.size() > 0) { + for (int j = 0; j < int(particlePtr->decay.size()); ++j) { + const DecayChannel& channel = particlePtr->decay[j]; + os << " " << setprecision(7) + << setw(5) << j + << setw(6) << channel.onMode() + << fixed<< setw(12) << channel.bRatio() + << setw(5) << channel.meMode() << " "; + for (int k = 0; k < channel.multiplicity(); ++k) + os << setw(8) << channel.product(k) << " "; + os << "\n"; + } + } + + } + + // End of loop over database contents. + os << "\n -------- End PYTHIA Particle Data Table -----------------" + << "--------------------------------------------------------------" + << "----------\n" << endl; + +} + +//********* + +// Check that table makes sense: e.g. consistent names and mass ranges, +// that branching ratios sum to unity, that charge is conserved and +// that phase space is open in each channel. +// verbosity = 0: mimimal amount of checks, e.g. that no channels open. +// = 1: further warning if individual channels closed +// (except for resonances). +// = 2: also print branching-ratio-averaged threshold mass. +// = 11, 12: as 1, 2, but include resonances in detailed checks. + +void ParticleDataTable::checkTable(int verbosity, ostream& os) { + + // Header. + os << "\n -------- PYTHIA Check of Particle Data Table ------------" + <<"------\n\n"; + int nErr = 0; + + // Loop through all particles. + for (map::iterator pdtEntry + = pdt.begin(); pdtEntry != pdt.end(); ++pdtEntry) { + particlePtr = &pdtEntry->second; + + // Extract some particle properties. Set some flags; + int id = particlePtr->id(); + bool hasAnti = particlePtr->hasAnti(); + int spinTypeNow = particlePtr->spinType(); + int chargeTypeNow = particlePtr->chargeType(); + int baryonTypeNow = particlePtr->baryonNumberType(); + double m0Now = particlePtr->m0(); + double mMinNow = particlePtr->mMin(); + double mMaxNow = particlePtr->mMax(); + double mWidthNow = particlePtr->mWidth(); + double tau0Now = particlePtr->tau0(); + bool isResonanceNow = particlePtr->isResonance(); + bool hasPrinted = false; + bool studyCloser = verbosity > 10 || !isResonanceNow; + + // Check that particle name consistent with charge information. + string particleName = particlePtr->name(1); + if (particleName.size() > 16) { + os << " Warning: particle " << id << " has name " << particleName + << " of length " << particleName.size() << "\n"; + hasPrinted = true; + ++nErr; + } + int nPlus = 0; + int nMinus = 0; + for (int i = 0; i < int(particleName.size()); ++i) { + if (particleName[i] == '+') ++nPlus; + if (particleName[i] == '-') ++nMinus; + } + if ( (nPlus > 0 && nMinus > 0) || ( nPlus + nMinus > 0 + && 3 * (nPlus - nMinus) != chargeTypeNow )) { + os << " Warning: particle " << id << " has name " << particleName + << " inconsistent with charge type " << chargeTypeNow << "\n"; + hasPrinted = true; + ++nErr; + } + + // Check that antiparticle name consistent with charge information. + if (hasAnti) { + particleName = particlePtr->name(-1); + if (particleName.size() > 16) { + os << " Warning: particle " << id << " has name " << particleName + << " of length " << particleName.size() << "\n"; + hasPrinted = true; + ++nErr; + } + nPlus = 0; + nMinus = 0; + for (int i = 0; i < int(particleName.size()); ++i) { + if (particleName[i] == '+') ++nPlus; + if (particleName[i] == '-') ++nMinus; + } + if ( (nPlus > 0 && nMinus > 0) || ( nPlus + nMinus > 0 + && 3 * (nPlus - nMinus) != -chargeTypeNow )) { + os << " Warning: particle " << -id << " has name " + << particleName << " inconsistent with charge type " + << -chargeTypeNow << "\n"; + hasPrinted = true; + ++nErr; + } + } + + // Check that mass, mass range and width are consistent. + if (particlePtr->useBreitWigner()) { + if (mMinNow > m0Now) { + os << " Error: particle " << id << " has mMin " + << fixed << setprecision(5) << mMinNow + << " larger than m0 " << m0Now << "\n"; + hasPrinted = true; + ++nErr; + } + if (mMaxNow > mMinNow && mMaxNow < m0Now) { + os << " Error: particle " << id << " has mMax " + << fixed << setprecision(5) << mMaxNow + << " smaller than m0 " << m0Now << "\n"; + hasPrinted = true; + ++nErr; + } + if (mMaxNow > mMinNow && mMaxNow - mMinNow < mWidthNow) { + os << " Warning: particle " << id << " has mMax - mMin " + << fixed << setprecision(5) << mMaxNow - mMinNow + << " smaller than mWidth " << mWidthNow << "\n"; + hasPrinted = true; + ++nErr; + } + } + + // Check that particle does not both have width and lifetime. + if (mWidthNow > 0. && tau0Now > 0.) { + os << " Warning: particle " << id << " has both nonvanishing width " + << scientific << setprecision(5) << mWidthNow << " and lifetime " + << tau0Now << "\n"; + hasPrinted = true; + ++nErr; + } + + // Begin study decay channels. + if (particlePtr->decay.size() > 0) { + + // Loop through all decay channels. + double bRatioSum = 0.; + double bRatioPos = 0.; + double bRatioNeg = 0.; + bool hasPosBR = false; + bool hasNegBR = false; + double threshMass = 0.; + bool openChannel = false; + for (int i = 0; i < particlePtr->decay.size(); ++i) { + + // Extract channel properties. + int onMode = particlePtr->decay[i].onMode(); + double bRatio = particlePtr->decay[i].bRatio(); + int meMode = particlePtr->decay[i].meMode(); + int mult = particlePtr->decay[i].multiplicity(); + int prod[8]; + for (int j = 0; j < 8; ++j) + prod[j] = particlePtr->decay[i].product(j); + + // Sum branching ratios. Include off-channels. + if (onMode == 0 || onMode == 1) bRatioSum += bRatio; + else if (onMode == 2) {bRatioPos += bRatio; hasPosBR = true;} + else if (onMode == 3) {bRatioNeg += bRatio; hasNegBR = true;} + + // Error printout when unknown decay product code. + for (int j = 0; j < 8; ++j) { + if ( prod[j] != 0 && !isParticle(prod[j]) ) { + os << " Error: unknown decay product for " << id + << " -> " << prod[j] << "\n"; + hasPrinted = true; + ++nErr; + continue; + } + } + + // Error printout when no decay products or 0 interspersed. + int nLast = 0; + for (int j = 0; j < 8; ++j) + if (prod[j] != 0) nLast = j + 1; + if (mult == 0 || mult != nLast) { + os << " Error: corrupted decay product list for " + << particlePtr->id() << " -> "; + for (int j = 0; j < 8; ++j) os << prod[j] << " "; + os << "\n"; + hasPrinted = true; + ++nErr; + continue; + } + + // Check charge conservation and open phase space in decay channel. + int chargeTypeSum = -chargeTypeNow; + int baryonTypeSum = -baryonTypeNow; + double avgFinalMass = 0.; + double minFinalMass = 0.; + bool canHandle = true; + for (int j = 0; j < mult; ++j) { + chargeTypeSum += chargeType( prod[j] ); + baryonTypeSum += baryonNumberType( prod[j] ); + avgFinalMass += m0( prod[j] ); + minFinalMass += m0Min( prod[j] ); + if (prod[j] == 81 || prod[j] == 82 || prod[j] == 83) + canHandle = false; + } + threshMass += bRatio * avgFinalMass; + + // Error printout when charge or baryon number not conserved. + if (chargeTypeSum != 0 && canHandle) { + os << " Error: 3*charge changed by " << chargeTypeSum + << " in " << id << " -> "; + for (int j = 0; j < mult; ++j) os << prod[j] << " "; + os << "\n"; + hasPrinted = true; + ++nErr; + continue; + } + if ( baryonTypeSum != 0 && canHandle && particlePtr->isHadron() ) { + os << " Error: 3*baryon number changed by " << baryonTypeSum + << " in " << id << " -> "; + for (int j = 0; j < mult; ++j) os << prod[j] << " "; + os << "\n"; + hasPrinted = true; + ++nErr; + continue; + } + + // Begin check that some matrix elements are used correctly. + bool correctME = true; + + // Check matrix element mode 0: recommended not into partons. + if (meMode == 0 && !isResonanceNow) { + bool hasPartons = false; + for (int j = 0; j < mult; ++j) { + int idAbs = abs(prod[j]); + if ( idAbs < 10 || idAbs == 21 || idAbs == 81 || idAbs == 82 + || idAbs == 83 || (idAbs > 1000 && idAbs < 10000 + && (idAbs/10)%10 == 0) ) hasPartons = true; + } + if (hasPartons) correctME = false; + } + + // Check matrix element mode 1: rho/omega -> pi+ pi- pi0. + bool useME1 = ( mult == 3 && spinTypeNow == 3 && id > 100 + && id < 1000 && particlePtr->decay[i].contains(211, -211, 111) ); + if ( meMode == 1 && !useME1 ) correctME = false; + if ( meMode != 1 && useME1 ) correctME = false; + + // Check matrix element mode 2: polarization in V -> PS + PS. + bool useME2 = ( mult == 2 && spinTypeNow == 3 && id > 100 + && id < 1000 && spinType(prod[0]) == 1 + && spinType(prod[1]) == 1 ); + if ( meMode == 2 && !useME2 ) correctME = false; + if ( meMode != 2 && useME2 ) correctME = false; + + // Check matrix element mode 11, 12 and 13: Dalitz decay with + // one or more particles in addition to the lepton pair, + // or double Dalitz decay. + bool useME11 = ( mult == 3 && !isResonanceNow + && (prod[1] == 11 || prod[1] == 13 || prod[1] == 15) + && prod[2] == -prod[1] ); + bool useME12 = ( mult > 3 && !isResonanceNow + && (prod[mult - 2] == 11 || prod[mult - 2] == 13 + || prod[mult - 2] == 15) && prod[mult - 1] == -prod[mult - 2] ); + bool useME13 = ( mult == 4 && !isResonanceNow + && (prod[0] == 11 || prod[0] == 13) && prod[1] == -prod[0] + && (prod[2] == 11 || prod[2] == 13) && prod[3] == -prod[2] ); + if (useME13) useME12 = false; + if ( meMode == 11 && !useME11 ) correctME = false; + if ( meMode != 11 && useME11 ) correctME = false; + if ( meMode == 12 && !useME12 ) correctME = false; + if ( meMode != 12 && useME12 ) correctME = false; + if ( meMode == 13 && !useME13 ) correctME = false; + if ( meMode != 13 && useME13 ) correctME = false; + + // Check matrix element mode 21: tau -> nu_tau hadrons. + bool useME21 = (id == 15 && mult > 2 && prod[0] == 16 + && abs(prod[1]) > 100); + if ( meMode == 21 && !useME21 ) correctME = false; + if ( meMode != 21 && useME21 ) correctME = false; + + // Check matrix element mode 22, but only for semileptonic decay. + // For a -> b c d require types u = 2, ubar = -2, d = 1, dbar = -1. + if ( isLepton(prod[0]) && isLepton(prod[1]) ) { + bool useME22 = false; + int typeA = 0; + int typeB = 0; + int typeC = 0; + if (particlePtr->isLepton()) { + typeA = (id > 0) ? 1 + (id-1)%2 : -1 - (1-id)%2; + } else if (particlePtr->isHadron()) { + int hQ = particlePtr->heaviestQuark(); + // Special case: for B_c either bbar or c decays. + if (id == 541 && heaviestQuark(prod[2]) == -5) hQ = 4; + typeA = (hQ > 0) ? 1 + (hQ-1)%2 : -1 - (1-hQ)%2; + } + typeB = (prod[0] > 0) ? 1 + (prod[0]-1)%2 : -1 - (1-prod[0])%2; + typeC = (prod[1] > 0) ? 1 + (prod[1]-1)%2 : -1 - (1-prod[1])%2; + // Special cases. + if ( (id == 130 || id == 310) && typeC * typeA < 0) typeA = -typeA; + if (mult == 3 && id == 2112 && prod[2] == 2212) typeA = 3 - typeA; + if (mult == 3 && id == 3222 && prod[2] == 3122) typeA = 3 - typeA; + if (mult > 2 && typeC == typeA && typeB * typeC < 0 + && (typeB + typeC)%2 != 0) useME22 = true; + if ( meMode == 22 && !useME22 ) correctME = false; + if ( meMode != 22 && useME22 ) correctME = false; + } + + // Check for matrix element mode 31. + if (meMode == 31) { + int nGamma = 0; + for (int j = 0; j < mult; ++j) if (prod[j] == 22) ++nGamma; + if (nGamma != 1) correctME = false; + } + + // Check for unknown mode, or resonance-only mode. + if ( !isResonanceNow && (meMode < 0 || (meMode > 2 && meMode <= 10) + || (meMode > 13 && meMode <= 20) || (meMode > 23 && meMode <= 30) + || (meMode > 31 && meMode <= 41) || meMode == 51 || meMode == 61 + || meMode == 71 || (meMode > 80 && meMode <= 90) + || (!particlePtr->isOctetHadron() && meMode > 92) ) ) + correctME = false; + + // Print if incorrect matrix element mode. + if ( !correctME ) { + os << " Warning: meMode " << meMode << " used for " + << id << " -> "; + for (int j = 0; j < mult; ++j) os << prod[j] << " "; + os << "\n"; + hasPrinted = true; + ++nErr; + } + + // Warning printout when no phase space for decay. + if ( studyCloser && verbosity > 0 && canHandle && onMode > 0 + && particlePtr->m0Min() - minFinalMass < 0. ) { + if (particlePtr->m0Max() - minFinalMass < 0.) + os << " Error: decay never possible for "; + else os << " Warning: decay sometimes not possible for "; + os << id << " -> "; + for (int j = 0; j < mult; ++j) os << prod[j] << " "; + os << "\n"; + hasPrinted = true; + ++nErr; + } + + // End loop over decay channels. + if (onMode > 0 && bRatio > 0.) openChannel = true; + } + + // Optional printout of threshold. + if (verbosity%10 > 1 && particlePtr->useBreitWigner()) { + threshMass /= bRatioSum; + os << " Info: particle " << id << fixed << setprecision(5) + << " has average mass threshold " << threshMass + << " while mMin is " << mMinNow << "\n"; + hasPrinted = true; + } + + // Error printout when no acceptable decay channels found. + if (studyCloser && !openChannel) { + os << " Error: no acceptable decay channel found for particle " + << id << "\n"; + hasPrinted = true; + ++nErr; + } + + // Warning printout when branching ratios do not sum to unity. + if (studyCloser && (!hasAnti || (!hasPosBR && !hasNegBR)) + && abs(bRatioSum + bRatioPos - 1.) > 1e-8) { + os << " Warning: particle " << id << fixed << setprecision(8) + << " has branching ratio sum " << bRatioSum << "\n"; + hasPrinted = true; + ++nErr; + } else if (studyCloser && hasAnti + && (abs(bRatioSum + bRatioPos - 1.) > 1e-8 + || abs(bRatioSum + bRatioNeg - 1.) > 1e-8)) { + os << " Warning: particle " << id << fixed << setprecision(8) + << " has branching ratio sum " << bRatioSum + bRatioPos + << " while its antiparticle has " << bRatioSum + bRatioNeg + << "\n"; + hasPrinted = true; + ++nErr; + } + + // End study of decay channels and loop over particles. + } + if (hasPrinted) os << "\n"; + } + + // Final output. Done. + os << " Total number of errors and warnings is " << nErr << "\n"; + os << "\n -------- End PYTHIA Check of Particle Data Table --------" + << "------\n" << endl; + +} + +//********* + +// Return the id of the sequentially next particle stored in table. + +int ParticleDataTable::nextId(int idIn) { + + // Return 0 for negative or unknown codes. Return first for 0. + if (idIn < 0 || (idIn > 0 && !isParticle(idIn))) return 0; + if (idIn == 0) return pdt.begin()->first; + + // Find pointer to current particle and step up. Return 0 if impossible. + map::const_iterator pdtIn = pdt.find(idIn); + if (pdtIn == pdt.end()) return 0; + return (++pdtIn)->first; + +} + +//********* + +// Fractional width associated with open channels of one or two resonances. + +double ParticleDataTable::resOpenFrac(int id1In, int id2In, int id3In) { + + // Default value. + double answer = 1.; + + // First resonance. + if (isParticle(id1In)) answer = pdt[abs(id1In)].resOpenFrac(id1In); + + // Possibly second resonance. + if (isParticle(id2In)) answer *= pdt[abs(id2In)].resOpenFrac(id2In); + + // Possibly third resonance. + if (isParticle(id3In)) answer *= pdt[abs(id2In)].resOpenFrac(id3In); + + // Done. + return answer; + +} + +//********* + +// Convert string to lowercase for case-insensitive comparisons. + +string ParticleDataTable::toLower(const string& name) { + + string temp(name); + for (int i = 0; i < int(temp.length()); ++i) + temp[i] = std::tolower(temp[i]); + return temp; + +} + +//********* + +// Allow several alternative inputs for true/false. + +bool ParticleDataTable::boolString(string tag) { + + string tagLow = toLower(tag); + return ( tagLow == "true" || tagLow == "1" || tagLow == "on" + || tagLow == "yes" || tagLow == "ok" ); + +} + +//********* + +// Extract XML value string following XML attribute. + +string ParticleDataTable::attributeValue(string line, string attribute) { + + if (line.find(attribute) == string::npos) return ""; + int iBegAttri = line.find(attribute); + int iBegQuote = line.find("\"", iBegAttri + 1); + int iEndQuote = line.find("\"", iBegQuote + 1); + return line.substr(iBegQuote + 1, iEndQuote - iBegQuote - 1); + +} + +//********* + +// Extract XML bool value following XML attribute. + +bool ParticleDataTable::boolAttributeValue(string line, string attribute) { + + string valString = attributeValue(line, attribute); + if (valString == "") return false; + return boolString(valString); + +} + +//********* + +// Extract XML int value following XML attribute. + +int ParticleDataTable::intAttributeValue(string line, string attribute) { + string valString = attributeValue(line, attribute); + if (valString == "") return 0; + istringstream valStream(valString); + int intVal; + valStream >> intVal; + return intVal; + +} + +//********* + +// Extract XML double value following XML attribute. + +double ParticleDataTable::doubleAttributeValue(string line, string attribute) { + string valString = attributeValue(line, attribute); + if (valString == "") return 0.; + istringstream valStream(valString); + double doubleVal; + valStream >> doubleVal; + return doubleVal; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/ParticleDecays.cxx b/PYTHIA8/pythia8130/src/ParticleDecays.cxx new file mode 100644 index 00000000000..fbaa6aa9924 --- /dev/null +++ b/PYTHIA8/pythia8130/src/ParticleDecays.cxx @@ -0,0 +1,1220 @@ +// ParticleDecays.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// ParticleDecays class. + +#include "ParticleDecays.h" + +namespace Pythia8 { + +//************************************************************************** + +// The ParticleDecays class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Number of times one tries to let decay happen (for 2 nested loops). +const int ParticleDecays::NTRYDECAY = 10; + +// Number of times one tries to pick valid hadronic content in decay. +const int ParticleDecays::NTRYPICK = 100; + +// Minimal Dalitz pair mass this factor above threshold. +const double ParticleDecays::MSAFEDALITZ = 1.000001; + +// These numbers are hardwired empirical parameters, +// intended to speed up the M-generator. +const double ParticleDecays::WTCORRECTION[11] = { 1., 1., 1., + 2., 5., 15., 60., 250., 1250., 7000., 50000. }; + +//********* + +// Initialize and save pointers. + +void ParticleDecays::init(Info* infoPtrIn, TimeShower* timesDecPtrIn, + StringFlav* flavSelPtrIn, DecayHandler* decayHandlePtrIn, + vector handledParticles) { + + // Save pointers to error messages handling and flavour generation. + infoPtr = infoPtrIn; + flavSelPtr = flavSelPtrIn; + + // Save pointer to timelike shower, as needed in some few decays. + timesDecPtr = timesDecPtrIn; + + // Save pointer for external handling of some decays. + decayHandlePtr = decayHandlePtrIn; + + // Set which particles should be handled externally. + if (decayHandlePtr != 0) + for (int i = 0; i < int(handledParticles.size()); ++i) + ParticleDataTable::doExternalDecay(handledParticles[i], true); + + // Safety margin in mass to avoid troubles. + mSafety = Settings::parm("ParticleDecays:mSafety"); + + // Lifetime and vertex rules for determining whether decay allowed. + limitTau0 = Settings::flag("ParticleDecays:limitTau0"); + tau0Max = Settings::parm("ParticleDecays:tau0Max"); + limitTau = Settings::flag("ParticleDecays:limitTau"); + tauMax = Settings::parm("ParticleDecays:tauMax"); + limitRadius = Settings::flag("ParticleDecays:limitRadius"); + rMax = Settings::parm("ParticleDecays:rMax"); + limitCylinder = Settings::flag("ParticleDecays:limitCylinder"); + xyMax = Settings::parm("ParticleDecays:xyMax"); + zMax = Settings::parm("ParticleDecays:zMax"); + limitDecay = limitTau0 || limitTau || limitRadius || limitCylinder; + + // B-Bbar mixing parameters. + mixB = Settings::flag("ParticleDecays:mixB"); + xBdMix = Settings::parm("ParticleDecays:xBdMix"); + xBsMix = Settings::parm("ParticleDecays:xBsMix"); + + // Suppression of extra-hadron momenta in semileptonic decays. + sigmaSoft = Settings::parm("ParticleDecays:sigmaSoft"); + + // Selection of multiplicity and colours in "phase space" model. + multIncrease = Settings::parm("ParticleDecays:multIncrease"); + multRefMass = Settings::parm("ParticleDecays:multRefMass"); + multGoffset = Settings::parm("ParticleDecays:multGoffset"); + colRearrange = Settings::parm("ParticleDecays:colRearrange"); + + // Minimum energy in system (+ m_q) from StringFragmentation. + stopMass = Settings::parm("StringFragmentation:stopMass"); + + // Parameters for Dalitz decay virtual gamma mass spectrum. + sRhoDal = pow2(ParticleDataTable::m0(113)); + wRhoDal = pow2(ParticleDataTable::mWidth(113)); + + // Allow showers in decays to qqbar/gg/ggg/gammagg. + doFSRinDecays = Settings::flag("ParticleDecays:FSRinDecays"); + +} + +//********* + +// Decay a particle; main method. + +bool ParticleDecays::decay( int iDec, Event& event) { + + // Check whether a decay is allowed, given the upcoming decay vertex. + Particle& decayer = event[iDec]; + if (limitDecay && !checkVertex(decayer)) return true; + + // Fill the decaying particle in slot 0 of arrays. + idDec = decayer.id(); + iProd.resize(0); + idProd.resize(0); + mProd.resize(0); + iProd.push_back( iDec ); + idProd.push_back( idDec ); + mProd.push_back( decayer.m() ); + bool foundChannel = false; + + // Check for oscillations B0 <-> B0bar or B_s0 <-> B_s0bar. + bool hasOscillated = (abs(idDec) == 511 || abs(idDec) == 531) + ? oscillateB(decayer) : false; + if (hasOscillated) {idDec = - idDec; idProd[0] = idDec;} + + // Particle data for decaying particle. + decDataPtr = &decayer.particleData(); + + // Optionally send on to external decay program. + bool doneExternally = false; + if (decDataPtr->doExternalDecay()) { + pProd.resize(0); + pProd.push_back(decayer.p()); + doneExternally = decayHandlePtr->decay(idProd, mProd, pProd, + iDec, event); + + // If it worked, then store the decay products in the event record. + if (doneExternally) { + mult = idProd.size() - 1; + int status = (hasOscillated) ? 94 : 93; + for (int i = 1; i <= mult; ++i) { + int iPos = event.append( idProd[i], status, iDec, 0, 0, 0, + 0, 0, pProd[i], mProd[i]); + iProd.push_back( iPos); + } + + // Also mark mother decayed and store daughters. + event[iDec].statusNeg(); + event[iDec].daughters( iProd[1], iProd[mult]); + } + } + + // Now begin normal internal decay treatment. + if (!doneExternally) { + + // Pick a decay channel; allow up to ten tries. + if (!decDataPtr->preparePick(idDec)) return false; + for (int iTryChannel = 0; iTryChannel < NTRYDECAY; ++iTryChannel) { + DecayChannel& channel = decDataPtr->pickChannel(); + meMode = channel.meMode(); + keepPartons = (meMode > 90 && meMode <= 100); + mult = channel.multiplicity(); + + // Allow up to ten tries for each channel (e.g with different masses). + for (int iTryMode = 0; iTryMode < NTRYDECAY; ++iTryMode) { + idProd.resize(1); + mProd.resize(1); + + // Extract and store the decay products. + hasPartons = false; + for (int i = 0; i < mult; ++i) { + int idNow = channel.product(i); + int idAbs = abs(idNow); + if ( idAbs < 10 || idAbs == 21 || idAbs == 81 || idAbs == 82 + || idAbs == 83 || (idAbs > 1000 && idAbs < 10000 + && (idAbs/10)%10 == 0) ) hasPartons = true; + if (idDec < 0 && ParticleDataTable::hasAnti(idNow)) idNow = -idNow; + double mNow = ParticleDataTable::mass(idNow); + idProd.push_back( idNow); + mProd.push_back( mNow); + } + + // Decays into partons usually translate into hadrons. + if (hasPartons && !keepPartons && !pickHadrons()) continue; + + // Need to set colour flow if explicit decay to partons. + cols.resize(0); + acols.resize(0); + for (int i = 0; i <= mult; ++i) { + cols.push_back(0); + acols.push_back(0); + } + if (hasPartons && keepPartons && !setColours(event)) continue; + + // Check that enough phase space for decay. + if (mult > 1) { + double mDiff = mProd[0]; + for (int i = 1; i <= mult; ++i) mDiff -= mProd[i]; + if (mDiff < mSafety) continue; + } + + // End of two trial loops. Check if succeeded or not. + foundChannel = true; + break; + } + if (foundChannel) break; + } + if (!foundChannel) { + infoPtr->errorMsg("Error in ParticleDecays::decay: " + "failed to find workable decay channel"); + return false; + } + + // Store decay products in the event record. + int status = (hasOscillated) ? 92 : 91; + for (int i = 1; i <= mult; ++i) { + int iPos = event.append( idProd[i], status, iDec, 0, 0, 0, + cols[i], acols[i], Vec4(0., 0., 0., 0.), mProd[i]); + iProd.push_back( iPos); + } + + // Pick mass of Dalitz decay. Temporarily change multiplicity. + if (meMode == 11 || meMode == 12 || meMode == 13) { + bool foundMass = dalitzMass(); + if (!foundMass) { + event.popBack(mult); + return false; + } + } + + // Do a decay, split by multiplicity. + bool decayed = false; + if (mult == 1) decayed = oneBody(event); + else if (mult == 2) decayed = twoBody(event); + else if (mult == 3) decayed = threeBody(event); + else decayed = mGenerator(event); + + // Kinematics of gamma* -> l- l+ in Dalitz decay. Restore multiplicity. + if (meMode == 11 || meMode == 12 || meMode == 13) + dalitzKinematics(event); + + // If the decay worked, then mark mother decayed and store daughters. + if (decayed) { + event[iDec].statusNeg(); + event[iDec].daughters( iProd[1], iProd[mult]); + + // Else remove unused daughters and return failure. + } else { + event.popBack(mult); + return false; + } + + // Now finished normal internal decay treatment. + } + + // Set decay vertex when this is displaced. + if (event[iDec].hasVertex() || event[iDec].tau() > 0.) { + Vec4 vDec = event[iDec].vDec(); + for (int i = 1; i <= mult; ++i) event[iProd[i]].vProd( vDec ); + } + + // Set lifetime of hadrons. + for (int i = 1; i <= mult; ++i) + event[iProd[i]].tau( event[iProd[i]].tau0() * Rndm::exp() ); + + // In a decay explicitly to partons then optionally do a shower, + // and always flag that partonic system should be fragmented. + if (hasPartons && keepPartons && doFSRinDecays) + timesDecPtr->shower( iProd[1], iProd.back(), event, mProd[0]); + + // Done. + return true; + +} + +//********* + +// Check whether a decay is allowed, given the upcoming decay vertex. + +bool ParticleDecays::checkVertex(Particle& decayer) { + + // Check whether any of the conditions are not fulfilled. + if (limitTau0 && decayer.tau0() > tau0Max) return false; + if (limitTau && decayer.tau() > tauMax) return false; + if (limitRadius && pow2(decayer.xDec()) + pow2(decayer.yDec()) + + pow2(decayer.zDec()) > pow2(rMax)) return false; + if (limitCylinder && (pow2(decayer.xDec()) + pow2(decayer.yDec()) + > pow2(xyMax) || abs(decayer.zDec()) > zMax) ) return false; + + // Done. + return true; + +} + +//********* + +// Check for oscillations B0 <-> B0bar or B_s0 <-> B_s0bar. + +bool ParticleDecays::oscillateB(Particle& decayer) { + + // Extract relevant information and decide. + double xBmix = (abs(decayer.id()) == 511) ? xBdMix : xBsMix; + double tau = decayer.tau(); + double tau0 = decayer.tau0(); + double probosc = pow2(sin(0.5 * xBmix * tau / tau0)); + return (probosc > Rndm::flat()); + +} + +//********* + +// Do a one-body decay. (Rare; e.g. for K0 -> K0_short.) + +bool ParticleDecays::oneBody(Event& event) { + + // References to the particles involved. + Particle& decayer = event[iProd[0]]; + Particle& prod = event[iProd[1]]; + + // Set momentum and expand mother information. + prod.p( decayer.p() ); + prod.m( decayer.m() ); + prod.mother2( iProd[0] ); + + // Done. + return true; + +} + +//********* + +// Do a two-body decay. + +bool ParticleDecays::twoBody(Event& event) { + + // References to the particles involved. + Particle& decayer = event[iProd[0]]; + Particle& prod1 = event[iProd[1]]; + Particle& prod2 = event[iProd[2]]; + + // Masses. + double m0 = mProd[0]; + double m1 = mProd[1]; + double m2 = mProd[2]; + + // Energies and absolute momentum in the rest frame. + if (m1 + m2 + mSafety > m0) return false; + double e1 = 0.5 * (m0*m0 + m1*m1 - m2*m2) / m0; + double e2 = 0.5 * (m0*m0 + m2*m2 - m1*m1) / m0; + double pAbs = 0.5 * sqrtpos( (m0 - m1 - m2) * (m0 + m1 + m2) + * (m0 + m1 - m2) * (m0 - m1 + m2) ) / m0; + + // When meMode = 2, for V -> PS2 + PS3 (V = vector, pseudoscalar), + // need to check if production is PS0 -> PS1/gamma + V. + int iMother = event[iProd[0]].mother1(); + int idSister = 0; + if (meMode == 2) { + if (iMother <= 0 || iMother >= iProd[0]) meMode = 0; + else { + int iDaughter1 = event[iMother].daughter1(); + int iDaughter2 = event[iMother].daughter2(); + if (iDaughter2 != iDaughter1 + 1) meMode = 0; + else { + int idMother = abs( event[iMother].id() ); + if (idMother <= 100 || idMother%10 !=1 + || (idMother/1000)%10 != 0) meMode = 0; + else { + int iSister = (iProd[0] == iDaughter1) ? iDaughter2 : iDaughter1; + idSister = abs( event[iSister].id() ); + if ( (idSister <= 100 || idSister%10 !=1 + || (idSister/1000)%10 != 0) && idSister != 22) meMode = 0; + } + } + } + } + + // Begin loop over matrix-element corrections. + double wtME, wtMEmax; + do { + wtME = 1.; + wtMEmax = 1.; + + // Isotropic angles give three-momentum. + double cosTheta = 2. * Rndm::flat() - 1.; + double sinTheta = sqrt(1. - cosTheta*cosTheta); + double phi = 2. * M_PI * Rndm::flat(); + double pX = pAbs * sinTheta * cos(phi); + double pY = pAbs * sinTheta * sin(phi); + double pZ = pAbs * cosTheta; + + // Fill four-momenta and boost them away from mother rest frame. + prod1.p( pX, pY, pZ, e1); + prod2.p( -pX, -pY, -pZ, e2); + prod1.bst( decayer.p(), decayer.m() ); + prod2.bst( decayer.p(), decayer.m() ); + + // Matrix element for PS0 -> PS1 + V1 -> PS1 + PS2 + PS3 of form + // cos**2(theta02) in V1 rest frame, and for PS0 -> gamma + V1 + // -> gamma + PS2 + PS3 of form sin**2(theta02). + if (meMode == 2) { + double p10 = decayer.p() * event[iMother].p(); + double p12 = decayer.p() * prod1.p(); + double p02 = event[iMother].p() * prod1.p(); + double s0 = pow2(event[iMother].m()); + double s1 = pow2(decayer.m()); + double s2 = pow2(prod1.m()); + if (idSister != 22) wtME = pow2(p10 * p12 - s1 * p02); + else wtME = s1 * (2. * p10 * p12 * p02 - s1 * p02*p02 + - s0 * p12*p12 - s2 * p10*p10 + s1 * s0 * s2); + wtME = max( wtME, 1e-6 * s1*s1 * s0 * s2); + wtMEmax = (p10*p10 - s1 * s0) * (p12*p12 - s1 * s2); + } + + // If rejected, try again with new invariant masses. + } while ( wtME < Rndm::flat() * wtMEmax ); + + // Done. + return true; + +} + +//********* + +// Do a three-body decay (except Dalitz decays). + +bool ParticleDecays::threeBody(Event& event) { + + // References to the particles involved. + Particle& decayer = event[iProd[0]]; + Particle& prod1 = event[iProd[1]]; + Particle& prod2 = event[iProd[2]]; + Particle& prod3 = event[iProd[3]]; + + // Mother and sum daughter masses. Fail if too close. + double m0 = mProd[0]; + double m1 = mProd[1]; + double m2 = mProd[2]; + double m3 = mProd[3]; + double mSum = m1 + m2 + m3; + double mDiff = m0 - mSum; + if (mDiff < mSafety) return false; + + // Kinematical limits for 2+3 mass. Maximum phase-space weight. + double m23Min = m2 + m3; + double m23Max = m0 - m1; + double p1Max = 0.5 * sqrtpos( (m0 - m1 - m23Min) * (m0 + m1 + m23Min) + * (m0 + m1 - m23Min) * (m0 - m1 + m23Min) ) / m0; + double p23Max = 0.5 * sqrtpos( (m23Max - m2 - m3) * (m23Max + m2 + m3) + * (m23Max + m2 - m3) * (m23Max - m2 + m3) ) / m23Max; + double wtPSmax = 0.5 * p1Max * p23Max; + + // Begin loop over matrix-element corrections. + double wtME, wtMEmax, wtPS, m23, p1Abs, p23Abs; + do { + wtME = 1.; + wtMEmax = 1.; + + // Pick an intermediate mass m23 flat in the allowed range. + do { + m23 = m23Min + Rndm::flat() * mDiff; + + // Translate into relative momenta and find phase-space weight. + p1Abs = 0.5 * sqrtpos( (m0 - m1 - m23) * (m0 + m1 + m23) + * (m0 + m1 - m23) * (m0 - m1 + m23) ) / m0; + p23Abs = 0.5 * sqrtpos( (m23 - m2 - m3) * (m23 + m2 + m3) + * (m23 + m2 - m3) * (m23 - m2 + m3) ) / m23; + wtPS = p1Abs * p23Abs; + + // If rejected, try again with new invariant masses. + } while ( wtPS < Rndm::flat() * wtPSmax ); + + // Set up m23 -> m2 + m3 isotropic in its rest frame. + double cosTheta = 2. * Rndm::flat() - 1.; + double sinTheta = sqrt(1. - cosTheta*cosTheta); + double phi = 2. * M_PI * Rndm::flat(); + double pX = p23Abs * sinTheta * cos(phi); + double pY = p23Abs * sinTheta * sin(phi); + double pZ = p23Abs * cosTheta; + double e2 = sqrt( m2*m2 + p23Abs*p23Abs); + double e3 = sqrt( m3*m3 + p23Abs*p23Abs); + prod2.p( pX, pY, pZ, e2); + prod3.p( -pX, -pY, -pZ, e3); + + // Set up m0 -> m1 + m23 isotropic in its rest frame. + cosTheta = 2. * Rndm::flat() - 1.; + sinTheta = sqrt(1. - cosTheta*cosTheta); + phi = 2. * M_PI * Rndm::flat(); + pX = p1Abs * sinTheta * cos(phi); + pY = p1Abs * sinTheta * sin(phi); + pZ = p1Abs * cosTheta; + double e1 = sqrt( m1*m1 + p1Abs*p1Abs); + double e23 = sqrt( m23*m23 + p1Abs*p1Abs); + prod1.p( pX, pY, pZ, e1); + + // Boost 2 + 3 to the 0 rest frame. + Vec4 p23( -pX, -pY, -pZ, e23); + prod2.bst( p23, m23 ); + prod3.bst( p23, m23 ); + + // Matrix-element weight for omega/phi -> pi+ pi- pi0. + if (meMode == 1) { + double p1p2 = prod1.p() * prod2.p(); + double p1p3 = prod1.p() * prod3.p(); + double p2p3 = prod2.p() * prod3.p(); + wtME = pow2(m1 * m2 * m3) - pow2(m1 * p2p3) - pow2(m2 * p1p3) + - pow2(m3 * p1p2) + 2. * p1p2 * p1p3 * p2p3; + wtMEmax = pow3(m0 * m0) / 150.; + + // Effective matrix element for nu spectrum in tau -> nu + hadrons. + } else if (meMode == 21) { + double x1 = 2. * prod1.e() / m0; + wtME = x1 * (3. - 2. * x1); + double xMax = min( 0.75, 2. * (1. - mSum / m0) ); + wtMEmax = xMax * (3. - 2. * xMax); + + // Matrix element for weak decay (only semileptonic for c and b). + } else if ((meMode == 22 || meMode == 23) && prod1.isLepton()) { + wtME = m0 * prod1.e() * (prod2.p() * prod3.p()); + wtMEmax = min( pow4(m0) / 16., m0 * (m0 - m1 - m2) * (m0 - m1 - m3) + * (m0 - m2 - m3) ); + + // Effective matrix element for weak decay to hadrons (B -> D, D -> K). + } else if (meMode == 22 || meMode == 23) { + double x1 = 2. * prod1.pAbs() / m0; + wtME = x1 * (3. - 2. * x1); + double xMax = min( 0.75, 2. * (1. - mSum / m0) ); + wtMEmax = xMax * (3. - 2. * xMax); + + // Effective matrix element for gamma spectrum in B -> gamma + hadrons. + } else if (meMode == 31) { + double x1 = 2. * prod1.e() / m0; + wtME = pow3(x1); + double x1Max = 1. - pow2(mSum / m0); + wtMEmax = pow3(x1Max); + + // Matrix-element weight for "onium" -> g + g + g or gamma + g + g. + } else if (meMode == 92) { + double x1 = 2. * prod1.e() / m0; + double x2 = 2. * prod2.e() / m0; + double x3 = 2. * prod3.e() / m0; + wtME = pow2( (1. - x1) / (x2 * x3) ) + pow2( (1. - x2) / (x1 * x3) ) + + pow2( (1. - x3) / (x1 * x2) ); + wtMEmax = 2.; + // For gamma + g + g require minimum mass for g + g system. + if (prod1.id() == 22 && sqrt(1. - x1) * m0 < 2. * stopMass) wtME = 0.; + if (prod2.id() == 22 && sqrt(1. - x2) * m0 < 2. * stopMass) wtME = 0.; + if (prod3.id() == 22 && sqrt(1. - x3) * m0 < 2. * stopMass) wtME = 0.; + } + + // If rejected, try again with new invariant masses. + } while ( wtME < Rndm::flat() * wtMEmax ); + + // Boost 1 + 2 + 3 to the current frame. + prod1.bst( decayer.p(), decayer.m() ); + prod2.bst( decayer.p(), decayer.m() ); + prod3.bst( decayer.p(), decayer.m() ); + + // Done. + return true; + +} + +//********* + +// Do a multibody decay using the M-generator algorithm. + +bool ParticleDecays::mGenerator(Event& event) { + + // Mother and sum daughter masses. Fail if too close or inconsistent. + double m0 = mProd[0]; + double mSum = mProd[1]; + for (int i = 2; i <= mult; ++i) mSum += mProd[i]; + double mDiff = m0 - mSum; + if (mDiff < mSafety) return false; + + // Begin setup of intermediate invariant masses. + mInv.resize(0); + for (int i = 0; i <= mult; ++i) mInv.push_back( mProd[i]); + + // Calculate the maximum weight in the decay. + double wtPS, wtME, wtMEmax; + double wtPSmax = 1. / WTCORRECTION[mult]; + double mMax = mDiff + mProd[mult]; + double mMin = 0.; + for (int i = mult - 1; i > 0; --i) { + mMax += mProd[i]; + mMin += mProd[i+1]; + double mNow = mProd[i]; + wtPSmax *= 0.5 * sqrtpos( (mMax - mMin - mNow) * (mMax + mMin + mNow) + * (mMax + mMin - mNow) * (mMax - mMin + mNow) ) / mMax; + } + + // Begin loop over matrix-element corrections. + do { + wtME = 1.; + wtMEmax = 1.; + + // Begin loop to find the set of intermediate invariant masses. + do { + wtPS = 1.; + + // Find and order random numbers in descending order. + rndmOrd.resize(0); + rndmOrd.push_back(1.); + for (int i = 1; i < mult - 1; ++i) { + double rndm = Rndm::flat(); + rndmOrd.push_back(rndm); + for (int j = i - 1; j > 0; --j) { + if (rndm > rndmOrd[j]) swap( rndmOrd[j], rndmOrd[j+1] ); + else break; + } + } + rndmOrd.push_back(0.); + + // Translate into intermediate masses and find weight. + for (int i = mult - 1; i > 0; --i) { + mInv[i] = mInv[i+1] + mProd[i] + (rndmOrd[i-1] - rndmOrd[i]) * mDiff; + wtPS *= 0.5 * sqrtpos( (mInv[i] - mInv[i+1] - mProd[i]) + * (mInv[i] + mInv[i+1] + mProd[i]) * (mInv[i] + mInv[i+1] - mProd[i]) + * (mInv[i] - mInv[i+1] + mProd[i]) ) / mInv[i]; + } + + // If rejected, try again with new invariant masses. + } while ( wtPS < Rndm::flat() * wtPSmax ); + + // Perform two-particle decays in the respective rest frame. + pInv.resize(mult + 1); + for (int i = 1; i < mult; ++i) { + double pAbs = 0.5 * sqrtpos( (mInv[i] - mInv[i+1] - mProd[i]) + * (mInv[i] + mInv[i+1] + mProd[i]) * (mInv[i] + mInv[i+1] - mProd[i]) + * (mInv[i] - mInv[i+1] + mProd[i]) ) / mInv[i]; + + // Isotropic angles give three-momentum. + double cosTheta = 2. * Rndm::flat() - 1.; + double sinTheta = sqrt(1. - cosTheta*cosTheta); + double phi = 2. * M_PI * Rndm::flat(); + double pX = pAbs * sinTheta * cos(phi); + double pY = pAbs * sinTheta * sin(phi); + double pZ = pAbs * cosTheta; + + // Calculate energies, fill four-momenta. + double eHad = sqrt( mProd[i]*mProd[i] + pAbs*pAbs); + double eInv = sqrt( mInv[i+1]*mInv[i+1] + pAbs*pAbs); + event[iProd[i]].p( pX, pY, pZ, eHad); + pInv[i+1].p( -pX, -pY, -pZ, eInv); + } + + // Boost decay products to the mother rest frame. + event[iProd[mult]].p( pInv[mult] ); + for (int iFrame = mult - 1; iFrame > 1; --iFrame) + for (int i = iFrame; i <= mult; ++i) + event[iProd[i]].bst( pInv[iFrame], mInv[iFrame]); + + // Effective matrix element for nu spectrum in tau -> nu + hadrons. + if (meMode == 21 && event[iProd[1]].isLepton()) { + double x1 = 2. * event[iProd[1]].e() / m0; + wtME = x1 * (3. - 2. * x1); + double xMax = min( 0.75, 2. * (1. - mSum / m0) ); + wtMEmax = xMax * (3. - 2. * xMax); + + // Effective matrix element for weak decay (only semileptonic for c and b). + // Particles 4 onwards should be made softer explicitly? + } else if ((meMode == 22 || meMode == 23) && event[iProd[1]].isLepton()) { + Vec4 pRest = event[iProd[3]].p(); + for (int i = 4; i <= mult; ++i) pRest += event[iProd[i]].p(); + wtME = m0 * event[iProd[1]].e() * (event[iProd[2]].p() * pRest); + for (int i = 4; i <= mult; ++i) wtME + *= exp(- event[iProd[i]].pAbs2() / pow2(sigmaSoft) ); + wtMEmax = pow4(m0) / 16.; + + // Effective matrix element for weak decay to hadrons (B -> D, D -> K). + } else if (meMode == 22 || meMode == 23) { + double x1 = 2. * event[iProd[1]].pAbs() / m0; + wtME = x1 * (3. - 2. * x1); + double xMax = min( 0.75, 2. * (1. - mSum / m0) ); + wtMEmax = xMax * (3. - 2. * xMax); + + // Effective matrix element for gamma spectrum in B -> gamma + hadrons. + } else if (meMode == 31) { + double x1 = 2. * event[iProd[1]].e() / m0; + wtME = pow3(x1); + double x1Max = 1. - pow2(mSum / m0); + wtMEmax = pow3(x1Max); + } + + // If rejected, try again with new invariant masses. + } while ( wtME < Rndm::flat() * wtMEmax ); + + // Boost decay products to the current frame. + pInv[1].p( event[iProd[0]].p() ); + for (int i = 1; i <= mult; ++i) event[iProd[i]].bst( pInv[1], mInv[1] ); + + // Done. + return true; + +} + +//********* + +// Select mass of lepton pair in a Dalitz decay. + +bool ParticleDecays::dalitzMass() { + + // Mother and sum daughter masses. + double mSum1 = 0; + for (int i = 1; i <= mult - 2; ++i) mSum1 += mProd[i]; + if (meMode == 13) mSum1 *= MSAFEDALITZ; + double mSum2 = MSAFEDALITZ * (mProd[mult -1] + mProd[mult]); + double mDiff = mProd[0] - mSum1 - mSum2; + + // Fail if too close or inconsistent. + if (mDiff < mSafety) return false; + if (idProd[mult - 1] + idProd[mult] != 0 + || mProd[mult - 1] != mProd[mult]) { + infoPtr->errorMsg("Error in ParticleDecays::dalitzMass:" + " inconsistent flavour/mass assignments"); + return false; + } + if ( meMode == 13 && (idProd[1] + idProd[2] != 0 + || mProd[1] != mProd[2]) ) { + infoPtr->errorMsg("Error in ParticleDecays::dalitzMass:" + " inconsistent flavour/mass assignments"); + return false; + } + + // Case 1: one Dalitz pair. + if (meMode == 11 || meMode == 12) { + + // Kinematical limits for gamma* squared mass. + double sGamMin = pow2(mSum2); + double sGamMax = pow2(mProd[0] - mSum1); + + // Select virtual gamma squared mass. Guessed form for meMode == 12. + double sGam, wtGam; + do { + sGam = sGamMin * pow( sGamMax / sGamMin, Rndm::flat() ); + wtGam = (1. + 0.5 * sGamMin / sGam) * sqrt(1. - sGamMin / sGam) + * pow3(1. - sGam / sGamMax) * sRhoDal * (sRhoDal + wRhoDal) + / ( pow2(sGam - sRhoDal) + sRhoDal * wRhoDal ); + } while ( wtGam < Rndm::flat() ); + + // Store results in preparation for doing a one-less-body decay. + --mult; + mProd[mult] = sqrt(sGam); + + // Case 2: two Dalitz pairs. + } else { + + // Kinematical limits for 1 + 2 and 3 + 4 gamma* masses. + double s0 = pow2(mProd[0]); + double s12Min = pow2(mSum1); + double s12Max = pow2(mProd[0] - mSum2); + double s34Min = pow2(mSum2); + double s34Max = pow2(mProd[0] - mSum1); + + // Select virtual gamma squared masses. Guessed form for meMode == 13. + double s12, s34, wt12, wt34, wtPAbs, wtAll; + do { + s12 = s12Min * pow( s12Max / s12Min, Rndm::flat() ); + wt12 = (1. + 0.5 * s12Min / s12) * sqrt(1. - s12Min / s12) + * sRhoDal * (sRhoDal + wRhoDal) + / ( pow2(s12 - sRhoDal) + sRhoDal * wRhoDal ); + s34 = s34Min * pow( s34Max / s34Min, Rndm::flat() ); + wt34 = (1. + 0.5 * s34Min / s34) * sqrt(1. - s34Min / s34) + * sRhoDal * (sRhoDal + wRhoDal) + / ( pow2(s34 - sRhoDal) + sRhoDal * wRhoDal ); + wtPAbs = sqrtpos( pow2(1. - (s12 + s34)/ s0) + - 4. * s12 * s34 / (s0 * s0) ); + wtAll = wt12 * wt34 * pow3(wtPAbs); + if (wtAll > 1.) infoPtr->errorMsg( + "Error in ParticleDecays::dalitzMass: weight > 1"); + } while (wtAll < Rndm::flat()); + + // Store results in preparation for doing a two-body decay. + mult = 2; + mProd[1] = sqrt(s12); + mProd[2] = sqrt(s34); + } + + // Done. + return true; + +} + +//********* + +// Do kinematics of gamma* -> l- l+ in Dalitz decay. + +bool ParticleDecays::dalitzKinematics(Event& event) { + + // Restore multiplicity. + int nDal = (meMode < 13) ? 1 : 2; + mult += nDal; + + // Loop over one or two lepton pairs. + for (int iDal = 0; iDal < nDal; ++iDal) { + + // References to the particles involved. + Particle& decayer = event[iProd[0]]; + Particle& prodA = (iDal == 0) ? event[iProd[mult - 1]] + : event[iProd[1]]; + Particle& prodB = (iDal == 0) ? event[iProd[mult]] + : event[iProd[2]]; + + // Reconstruct required rotations and boosts backwards. + Vec4 pDec = decayer.p(); + int iGam = (meMode < 13) ? mult - 1 : 2 - iDal; + Vec4 pGam = event[iProd[iGam]].p(); + Vec4 pGamOld = pGam; + pGam.bstback( pDec, decayer.m() ); + double phiGam = pGam.phi(); + pGam.rot( 0., -phiGam); + double thetaGam = pGam.theta(); + pGam.rot( -thetaGam, 0.); + + // Masses and phase space in gamma* rest frame. + double mGam = (meMode < 13) ? mProd[mult - 1] : mProd[2 - iDal]; + double mA = prodA.m(); + double mB = prodB.m(); + double mGamMin = MSAFEDALITZ * (mA + mB); + double mGamRat = pow2(mGamMin / mGam); + double pGamAbs = 0.5 * sqrtpos( (mGam - mA - mB) * (mGam + mA + mB) ); + + // Set up decay in gamma* rest frame, reference along +z axis. + double cosTheta, cos2Theta; + do { + cosTheta = 2. * Rndm::flat() - 1.; + cos2Theta = cosTheta * cosTheta; + } while ( 1. + cos2Theta + mGamRat * (1. - cos2Theta) + < 2. * Rndm::flat() ); + double sinTheta = sqrt(1. - cosTheta*cosTheta); + double phi = 2. * M_PI * Rndm::flat(); + double pX = pGamAbs * sinTheta * cos(phi); + double pY = pGamAbs * sinTheta * sin(phi); + double pZ = pGamAbs * cosTheta; + double eA = sqrt( mA*mA + pGamAbs*pGamAbs); + double eB = sqrt( mB*mB + pGamAbs*pGamAbs); + prodA.p( pX, pY, pZ, eA); + prodB.p( -pX, -pY, -pZ, eB); + + // Boost to lab frame. + prodA.bst( pGam, mGam); + prodB.bst( pGam, mGam); + prodA.rot( thetaGam, phiGam); + prodB.rot( thetaGam, phiGam); + prodA.bst( pDec, decayer.m() ); + prodB.bst( pDec, decayer.m() ); + } + + // Done. + return true; + +} + +//********* + +// Translate a partonic content into a set of actual hadrons. + +bool ParticleDecays::pickHadrons() { + + // Find partonic decay products. Rest are known id's, mainly hadrons, + // when necessary shuffled to beginning of idProd list. + idPartons.resize(0); + int nPartons = 0; + int nKnown = 0; + bool closedGLoop = false; + for (int i = 1; i <= mult; ++i) { + int idAbs = abs(idProd[i]); + if ( idAbs < 9 || (idAbs > 1000 && idAbs < 10000 && (idAbs/10)%10 == 0) + || idAbs == 81 || idAbs == 82 || idAbs == 83) { + ++nPartons; + idPartons.push_back(idProd[i]); + if (idAbs == 83) closedGLoop = true; + } else { + ++nKnown; + if (nPartons > 0) { + idProd[nKnown] = idProd[i]; + mProd[nKnown] = mProd[i]; + } + } + } + + // Replace generic spectator flavour code by the actual one. + for (int i = 0; i < nPartons; ++i) { + int idPart = idPartons[i]; + int idNew = idPart; + if (idPart == 81) { + int idAbs = abs(idDec); + if ( (idAbs/1000)%10 == 0 ) { + idNew = -(idAbs/10)%10; + if ((idAbs/100)%2 == 1) idNew = -idNew; + } else if ( (idAbs/100)%10 >= (idAbs/10)%10 ) + idNew = 100 * ((idAbs/10)%100) + 3; + else idNew = 1000 * ((idAbs/10)%10) + 100 * ((idAbs/100)%10) + 1; + if (idDec < 0) idNew = -idNew; + + // Replace generic random flavour by a randomly selected one. + } else if (idPart == 82 || idPart == 83) { + double mFlav; + do { + int idDummy = -flavSelPtr->pickLightQ(); + FlavContainer flavDummy(idDummy, idPart - 82); + do idNew = flavSelPtr->pick(flavDummy).id; + while (idNew == 0); + mFlav = ParticleDataTable::constituentMass(idNew); + } while (2. * mFlav + stopMass > mProd[0]); + } else if (idPart == -82 || idPart == -83) { + idNew = -idPartons[i-1]; + } + idPartons[i] = idNew; + } + + // Determine whether fixed multiplicity or to be selected at random. + int nMin = max( 2, nKnown + nPartons / 2); + if (meMode == 23) nMin = 3; + if (meMode > 41 && meMode <= 50) nMin = meMode - 40; + if (meMode > 51 && meMode <= 60) nMin = meMode - 50; + int nFix = 0; + if (meMode == 0) nFix = nMin; + if (meMode == 11) nFix = 3; + if (meMode == 12) nFix = 4; + if (meMode > 61 && meMode <= 70) nFix = meMode - 60; + if (meMode > 71 && meMode <= 80) nFix = meMode - 70; + if (nFix > 0 && nKnown + nPartons/2 > nFix) return false; + + // Initial values for loop to set new hadronic content. + int nFilled = nKnown + 1; + int nTotal, nNew, nSpec, nLeft; + double mDiff; + int nTry = 0; + bool diquarkClash = false; + bool usedChannel = false; + + // Begin loop; interrupt if multiple tries fail. + do { + ++nTry; + if (nTry > NTRYPICK) return false; + + // Initialize variables inside new try. + nFilled = nKnown + 1; + idProd.resize(nFilled); + mProd.resize(nFilled); + nTotal = nKnown; + nNew = 0; + nSpec = 0; + nLeft = nPartons; + mDiff = mProd[0]; + for (int i = 1; i < nFilled; ++i) mDiff -= mProd[i]; + diquarkClash = false; + usedChannel = false; + + // For weak decays collapse spectators to one particle. + if ( (meMode == 22 || meMode == 23) && nLeft > 1) { + FlavContainer flav1( idPartons[nPartons - 2] ); + FlavContainer flav2( idPartons[nPartons - 1] ); + int idHad; + do idHad = flavSelPtr->combine( flav1, flav2); + while (idHad == 0); + double mHad = ParticleDataTable::mass(idHad); + mDiff -= mHad; + idProd.push_back( idHad); + mProd.push_back( mHad); + ++nFilled; + nSpec = 1; + nLeft -= 2; + } + + // If there are partons left, then determine how many hadrons to pick. + if (nLeft > 0) { + + // For B -> gamma + X use geometrical distribution. + if (meMode == 31) { + double geom = Rndm::flat(); + nTotal = 1; + do { + ++nTotal; + geom *= 2.; + } while (geom < 1. && nTotal < 10); + + // Calculate mass excess and from there average multiplicity. + } else if (nFix == 0) { + double mDiffPS = mDiff; + for (int i = 0; i < nLeft; ++i) + mDiffPS -= ParticleDataTable::constituentMass( idPartons[i] ); + double average = 0.5 * (nKnown + nSpec) + 0.25 * nPartons + + multIncrease * log( max( 1.1, mDiffPS / multRefMass ) ); + if (closedGLoop) average += multGoffset; + + // Pick multiplicity according to Poissonian. + double value = 1.; + double sum = 1.; + for (int nNow = nMin + 1; nNow <= 10; ++nNow) { + value *= average / nNow; + sum += value; + } + nTotal = nMin; + value = 1.; + sum *= Rndm::flat(); + sum -= value; + if (sum > 0.) do { + ++nTotal; + value *= average / nTotal; + sum -= value; + } while (sum > 0. && nTotal < 10); + + // Alternatively predetermined multiplicity. + } else { + nTotal = nFix; + } + nNew = nTotal - nKnown - nSpec; + + // Set up ends of fragmented system, as copy of idPartons. + flavEnds.resize(0); + for (int i = 0; i < nLeft; ++i) { + flavEnds.push_back( FlavContainer(idPartons[i]) ); + if (abs(idPartons[i]) > 100) flavSelPtr->assignPopQ( flavEnds[i] ); + } + + // Fragment off at random, but save nLeft/2 for final recombination. + if (nNew > nLeft/2) { + FlavContainer flavNew; + int idHad; + for (int i = 0; i < nNew - nLeft/2; ++i) { + // When four quarks consider last one to be spectator. + int iEnd = int( (nLeft - 1.) * Rndm::flat() ); + // Pick new flavour and form a new hadron. + do { + flavNew = flavSelPtr->pick( flavEnds[iEnd] ); + idHad = flavSelPtr->combine( flavEnds[iEnd], flavNew); + } while (idHad == 0); + // Store new hadron and endpoint flavour. + idProd.push_back( idHad); + flavEnds[iEnd].anti(flavNew); + } + } + + // When only two quarks left, combine to form final hadron. + if (nLeft == 2) { + int idHad; + if ( abs(flavEnds[0].id) > 8 && abs(flavEnds[1].id) > 8) + diquarkClash = true; + else { + do idHad = flavSelPtr->combine( flavEnds[0], flavEnds[1]); + while (idHad == 0); + idProd.push_back( idHad); + } + + // If four quarks, decide how to pair them up. + } else { + int iEnd1 = 0; + int iEnd2 = 1; + int iEnd3 = 2; + int iEnd4 = 3; + if ( Rndm::flat() < colRearrange) iEnd2 = 3; + int relColSign = + ( (flavEnds[iEnd1].id > 0 && flavEnds[iEnd1].id < 9) + || flavEnds[iEnd1].id < -10 ) ? 1 : -1; + if ( (flavEnds[iEnd2].id < 0 && flavEnds[iEnd2].id > -9) + || flavEnds[iEnd2].id > 10 ) relColSign *= -1; + if (relColSign == 1) iEnd2 = 2; + if (iEnd2 == 2) iEnd3 = 1; + if (iEnd2 == 3) iEnd4 = 1; + + // Then combine to get final two hadrons. + int idHad; + if ( abs(flavEnds[iEnd1].id) > 8 && abs(flavEnds[iEnd2].id) > 8) + diquarkClash = true; + else { + do idHad = flavSelPtr->combine( flavEnds[iEnd1], flavEnds[iEnd2]); + while (idHad == 0); + idProd.push_back( idHad); + } + if ( abs(flavEnds[iEnd3].id) > 8 && abs(flavEnds[iEnd4].id) > 8) + diquarkClash = true; + else { + do idHad = flavSelPtr->combine( flavEnds[iEnd3], flavEnds[iEnd4]); + while (idHad == 0); + idProd.push_back( idHad); + } + } + + // Find masses of the new hadrons. + for (int i = nFilled; i < int(idProd.size()) ; ++i) { + double mHad = ParticleDataTable::mass(idProd[i]); + mProd.push_back( mHad); + mDiff -= mHad; + } + } + + // Optional: check that this decay mode is not explicitly defined. + if ( (meMode > 61 && meMode <= 80) && mDiff > mSafety && !diquarkClash ) { + int idMatch[10], idPNow; + usedChannel = false; + bool matched = false; + // Loop through all channels. Done if not same multiplicity. + for (int i = 0; i < decDataPtr->decay.size(); ++i) { + DecayChannel& channel = decDataPtr->decay[i]; + if (channel.multiplicity() != nTotal) continue; + for (int k = 0; k < nTotal; ++k) idMatch[k] = channel.product(k); + // Match particles one by one until fail. + // Do not distinguish K0/K0bar/K0short/K0long at this stage. + for (int j = 0; j < nTotal; ++j) { + matched = false; + idPNow = idProd[j + 1]; + if (idPNow == -311 || idPNow == 130 || idPNow == 310) idPNow = 311; + for (int k = 0; k < nTotal - j; ++k) + if (idMatch[k] == idPNow || (idMatch[k] == -311 && idPNow == 311)) { + // Compress list of unmatched when matching worked. + idMatch[k] = idMatch[nTotal - 1 - j]; + matched = true; + break; + } + if (!matched) break; + } + // If matching worked, then chosen channel to be rejected. + if (matched) {usedChannel = true; break;} + } + } + + // Keep on trying until enough phase space and no clash. + } while (mDiff < mSafety || diquarkClash || usedChannel); + + // Update particle multiplicity. + mult = idProd.size() - 1; + + // For Dalitz decays shuffle Dalitz pair to the end of the list. + if (meMode == 11 || meMode == 12) { + int iL1 = 0; + int iL2 = 0; + for (int i = 1; i <= mult; ++i) { + if (idProd[i] == 11 || idProd[i] == 13 || idProd[i] == 15) iL1 = i; + if (idProd[i] == -11 || idProd[i] == -13 || idProd[i] == -15) iL2 = i; + } + if (iL1 > 0 && iL2 > 0) { + int idL1 = idProd[iL1]; + int idL2 = idProd[iL2]; + double mL1 = mProd[iL1]; + double mL2 = mProd[iL2]; + int iMove = 0; + for (int i = 1; i <= mult; ++i) if (i != iL1 && i != iL2) { + ++iMove; + idProd[iMove] = idProd[i]; + mProd[iMove] = mProd[i]; + } + idProd[mult - 1] = idL1; + idProd[mult] = idL2; + mProd[mult - 1] = mL1; + mProd[mult] = mL2; + } + } + + // Done. + return true; + +} + +//********* + +// Set colour flow and scale in a decay explicitly to partons. + +bool ParticleDecays::setColours(Event& event) { + + // Decay to q qbar (or qbar q). + if (meMode == 91 && idProd[1] > 0 && idProd[1] < 9) { + int newCol = event.nextColTag(); + cols[1] = newCol; + acols[2] = newCol; + } else if (meMode == 91 && idProd[1] < 0 && idProd[1] > -9) { + int newCol = event.nextColTag(); + cols[2] = newCol; + acols[1] = newCol; + + // Decay to g g. + } else if (meMode == 91 && idProd[1] == 21) { + int newCol1 = event.nextColTag(); + int newCol2 = event.nextColTag(); + cols[1] = newCol1; + acols[1] = newCol2; + cols[2] = newCol2; + acols[2] = newCol1; + + // Decay to g g g. + } else if (meMode == 92 && idProd[1] == 21 && idProd[2] == 21 + && idProd[3] == 21) { + int newCol1 = event.nextColTag(); + int newCol2 = event.nextColTag(); + int newCol3 = event.nextColTag(); + cols[1] = newCol1; + acols[1] = newCol2; + cols[2] = newCol2; + acols[2] = newCol3; + cols[3] = newCol3; + acols[3] = newCol1; + + // Decay to g g gamma: locate which is gamma. + } else if (meMode == 92) { + int iGlu1 = (idProd[1] == 21) ? 1 : 3; + int iGlu2 = (idProd[2] == 21) ? 2 : 3; + int newCol1 = event.nextColTag(); + int newCol2 = event.nextColTag(); + cols[iGlu1] = newCol1; + acols[iGlu1] = newCol2; + cols[iGlu2] = newCol2; + acols[iGlu2] = newCol1; + + // Unknown decay mode means failure. + } else return false; + + // Set maximum scale to be mass of decaying particle. + double scale = mProd[0]; + for (int i = 1; i <= mult; ++i) event[iProd[i]].scale(scale); + + // Done. + return true; + +} + +//************************************************************************** + +} // end namespace Pythia8 + diff --git a/PYTHIA8/pythia8130/src/PartonDistributions.cxx b/PYTHIA8/pythia8130/src/PartonDistributions.cxx new file mode 100644 index 00000000000..84a12f0b0b6 --- /dev/null +++ b/PYTHIA8/pythia8130/src/PartonDistributions.cxx @@ -0,0 +1,579 @@ +// PartonDistributions.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the PDF, +// GRV94L, CTEQ5L, LHAPDF and Lepton classes. + +#include "PartonDistributions.h" +#include "LHAPDFInterface.h" + +namespace Pythia8 { + +//************************************************************************** + +// Base class for parton distribution functions. + +//********* + +// Standard parton densities. + +double PDF::xf(int id, double x, double Q2) { + + // Need to update if flavour, x or Q2 changed. + // Use idSav = 9 to indicate that ALL flavours are up-to-date. + // Assume that flavour and antiflavour always updated simultaneously. + if ( (abs(idSav) != abs(id) && idSav != 9) || x != xSav || Q2 != Q2Sav) + {idSav = id; xfUpdate(id, x, Q2); xSav = x; Q2Sav = Q2;} + + // Baryon beam. + if (abs(idBeam) > 100) { + int idNow = (idBeam > 0) ? id : -id; + int idAbs = abs(id); + if (idNow == 0 || idAbs == 21) return max(0., xg); + if (idNow == 1) return max(0., xd); + if (idNow == -1) return max(0., xdbar); + if (idNow == 2) return max(0., xu); + if (idNow == -2) return max(0., xubar); + if (idAbs == 3) return max(0., xs); + if (idAbs == 4) return max(0., xc); + if (idAbs == 5) return max(0., xb); + return 0.; + + // Lepton beam. + } else { + if (id == idBeam ) return max(0., xlepton); + if (abs(id) == 22) return max(0., xgamma); + return 0.; + } + +} + +//********* + +// Only valence part of parton densities. + +double PDF::xfVal(int id, double x, double Q2) { + + // Need to update if flavour, x or Q2 changed. + // Use idSav = 9 to indicate that ALL flavours are up-to-date. + // Assume that flavour and antiflavour always updated simultaneously. + if ( (abs(idSav) != abs(id) && idSav != 9) || x != xSav || Q2 != Q2Sav) + {idSav = id; xfUpdate(id, x, Q2); xSav = x; Q2Sav = Q2;} + + // Baryon beam. + if (abs(idBeam) > 100) { + int idNow = (idBeam > 0) ? id : -id; + if (idNow == 1) return max(0., xdVal); + if (idNow == 2) return max(0., xuVal); + return 0.; + + // Lepton beam. + } else { + if (id == idBeam) return max(0., xlepton); + return 0.; + } + +} + +//********* + +// Only sea part of parton densities. + +double PDF::xfSea(int id, double x, double Q2) { + + // Need to update if flavour, x or Q2 changed. + // Use idSav = 9 to indicate that ALL flavours are up-to-date. + // Assume that flavour and antiflavour always updated simultaneously. + if ( (abs(idSav) != abs(id) && idSav != 9) || x != xSav || Q2 != Q2Sav) + {idSav = id; xfUpdate(id, x, Q2); xSav = x; Q2Sav = Q2;} + + // Baryon beam. + if (abs(idBeam) > 100) { + int idNow = (idBeam > 0) ? id : -id; + int idAbs = abs(id); + if (idNow == 0 || idAbs == 21) return max(0., xg); + if (idNow == 1) return max(0., xdSea); + if (idNow == -1) return max(0., xdbar); + if (idNow == 2) return max(0., xuSea); + if (idNow == -2) return max(0., xubar); + if (idAbs == 3) return max(0., xs); + if (idAbs == 4) return max(0., xc); + if (idAbs == 5) return max(0., xb); + if (idAbs == 5) return max(0., xb); + return 0.; + + // Lepton beam. + } else { + if (abs(id) == 22) return max(0., xgamma); + return 0.; + } + +} + +//************************************************************************** + +// Gives the GRV 94 L (leading order) parton distribution function set +// in parametrized form. Authors: M. Glueck, E. Reya and A. Vogt. +// Ref: M. Glueck, E. Reya and A. Vogt, Z.Phys. C67 (1995) 433. + +void GRV94L::xfUpdate(int id, double x, double Q2) { + + // Common expressions. + double mu2 = 0.23; + double lam2 = 0.2322 * 0.2322; + double s = log (log(Q2/lam2) / log(mu2/lam2)); + double ds = sqrt(s); + double s2 = s * s; + double s3 = s2 * s; + + // uv : + double nu = 2.284 + 0.802 * s + 0.055 * s2; + double aku = 0.590 - 0.024 * s; + double bku = 0.131 + 0.063 * s; + double au = -0.449 - 0.138 * s - 0.076 * s2; + double bu = 0.213 + 2.669 * s - 0.728 * s2; + double cu = 8.854 - 9.135 * s + 1.979 * s2; + double du = 2.997 + 0.753 * s - 0.076 * s2; + double uv = grvv (x, nu, aku, bku, au, bu, cu, du); + + // dv : + double nd = 0.371 + 0.083 * s + 0.039 * s2; + double akd = 0.376; + double bkd = 0.486 + 0.062 * s; + double ad = -0.509 + 3.310 * s - 1.248 * s2; + double bd = 12.41 - 10.52 * s + 2.267 * s2; + double cd = 6.373 - 6.208 * s + 1.418 * s2; + double dd = 3.691 + 0.799 * s - 0.071 * s2; + double dv = grvv (x, nd, akd, bkd, ad, bd, cd, dd); + + // udb : + double alx = 1.451; + double bex = 0.271; + double akx = 0.410 - 0.232 * s; + double bkx = 0.534 - 0.457 * s; + double agx = 0.890 - 0.140 * s; + double bgx = -0.981; + double cx = 0.320 + 0.683 * s; + double dx = 4.752 + 1.164 * s + 0.286 * s2; + double ex = 4.119 + 1.713 * s; + double esx = 0.682 + 2.978 * s; + double udb = grvw (x, s, alx, bex, akx, bkx, agx, bgx, cx, + dx, ex, esx); + + // del : + double ne = 0.082 + 0.014 * s + 0.008 * s2; + double ake = 0.409 - 0.005 * s; + double bke = 0.799 + 0.071 * s; + double ae = -38.07 + 36.13 * s - 0.656 * s2; + double be = 90.31 - 74.15 * s + 7.645 * s2; + double ce = 0.; + double de = 7.486 + 1.217 * s - 0.159 * s2; + double del = grvv (x, ne, ake, bke, ae, be, ce, de); + + // sb : + double sts = 0.; + double als = 0.914; + double bes = 0.577; + double aks = 1.798 - 0.596 * s; + double as = -5.548 + 3.669 * ds - 0.616 * s; + double bs = 18.92 - 16.73 * ds + 5.168 * s; + double dst = 6.379 - 0.350 * s + 0.142 * s2; + double est = 3.981 + 1.638 * s; + double ess = 6.402; + double sb = grvs (x, s, sts, als, bes, aks, as, bs, dst, est, ess); + + // cb : + double stc = 0.888; + double alc = 1.01; + double bec = 0.37; + double akc = 0.; + double ac = 0.; + double bc = 4.24 - 0.804 * s; + double dct = 3.46 - 1.076 * s; + double ect = 4.61 + 1.49 * s; + double esc = 2.555 + 1.961 * s; + double chm = grvs (x, s, stc, alc, bec, akc, ac, bc, dct, ect, esc); + + // bb : + double stb = 1.351; + double alb = 1.00; + double beb = 0.51; + double akb = 0.; + double ab = 0.; + double bb = 1.848; + double dbt = 2.929 + 1.396 * s; + double ebt = 4.71 + 1.514 * s; + double esb = 4.02 + 1.239 * s; + double bot = grvs (x, s, stb, alb, beb, akb, ab, bb, dbt, ebt, esb); + + // gl : + double alg = 0.524; + double beg = 1.088; + double akg = 1.742 - 0.930 * s; + double bkg = - 0.399 * s2; + double ag = 7.486 - 2.185 * s; + double bg = 16.69 - 22.74 * s + 5.779 * s2; + double cg = -25.59 + 29.71 * s - 7.296 * s2; + double dg = 2.792 + 2.215 * s + 0.422 * s2 - 0.104 * s3; + double eg = 0.807 + 2.005 * s; + double esg = 3.841 + 0.316 * s; + double gl = grvw (x, s, alg, beg, akg, bkg, ag, bg, cg, + dg, eg, esg); + + // Update values + xg = gl; + xu = uv + 0.5*(udb - del); + xd = dv + 0.5*(udb + del); + xubar = 0.5*(udb - del); + xdbar = 0.5*(udb + del); + xs = sb; + xc = chm; + xb = bot; + + // Subdivision of valence and sea. + xuVal = uv; + xuSea = xubar; + xdVal = dv; + xdSea = xdbar; + + // idSav = 9 to indicate that all flavours reset. id change dummy. + idSav = 9; + id = 0; + +} + +//********* + +double GRV94L::grvv (double x, double n, double ak, double bk, double a, + double b, double c, double d) { + + double dx = sqrt(x); + return n * pow(x, ak) * (1. + a * pow(x, bk) + x * (b + c * dx)) * + pow(1. - x, d); + +} + +//********* + +double GRV94L::grvw (double x, double s, double al, double be, double ak, + double bk, double a, double b, double c, double d, double e, double es) { + + double lx = log(1./x); + return (pow(x, ak) * (a + x * (b + x * c)) * pow(lx, bk) + pow(s, al) + * exp(-e + sqrt(es * pow(s, be) * lx))) * pow(1. - x, d); + +} + +//********* + +double GRV94L::grvs (double x, double s, double sth, double al, double be, + double ak, double ag, double b, double d, double e, double es) { + + if(s <= sth) { + return 0.; + } else { + double dx = sqrt(x); + double lx = log(1./x); + return pow(s - sth, al) / pow(lx, ak) * (1. + ag * dx + b * x) * + pow(1. - x, d) * exp(-e + sqrt(es * pow(s, be) * lx)); + } + +} + +//************************************************************************** + +// Gives the CTEQ 5 L (leading order) parton distribution function set +// in parametrized form. Parametrization by J. Pumplin. +// Ref: CTEQ Collaboration, H.L. Lai et al., Eur.Phys.J. C12 (2000) 375. + +// The range of (x, Q) covered by this parametrization of the QCD +// evolved parton distributions is 1E-6 < x < 1, 1.1 GeV < Q < 10 TeV. +// In the current implementation, densities are frozen at borders. + +void CTEQ5L::xfUpdate(int id, double x, double Q2) { + + // Constrain x and Q2 to range for which parametrization is valid. + double Q = sqrt( max( 1., min( 1e8, Q2) ) ); + x = max( 1e-6, min( 1.-1e-10, x) ); + + // Derived kinematical quantities. + double y = - log(x); + double u = log( x / 0.00001); + double x1 = 1. - x; + double x1L = log(1. - x); + double sumUbarDbar = 0.; + + // Parameters of parametrizations. + const double Qmin[8] = { 0., 0., 0., 0., 0., 0., 1.3, 4.5}; + const double alpha[8] = { 0.2987216, 0.3407552, 0.4491863, 0.2457668, + 0.5293999, 0.3713141, 0.03712017, 0.004952010 }; + const double ut1[8] = { 4.971265, 2.612618, -0.4656819, 3.862583, + 0.1895615, 3.753257, 4.400772, 5.562568 }; + const double ut2[8] = { -1.105128, -1.258304e5, -274.2390, -1.265969, + -3.069097, -1.113085, -1.356116, -1.801317 }; + const double am[8][9][3] = { + // d. + { { 0.5292616E+01, -0.2751910E+01, -0.2488990E+01 }, + { 0.9714424E+00, 0.1011827E-01, -0.1023660E-01 }, + { -0.1651006E+02, 0.7959721E+01, 0.8810563E+01 }, + { -0.1643394E+02, 0.5892854E+01, 0.9348874E+01 }, + { 0.3067422E+02, 0.4235796E+01, -0.5112136E+00 }, + { 0.2352526E+02, -0.5305168E+01, -0.1169174E+02 }, + { -0.1095451E+02, 0.3006577E+01, 0.5638136E+01 }, + { -0.1172251E+02, -0.2183624E+01, 0.4955794E+01 }, + { 0.1662533E-01, 0.7622870E-02, -0.4895887E-03 } }, + // u. + { { 0.9905300E+00, -0.4502235E+00, 0.1624441E+00 }, + { 0.8867534E+00, 0.1630829E-01, -0.4049085E-01 }, + { 0.8547974E+00, 0.3336301E+00, 0.1371388E+00 }, + { 0.2941113E+00, -0.1527905E+01, 0.2331879E+00 }, + { 0.3384235E+02, 0.3715315E+01, 0.8276930E+00 }, + { 0.6230115E+01, 0.3134639E+01, -0.1729099E+01 }, + { -0.1186928E+01, -0.3282460E+00, 0.1052020E+00 }, + { -0.8545702E+01, -0.6247947E+01, 0.3692561E+01 }, + { 0.1724598E-01, 0.7120465E-02, 0.4003646E-04 } }, + // g. + { { 0.1193572E+03, -0.3886845E+01, -0.1133965E+01 }, + { -0.9421449E+02, 0.3995885E+01, 0.1607363E+01 }, + { 0.4206383E+01, 0.2485954E+00, 0.2497468E+00 }, + { 0.1210557E+03, -0.3015765E+01, -0.1423651E+01 }, + { -0.1013897E+03, -0.7113478E+00, 0.2621865E+00 }, + { -0.1312404E+01, -0.9297691E+00, -0.1562531E+00 }, + { 0.1627137E+01, 0.4954111E+00, -0.6387009E+00 }, + { 0.1537698E+00, -0.2487878E+00, 0.8305947E+00 }, + { 0.2496448E-01, 0.2457823E-02, 0.8234276E-03 } }, + // ubar + dbar. + { { 0.2647441E+02, 0.1059277E+02, -0.9176654E+00 }, + { 0.1990636E+01, 0.8558918E-01, 0.4248667E-01 }, + { -0.1476095E+02, -0.3276255E+02, 0.1558110E+01 }, + { -0.2966889E+01, -0.3649037E+02, 0.1195914E+01 }, + { -0.1000519E+03, -0.2464635E+01, 0.1964849E+00 }, + { 0.3718331E+02, 0.4700389E+02, -0.2772142E+01 }, + { -0.1872722E+02, -0.2291189E+02, 0.1089052E+01 }, + { -0.1628146E+02, -0.1823993E+02, 0.2537369E+01 }, + { -0.1156300E+01, -0.1280495E+00, 0.5153245E-01 } }, + // dbar/ubar. + { { -0.6556775E+00, 0.2490190E+00, 0.3966485E-01 }, + { 0.1305102E+01, -0.1188925E+00, -0.4600870E-02 }, + { -0.2371436E+01, 0.3566814E+00, -0.2834683E+00 }, + { -0.6152826E+01, 0.8339877E+00, -0.7233230E+00 }, + { -0.8346558E+01, 0.2892168E+01, 0.2137099E+00 }, + { 0.1279530E+02, 0.1021114E+00, 0.5787439E+00 }, + { 0.5858816E+00, -0.1940375E+01, -0.4029269E+00 }, + { -0.2795725E+02, -0.5263392E+00, 0.1290229E+01 }, + { 0.0000000E+00, 0.0000000E+00, 0.0000000E+00 } }, + // sbar. + { { 0.1580931E+01, -0.2273826E+01, -0.1822245E+01 }, + { 0.2702644E+01, 0.6763243E+00, 0.7231586E-02 }, + { -0.1857924E+02, 0.3907500E+01, 0.5850109E+01 }, + { -0.3044793E+02, 0.2639332E+01, 0.5566644E+01 }, + { -0.4258011E+01, -0.5429244E+01, 0.4418946E+00 }, + { 0.3465259E+02, -0.5532604E+01, -0.4904153E+01 }, + { -0.1658858E+02, 0.2923275E+01, 0.2266286E+01 }, + { -0.1149263E+02, 0.2877475E+01, -0.7999105E+00 }, + { 0.0000000E+00, 0.0000000E+00, 0.0000000E+00 } }, + // cbar. + { { -0.8293661E+00, -0.3982375E+01, -0.6494283E-01 }, + { 0.2754618E+01, 0.8338636E+00, -0.6885160E-01 }, + { -0.1657987E+02, 0.1439143E+02, -0.6887240E+00 }, + { -0.2800703E+02, 0.1535966E+02, -0.7377693E+00 }, + { -0.6460216E+01, -0.4783019E+01, 0.4913297E+00 }, + { 0.3141830E+02, -0.3178031E+02, 0.7136013E+01 }, + { -0.1802509E+02, 0.1862163E+02, -0.4632843E+01 }, + { -0.1240412E+02, 0.2565386E+02, -0.1066570E+02 }, + { 0.0000000E+00, 0.0000000E+00, 0.0000000E+00 } }, + // bbar. + { { -0.6031237E+01, 0.1992727E+01, -0.1076331E+01 }, + { 0.2933912E+01, 0.5839674E+00, 0.7509435E-01 }, + { -0.8284919E+01, 0.1488593E+01, -0.8251678E+00 }, + { -0.1925986E+02, 0.2805753E+01, -0.3015446E+01 }, + { -0.9480483E+01, -0.9767837E+00, -0.1165544E+01 }, + { 0.2193195E+02, -0.1788518E+02, 0.9460908E+01 }, + { -0.1327377E+02, 0.1201754E+02, -0.6277844E+01 }, + { 0.0000000E+00, 0.0000000E+00, 0.0000000E+00 }, + { 0.0000000E+00, 0.0000000E+00, 0.0000000E+00 } } }; + + // Loop over 8 different parametrizations. Check if inside allowed region. + for (int i = 0; i < 8; ++i) { + double answer = 0.; + if (Q > max(Qmin[i], alpha[i])) { + + // Evaluate answer. + double tmp = log(Q / alpha[i]); + double sb = log(tmp); + double sb1 = sb - 1.2; + double sb2 = sb1*sb1; + double af[9]; + for (int j = 0; j < 9; ++j) + af[j] = am[i][j][0] + sb1 * am[i][j][1] + sb2 * am[i][j][2]; + double part1 = af[1] * pow( y, 1. + 0.01 * af[4]) * (1. + af[8] * u); + double part2 = af[0] * x1 + af[3] * x; + double part3 = x * x1 * (af[5] + af[6] * x1 + af[7] * x * x1); + double part4 = (ut2[i] < -100.) ? ut1[i] * x1L + af[2] * x1L + : ut1[i] * x1L + af[2] * log(x1 + exp(ut2[i])); + answer = x * exp( part1 + part2 + part3 + part4); + answer *= 1. - Qmin[i] / Q; + } + + // Store results. + if (i == 0) xd = x * answer; + else if (i == 1) xu = x * answer; + else if (i == 2) xg = x * answer; + else if (i == 3) sumUbarDbar = x * answer; + else if (i == 4) { xubar = sumUbarDbar / (1. + answer); + xdbar = sumUbarDbar * answer / (1. + answer); } + else if (i == 5) xs = x * answer; + else if (i == 6) xc = x * answer; + else if (i == 7) xb = x * answer; + } + + // Subdivision of valence and sea. + xuVal = xu - xubar; + xuSea = xubar; + xdVal = xd - xdbar; + xdSea = xdbar; + + // idSav = 9 to indicate that all flavours reset. id change is dummy here. + idSav = 9; + id = 0; + +} + +//************************************************************************** + +// Interface to the LHAPDF library. + +//********* + +// Definitions of static variables. + +string LHAPDF::latestSetName = " "; +int LHAPDF::latestMember = -1; +int LHAPDF::latestNSet = 0; + +//********* + +// Initialize a parton density function from LHAPDF. + +void LHAPDF::init(string setName, int member, Info* infoPtr) { + + // If already initialized then need not do anything. + if (setName == latestSetName && member == latestMember + && nSet == latestNSet) return; + + // Initialize set. If first character is '/' then assume that name + // is given with path, else not. + if (setName[0] == '/') LHAPDFInterface::initPDFsetM( nSet, setName); + else LHAPDFInterface::initPDFsetByNameM( nSet, setName); + + // Check that not dummy library was linked and put nSet negative. + isSet = (nSet >= 0); + if (!isSet) { + if (infoPtr > 0) infoPtr->errorMsg("Error from LHAPDF::init: " + "you try to use LHAPDF but did not link it"); + else cout << "Error from LHAPDF::init: you try to use LHAPDF " + << "but did not link it" << endl; + } + + // Initialize member. + LHAPDFInterface::initPDFM(nSet, member); + + // Do not collect statistics on under/overflow to save time and space. + LHAPDFInterface::setPDFparm( "NOSTAT" ); + LHAPDFInterface::setPDFparm( "LOWKEY" ); + + // Save values to avoid unnecessary reinitializations. + latestSetName = setName; + latestMember = member; + latestNSet = nSet; + +} + +//********* + +// Allow optional extrapolation beyond boundaries. + +void LHAPDF::setExtrapolate(bool extrapol) { + + LHAPDFInterface::setPDFparm( (extrapol) ? "EXTRAPOLATE" : "18" ); + +} + +//********* + +// Give the parton distribution function set from LHAPDF. + +void LHAPDF::xfUpdate(int , double x, double Q2) { + + // Let LHAPDF do the evaluation of parton densities. + double Q = sqrt( max( 0., Q2)); + LHAPDFInterface::evolvePDFM( nSet, x, Q, xfArray); + + // Update values. + xg = xfArray[6]; + xu = xfArray[8]; + xd = xfArray[7]; + xubar = xfArray[4]; + xdbar = xfArray[5]; + xs = xfArray[9]; + xc = xfArray[10]; + xb = xfArray[11]; + + // Subdivision of valence and sea. + xuVal = xu - xubar; + xuSea = xubar; + xdVal = xd - xdbar; + xdSea = xdbar; + + // idSav = 9 to indicate that all flavours reset. + idSav = 9; + +} + +//************************************************************************** + +// Gives electron (or muon, or tau) parton distribution. + +// Constant. alphaEM(0) could be taken from settings but safer this way. +const double Lepton::ALPHAEM = 0.00729735; + +void Lepton::xfUpdate(int id, double x, double Q2) { + + // Squared mass of lepton species: electron, muon, tau. + if (!isInit) { + m2Lep = pow2( ParticleDataTable::m0(idBeam) ); + isInit = true; + } + + // Electron inside electron, see R. Kleiss et al., in Z physics at + // LEP 1, CERN 89-08, p. 34 + double xLog = log(max(1e-10,x)); + double xMinusLog = log( max(1e-10, 1. - x) ); + double Q2Log = log( max(3., Q2/m2Lep) ); + double beta = (ALPHAEM / M_PI) * (Q2Log - 1.); + double delta = 1. + (ALPHAEM / M_PI) * (1.5 * Q2Log + 1.289868) + + pow2(ALPHAEM / M_PI) * (-2.164868 * Q2Log*Q2Log + + 9.840808 * Q2Log - 10.130464); + double fPrel = beta * pow(1. - x, beta - 1.) * sqrtpos( delta ) + - 0.5 * beta * (1. + x) + 0.125 * beta*beta * ( (1. + x) + * (-4. * xMinusLog + 3. * xLog) - 4. * xLog / (1. - x) - 5. - x); + + // Zero distribution for very large x and rescale it for intermediate. + if (x > 1. - 1e-10) fPrel = 0.; + else if (x > 1. - 1e-7) fPrel *= pow(1000.,beta) / (pow(1000.,beta) - 1.); + xlepton = x * fPrel; + + // Photon inside electron (one possible scheme - primitive). + xgamma = (0.5 * ALPHAEM / M_PI) * Q2Log * (1. + pow2(1. - x)); + + // idSav = 9 to indicate that all flavours reset. id change is dummy here. + idSav = 9; + id = 0; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/PartonLevel.cxx b/PYTHIA8/pythia8130/src/PartonLevel.cxx new file mode 100644 index 00000000000..17165237a2b --- /dev/null +++ b/PYTHIA8/pythia8130/src/PartonLevel.cxx @@ -0,0 +1,707 @@ +// PartonLevel.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the PartonLevel class. + +#include "PartonLevel.h" + +namespace Pythia8 { + +//************************************************************************** + +// The PartonLevel class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Maximum number of tries to produce parton level from given input.. +const int PartonLevel::NTRY = 10; + +//********* + +// Main routine to initialize the parton-level generation process. + +bool PartonLevel::init( Info* infoPtrIn, BeamParticle* beamAPtrIn, + BeamParticle* beamBPtrIn, SigmaTotal* sigmaTotPtr, + TimeShower* timesDecPtrIn, TimeShower* timesPtrIn, + SpaceShower* spacePtrIn, UserHooks* userHooksPtrIn) { + + // Store input pointers and modes for future use. + infoPtr = infoPtrIn; + beamAPtr = beamAPtrIn; + beamBPtr = beamBPtrIn; + timesDecPtr = timesDecPtrIn; + timesPtr = timesPtrIn; + spacePtr = spacePtrIn; + userHooksPtr = userHooksPtrIn; + + // Main flags. + doMI = Settings::flag("PartonLevel:MI"); + doISR = Settings::flag("PartonLevel:ISR"); + bool FSR = Settings::flag("PartonLevel:FSR"); + bool FSRinProcess = Settings::flag("PartonLevel:FSRinProcess"); + bool interleaveFSR = Settings::flag("TimeShower:interleave"); + doFSRduringProcess = FSR && FSRinProcess && interleaveFSR; + doFSRafterProcess = FSR && FSRinProcess && !interleaveFSR; + doFSRinResonances = FSR && Settings::flag("PartonLevel:FSRinResonances"); + doRemnants = true; + doSecondHard = Settings::flag("SecondHard:generate"); + + // Need MI initialization for minbias processes, even if only first MI. + // But no need to initialize MI if never going to use it. + doMIinit = doMI; + if (Settings::flag("SoftQCD:minBias") || Settings::flag("SoftQCD:all")) + doMIinit = true; + if (!Settings::flag("PartonLevel:all")) doMIinit = false; + + // Flag if lepton beams, and if non-resolved ones. May change main flags. + hasLeptonBeams = ( beamAPtr->isLepton() || beamBPtr->isLepton() ); + hasPointLeptons = ( hasLeptonBeams + && (beamAPtr->isUnresolved() || beamBPtr->isUnresolved() ) ); + if (hasLeptonBeams) { + doMI = false; + doMIinit = false; + } + if (hasPointLeptons) { + doISR = false; + doRemnants = false; + } + + // Possibility to allow user veto during evolution. + canVetoPT = (userHooksPtr > 0) ? userHooksPtr->canVetoPT() : false; + pTvetoPT = (canVetoPT) ? userHooksPtr->scaleVetoPT() : -1.; + canVetoStep = (userHooksPtr > 0) ? userHooksPtr->canVetoStep() : false; + nVetoStep = (canVetoStep) ? userHooksPtr->numberVetoStep() : -1; + + // Set info and initialize the respective program elements. + timesPtr->init( beamAPtr, beamBPtr); + if (doISR) spacePtr->init( beamAPtr, beamBPtr); + doMI = multi.init( doMIinit, infoPtr, beamAPtr, beamBPtr, sigmaTotPtr); + remnants.init( infoPtr, beamAPtr, beamBPtr); + + // Succeeded. (Check return values from other classes??) + return true; +} + +//********* + +// Main routine to do the parton-level evolution. + +bool PartonLevel::next( Event& process, Event& event) { + + // Special case if unresolved = elastic/diffractive event. + if (!infoPtr->isResolved()) return setupUnresolvedSys( process, event); + + // Special case if minimum bias: do hardest interaction. + if (doMIinit) multi.clear(); + if (infoPtr->isMinBias()) { + multi.pTfirst(); + multi.setupFirstSys( process); + } + + // Allow up to ten tries; failure possible for beam remnants. + // Main cause: inconsistent colour flow at the end of the day. + bool physical = true; + int nRad = 0; + for (int iTry = 0; iTry < NTRY; ++ iTry) { + + // Reset flag, counters and max scales. + physical = true; + nMI = (doSecondHard) ? 2 : 1; + nISR = 0; + nFSRinProc = 0; + nFSRinRes = 0; + nISRhard = 0; + nFSRhard = 0; + pTsaveMI = 0.; + pTsaveISR = 0.; + pTsaveFSR = 0.; + + // Identify hard interaction system for showers. + setupHardSys( process, event); + + // Check matching of process scale to maximum ISR/MI scales. + double Q2Fac = infoPtr->Q2Fac(); + double Q2Ren = infoPtr->Q2Ren(); + bool limitPTmaxISR = (doISR) + ? spacePtr->limitPTmax( event, Q2Fac, Q2Ren) : false; + bool limitPTmaxMI = (doMI) ? multi.limitPTmax( event) : false; + + // Set hard scale, maximum for showers and multiple interactions, + double pTscale = process.scale(); + if (doSecondHard) pTscale = max( pTscale, process.scaleSecond() ); + double pTmaxMI = (limitPTmaxMI) ? pTscale : infoPtr->eCM(); + double pTmaxISR = (limitPTmaxISR) ? spacePtr->enhancePTmax() * pTscale + : infoPtr->eCM(); + double pTmaxFSR = timesPtr->enhancePTmax() * pTscale; + double pTmax = max( pTmaxMI, max( pTmaxISR, pTmaxFSR) ); + pTsaveMI = pTmaxMI; + pTsaveISR = pTmaxISR; + pTsaveFSR = pTmaxFSR; + + // Prepare the classes to begin the generation. + if (doMI) multi.prepare( pTmaxMI); + if (doISR) spacePtr->prepare( 0, event, limitPTmaxISR); + if (doFSRduringProcess) timesPtr->prepare( 0, event); + if (doSecondHard && doISR) spacePtr->prepare( 1, event, limitPTmaxISR); + if (doSecondHard && doFSRduringProcess) timesPtr->prepare( 1, event); + + // Set up initial veto scale. + doVeto = false; + double pTveto = pTvetoPT; + typeLatest = 0; + + // Begin evolution down in pT from hard pT scale. + do { + + typeVetoStep = 0; + nRad = nISR + nFSRinProc; + + // Find next pT value for FSR, MI and ISR. + // Order calls to minimize time expenditure. + double pTgen = 0.; + double pTtimes = (doFSRduringProcess) + ? timesPtr->pTnext( event, pTmaxFSR, pTgen) : -1.; + pTgen = max( pTgen, pTtimes); + double pTmulti = (doMI) + ? multi.pTnext( pTmaxMI, pTgen) : -1.; + pTgen = max( pTgen, pTmulti); + double pTspace = (doISR) + ? spacePtr->pTnext( event, pTmaxISR, pTgen, nRad) : -1.; + + // Allow a user veto. Only do it once, so remember to change pTveto. + if (pTveto > 0. && pTveto > pTmulti && pTveto > pTspace + && pTveto > pTtimes) { + pTveto = -1.; + doVeto = userHooksPtr->doVetoPT( typeLatest, event); + // Abort event if vetoed. + if (doVeto) return false; + } + + // Do a multiple interaction (if allowed). + if (pTmulti > 0. && pTmulti > pTspace && pTmulti > pTtimes) { + multi.scatter( event); + typeLatest = 1; + ++nMI; + if (doISR) spacePtr->prepare( nMI - 1, event); + if (doFSRduringProcess) timesPtr->prepare( nMI - 1, event); + pTmaxMI = pTmulti; + pTmaxISR = min( pTmulti, pTmaxISR); + pTmaxFSR = min( pTmulti, pTmaxFSR); + pTmax = pTmulti; + } + + // Do an initial-state emission (if allowed). + else if (pTspace > 0. && pTspace > pTtimes) { + if (spacePtr->branch( event)) { + typeLatest = 2; + iSysNow = spacePtr->system(); + ++nISR; + if (iSysNow == 0) ++nISRhard; + if (doFSRduringProcess) timesPtr->update( iSysNow, event); + if (canVetoStep && iSysNow == 0 && nISRhard <= nVetoStep) + typeVetoStep = 2; + } + pTmaxMI = min( pTspace, pTmaxMI); + pTmaxISR = pTspace; + pTmaxFSR = min( pTspace, pTmaxFSR); + pTmax = pTspace; + } + + // Do a final-state emission (if allowed). + else if (pTtimes > 0.) { + if (timesPtr->branch( event)) { + typeLatest = 3; + iSysNow = timesPtr->system(); + ++nFSRinProc; + if (iSysNow == 0) ++nFSRhard; + if (doISR) spacePtr->update( iSysNow, event); + if (canVetoStep && iSysNow == 0 && nFSRhard <= nVetoStep) + typeVetoStep = 3; + } + pTmaxMI = min( pTtimes, pTmaxMI); + pTmaxISR = min( pTtimes, pTmaxISR); + pTmaxFSR = pTtimes; + pTmax = pTtimes; + } + + // If no pT scales above zero then nothing to be done. + else pTmax = 0.; + + // Optionally check for a veto after the first few emissions. + if (typeVetoStep > 0) { + doVeto = userHooksPtr->doVetoStep( typeVetoStep, nISRhard, + nFSRhard, event); + // Abort event if vetoed. + if (doVeto) return false; + } + + // Keep on evolving until nothing is left to be done. + } while (pTmax > 0.); + + // Do all final-state emissions if not already considered above. + if (doFSRafterProcess) { + + // Find largest scale for final partons. + pTmax = 0.; + for (int i = 0; i < event.size(); ++i) + if (event[i].isFinal() && event[i].scale() > pTmax) + pTmax = event[i].scale(); + pTsaveFSR = pTmax; + + // Prepare all subsystems for evolution. + for (int iSys = 0; iSys < event.sizeSystems(); ++iSys) + timesPtr->prepare( iSys, event); + + // Set up initial veto scale. + doVeto = false; + pTveto = pTvetoPT; + + // Begin evolution down in pT from hard pT scale. + do { + typeVetoStep = 0; + double pTtimes = timesPtr->pTnext( event, pTmax, 0.); + + // Allow a user veto. Only do it once, so remember to change pTveto. + if (pTveto > 0. && pTveto > pTtimes) { + pTveto = -1.; + doVeto = userHooksPtr->doVetoPT( 4, event); + // Abort event if vetoed. + if (doVeto) return false; + } + + // Do a final-state emission (if allowed). + if (pTtimes > 0.) { + if (timesPtr->branch( event)) { + iSysNow = timesPtr->system(); + ++nFSRinProc; + if (iSysNow == 0) ++nFSRhard; + if (canVetoStep && iSysNow == 0 && nFSRhard <= nVetoStep) + typeVetoStep = 4; + } + pTmax = pTtimes; + } + + // If no pT scales above zero then nothing to be done. + else pTmax = 0.; + + // Optionally check for a veto after the first few emissions. + if (typeVetoStep > 0) { + doVeto = userHooksPtr->doVetoStep( typeVetoStep, nISRhard, + nFSRhard, event); + // Abort event if vetoed. + if (doVeto) return false; + } + + // Keep on evolving until nothing is left to be done. + } while (pTmax > 0.); + } + + // Add beam remnants, including primordial kT kick and colour tracing. + if (doRemnants && !remnants.add( event)) physical = false; + + // If no problems then done, else restore and loop. + if (physical) break; + event.clear(); + beamAPtr->clear(); + beamBPtr->clear(); + + // End loop over ten tries. Hopefully it worked + } + if (!physical) return false; + + // Perform showers in resonance decay chains. + nFSRinRes = resonanceShowers( process, event); + + // Store event properties. + infoPtr->setImpact( multi.bMI(), multi.enhanceMI()); + infoPtr->setEvolution( pTsaveMI, pTsaveISR, pTsaveFSR, + nMI, nISR, nFSRinProc, nFSRinRes); + + // Done. + return true; +} + +//********* + +// Set up the hard process(es), excluding subsequent resonance decays. + +void PartonLevel::setupHardSys( Event& process, Event& event) { + + // Incoming partons to hard process are stored in slots 3 and 4. + int inP = 3; + int inM = 4; + + // If two hard interactions then find where second begins. + int iBeginSecond = process.size(); + if (doSecondHard) { + iBeginSecond = 5; + while (process[iBeginSecond].status() != -21) ++iBeginSecond; + } + + // If incoming partons are massive then recalculate to put them massless. + if (process[inP].m() != 0. || process[inM].m() != 0.) { + double pPlus = process[inP].pPlus() + process[inM].pPlus(); + double pMinus = process[inP].pMinus() + process[inM].pMinus(); + process[inP].pz( 0.5 * pPlus); + process[inP].e( 0.5 * pPlus); + process[inP].m( 0.); + process[inM].pz(-0.5 * pMinus); + process[inM].e( 0.5 * pMinus); + process[inM].m( 0.); + } + + // Add incoming hard-scattering partons to list in beam remnants. + double x1 = process[inP].pPlus() / process[0].e(); + beamAPtr->append( inP, process[inP].id(), x1); + double x2 = process[inM].pMinus() / process[0].e(); + beamBPtr->append( inM, process[inM].id(), x2); + + // Scale. Find whether incoming partons are valence or sea. Store. + double scale = process.scale(); + beamAPtr->xfISR( 0, process[inP].id(), x1, scale*scale); + int vsc1 = beamAPtr->pickValSeaComp(); + beamBPtr->xfISR( 0, process[inM].id(), x2, scale*scale); + int vsc2 = beamBPtr->pickValSeaComp(); + bool isVal1 = (vsc1 == -3); + bool isVal2 = (vsc2 == -3); + infoPtr->setValence( isVal1, isVal2); + + // Initialize info needed for subsequent sequential decays + showers. + nHardDone = 0; + iPosBefShow.resize( process.size() ); + + // Add the beam and hard subprocess partons to the event record. + for (int i = 0; i < iBeginSecond; ++ i) { + if (process[i].mother1() > inM) break; + event.append(process[i]); + iPosBefShow[i] = i; + + // Currently outgoing ones should not count as decayed. + if (event[i].status() == -22) { + event[i].statusPos(); + event[i].daughters(0, 0); + } + + // Complete task of copying hard subsystem into event record. + ++nHardDone; + } + + // Store participating partons as first set in list of all systems. + event.newSystem(); + for (int i = inP; i < nHardDone; ++i) event.addToSystem(0, i); + + // Identify second hard process where applicable. + // Since internally generated incoming partons are guaranteed massless. + if (doSecondHard) { + int inP2 = iBeginSecond; + int inM2 = iBeginSecond + 1; + + // Add incoming hard-scattering partons to list in beam remnants. + // Not valid if not in rest frame?? + x1 = process[inP2].pPlus() / process[0].e(); + beamAPtr->append( inP2, process[inP2].id(), x1); + x2 = process[inM2].pMinus() / process[0].e(); + beamBPtr->append( inM2, process[inM2].id(), x2); + + // Find whether incoming partons are valence or sea. + scale = process.scaleSecond(); + beamAPtr->xfISR( 1, process[inP2].id(), x1, scale*scale); + beamAPtr->pickValSeaComp(); + beamBPtr->xfISR( 1, process[inM2].id(), x2, scale*scale); + beamBPtr->pickValSeaComp(); + + // Add the beam and hard subprocess partons to the event record. + for (int i = inP2; i < process.size(); ++ i) { + int mother = process[i].mother1(); + if ( (mother > 2 && mother < inP2) || mother > inM2 ) break; + event.append(process[i]); + iPosBefShow[i] = i; + + // Currently outgoing ones should not count as decayed. + if (event[i].status() == -22) { + event[i].statusPos(); + event[i].daughters(0, 0); + } + + // Complete task of copying hard subsystem into event record. + ++nHardDone; + } + + // Store participating partons as second set in list of all systems. + event.newSystem(); + for (int i = inP2; i < nHardDone; ++i) event.addToSystem(1, i); + + // End code for second hard process. + } + + // Update event colour tag to maximum in whole process. + int maxColTag = 0; + for (int i = 0; i < process.size(); ++ i) { + if (process[i].col() > maxColTag) maxColTag = process[i].col(); + if (process[i].acol() > maxColTag) maxColTag = process[i].acol(); + } + event.initColTag(maxColTag); + + // Copy junctions from process to event. + for (int i = 0; i < process.sizeJunction(); ++i) + event.appendJunction( process.getJunction(i)); + + // Done. +} + +//********* + +// Set up an unresolved process, i.e. elastic or diffractive. + +bool PartonLevel::setupUnresolvedSys( Event& process, Event& event) { + + // Copy particles from process to event. + for (int i = 0; i < process.size(); ++ i) event.append( process[i]); + + // Loop to find diffractively excited beams. + for (int i = 0; i < 2; ++i) + if ( (i == 0 && infoPtr->isDiffractiveA()) + || (i == 1 && infoPtr->isDiffractiveB()) ) { + int iBeam = i + 3; + BeamParticle* beamPtr = (i == 0) ? beamAPtr : beamBPtr; + + // Diffractive mass. Reconstruct boost and rotation to event cm frame. + double mDiff = process[iBeam].m(); + double m2Diff = mDiff*mDiff; + double beta = process[iBeam].pAbs() / process[iBeam].e(); + double theta = process[iBeam].theta(); + double phi = process[iBeam].phi(); + + // Pick quark or gluon kicked out and flavour subdivision. + bool gluonIsKicked = beamPtr->pickGluon(mDiff); + int id1 = beamPtr->pickValence(); + int id2 = beamPtr->pickRemnant(); + + // Find flavour masses. Scale them down if too big. + double m1 = ParticleDataTable::constituentMass(id1); + double m2 = ParticleDataTable::constituentMass(id2); + if (m1 + m2 > 0.5 * mDiff) { + double reduce = 0.5 * mDiff / (m1 + m2); + m1 *= reduce; + m2 *= reduce; + } + + // If quark is kicked out, then trivial kinematics in rest frame. + if (!gluonIsKicked) { + double pAbs = sqrt( pow2(m2Diff - m1*m1 - m2*m2) + - pow2(2. * m1 * m2) ) / (2. * mDiff); + double e1 = (m2Diff + m1*m1 - m2*m2) / (2. * mDiff); + double e2 = (m2Diff + m2*m2 - m1*m1) / (2. * mDiff); + Vec4 p1(0.,0., -pAbs, e1); + Vec4 p2(0.,0., pAbs, e2); + + // Boost and rotate to event cm frame. + p1.bst(0., 0., beta); p1.rot(theta, phi); + p2.bst(0., 0., beta); p2.rot(theta, phi); + + // Set colours. + int col1, acol1, col2, acol2; + if (ParticleDataTable::colType(id1) == 1) { + col1 = event.nextColTag(); acol1 = 0; + col2 = 0; acol2 = col1; + } else { + col1 = 0; acol1 = event.nextColTag(); + col2 = acol1; acol2 = 0; + } + + // Store partons of diffractive system and mark system decayed. + int iDauBeg = event.append( id1, 23, iBeam, 0, 0, 0, col1, acol1, + p1, m1); + int iDauEnd = event.append( id2, 63, iBeam, 0, 0, 0, col2, acol2, + p2, m2); + event[iBeam].statusNeg(); + event[iBeam].daughters(iDauBeg, iDauEnd); + + + // If gluon is kicked out: share momentum between two remnants. + } else { + double m2Sys, zSys, pxSys, pySys, mTS1, mTS2; + zSys = beamPtr->zShare(mDiff, m1, m2); + + // Provide relative pT kick in remnant. Construct (transverse) masses. + pxSys = beamPtr->pxShare(); + pySys = beamPtr->pyShare(); + mTS1 = m1*m1 + pxSys*pxSys + pySys*pySys; + mTS2 = m2*m2 + pxSys*pxSys + pySys*pySys; + m2Sys = mTS1 / zSys + mTS2 / (1. - zSys); + + // Momentum of kicked-out massless gluon in diffractive rest frame. + double pAbs = (m2Diff - m2Sys) / (2. * mDiff); + Vec4 pG(0., 0., -pAbs, pAbs); + Vec4 pRem(0., 0., pAbs, mDiff - pAbs); + + // Momenta of the two beam remnant flavours. (Lightcone p+ = m_diff!) + double e1 = 0.5 * (zSys * mDiff + mTS1 / (zSys * mDiff)); + double pL1 = 0.5 * (zSys * mDiff - mTS1 / (zSys * mDiff)); + Vec4 p1(pxSys, pySys, pL1, e1); + Vec4 p2 = pRem - p1; + + // Boost and rotate to event cm frame. + pG.bst(0., 0., beta); pG.rot(theta, phi); + p1.bst(0., 0., beta); p1.rot(theta, phi); + p2.bst(0., 0., beta); p2.rot(theta, phi); + + // Set colours. + int colG, acolG, col1, acol1, col2, acol2; + if (ParticleDataTable::colType(id1) == 1) { + col1 = event.nextColTag(); acol1 = 0; + colG = event.nextColTag(); acolG = col1; + col2 = 0; acol2 = colG; + } else { + col1 = 0; acol1 = event.nextColTag(); + colG = acol1; acolG = event.nextColTag(); + col2 = acolG; acol2 = 0; + } + + // Store partons of diffractive system and mark system decayed. + int iDauBeg = event.append( 21, 23, iBeam, 0, 0, 0, colG, acolG, + pG, m1); + event.append( id1, 63, iBeam, 0, 0, 0, col1, acol1, p1, m1); + int iDauEnd = event.append( id2, 63, iBeam, 0, 0, 0, col2, acol2, + p2, m2); + event[iBeam].statusNeg(); + event[iBeam].daughters(iDauBeg, iDauEnd); + } + + // End loop over beams. Done. + } + return true; +} + +//********* + +// Handle showers in successive resonance decays. + +int PartonLevel::resonanceShowers( Event& process, Event& event) { + + // Isolate next system to be processed, if anything remains. + int nFSRres = 0; + while (nHardDone < process.size()) { + int iBegin = nHardDone; + + // Mother in hard process and in complete event (after shower). + int iHardMother = process[iBegin].mother1(); + Particle& hardMother = process[iHardMother]; + int iBefMother = iPosBefShow[iHardMother]; + int iAftMother = event.iBotCopyId(iBefMother); + Particle& aftMother = event[iAftMother]; + + // From now mother counts as decayed. + aftMother.statusNeg(); + + // Mother can have been moved by showering (in any of previous steps), + // so prepare to update colour and momentum information for system. + int colBef = hardMother.col(); + int acolBef = hardMother.acol(); + int colAft = aftMother.col(); + int acolAft = aftMother.acol(); + RotBstMatrix M; + M.bst( hardMother.p(), aftMother.p()); + + // Extract next partons from hard event into normal event record. + for (int i = iBegin; i < process.size(); ++ i) { + if (process[i].mother1() != iHardMother) break; + int iNow = event.append( process[i] ); + iPosBefShow[i] = iNow; + Particle& now = event.back(); + + // Currently outgoing ones should not count as decayed. + if (now.status() == -22) { + now.statusPos(); + now.daughters(0, 0); + } + + // Update daughter and mother information. + if (i == iBegin) aftMother.daughter1( iNow); + else aftMother.daughter2( iNow); + now.mother1(iAftMother); + + // Update colour and momentum information. + if (now.col() == colBef) now.col( colAft); + if (now.acol() == acolBef) now.acol( acolAft); + now.rotbst( M); + + // Complete task of copying next subsystem into event record. + ++nHardDone; + } + int iEnd = nHardDone - 1; + + // Do parton showers inside subsystem: maximum scale by mother mass. + if (doFSRinResonances) { + double pTmax = 0.5 * hardMother.m(); + nFSRhard = 0; + + // Add new system, with two empty beam slots. + int iSys = event.newSystem(); + event.addToSystem( iSys, 0); + event.addToSystem( iSys, 0); + + // Loop over allowed range to find all final-state particles. + for (int i = iPosBefShow[iBegin]; i <= iPosBefShow[iEnd]; ++i) + if (event[i].isFinal()) event.addToSystem( iSys, i); + + // Let prepare routine do the setup. + timesDecPtr->prepare( iSys, event); + + // Set up initial veto scale. + doVeto = false; + double pTveto = pTvetoPT; + + // Begin evolution down in pT from hard pT scale. + do { + typeVetoStep = 0; + double pTtimes = timesDecPtr->pTnext( event, pTmax, 0.); + + // Allow a user veto. Only do it once, so remember to change pTveto. + if (pTveto > 0. && pTveto > pTtimes) { + pTveto = -1.; + doVeto = userHooksPtr->doVetoPT( 5, event); + // Abort event if vetoed. + if (doVeto) return false; + } + + // Do a final-state emission (if allowed). + if (pTtimes > 0.) { + if (timesDecPtr->branch( event)) { + ++nFSRres; + ++nFSRhard; + if (canVetoStep && nFSRhard <= nVetoStep) typeVetoStep = 5; + } + pTmax = pTtimes; + } + + // If no pT scales above zero then nothing to be done. + else pTmax = 0.; + + // Optionally check for a veto after the first few emissions. + if (typeVetoStep > 0) { + doVeto = userHooksPtr->doVetoStep( typeVetoStep, 0, nFSRhard, + event); + // Abort event if vetoed. + if (doVeto) return false; + } + + // Keep on evolving until nothing is left to be done. + } while (pTmax > 0.); + + } + + // No more systems to be processed. Return total number of emissions. + } + return nFSRres; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/PhaseSpace.cxx b/PYTHIA8/pythia8130/src/PhaseSpace.cxx new file mode 100644 index 00000000000..83d72ed5b6d --- /dev/null +++ b/PYTHIA8/pythia8130/src/PhaseSpace.cxx @@ -0,0 +1,2842 @@ +// PhaseSpace.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// PhaseSpace and PhaseSpace2to2tauyz classes. + +#include "PhaseSpace.h" + +namespace Pythia8 { + +//************************************************************************** + +// The PhaseSpace class. +// Base class for phase space generators. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Number of trial maxima around which maximum search is performed. +const int PhaseSpace::NMAXTRY = 2; + +// Number of three-body trials in phase space optimization. +const int PhaseSpace::NTRY3BODY = 20; + +// Maximum cross section increase, just in case true maximum not found. +const double PhaseSpace::SAFETYMARGIN = 1.05; + +// Small number to avoid division by zero. +const double PhaseSpace::TINY = 1e-20; + +// Fraction of total weight that is shared evenly between all shapes. +const double PhaseSpace::EVENFRAC = 0.4; + +// Two cross sections with a small relative error are assumed same. +const double PhaseSpace::SAMESIGMA = 1e-6; + +// Do not include resonances peaked too far outside allowed mass region. +const double PhaseSpace::WIDTHMARGIN = 20.; + +// Special optimization treatment when two resonances at almost same mass. +const double PhaseSpace::SAMEMASS = 0.01; + +// Minimum phase space left when kinematics constraints are combined. +const double PhaseSpace::MASSMARGIN = 0.01; + +// When using Breit-Wigners in 2 -> 2 raise maximum weight estimate. +const double PhaseSpace::EXTRABWWTMAX = 1.25; + +// Size of Breit-Wigner threshold region, for mass selection biasing. +const double PhaseSpace::THRESHOLDSIZE = 3.; + +// Step size in optimal-mass search, for mass selection biasing. +const double PhaseSpace::THRESHOLDSTEP = 0.2; + +// Minimal rapidity range for allowed open range (in 2 -> 3). +const double PhaseSpace::YRANGEMARGIN = 1e-6; + +// Cutoff for f_e^e at x < 1 - 10^{-10} to be used in phase space selection. +// Note: the ...MIN quantities come from 1 - x_max or 1 - tau_max. +const double PhaseSpace::LEPTONXMIN = 1e-10; +const double PhaseSpace::LEPTONXMAX = 1. - 1e-10; +const double PhaseSpace::LEPTONXLOGMIN = log(1e-10); +const double PhaseSpace::LEPTONXLOGMAX = log(1. - 1e-10); +const double PhaseSpace::LEPTONTAUMIN = 2e-10; + +// Safety to avoid division with unreasonably small value for z selection. +const double PhaseSpace::SHATMINZ = 1.; + +// Regularization for small pT2min in z = cos(theta) selection. +const double PhaseSpace::PT2RATMINZ = 0.0001; + +// These numbers are hardwired empirical parameters, +// intended to speed up the M-generator. +const double PhaseSpace::WTCORRECTION[11] = { 1., 1., 1., + 2., 5., 15., 60., 250., 1250., 7000., 50000. }; + +//********* + +// Perform simple initialization and store pointers. + +void PhaseSpace::init(SigmaProcess* sigmaProcessPtrIn, Info* infoPtrIn, + BeamParticle* beamAPtrIn, BeamParticle* beamBPtrIn, + SigmaTotal* sigmaTotPtrIn, UserHooks* userHooksPtrIn) { + + // Store input pointers for future use. + sigmaProcessPtr = sigmaProcessPtrIn; + infoPtr = infoPtrIn; + beamAPtr = beamAPtrIn; + beamBPtr = beamBPtrIn; + sigmaTotPtr = sigmaTotPtrIn; + userHooksPtr = userHooksPtrIn; + + // Some commonly used beam information. + idA = beamAPtr->id(); + idB = beamBPtr->id(); + mA = beamAPtr->m(); + mB = beamBPtr->m(); + eCM = infoPtr->eCM(); + s = eCM * eCM; + + // Flag if lepton beams, and if non-resolved ones. + hasLeptonBeams = ( beamAPtr->isLepton() || beamBPtr->isLepton() ); + hasPointLeptons = ( hasLeptonBeams + && (beamAPtr->isUnresolved() || beamBPtr->isUnresolved() ) ); + + // Standard phase space cuts. + mHatGlobalMin = Settings::parm("PhaseSpace:mHatMin"); + mHatGlobalMax = Settings::parm("PhaseSpace:mHatMax"); + pTHatGlobalMin = Settings::parm("PhaseSpace:pTHatMin"); + pTHatGlobalMax = Settings::parm("PhaseSpace:pTHatMax"); + pTHatMinDiverge = Settings::parm("PhaseSpace:pTHatMinDiverge"); + + // When to use Breit-Wigners. + useBreitWigners = Settings::flag("PhaseSpace:useBreitWigners"); + minWidthBreitWigners = Settings::parm("PhaseSpace:minWidthBreitWigners"); + + // Whether generation is with variable energy. + doEnergySpread = Settings::flag("Beams:allowMomentumSpread"); + + // Print flag for maximization information. + showSearch = Settings::flag("PhaseSpace:showSearch"); + showViolation = Settings::flag("PhaseSpace:showViolation"); + + // Know whether a Z0 is pure Z0 or admixed with gamma*. + gmZmodeGlobal = Settings::mode("WeakZ0:gmZmode"); + + // Default event-specific kinematics properties. + x1H = 1.; + x2H = 1.; + m3 = 0.; + m4 = 0.; + m5 = 0.; + s3 = m3 * m3; + s4 = m4 * m4; + s5 = m5 * m5; + mHat = eCM; + sH = s; + tH = 0.; + uH = 0.; + pTH = 0.; + theta = 0.; + phi = 0.; + runBW3H = 1.; + runBW4H = 1.; + runBW5H = 1.; + + // Default cross section information. + sigmaNw = 0.; + sigmaMx = 0.; + sigmaNeg = 0.; + newSigmaMx = false; + + // Flag if user should be allow to reweight cross section. + canModifySigma = (userHooksPtr > 0) + ? userHooksPtr->canModifySigma() : false; + +} + +//********* + +// Allow for nonisotropic decays when ME's available. + +void PhaseSpace::decayKinematics( Event& process) { + + // Identify sets of sister partons. + int iResEnd = 4; + for (int iResBeg = 5; iResBeg < process.size(); ++iResBeg) { + if (iResBeg <= iResEnd) continue; + iResEnd = iResBeg; + while ( iResEnd < process.size() - 1 + && process[iResEnd + 1].mother1() == process[iResBeg].mother1() + && process[iResEnd + 1].mother2() == process[iResBeg].mother2() ) + ++iResEnd; + + // Check that at least one of them is a resonance. + bool hasRes = false; + for (int iRes = iResBeg; iRes <= iResEnd; ++iRes) + if ( !process[iRes].isFinal() ) hasRes = true; + if ( !hasRes ) continue; + + // Evaluate matrix element and decide whether to keep kinematics. + double decWt = sigmaProcessPtr->weightDecay( process, iResBeg, iResEnd); + if (decWt < 0.) infoPtr->errorMsg("Warning in PhaseSpace::decay" + "Kinematics: negative angular weight"); + if (decWt > 1.) infoPtr->errorMsg("Warning in PhaseSpace::decay" + "Kinematics: angular weight above unity"); + while (decWt < Rndm::flat() ) { + + // Find resonances for which to redo decay angles. + for (int iRes = iResBeg; iRes < process.size(); ++iRes) { + if ( process[iRes].isFinal() ) continue; + int iResMother = iRes; + while (iResMother > iResEnd) + iResMother = process[iResMother].mother1(); + if (iResMother < iResBeg) continue; + + // Do decay of this mother isotropically in phase space. + decayKinematicsStep( process, iRes); + + // End loop over resonance decay chains. + } + + // Ready to allow new test of matrix element. + decWt = sigmaProcessPtr->weightDecay( process, iResBeg, iResEnd); + if (decWt < 0.) infoPtr->errorMsg("Warning in PhaseSpace::decay" + "Kinematics: negative angular weight"); + if (decWt > 1.) infoPtr->errorMsg("Warning in PhaseSpace::decay" + "Kinematics: angular weight above unity"); + } + + // End loop over sets of sister resonances/partons. + } + +} + +//********* + +// Reselect decay products momenta isotropically in phase space. +// Does not redo secondary vertex position! + +void PhaseSpace::decayKinematicsStep( Event& process, int iRes) { + + // Multiplicity and mother mass and four-momentum. + int i1 = process[iRes].daughter1(); + int mult = process[iRes].daughter2() + 1 - i1; + double m0 = process[iRes].m(); + Vec4 pRes = process[iRes].p(); + + // Description of two-body decays as simple special case. + if (mult == 2) { + + // Products and product masses. + int i2 = i1 + 1; + double m1t = process[i1].m(); + double m2t = process[i2].m(); + + // Energies and absolute momentum in the rest frame. + double e1 = 0.5 * (m0*m0 + m1t*m1t - m2t*m2t) / m0; + double e2 = 0.5 * (m0*m0 + m2t*m2t - m1t*m1t) / m0; + double p12 = 0.5 * sqrtpos( (m0 - m1t - m2t) * (m0 + m1t + m2t) + * (m0 + m1t - m2t) * (m0 - m1t + m2t) ) / m0; + + // Pick isotropic angles to give three-momentum. + double cosTheta = 2. * Rndm::flat() - 1.; + double sinTheta = sqrt(1. - cosTheta*cosTheta); + double phi12 = 2. * M_PI * Rndm::flat(); + double pX = p12 * sinTheta * cos(phi12); + double pY = p12 * sinTheta * sin(phi12); + double pZ = p12 * cosTheta; + + // Fill four-momenta in mother rest frame and then boost to lab frame. + Vec4 p1( pX, pY, pZ, e1); + Vec4 p2( -pX, -pY, -pZ, e2); + p1.bst( pRes ); + p2.bst( pRes ); + + // Done for two-body decay. + process[i1].p( p1 ); + process[i2].p( p2 ); + return; + } + + // Description of three-body decays as semi-simple special case. + if (mult == 3) { + + // Products and product masses. + int i2 = i1 + 1; + int i3 = i2 + 1; + double m1t = process[i1].m(); + double m2t = process[i2].m(); + double m3t = process[i3].m(); + double mDiff = m0 - (m1t + m2t + m3t); + + // Kinematical limits for 2+3 mass. Maximum phase-space weight. + double m23Min = m2t + m3t; + double m23Max = m0 - m1t; + double p1Max = 0.5 * sqrtpos( (m0 - m1t - m23Min) + * (m0 + m1t + m23Min) * (m0 + m1t - m23Min) + * (m0 - m1t + m23Min) ) / m0; + double p23Max = 0.5 * sqrtpos( (m23Max - m2t - m3t) + * (m23Max + m2t + m3t) * (m23Max + m2t - m3t) + * (m23Max - m2t + m3t) ) / m23Max; + double wtPSmax = 0.5 * p1Max * p23Max; + + // Pick an intermediate mass m23 flat in the allowed range. + double wtPS, m23, p1Abs, p23Abs; + do { + m23 = m23Min + Rndm::flat() * mDiff; + + // Translate into relative momenta and find phase-space weight. + p1Abs = 0.5 * sqrtpos( (m0 - m1t - m23) * (m0 + m1t + m23) + * (m0 + m1t - m23) * (m0 - m1t + m23) ) / m0; + p23Abs = 0.5 * sqrtpos( (m23 - m2t - m3t) * (m23 + m2t + m3t) + * (m23 + m2t - m3t) * (m23 - m2t + m3t) ) / m23; + wtPS = p1Abs * p23Abs; + + // If rejected, try again with new invariant masses. + } while ( wtPS < Rndm::flat() * wtPSmax ); + + // Set up m23 -> m2 + m3 isotropic in its rest frame. + double cosTheta = 2. * Rndm::flat() - 1.; + double sinTheta = sqrt(1. - cosTheta*cosTheta); + double phi23 = 2. * M_PI * Rndm::flat(); + double pX = p23Abs * sinTheta * cos(phi23); + double pY = p23Abs * sinTheta * sin(phi23); + double pZ = p23Abs * cosTheta; + double e2 = sqrt( m2t*m2t + p23Abs*p23Abs); + double e3 = sqrt( m3t*m3t + p23Abs*p23Abs); + Vec4 p2( pX, pY, pZ, e2); + Vec4 p3( -pX, -pY, -pZ, e3); + + // Set up 0 -> 1 + 23 isotropic in its rest frame. + cosTheta = 2. * Rndm::flat() - 1.; + sinTheta = sqrt(1. - cosTheta*cosTheta); + phi23 = 2. * M_PI * Rndm::flat(); + pX = p1Abs * sinTheta * cos(phi23); + pY = p1Abs * sinTheta * sin(phi23); + pZ = p1Abs * cosTheta; + double e1 = sqrt( m1t*m1t + p1Abs*p1Abs); + double e23 = sqrt( m23*m23 + p1Abs*p1Abs); + Vec4 p1( pX, pY, pZ, e1); + + // Boost 2 + 3 to the 0 rest frame and then boost to lab frame. + Vec4 p23( -pX, -pY, -pZ, e23); + p2.bst( p23 ); + p3.bst( p23 ); + p1.bst( pRes ); + p2.bst( pRes ); + p3.bst( pRes ); + + // Done for three-body decay. + process[i1].p( p1 ); + process[i2].p( p2 ); + process[i3].p( p3 ); + return; + } + + // Do a multibody decay using the M-generator algorithm. + + // Set up masses and four-momenta in a vector, with mother in slot 0. + vector mProd; + mProd.push_back( m0); + for (int i = i1; i <= process[iRes].daughter2(); ++i) + mProd.push_back( process[i].m() ); + vector pProd; + pProd.push_back( pRes); + + // Sum of daughter masses. + double mSum = mProd[1]; + for (int i = 2; i <= mult; ++i) mSum += mProd[i]; + double mDiff = m0 - mSum; + + // Begin setup of intermediate invariant masses. + vector mInv; + for (int i = 0; i <= mult; ++i) mInv.push_back( mProd[i]); + + // Calculate the maximum weight in the decay. + double wtPSmax = 1. / WTCORRECTION[mult]; + double mMaxWT = mDiff + mProd[mult]; + double mMinWT = 0.; + for (int i = mult - 1; i > 0; --i) { + mMaxWT += mProd[i]; + mMinWT += mProd[i+1]; + double mNow = mProd[i]; + wtPSmax *= 0.5 * sqrtpos( (mMaxWT - mMinWT - mNow) + * (mMaxWT + mMinWT + mNow) * (mMaxWT + mMinWT - mNow) + * (mMaxWT - mMinWT + mNow) ) / mMaxWT; + } + + // Begin loop to find the set of intermediate invariant masses. + vector rndmOrd; + double wtPS; + do { + wtPS = 1.; + + // Find and order random numbers in descending order. + rndmOrd.resize(0); + rndmOrd.push_back(1.); + for (int i = 1; i < mult - 1; ++i) { + double rndm = Rndm::flat(); + rndmOrd.push_back(rndm); + for (int j = i - 1; j > 0; --j) { + if (rndm > rndmOrd[j]) swap( rndmOrd[j], rndmOrd[j+1] ); + else break; + } + } + rndmOrd.push_back(0.); + + // Translate into intermediate masses and find weight. + for (int i = mult - 1; i > 0; --i) { + mInv[i] = mInv[i+1] + mProd[i] + (rndmOrd[i-1] - rndmOrd[i]) * mDiff; + wtPS *= 0.5 * sqrtpos( (mInv[i] - mInv[i+1] - mProd[i]) + * (mInv[i] + mInv[i+1] + mProd[i]) * (mInv[i] + mInv[i+1] - mProd[i]) + * (mInv[i] - mInv[i+1] + mProd[i]) ) / mInv[i]; + } + + // If rejected, try again with new invariant masses. + } while ( wtPS < Rndm::flat() * wtPSmax ); + + // Perform two-particle decays in the respective rest frame. + vector pInv; + pInv.resize(mult + 1); + for (int i = 1; i < mult; ++i) { + double p12 = 0.5 * sqrtpos( (mInv[i] - mInv[i+1] - mProd[i]) + * (mInv[i] + mInv[i+1] + mProd[i]) * (mInv[i] + mInv[i+1] - mProd[i]) + * (mInv[i] - mInv[i+1] + mProd[i]) ) / mInv[i]; + + // Isotropic angles give three-momentum. + double cosTheta = 2. * Rndm::flat() - 1.; + double sinTheta = sqrt(1. - cosTheta*cosTheta); + double phiLoc = 2. * M_PI * Rndm::flat(); + double pX = p12 * sinTheta * cos(phiLoc); + double pY = p12 * sinTheta * sin(phiLoc); + double pZ = p12 * cosTheta; + + // Calculate energies, fill four-momenta. + double eHad = sqrt( mProd[i]*mProd[i] + p12*p12); + double eInv = sqrt( mInv[i+1]*mInv[i+1] + p12*p12); + pProd.push_back( Vec4( pX, pY, pZ, eHad) ); + pInv[i+1].p( -pX, -pY, -pZ, eInv); + } + pProd.push_back( pInv[mult] ); + + // Boost decay products to the mother rest frame and on to lab frame. + pInv[1] = pProd[0]; + for (int iFrame = mult - 1; iFrame > 0; --iFrame) + for (int i = iFrame; i <= mult; ++i) pProd[i].bst(pInv[iFrame]); + + // Done for multibody decay. + for (int i = 1; i < mult; ++i) + process[i1 + i - 1].p( pProd[i] ); + return; + +} + +//********* + +// Determine how 3-body phase space should be sampled. + +void PhaseSpace::setup3Body() { + + // Check for massive t-channel propagator particles. + int idTchan1 = abs( sigmaProcessPtr->idTchan1() ); + int idTchan2 = abs( sigmaProcessPtr->idTchan2() ); + mTchan1 = (idTchan1 == 0) ? 0. : ParticleDataTable::m0(idTchan1); + mTchan2 = (idTchan2 == 0) ? 0. : ParticleDataTable::m0(idTchan2); + sTchan1 = mTchan1 * mTchan1; + sTchan2 = mTchan2 * mTchan2; + + // Find coefficients of different pT2 selection terms. Mirror choice. + frac3Pow1 = sigmaProcessPtr->tChanFracPow1(); + frac3Pow2 = sigmaProcessPtr->tChanFracPow2(); + frac3Flat = 1. - frac3Pow1 - frac3Pow2; + useMirrorWeight = sigmaProcessPtr->useMirrorWeight(); + +} + +//********* + +// Determine how phase space should be sampled. + +bool PhaseSpace::setupSampling123(bool is2, bool is3, ostream& os) { + + // Optional printout. + if (showSearch) os << "\n PYTHIA Optimization printout for " + << sigmaProcessPtr->name() << "\n \n" << scientific << setprecision(3); + + // Check that open range in tau (+ set tauMin, tauMax). + if (!limitTau(is2, is3)) return false; + + // Reset coefficients and matrices of equation system to solve. + int binTau[8], binY[8], binZ[8]; + double vecTau[8], matTau[8][8], vecY[8], matY[8][8], vecZ[8], matZ[8][8]; + for (int i = 0; i < 8; ++i) { + tauCoef[i] = 0.; + yCoef[i] = 0.; + zCoef[i] = 0.; + binTau[i] = 0; + binY[i] = 0; + binZ[i] = 0; + vecTau[i] = 0.; + vecY[i] = 0.; + vecZ[i] = 0.; + for (int j = 0; j < 8; ++j) { + matTau[i][j] = 0.; + matY[i][j] = 0.; + matZ[i][j] = 0.; + } + } + sigmaMx = 0.; + sigmaNeg = 0.; + + // Number of used coefficients/points for each dimension: tau, y, c. + nTau = (hasPointLeptons) ? 1 : 2; + nY = (hasPointLeptons) ? 1 : 3; + nZ = (is2) ? 5 : 1; + + // Identify if any resonances contribute in s-channel. + idResA = sigmaProcessPtr->resonanceA(); + if (idResA != 0) { + mResA = ParticleDataTable::m0(idResA); + GammaResA = ParticleDataTable::mWidth(idResA); + if (mHatMin > mResA + WIDTHMARGIN * GammaResA || (mHatMax > 0. + && mHatMax < mResA - WIDTHMARGIN * GammaResA) ) idResA = 0; + } + idResB = sigmaProcessPtr->resonanceB(); + if (idResB != 0) { + mResB = ParticleDataTable::m0(idResB); + GammaResB = ParticleDataTable::mWidth(idResB); + if (mHatMin > mResB + WIDTHMARGIN * GammaResB || (mHatMax > 0. + && mHatMax < mResB - WIDTHMARGIN * GammaResB) ) idResB = 0; + } + if (idResA == 0 && idResB != 0) { + idResA = idResB; + mResA = mResB; + GammaResA = GammaResB; + idResB = 0; + } + + // More sampling in tau if resonances in s-channel. + if (idResA !=0 && !hasPointLeptons) { + nTau += 2; + tauResA = mResA * mResA / s; + widResA = mResA * GammaResA / s; + } + if (idResB != 0 && !hasPointLeptons) { + nTau += 2; + tauResB = mResB * mResB / s; + widResB = mResB * GammaResB / s; + } + + // More sampling in tau and y if incoming lepton beams. + if (hasLeptonBeams && !hasPointLeptons) { + ++nTau; + nY += 2; + } + + // Special case when both resonances have same mass. + sameResMass = false; + if (idResB != 0 && abs(mResA - mResB) < SAMEMASS * (GammaResA + GammaResB)) + sameResMass = true; + + // Default z value and weight required for 2 -> 1. Number of dimensions. + z = 0.; + wtZ = 1.; + int nVar = (is2) ? 3 : 2; + + // Initial values, to be modified later. + tauCoef[0] = 1.; + yCoef[0] = 0.5; + yCoef[1] = 0.5; + zCoef[0] = 1.; + + // Step through grid in tau. Set limits on y and z generation. + for (int iTau = 0; iTau < nTau; ++iTau) { + double posTau = 0.5; + if (sameResMass && iTau > 1 && iTau < 6) posTau = (iTau < 4) ? 0.4 : 0.6; + selectTau( iTau, posTau, is2); + if (!limitY()) continue; + if (is2 && !limitZ()) continue; + + // Step through grids in y and z. + for (int iY = 0; iY < nY; ++iY) { + selectY( iY, 0.5); + for (int iZ = 0; iZ < nZ; ++iZ) { + if (is2) selectZ( iZ, 0.5); + double sigmaTmp = 0.; + + // 2 -> 1: calculate cross section, weighted by phase-space volume. + if (!is2 && !is3) { + sigmaProcessPtr->set1Kin( x1H, x2H, sH); + sigmaTmp = sigmaProcessPtr->sigmaPDF(); + sigmaTmp *= wtTau * wtY; + + // 2 -> 2: calculate cross section, weighted by phase-space volume + // and Breit-Wigners for masses + } else if (is2) { + sigmaProcessPtr->set2Kin( x1H, x2H, sH, tH, m3, m4, + runBW3H, runBW4H); + sigmaTmp = sigmaProcessPtr->sigmaPDF(); + sigmaTmp *= wtTau * wtY * wtZ * wtBW; + + // 2 -> 3: repeat internal 3-body phase space several times and + // keep maximal cross section, weighted by phase-space volume + // and Breit-Wigners for masses + } else if (is3) { + for (int iTry3 = 0; iTry3 < NTRY3BODY; ++iTry3) { + if (!select3Body()) continue; + sigmaProcessPtr->set3Kin( x1H, x2H, sH, p3cm, p4cm, p5cm, + m3, m4, m5, runBW3H, runBW4H, runBW5H); + double sigmaTry = sigmaProcessPtr->sigmaPDF(); + sigmaTry *= wtTau * wtY * wt3Body * wtBW; + if (sigmaTry > sigmaTmp) sigmaTmp = sigmaTry; + } + } + + // Allow possibility for user to modify cross section. (3body??) + if (canModifySigma) sigmaTmp + *= userHooksPtr->multiplySigmaBy( sigmaProcessPtr, this, false); + + // Check if current maximum exceeded. + if (sigmaTmp > sigmaMx) sigmaMx = sigmaTmp; + + // Optional printout. Protect against negative cross sections. + if (showSearch) os << " tau =" << setw(11) << tau << " y =" + << setw(11) << y << " z =" << setw(11) << z + << " sigma =" << setw(11) << sigmaTmp << "\n"; + if (sigmaTmp < 0.) sigmaTmp = 0.; + + // Sum up tau cross-section pieces in points used. + if (!hasPointLeptons) { + binTau[iTau] += 1; + vecTau[iTau] += sigmaTmp; + matTau[iTau][0] += 1. / intTau0; + matTau[iTau][1] += (1. / intTau1) / tau; + if (idResA != 0) { + matTau[iTau][2] += (1. / intTau2) / (tau + tauResA); + matTau[iTau][3] += (1. / intTau3) + * tau / ( pow2(tau - tauResA) + pow2(widResA) ); + } + if (idResB != 0) { + matTau[iTau][4] += (1. / intTau4) / (tau + tauResB); + matTau[iTau][5] += (1. / intTau5) + * tau / ( pow2(tau - tauResB) + pow2(widResB) ); + } + if (hasLeptonBeams) matTau[iTau][nTau - 1] += (1. / intTau6) + * tau / max( LEPTONTAUMIN, 1. - tau); + } + + // Sum up y cross-section pieces in points used. + if (!hasPointLeptons) { + binY[iY] += 1; + vecY[iY] += sigmaTmp; + matY[iY][0] += (yMax / intY01) * (y + yMax); + matY[iY][1] += (yMax / intY01) * (yMax - y); + matY[iY][2] += (yMax / intY2) / cosh(y); + if (hasLeptonBeams) { + matY[iY][3] += (yMax / intY34) + / max( LEPTONXMIN, 1. - exp( y - yMax) ); + matY[iY][4] += (yMax / intY34) + / max( LEPTONXMIN, 1. - exp(-y - yMax) ); + } + } + + // Integrals over z expressions at tauMax, to be used below. + if (is2) { + double p2AbsMax = 0.25 * (pow2(tauMax * s - s3 - s4) + - 4. * s3 * s4) / (tauMax * s); + double zMaxMax = sqrtpos( 1. - pT2HatMin / p2AbsMax ); + double zPosMaxMax = max(ratio34, unity34 + zMaxMax); + double zNegMaxMax = max(ratio34, unity34 - zMaxMax); + double intZ0Max = 2. * zMaxMax; + double intZ12Max = log( zPosMaxMax / zNegMaxMax); + double intZ34Max = 1. / zNegMaxMax - 1. / zPosMaxMax; + + // Sum up z cross-section pieces in points used. + binZ[iZ] += 1; + vecZ[iZ] += sigmaTmp; + matZ[iZ][0] += 1.; + matZ[iZ][1] += (intZ0Max / intZ12Max) / zNeg; + matZ[iZ][2] += (intZ0Max / intZ12Max) / zPos; + matZ[iZ][3] += (intZ0Max / intZ34Max) / pow2(zNeg); + matZ[iZ][4] += (intZ0Max / intZ34Max) / pow2(zPos); + } + + // End of loops over phase space points. + } + } + } + + // Fail if no non-vanishing cross sections. + if (sigmaMx <= 0.) { + sigmaMx = 0.; + return false; + } + + // Solve respective equation system for better phase space coefficients. + if (!hasPointLeptons) solveSys( nTau, binTau, vecTau, matTau, tauCoef); + if (!hasPointLeptons) solveSys( nY, binY, vecY, matY, yCoef); + if (is2) solveSys( nZ, binZ, vecZ, matZ, zCoef); + if (showSearch) os << "\n"; + + // Provide cumulative sum of coefficients. + tauCoefSum[0] = tauCoef[0]; + yCoefSum[0] = yCoef[0]; + zCoefSum[0] = zCoef[0]; + for (int i = 1; i < 8; ++ i) { + tauCoefSum[i] = tauCoefSum[i - 1] + tauCoef[i]; + yCoefSum[i] = yCoefSum[i - 1] + yCoef[i]; + zCoefSum[i] = zCoefSum[i - 1] + zCoef[i]; + } + // The last element should be > 1 to be on safe side in selection below. + tauCoefSum[nTau - 1] = 2.; + yCoefSum[nY - 1] = 2.; + zCoefSum[nZ - 1] = 2.; + + + // Begin find two most promising maxima among same points as before. + int iMaxTau[NMAXTRY + 2], iMaxY[NMAXTRY + 2], iMaxZ[NMAXTRY + 2]; + double sigMax[NMAXTRY + 2]; + int nMax = 0; + + // Scan same grid as before in tau, y, z. + for (int iTau = 0; iTau < nTau; ++iTau) { + double posTau = 0.5; + if (sameResMass && iTau > 1 && iTau < 6) posTau = (iTau < 4) ? 0.4 : 0.6; + selectTau( iTau, posTau, is2); + if (!limitY()) continue; + if (is2 && !limitZ()) continue; + for (int iY = 0; iY < nY; ++iY) { + selectY( iY, 0.5); + for (int iZ = 0; iZ < nZ; ++iZ) { + if (is2) selectZ( iZ, 0.5); + double sigmaTmp = 0.; + + // 2 -> 1: calculate cross section, weighted by phase-space volume. + if (!is2 && !is3) { + sigmaProcessPtr->set1Kin( x1H, x2H, sH); + sigmaTmp = sigmaProcessPtr->sigmaPDF(); + sigmaTmp *= wtTau * wtY; + + // 2 -> 2: calculate cross section, weighted by phase-space volume + // and Breit-Wigners for masses + } else if (is2) { + sigmaProcessPtr->set2Kin( x1H, x2H, sH, tH, m3, m4, + runBW3H, runBW4H); + sigmaTmp = sigmaProcessPtr->sigmaPDF(); + sigmaTmp *= wtTau * wtY * wtZ * wtBW; + + // 2 -> 3: repeat internal 3-body phase space several times and + // keep maximal cross section, weighted by phase-space volume + // and Breit-Wigners for masses + } else if (is3) { + for (int iTry3 = 0; iTry3 < NTRY3BODY; ++iTry3) { + if (!select3Body()) continue; + sigmaProcessPtr->set3Kin( x1H, x2H, sH, p3cm, p4cm, p5cm, + m3, m4, m5, runBW3H, runBW4H, runBW5H); + double sigmaTry = sigmaProcessPtr->sigmaPDF(); + sigmaTry *= wtTau * wtY * wt3Body * wtBW; + if (sigmaTry > sigmaTmp) sigmaTmp = sigmaTry; + } + } + + // Allow possibility for user to modify cross section. (3body??) + if (canModifySigma) sigmaTmp + *= userHooksPtr->multiplySigmaBy( sigmaProcessPtr, this, false); + + // Optional printout. Protect against negative cross section. + if (showSearch) os << " tau =" << setw(11) << tau << " y =" + << setw(11) << y << " z =" << setw(11) << z + << " sigma =" << setw(11) << sigmaTmp << "\n"; + if (sigmaTmp < 0.) sigmaTmp = 0.; + + // Check that point is not simply mirror of already found one. + bool mirrorPoint = false; + for (int iMove = 0; iMove < nMax; ++iMove) + if (abs(sigmaTmp - sigMax[iMove]) < SAMESIGMA + * (sigmaTmp + sigMax[iMove])) mirrorPoint = true; + + // Add to or insert in maximum list. Only first two count. + if (!mirrorPoint) { + int iInsert = 0; + for (int iMove = nMax - 1; iMove >= -1; --iMove) { + iInsert = iMove + 1; + if (iInsert == 0 || sigmaTmp < sigMax[iMove]) break; + iMaxTau[iMove + 1] = iMaxTau[iMove]; + iMaxY[iMove + 1] = iMaxY[iMove]; + iMaxZ[iMove + 1] = iMaxZ[iMove]; + sigMax[iMove + 1] = sigMax[iMove]; + } + iMaxTau[iInsert] = iTau; + iMaxY[iInsert] = iY; + iMaxZ[iInsert] = iZ; + sigMax[iInsert] = sigmaTmp; + if (nMax < NMAXTRY) ++nMax; + } + + // Found two most promising maxima. + } + } + } + if (showSearch) os << "\n"; + + // Read out starting position for search. + sigmaMx = sigMax[0]; + int beginVar = (hasPointLeptons) ? 2 : 0; + for (int iMax = 0; iMax < nMax; ++iMax) { + int iTau = iMaxTau[iMax]; + int iY = iMaxY[iMax]; + int iZ = iMaxZ[iMax]; + double tauVal = 0.5; + double yVal = 0.5; + double zVal = 0.5; + int iGrid; + double varVal, varNew, deltaVar, marginVar, sigGrid[3]; + + // Starting point and step size in parameter space. + for (int iRepeat = 0; iRepeat < 2; ++iRepeat) { + // Run through (possibly a subset of) tau, y and z. + for (int iVar = beginVar; iVar < nVar; ++iVar) { + if (iVar == 0) varVal = tauVal; + else if (iVar == 1) varVal = yVal; + else varVal = zVal; + deltaVar = (iRepeat == 0) ? 0.1 + : max( 0.01, min( 0.05, min( varVal - 0.02, 0.98 - varVal) ) ); + marginVar = (iRepeat == 0) ? 0.02 : 0.002; + int moveStart = (iRepeat == 0 && iVar == 0) ? 0 : 1; + for (int move = moveStart; move < 9; ++move) { + + // Define new parameter-space point by step in one dimension. + if (move == 0) { + iGrid = 1; + varNew = varVal; + } else if (move == 1) { + iGrid = 2; + varNew = varVal + deltaVar; + } else if (move == 2) { + iGrid = 0; + varNew = varVal - deltaVar; + } else if (sigGrid[2] >= max( sigGrid[0], sigGrid[1]) + && varVal + 2. * deltaVar < 1. - marginVar) { + varVal += deltaVar; + sigGrid[0] = sigGrid[1]; + sigGrid[1] = sigGrid[2]; + iGrid = 2; + varNew = varVal + deltaVar; + } else if (sigGrid[0] >= max( sigGrid[1], sigGrid[2]) + && varVal - 2. * deltaVar > marginVar) { + varVal -= deltaVar; + sigGrid[2] = sigGrid[1]; + sigGrid[1] = sigGrid[0]; + iGrid = 0; + varNew = varVal - deltaVar; + } else if (sigGrid[2] >= sigGrid[0]) { + deltaVar *= 0.5; + varVal += deltaVar; + sigGrid[0] = sigGrid[1]; + iGrid = 1; + varNew = varVal; + } else { + deltaVar *= 0.5; + varVal -= deltaVar; + sigGrid[2] = sigGrid[1]; + iGrid = 1; + varNew = varVal; + } + + // Convert to relevant variables and find derived new limits. + bool insideLimits = true; + if (iVar == 0) { + tauVal = varNew; + selectTau( iTau, tauVal, is2); + if (!limitY()) insideLimits = false; + if (is2 && !limitZ()) insideLimits = false; + if (insideLimits) { + selectY( iY, yVal); + if (is2) selectZ( iZ, zVal); + } + } else if (iVar == 1) { + yVal = varNew; + selectY( iY, yVal); + } else if (iVar == 2) { + zVal = varNew; + selectZ( iZ, zVal); + } + + // Evaluate cross-section. + double sigmaTmp = 0.; + if (insideLimits) { + + // 2 -> 1: calculate cross section, weighted by phase-space volume. + if (!is2 && !is3) { + sigmaProcessPtr->set1Kin( x1H, x2H, sH); + sigmaTmp = sigmaProcessPtr->sigmaPDF(); + sigmaTmp *= wtTau * wtY; + + // 2 -> 2: calculate cross section, weighted by phase-space volume + // and Breit-Wigners for masses + } else if (is2) { + sigmaProcessPtr->set2Kin( x1H, x2H, sH, tH, m3, m4, + runBW3H, runBW4H); + sigmaTmp = sigmaProcessPtr->sigmaPDF(); + sigmaTmp *= wtTau * wtY * wtZ * wtBW; + + // 2 -> 3: repeat internal 3-body phase space several times and + // keep maximal cross section, weighted by phase-space volume + // and Breit-Wigners for masses + } else if (is3) { + for (int iTry3 = 0; iTry3 < NTRY3BODY; ++iTry3) { + if (!select3Body()) continue; + sigmaProcessPtr->set3Kin( x1H, x2H, sH, p3cm, p4cm, p5cm, + m3, m4, m5, runBW3H, runBW4H, runBW5H); + double sigmaTry = sigmaProcessPtr->sigmaPDF(); + sigmaTry *= wtTau * wtY * wt3Body * wtBW; + if (sigmaTry > sigmaTmp) sigmaTmp = sigmaTry; + } + } + + // Allow possibility for user to modify cross section. + if (canModifySigma) sigmaTmp + *= userHooksPtr->multiplySigmaBy( sigmaProcessPtr, this, false); + + // Optional printout. Protect against negative cross section. + if (showSearch) os << " tau =" << setw(11) << tau << " y =" + << setw(11) << y << " z =" << setw(11) << z + << " sigma =" << setw(11) << sigmaTmp << "\n"; + if (sigmaTmp < 0.) sigmaTmp = 0.; + } + + // Save new maximum. Final maximum. + sigGrid[iGrid] = sigmaTmp; + if (sigmaTmp > sigmaMx) sigmaMx = sigmaTmp; + } + } + } + } + sigmaMx *= SAFETYMARGIN; + + // Optional printout. + if (showSearch) os << "\n Final maximum = " << setw(11) << sigmaMx << endl; + + // Done. + return true; +} + +//********* + +// Select a trial kinematics phase space point. +// Note: by In is meant the integral over the quantity multiplying +// coefficient cn. The sum of cn is normalized to unity. + +bool PhaseSpace::trialKin123(bool is2, bool is3, bool inEvent, ostream& os) { + + // Allow for possibility that energy varies from event to event. + if (doEnergySpread) { + eCM = infoPtr->eCM(); + s = eCM * eCM; + + // Find shifted tauRes values. + if (idResA !=0 && !hasPointLeptons) { + tauResA = mResA * mResA / s; + widResA = mResA * GammaResA / s; + } + if (idResB != 0 && !hasPointLeptons) { + tauResB = mResB * mResB / s; + widResB = mResB * GammaResB / s; + } + } + + // Choose tau according to h1(tau)/tau, where + // h1(tau) = c0/I0 + (c1/I1) * 1/tau + // + (c2/I2) / (tau + tauResA) + // + (c3/I3) * tau / ((tau - tauResA)^2 + widResA^2) + // + (c4/I4) / (tau + tauResB) + // + (c5/I5) * tau / ((tau - tauResB)^2 + widResB^2) + // + (c6/I6) * tau / (1 - tau). + if (!limitTau(is2, is3)) return false; + int iTau = 0; + if (!hasPointLeptons) { + double rTau = Rndm::flat(); + while (rTau > tauCoefSum[iTau]) ++iTau; + } + selectTau( iTau, Rndm::flat(), is2); + + // Choose y according to h2(y), where + // h2(y) = (c0/I0) * (y-ymin) + (c1/I1) * (ymax-y) + // + (c2/I2) * 1/cosh(y) + (c3/I3) * 1 / (1 - exp(y-ymax)) + // + (c4/I4) * 1 / (1 - exp(ymin-y)). + if (!limitY()) return false; + int iY = 0; + if (!hasPointLeptons) { + double rY = Rndm::flat(); + while (rY > yCoefSum[iY]) ++iY; + } + selectY( iY, Rndm::flat()); + + // Choose z = cos(thetaHat) according to h3(z), where + // h3(z) = c0/I0 + (c1/I1) * 1/(A - z) + (c2/I2) * 1/(A + z) + // + (c3/I3) * 1/(A - z)^2 + (c4/I4) * 1/(A + z)^2, + // where A = 1 + 2*(m3*m4/sH)^2 (= 1 for massless products). + if (is2) { + if (!limitZ()) return false; + int iZ = 0; + double rZ = Rndm::flat(); + while (rZ > zCoefSum[iZ]) ++iZ; + selectZ( iZ, Rndm::flat()); + } + + // 2 -> 1: calculate cross section, weighted by phase-space volume. + if (!is2 && !is3) { + sigmaProcessPtr->set1Kin( x1H, x2H, sH); + sigmaNw = sigmaProcessPtr->sigmaPDF(); + sigmaNw *= wtTau * wtY; + + // 2 -> 2: calculate cross section, weighted by phase-space volume + // and Breit-Wigners for masses + } else if (is2) { + sigmaProcessPtr->set2Kin( x1H, x2H, sH, tH, m3, m4, runBW3H, runBW4H); + sigmaNw = sigmaProcessPtr->sigmaPDF(); + sigmaNw *= wtTau * wtY * wtZ * wtBW; + + // 2 -> 3: also sample internal 3-body phase, weighted by + // 2 -> 1 phase-space volume and Breit-Wigners for masses + } else if (is3) { + if (!select3Body()) sigmaNw = 0.; + else { + sigmaProcessPtr->set3Kin( x1H, x2H, sH, p3cm, p4cm, p5cm, + m3, m4, m5, runBW3H, runBW4H, runBW5H); + sigmaNw = sigmaProcessPtr->sigmaPDF(); + sigmaNw *= wtTau * wtY * wt3Body * wtBW; + } + } + + // Allow possibility for user to modify cross section. + if (canModifySigma) sigmaNw + *= userHooksPtr->multiplySigmaBy( sigmaProcessPtr, this, inEvent); + + // Check if maximum violated. + newSigmaMx = false; + if (sigmaNw > sigmaMx) { + infoPtr->errorMsg("Warning in PhaseSpace2to2tauyz::trialKin: " + "maximum for cross section violated"); + double violFact = SAFETYMARGIN * sigmaNw / sigmaMx; + sigmaMx = SAFETYMARGIN * sigmaNw; + newSigmaMx = true; + + // Optional printout of (all) violations. + if (showViolation) { + if (violFact < 9.99) os << fixed; + else os << scientific; + os << " PYTHIA Maximum for " << sigmaProcessPtr->name() + << " increased by factor " << setprecision(3) << violFact + << " to " << scientific << sigmaMx << endl; + } + } + + // Check if negative cross section. + if (sigmaNw < sigmaNeg) { + infoPtr->errorMsg("Warning in PhaseSpace2to2tauyz::trialKin:" + " negative cross section set 0", "for " + sigmaProcessPtr->name() ); + sigmaNeg = sigmaNw; + + // Optional printout of (all) violations. + if (showViolation) os << " PYTHIA Negative minimum for " + << sigmaProcessPtr->name() << " changed to " << scientific + << setprecision(3) << sigmaNeg << endl; + } + if (sigmaNw < 0.) sigmaNw = 0.; + + // Done. + return true; +} + +//********* + +// Find range of allowed tau values. + +bool PhaseSpace::limitTau(bool is2, bool is3) { + + // Trivial reply for unresolved lepton beams. + if (hasPointLeptons) { + tauMin = 1.; + tauMax = 1.; + return true; + } + + // Requirements from allowed mHat range. + tauMin = sHatMin / s; + tauMax = (mHatMax < mHatMin) ? 1. : min( 1., sHatMax / s); + + // Requirements from allowed pT range and masses. + if (is2 || is3) { + double mT3Min = sqrt(s3 + pT2HatMin); + double mT4Min = sqrt(s4 + pT2HatMin); + double mT5Min = (is3) ? sqrt(s5 + pT2HatMin) : 0.; + tauMin = max( tauMin, pow2(mT3Min + mT4Min + mT5Min) / s); + } + + // Check that there is an open range. + return (tauMax > tauMin); +} + +//********* + +// Find range of allowed y values. + +bool PhaseSpace::limitY() { + + // Trivial reply for unresolved lepton beams. + if (hasPointLeptons) { + yMax = 1.; + return true; + } + + // Requirements from selected tau value. + yMax = -0.5 * log(tau); + + // For lepton beams requirements from cutoff for f_e^e. + double yMaxMargin = (hasLeptonBeams) ? yMax + LEPTONXLOGMAX : yMax; + + // Check that there is an open range. + return (yMaxMargin > 0.); +} + +//********* + +// Find range of allowed z = cos(theta) values. + +bool PhaseSpace::limitZ() { + + // Default limits. + zMin = 0.; + zMax = 1.; + + // Requirements from pTHat limits. + zMax = sqrtpos( 1. - pT2HatMin / p2Abs ); + if (pTHatMax > pTHatMin) zMin = sqrtpos( 1. - pT2HatMax / p2Abs ); + + // Check that there is an open range. + return (zMax > zMin); +} + +//********* + +// Select tau according to a choice of shapes. + +void PhaseSpace::selectTau(int iTau, double tauVal, bool is2) { + + // Trivial reply for unresolved lepton beams. + if (hasPointLeptons) { + tau = 1.; + wtTau = 1.; + sH = s; + mHat = sqrt(sH); + if (is2) { + p2Abs = 0.25 * (pow2(sH - s3 - s4) - 4. * s3 * s4) / sH; + pAbs = sqrtpos( p2Abs ); + } + return; + } + + // Contributions from s-channel resonances. + double tRatA = 0.; + double aLowA = 0.; + double aUppA = 0.; + if (idResA !=0) { + tRatA = ((tauResA + tauMax) / (tauResA + tauMin)) * (tauMin / tauMax); + aLowA = atan( (tauMin - tauResA) / widResA); + aUppA = atan( (tauMax - tauResA) / widResA); + } + double tRatB = 0.; + double aLowB = 0.; + double aUppB = 0.; + if (idResB != 0) { + tRatB = ((tauResB + tauMax) / (tauResB + tauMin)) * (tauMin / tauMax); + aLowB = atan( (tauMin - tauResB) / widResB); + aUppB = atan( (tauMax - tauResB) / widResB); + } + + // Contributions from 1 / (1 - tau) for lepton beams. + double aLowT = 0.; + double aUppT = 0.; + if (hasLeptonBeams) { + aLowT = log( max( LEPTONTAUMIN, 1. - tauMin) ); + aUppT = log( max( LEPTONTAUMIN, 1. - tauMax) ); + intTau6 = aLowT - aUppT; + } + + // Select according to 1/tau or 1/tau^2. + if (iTau == 0) tau = tauMin * pow( tauMax / tauMin, tauVal); + else if (iTau == 1) tau = tauMax * tauMin + / (tauMin + (tauMax - tauMin) * tauVal); + + // Select according to 1 / (1 - tau) for lepton beams. + else if (hasLeptonBeams && iTau == nTau - 1) + tau = 1. - exp( aUppT + intTau6 * tauVal ); + + // Select according to 1 / (tau * (tau + tauRes)) or + // 1 / ((tau - tauRes)^2 + widRes^2) for resonances A and B. + else if (iTau == 2) tau = tauResA * tauMin + / ((tauResA + tauMin) * pow( tRatA, tauVal) - tauMin); + else if (iTau == 3) tau = tauResA + widResA + * tan( aLowA + (aUppA - aLowA) * tauVal); + else if (iTau == 4) tau = tauResB * tauMin + / ((tauResB + tauMin) * pow( tRatB, tauVal) - tauMin); + else if (iTau == 5) tau = tauResB + widResB + * tan( aLowB + (aUppB - aLowB) * tauVal); + + // Phase space weight in tau. + intTau0 = log( tauMax / tauMin); + intTau1 = (tauMax - tauMin) / (tauMax * tauMin); + double invWtTau = (tauCoef[0] / intTau0) + (tauCoef[1] / intTau1) / tau; + if (idResA != 0) { + intTau2 = -log(tRatA) / tauResA; + intTau3 = (aUppA - aLowA) / widResA; + invWtTau += (tauCoef[2] / intTau2) / (tau + tauResA) + + (tauCoef[3] / intTau3) * tau / ( pow2(tau - tauResA) + pow2(widResA) ); + } + if (idResB != 0) { + intTau4 = -log(tRatB) / tauResB; + intTau5 = (aUppB - aLowB) / widResB; + invWtTau += (tauCoef[4] / intTau4) / (tau + tauResB) + + (tauCoef[5] / intTau5) * tau / ( pow2(tau - tauResB) + pow2(widResB) ); + } + if (hasLeptonBeams) + invWtTau += (tauCoef[nTau - 1] / intTau6) + * tau / max( LEPTONTAUMIN, 1. - tau); + wtTau = 1. / invWtTau; + + // Calculate sHat and absolute momentum of outgoing partons. + sH = tau * s; + mHat = sqrt(sH); + if (is2) { + p2Abs = 0.25 * (pow2(sH - s3 - s4) - 4. * s3 * s4) / sH; + pAbs = sqrtpos( p2Abs ); + } + +} + +//********* + +// Select y according to a choice of shapes. + +void PhaseSpace::selectY(int iY, double yVal) { + + // Trivial reply for unresolved lepton beams. + if (hasPointLeptons) { + y = 0.; + wtY = 1.; + x1H = 1.; + x2H = 1.; + return; + } + + // Standard expressions used below. + double atanMax = atan( exp(yMax) ); + double atanMin = atan( exp(-yMax) ); + double aUppY = (hasLeptonBeams) + ? log( max( LEPTONXMIN, LEPTONXMAX / tau - 1. ) ) : 0.; + double aLowY = LEPTONXLOGMIN; + + // y - y_min or mirrored y_max - y. + if (iY <= 1) y = yMax * (2. * sqrt(yVal) - 1.); + + // 1 / cosh(y). + else if (iY == 2) + y = log( tan( atanMin + (atanMax - atanMin) * yVal ) ); + + // 1 / (1 - exp(y - y_max)) or mirrored 1 / (1 - exp(y_min - y)). + else y = yMax - log( 1. + exp(aLowY + (aUppY - aLowY) * yVal) ); + + // Mirror two cases. + if (iY == 1 || iY == 4) y = -y; + + // Phase space integral in y. + intY01 = 0.5 * pow2(2. * yMax); + intY2 = 2. * (atanMax - atanMin); + intY34 = aUppY - aLowY; + double invWtY = (yCoef[0] / intY01) * (y + yMax) + + (yCoef[1] / intY01) * (yMax - y) + (yCoef[2] / intY2) / cosh(y); + if (hasLeptonBeams) invWtY + += (yCoef[3] / intY34) / max( LEPTONXMIN, 1. - exp( y - yMax) ) + + (yCoef[4] / intY34) / max( LEPTONXMIN, 1. - exp(-y - yMax) ); + wtY = 1. / invWtY; + + // Calculate x1 and x2. + x1H = sqrt(tau) * exp(y); + x2H = sqrt(tau) * exp(-y); +} + +//********* + +// Select z = cos(theta) according to a choice of shapes. +// The selection is split in the positive- and negative-z regions, +// since a pTmax cut can remove the region around z = 0. + +void PhaseSpace::selectZ(int iZ, double zVal) { + + // Mass-dependent dampening of pT -> 0 limit. + ratio34 = max(TINY, 2. * s3 * s4 / pow2(sH)); + unity34 = 1. + ratio34; + double ratiopT2 = 2. * pT2HatMin / max( SHATMINZ, sH); + if (ratiopT2 < PT2RATMINZ) ratio34 = max( ratio34, ratiopT2); + + // Common expressions in z limits. + double zPosMax = max(ratio34, unity34 + zMax); + double zNegMax = max(ratio34, unity34 - zMax); + double zPosMin = max(ratio34, unity34 + zMin); + double zNegMin = max(ratio34, unity34 - zMin); + + // Flat in z. + if (iZ == 0) { + if (zVal < 0.5) z = -(zMax + (zMin - zMax) * 2. * zVal); + else z = zMin + (zMax - zMin) * (2. * zVal - 1.); + + // 1 / (unity34 - z). + } else if (iZ == 1) { + double areaNeg = log(zPosMax / zPosMin); + double areaPos = log(zNegMin / zNegMax); + double area = areaNeg + areaPos; + if (zVal * area < areaNeg) { + double zValMod = zVal * area / areaNeg; + z = unity34 - zPosMax * pow(zPosMin / zPosMax, zValMod); + } else { + double zValMod = (zVal * area - areaNeg)/ areaPos; + z = unity34 - zNegMin * pow(zNegMax / zNegMin, zValMod); + } + + // 1 / (unity34 + z). + } else if (iZ == 2) { + double areaNeg = log(zNegMin / zNegMax); + double areaPos = log(zPosMax / zPosMin); + double area = areaNeg + areaPos; + if (zVal * area < areaNeg) { + double zValMod = zVal * area / areaNeg; + z = zNegMax * pow(zNegMin / zNegMax, zValMod) - unity34; + } else { + double zValMod = (zVal * area - areaNeg)/ areaPos; + z = zPosMin * pow(zPosMax / zPosMin, zValMod) - unity34; + } + + // 1 / (unity34 - z)^2. + } else if (iZ == 3) { + double areaNeg = 1. / zPosMin - 1. / zPosMax; + double areaPos = 1. / zNegMax - 1. / zNegMin; + double area = areaNeg + areaPos; + if (zVal * area < areaNeg) { + double zValMod = zVal * area / areaNeg; + z = unity34 - 1. / (1./zPosMax + areaNeg * zValMod); + } else { + double zValMod = (zVal * area - areaNeg)/ areaPos; + z = unity34 - 1. / (1./zNegMin + areaPos * zValMod); + } + + // 1 / (unity34 + z)^2. + } else if (iZ == 4) { + double areaNeg = 1. / zNegMax - 1. / zNegMin; + double areaPos = 1. / zPosMin - 1. / zPosMax; + double area = areaNeg + areaPos; + if (zVal * area < areaNeg) { + double zValMod = zVal * area / areaNeg; + z = 1. / (1./zNegMax - areaNeg * zValMod) - unity34; + } else { + double zValMod = (zVal * area - areaNeg)/ areaPos; + z = 1. / (1./zPosMin - areaPos * zValMod) - unity34; + } + } + + // Safety check for roundoff errors. Combinations with z. + if (z < 0.) z = min(-zMin, max(-zMax, z)); + else z = min(zMax, max(zMin, z)); + zNeg = max(ratio34, unity34 - z); + zPos = max(ratio34, unity34 + z); + + // Phase space integral in z. + double intZ0 = 2. * (zMax - zMin); + double intZ12 = log( (zPosMax * zNegMin) / (zPosMin * zNegMax) ); + double intZ34 = 1. / zPosMin - 1. / zPosMax + 1. / zNegMax + - 1. / zNegMin; + wtZ = mHat * pAbs / ( (zCoef[0] / intZ0) + (zCoef[1] / intZ12) / zNeg + + (zCoef[2] / intZ12) / zPos + (zCoef[3] / intZ34) / pow2(zNeg) + + (zCoef[4] / intZ34) / pow2(zPos) ); + + // Calculate tHat and uHat. Also gives pTHat. + double sH34 = -0.5 * (sH - s3 - s4); + tH = sH34 + mHat * pAbs * z; + uH = sH34 - mHat * pAbs * z; + pTH = sqrtpos( (tH * uH - s3 * s4) / sH); + +} + +//********* + +// Select three-body phase space according to a cylindrically based form +// that can be chosen to favour low pT based on the form of propagators. + +bool PhaseSpace::select3Body() { + + // Upper and lower limits of pT choice for 4 and 5. + double m35S = pow2(m3 + m5); + double pT4Smax = 0.25 * ( pow2(sH - s4 - m35S) - 4. * s4 * m35S ) / sH; + if (pTHatMax > pTHatMin) pT4Smax = min( pT2HatMax, pT4Smax); + double pT4Smin = pT2HatMin; + double m34S = pow2(m3 + m4); + double pT5Smax = 0.25 * ( pow2(sH - s5 - m34S) - 4. * s5 * m34S ) / sH; + if (pTHatMax > pTHatMin) pT5Smax = min( pT2HatMax, pT5Smax); + double pT5Smin = pT2HatMin; + + // Check that pT ranges not closed. + if ( pT4Smax < pow2(pTHatMin + MASSMARGIN) ) return false; + if ( pT5Smax < pow2(pTHatMin + MASSMARGIN) ) return false; + + // Select pT4S according to c0 + c1/(M^2 + pT^2) + c2/(M^2 + pT^2)^2. + double pTSmaxProp = pT4Smax + sTchan1; + double pTSminProp = pT4Smin + sTchan1; + double pTSratProp = pTSmaxProp / pTSminProp; + double pTSdiff = pT4Smax - pT4Smin; + double rShape = Rndm::flat(); + double pT4S = 0.; + if (rShape < frac3Flat) pT4S = pT4Smin + Rndm::flat() * pTSdiff; + else if (rShape < frac3Flat + frac3Pow1) pT4S = max( pT2HatMin, + pTSminProp * pow( pTSratProp, Rndm::flat() ) - sTchan1 ); + else pT4S = max( pT2HatMin, pTSminProp * pTSmaxProp + / (pTSminProp + Rndm::flat()* pTSdiff) - sTchan1 ); + double wt4 = pTSdiff / ( frac3Flat + + frac3Pow1 * pTSdiff / (log(pTSratProp) * (pT4S + sTchan1)) + + frac3Pow2 * pTSminProp * pTSmaxProp / pow2(pT4S + sTchan1) ); + + // Select pT5S according to c0 + c1/(M^2 + pT^2) + c2/(M^2 + pT^2)^2. + pTSmaxProp = pT5Smax + sTchan2; + pTSminProp = pT5Smin + sTchan2; + pTSratProp = pTSmaxProp / pTSminProp; + pTSdiff = pT5Smax - pT5Smin; + rShape = Rndm::flat(); + double pT5S = 0.; + if (rShape < frac3Flat) pT5S = pT5Smin + Rndm::flat() * pTSdiff; + else if (rShape < frac3Flat + frac3Pow1) pT5S = max( pT2HatMin, + pTSminProp * pow( pTSratProp, Rndm::flat() ) - sTchan2 ); + else pT5S = max( pT2HatMin, pTSminProp * pTSmaxProp + / (pTSminProp + Rndm::flat()* pTSdiff) - sTchan2 ); + double wt5 = pTSdiff / ( frac3Flat + + frac3Pow1 * pTSdiff / (log(pTSratProp) * (pT5S + sTchan2)) + + frac3Pow2 * pTSminProp * pTSmaxProp / pow2(pT5S + sTchan2) ); + + // Select azimuthal angles and check that third pT in range. + double phi4 = 2. * M_PI * Rndm::flat(); + double phi5 = 2. * M_PI * Rndm::flat(); + double pT3S = max( 0., pT4S + pT5S + 2. * sqrt(pT4S * pT5S) + * cos(phi4 - phi5) ); + if ( pT3S < pT2HatMin || (pTHatMax > pTHatMin && pT3S > pT2HatMax) ) + return false; + + // Calculate transverse masses and check that phase space not closed. + double sT3 = s3 + pT3S; + double sT4 = s4 + pT4S; + double sT5 = s5 + pT5S; + double mT3 = sqrt(sT3); + double mT4 = sqrt(sT4); + double mT5 = sqrt(sT5); + if ( mT3 + mT4 + mT5 + MASSMARGIN > mHat ) return false; + + // Select rapidity for particle 3 and check that phase space not closed. + double m45S = pow2(mT4 + mT5); + double y3max = log( ( sH + sT3 - m45S + sqrtpos( pow2(sH - sT3 - m45S) + - 4 * sT3 * m45S ) ) / (2. * mHat * mT3) ); + if (y3max < YRANGEMARGIN) return false; + double y3 = (2. * Rndm::flat() - 1.) * (1. - YRANGEMARGIN) * y3max; + double pz3 = mT3 * sinh(y3); + double e3 = mT3 * cosh(y3); + + // Find momentum transfers in the two mirror solutions (in 4-5 frame). + double pz45 = -pz3; + double e45 = mHat - e3; + double sT45 = e45 * e45 - pz45 * pz45; + double lam45 = sqrtpos( pow2(sT45 - sT4 - sT5) - 4. * sT4 * sT5 ); + if (lam45 < YRANGEMARGIN * sH) return false; + double lam4e = sT45 + sT4 - sT5; + double lam5e = sT45 + sT5 - sT4; + double tFac = -0.5 * mHat / sT45; + double t1Pos = tFac * (e45 - pz45) * (lam4e - lam45); + double t1Neg = tFac * (e45 - pz45) * (lam4e + lam45); + double t2Pos = tFac * (e45 + pz45) * (lam5e - lam45); + double t2Neg = tFac * (e45 + pz45) * (lam5e + lam45); + + // Construct relative mirror weights and make choice. + double wtPosUnnorm = 1.; + double wtNegUnnorm = 1.; + if (useMirrorWeight) { + wtPosUnnorm = 1./ pow2( (t1Pos - sTchan1) * (t2Pos - sTchan2) ); + wtNegUnnorm = 1./ pow2( (t1Neg - sTchan1) * (t2Neg - sTchan2) ); + } + double wtPos = wtPosUnnorm / (wtPosUnnorm + wtNegUnnorm); + double wtNeg = wtNegUnnorm / (wtPosUnnorm + wtNegUnnorm); + double epsilon = (Rndm::flat() < wtPos) ? 1. : -1.; + + // Construct four-vectors in rest frame of subprocess. + double px4 = sqrt(pT4S) * cos(phi4); + double py4 = sqrt(pT4S) * sin(phi4); + double px5 = sqrt(pT5S) * cos(phi5); + double py5 = sqrt(pT5S) * sin(phi5); + double pz4 = 0.5 * (pz45 * lam4e + epsilon * e45 * lam45) / sT45; + double pz5 = pz45 - pz4; + double e4 = sqrt(sT4 + pz4 * pz4); + double e5 = sqrt(sT5 + pz5 * pz5); + p3cm = Vec4( -(px4 + px5), -(py4 + py5), pz3, e3); + p4cm = Vec4( px4, py4, pz4, e4); + p5cm = Vec4( px5, py5, pz5, e5); + + // Total weight to associate with kinematics choice. + wt3Body = wt4 * wt5 * (2. * y3max) / (128. * pow3(M_PI) * lam45); + wt3Body *= (epsilon > 0.) ? 1. / wtPos : 1. / wtNeg; + + // Cross section of form |M|^2/(2 sHat) dPS_3 so need 1/(2 sHat). + wt3Body /= (2. * sH); + + // Done. + return true; + +} + +//********* + +// Solve linear equation system for better phase space coefficients. + +void PhaseSpace::solveSys( int n, int bin[8], double vec[8], + double mat[8][8], double coef[8], ostream& os) { + + // Optional printout. + if (showSearch) { + os << "\n Equation system: " << setw(5) << bin[0]; + for (int j = 0; j < n; ++j) os << setw(12) << mat[0][j]; + os << setw(12) << vec[0] << "\n"; + for (int i = 1; i < n; ++i) { + os << " " << setw(5) << bin[i]; + for (int j = 0; j < n; ++j) os << setw(12) << mat[i][j]; + os << setw(12) << vec[i] << "\n"; + } + } + + // Local variables. + double vecNor[8], coefTmp[8]; + for (int i = 0; i < n; ++i) coefTmp[i] = 0.; + + // Check if equation system solvable. + bool canSolve = true; + for (int i = 0; i < n; ++i) if (bin[i] == 0) canSolve = false; + double vecSum = 0.; + for (int i = 0; i < n; ++i) vecSum += vec[i]; + if (abs(vecSum) < TINY) canSolve = false; + + // Solve to find relative importance of cross-section pieces. + if (canSolve) { + for (int i = 0; i < n; ++i) vecNor[i] = max( 0.1, vec[i] / vecSum); + for (int k = 0; k < n - 1; ++k) { + for (int i = k + 1; i < n; ++i) { + if (abs(mat[k][k]) < TINY) {canSolve = false; break;} + double ratio = mat[i][k] / mat[k][k]; + vec[i] -= ratio * vec[k]; + for (int j = k; j < n; ++j) mat[i][j] -= ratio * mat[k][j]; + } + if (!canSolve) break; + } + if (canSolve) { + for (int k = n - 1; k >= 0; --k) { + for (int j = k + 1; j < n; ++j) vec[k] -= mat[k][j] * coefTmp[j]; + coefTmp[k] = vec[k] / mat[k][k]; + } + } + } + + // Share evenly if failure. + if (!canSolve) for (int i = 0; i < n; ++i) { + coefTmp[i] = 1.; + vecNor[i] = 0.1; + if (vecSum > TINY) vecNor[i] = max(0.1, vec[i] / vecSum); + } + + // Normalize coefficients, with piece shared democratically. + double coefSum = 0.; + vecSum = 0.; + for (int i = 0; i < n; ++i) { + coefTmp[i] = max( 0., coefTmp[i]); + coefSum += coefTmp[i]; + vecSum += vecNor[i]; + } + if (coefSum > 0.) for (int i = 0; i < n; ++i) coef[i] = EVENFRAC / n + + (1. - EVENFRAC) * 0.5 * (coefTmp[i] / coefSum + vecNor[i] / vecSum); + else for (int i = 0; i < n; ++i) coef[i] = 1. / n; + + // Optional printout. + if (showSearch) { + os << " Solution: "; + for (int i = 0; i < n; ++i) os << setw(12) << coef[i]; + os << "\n"; + } +} + +//********* + +// Setup mass selection for one resonance at a time - part 1. + +void PhaseSpace::setupMass1(int iM) { + + // Identity for mass seletion; is 0 also for light quarks (not yet selected). + if (iM == 3) idMass[iM] = abs(sigmaProcessPtr->id3Mass()); + if (iM == 4) idMass[iM] = abs(sigmaProcessPtr->id4Mass()); + if (iM == 5) idMass[iM] = abs(sigmaProcessPtr->id5Mass()); + + // Masses and widths of resonances. + if (idMass[iM] == 0) { + mPeak[iM] = 0.; + mWidth[iM] = 0.; + mMin[iM] = 0.; + mMax[iM] = 0.; + } else { + mPeak[iM] = ParticleDataTable::m0(idMass[iM]); + mWidth[iM] = ParticleDataTable::mWidth(idMass[iM]); + mMin[iM] = ParticleDataTable::mMin(idMass[iM]); + mMax[iM] = ParticleDataTable::mMax(idMass[iM]); + // gmZmode == 1 means pure photon propagator; set at lower mass limit. + if (idMass[iM] == 23 && gmZmode == 1) mPeak[iM] = mMin[iM]; + } + + // Mass and width combinations for Breit-Wigners. + sPeak[iM] = mPeak[iM] * mPeak[iM]; + useBW[iM] = useBreitWigners && (mWidth[iM] > minWidthBreitWigners); + if (!useBW[iM]) mWidth[iM] = 0.; + mw[iM] = mPeak[iM] * mWidth[iM]; + wmRat[iM] = (idMass[iM] == 0 || mPeak[iM] == 0.) + ? 0. : mWidth[iM] / mPeak[iM]; + + // Simple Breit-Wigner range, upper edge to be corrected subsequently. + if (useBW[iM]) { + mLower[iM] = mMin[iM]; + mUpper[iM] = mHatMax; + } + +} + +//********* + +// Setup mass selection for one resonance at a time - part 2. + +void PhaseSpace::setupMass2(int iM, double distToThresh) { + + // Store reduced Breit-Wigner range. + if (mMax[iM] > mMin[iM]) mUpper[iM] = min( mUpper[iM], mMax[iM]); + sLower[iM] = mLower[iM] * mLower[iM]; + sUpper[iM] = mUpper[iM] * mUpper[iM]; + + // Prepare to select m3 by BW + flat + 1/s_3. + // Determine relative coefficients by allowed mass range. + if (distToThresh > THRESHOLDSIZE) { + fracFlat[iM] = 0.1; + fracInv[iM] = 0.1; + } else if (distToThresh > - THRESHOLDSIZE) { + fracFlat[iM] = 0.25 - 0.15 * distToThresh / THRESHOLDSIZE; + fracInv [iM] = 0.15 - 0.05 * distToThresh / THRESHOLDSIZE; + } else { + fracFlat[iM] = 0.4; + fracInv[iM] = 0.2; + } + + // For gamma*/Z0: increase 1/s_i part and introduce 1/s_i^2 part. + fracInv2[iM] = 0.; + if (idMass[iM] == 23 && gmZmode == 0) { + fracFlat[iM] *= 0.5; + fracInv[iM] = 0.5 * fracInv[iM] + 0.25; + fracInv2[iM] = 0.25; + } else if (idMass[iM] == 23 && gmZmode == 1) { + fracFlat[iM] = 0.1; + fracInv[iM] = 0.4; + fracInv2[iM] = 0.4; + } + + // Normalization integrals for the respective contribution. + atanLower[iM] = atan( (sLower[iM] - sPeak[iM])/ mw[iM] ); + atanUpper[iM] = atan( (sUpper[iM] - sPeak[iM])/ mw[iM] ); + intBW[iM] = atanUpper[iM] - atanLower[iM]; + intFlat[iM] = sUpper[iM] - sLower[iM]; + intInv[iM] = log( sUpper[iM] / sLower[iM] ); + intInv2[iM] = 1./sLower[iM] - 1./sUpper[iM]; + +} + +//********* + +// Select Breit-Wigner-distributed or fixed masses. + +void PhaseSpace::trialMass(int iM) { + + // References to masses to be set. + double& mSet = (iM == 3) ? m3 : ( (iM == 4) ? m4 : m5 ); + double& sSet = (iM == 3) ? s3 : ( (iM == 4) ? s4 : s5 ); + + // Distribution for m_i is BW + flat + 1/s_i + 1/s_i^2. + if (useBW[iM]) { + double pickForm = Rndm::flat(); + if (pickForm > fracFlat[iM] + fracInv[iM] + fracInv2[iM]) + sSet = sPeak[iM] + mw[iM] * tan( atanLower[iM] + + Rndm::flat() * intBW[iM] ); + else if (pickForm > fracInv[iM] + fracInv2[iM]) + sSet = sLower[iM] + Rndm::flat() * (sUpper[iM] - sLower[iM]); + else if (pickForm > fracInv2[iM]) + sSet = sLower[iM] * pow( sUpper[iM] / sLower[iM], Rndm::flat() ); + else sSet = sLower[iM] * sUpper[iM] + / (sLower[iM] + Rndm::flat() * (sUpper[iM] - sLower[iM])); + mSet = sqrt(sSet); + + // Else m_i is fixed at peak value. + } else { + mSet = mPeak[iM]; + sSet = sPeak[iM]; + } + +} + +//********* + +// Naively a fixed-width Breit-Wigner is used to pick the mass. +// Here come the correction factors for +// (i) preselection according to BW + flat in s_i + 1/s_i + 1/s_i^2, +// (ii) reduced allowed mass range, +// (iii) running width, i.e. m0*Gamma0 -> s*Gamma0/m0. +// In the end, the weighted distribution is a running-width BW. + +double PhaseSpace::weightMass(int iM) { + + // Reference to mass and to Breit-Wigner weight to be set. + double& sSet = (iM == 3) ? s3 : ( (iM == 4) ? s4 : s5 ); + double& runBWH = (iM == 3) ? runBW3H : ( (iM == 4) ? runBW4H : runBW5H ); + + // Default weight if no Breit-Wigner. + runBWH = 1.; + if (!useBW[iM]) return 1.; + + // Weight of generated distribution. + double genBW = (1. - fracFlat[iM] - fracInv[iM] - fracInv2[iM]) + * mw[iM] / ( (pow2(sSet - sPeak[iM]) + pow2(mw[iM])) * intBW[iM]) + + fracFlat[iM] / intFlat[iM] + fracInv[iM] / (sSet * intInv[iM]) + + fracInv2[iM] / (sSet*sSet * intInv2[iM]); + + // Weight of distribution with running width in Breit-Wigner. + double mwRun = sSet * wmRat[iM]; + runBWH = mwRun / (pow2(sSet - sPeak[iM]) + pow2(mwRun)) / M_PI; + + // Done. + return (runBWH / genBW); + +} + +//************************************************************************** + +// PhaseSpace2to1tauy class. +// 2 -> 1 kinematics for normal subprocesses. + +//********* + +// Set limits for resonance mass selection. + +bool PhaseSpace2to1tauy::setupMass() { + + // Treat Z0 as such or as gamma*/Z0 + gmZmode = gmZmodeGlobal; + int gmZmodeProc = sigmaProcessPtr->gmZmode(); + if (gmZmodeProc >= 0) gmZmode = gmZmodeProc; + + // Mass limits for current resonance. + int idRes = abs(sigmaProcessPtr->resonanceA()); + int idTmp = abs(sigmaProcessPtr->resonanceB()); + if (idTmp > 0) idRes = idTmp; + double mResMin = (idRes == 0) ? 0. : ParticleDataTable::mMin(idRes); + double mResMax = (idRes == 0) ? 0. : ParticleDataTable::mMax(idRes); + + // Compare with global mass limits and pick tighter of them. + mHatMin = max( mResMin, mHatGlobalMin); + sHatMin = mHatMin*mHatMin; + mHatMax = eCM; + if (mResMax > mResMin) mHatMax = min( mHatMax, mResMax); + if (mHatGlobalMax > mHatGlobalMin) mHatMax = min( mHatMax, mHatGlobalMax); + sHatMax = mHatMax*mHatMax; + + // Default Breit-Wigner weight. + wtBW = 1.; + + // Fail if mass window (almost) closed. + return (mHatMax > mHatMin + MASSMARGIN); + +} + +//********* + +// Construct the four-vector kinematics from the trial values. + +bool PhaseSpace2to1tauy::finalKin() { + + // Particle masses; incoming always on mass shell. + mH[1] = 0.; + mH[2] = 0.; + mH[3] = mHat; + + // Incoming partons along beam axes. Outgoing has sum of momenta. + pH[1] = Vec4( 0., 0., 0.5 * eCM * x1H, 0.5 * eCM * x1H); + pH[2] = Vec4( 0., 0., -0.5 * eCM * x2H, 0.5 * eCM * x2H); + pH[3] = pH[1] + pH[2]; + + // Done. + return true; +} + +//************************************************************************** + +// PhaseSpace2to2tauyz class. +// 2 -> 2 kinematics for normal subprocesses. + +//********* + +// Set up for fixed or Breit-Wigner mass selection. + +bool PhaseSpace2to2tauyz::setupMasses() { + + // Treat Z0 as such or as gamma*/Z0 + gmZmode = gmZmodeGlobal; + int gmZmodeProc = sigmaProcessPtr->gmZmode(); + if (gmZmodeProc >= 0) gmZmode = gmZmodeProc; + + // Set sHat limits - based on global limits only. + mHatMin = mHatGlobalMin; + sHatMin = mHatMin*mHatMin; + mHatMax = eCM; + if (mHatGlobalMax > mHatGlobalMin) mHatMax = min( eCM, mHatGlobalMax); + sHatMax = mHatMax*mHatMax; + + // Masses and widths of resonances. + setupMass1(3); + setupMass1(4); + + // Reduced mass range when two massive particles. + if (useBW[3]) mUpper[3] -= (useBW[4]) ? mMin[4] : mPeak[4]; + if (useBW[4]) mUpper[4] -= (useBW[3]) ? mMin[3] : mPeak[3]; + + // If closed phase space then unallowed process. + bool physical = true; + if (useBW[3] && mUpper[3] < mLower[3] + MASSMARGIN) physical = false; + if (useBW[4] && mUpper[4] < mLower[4] + MASSMARGIN) physical = false; + if (!useBW[3] && !useBW[4] && mHatMax < mPeak[3] + mPeak[4] + MASSMARGIN) + physical = false; + if (!physical) return false; + + // If either particle is massless then need extra pTHat cut. + pTHatMin = pTHatGlobalMin; + if (mPeak[3] < pTHatMinDiverge || mPeak[4] < pTHatMinDiverge) + pTHatMin = max( pTHatMin, pTHatMinDiverge); + pT2HatMin = pTHatMin * pTHatMin; + pTHatMax = pTHatGlobalMax; + pT2HatMax = pTHatMax * pTHatMax; + + // Prepare to select m3 by BW + flat + 1/s_3. + if (useBW[3]) { + double distToThreshA = (mHatMax - mPeak[3] - mPeak[4]) * mWidth[3] + / (pow2(mWidth[3]) + pow2(mWidth[4])); + double distToThreshB = (mHatMax - mPeak[3] - mMin[4]) / mWidth[3]; + double distToThresh = min( distToThreshA, distToThreshB); + setupMass2(3, distToThresh); + } + + // Prepare to select m4 by BW + flat + 1/s_4. + if (useBW[4]) { + double distToThreshA = (mHatMax - mPeak[3] - mPeak[4]) * mWidth[4] + / (pow2(mWidth[3]) + pow2(mWidth[4])); + double distToThreshB = (mHatMax - mMin[3] - mPeak[4]) / mWidth[4]; + double distToThresh = min( distToThreshA, distToThreshB); + setupMass2(4, distToThresh); + } + + // Initialization masses. Special cases when constrained phase space. + m3 = (useBW[3]) ? min(mPeak[3], mUpper[3]) : mPeak[3]; + m4 = (useBW[4]) ? min(mPeak[4], mUpper[4]) : mPeak[4]; + if (m3 + m4 + THRESHOLDSIZE * (mWidth[3] + mWidth[4]) + MASSMARGIN + > mHatMax) { + if (useBW[3] && useBW[4]) physical = constrainedM3M4(); + else if (useBW[3]) physical = constrainedM3(); + else if (useBW[4]) physical = constrainedM4(); + } + s3 = m3*m3; + s4 = m4*m4; + + // Correct selected mass-spectrum to running-width Breit-Wigner. + // Extra safety margin for maximum search. + wtBW = 1.; + if (useBW[3]) wtBW *= weightMass(3) * EXTRABWWTMAX; + if (useBW[4]) wtBW *= weightMass(4) * EXTRABWWTMAX; + + // Done. + return physical; + +} + + +//********* + +// Select Breit-Wigner-distributed or fixed masses. + +bool PhaseSpace2to2tauyz::trialMasses() { + + // By default vanishing cross section. + sigmaNw = 0.; + wtBW = 1.; + + // Pick m3 and m4 independently. + trialMass(3); + trialMass(4); + + // If outside phase space then reject event. + if (m3 + m4 + MASSMARGIN > mHatMax) return false; + + // Correct selected mass-spectrum to running-width Breit-Wigner. + if (useBW[3]) wtBW *= weightMass(3); + if (useBW[4]) wtBW *= weightMass(4); + + // Done. + return true; +} + +//********* + +// Construct the four-vector kinematics from the trial values. + +bool PhaseSpace2to2tauyz::finalKin() { + + // Assign masses to particles assumed massless in matrix elements. + int id3 = sigmaProcessPtr->id(3); + int id4 = sigmaProcessPtr->id(4); + if (idMass[3] == 0) { m3 = ParticleDataTable::m0(id3); s3 = m3*m3; } + if (idMass[4] == 0) { m4 = ParticleDataTable::m0(id4); s4 = m4*m4; } + + // Sometimes swap tHat <-> uHat to reflect chosen final-state order. + if (sigmaProcessPtr->swappedTU()) { + swap(tH, uH); + z = -z; + } + + // Check that phase space still open after new mass assignment. + if (m3 + m4 + MASSMARGIN > mHat) { + infoPtr->errorMsg("Warning in PhaseSpace2to2tauyz::finalKin: " + "failed after mass assignment"); + return false; + } + p2Abs = 0.25 * (pow2(sH - s3 - s4) - 4. * s3 * s4) / sH; + pAbs = sqrtpos( p2Abs ); + + // Particle masses; incoming always on mass shell. + mH[1] = 0.; + mH[2] = 0.; + mH[3] = m3; + mH[4] = m4; + + // Incoming partons along beam axes. + pH[1] = Vec4( 0., 0., 0.5 * eCM * x1H, 0.5 * eCM * x1H); + pH[2] = Vec4( 0., 0., -0.5 * eCM * x2H, 0.5 * eCM * x2H); + + // Outgoing partons initially in collision CM frame along beam axes. + pH[3] = Vec4( 0., 0., pAbs, 0.5 * (sH + s3 - s4) / mHat); + pH[4] = Vec4( 0., 0., -pAbs, 0.5 * (sH + s4 - s3) / mHat); + + // Then rotate and boost them to overall CM frame + theta = acos(z); + phi = 2. * M_PI * Rndm::flat(); + betaZ = (x1H - x2H)/(x1H + x2H); + pH[3].rot( theta, phi); + pH[4].rot( theta, phi); + pH[3].bst( 0., 0., betaZ); + pH[4].bst( 0., 0., betaZ); + pTH = pAbs * sin(theta); + + // Done. + return true; +} + +//********* + +// Special choice of m3 and m4 when mHatMax push them off mass shell. +// Vary x in expression m3 + m4 = mHatMax - x * (Gamma3 + Gamma4). +// For each x try to put either 3 or 4 as close to mass shell as possible. +// Maximize BW_3 * BW_4 * beta_34, where latter approximate phase space. + +bool PhaseSpace2to2tauyz::constrainedM3M4() { + + // Initial values. + bool foundNonZero = false; + double wtMassMax = 0.; + double m3WtMax = 0.; + double m4WtMax = 0.; + double xMax = (mHatMax - mLower[3] - mLower[4]) / (mWidth[3] + mWidth[4]); + double xStep = THRESHOLDSTEP * min(1., xMax); + double xNow = 0.; + double wtMassXbin, wtMassMaxOld, m34, mT34Min, wtMassNow, + wtBW3Now, wtBW4Now, beta34Now; + + // Step through increasing x values. + do { + xNow += xStep; + wtMassXbin = 0.; + wtMassMaxOld = wtMassMax; + m34 = mHatMax - xNow * (mWidth[3] + mWidth[4]); + + // Study point where m3 as close as possible to on-shell. + m3 = min( mUpper[3], m34 - mLower[4]); + if (m3 > mPeak[3]) m3 = max( mLower[3], mPeak[3]); + m4 = m34 - m3; + if (m4 < mLower[4]) {m4 = mLower[4]; m3 = m34 - m4;} + + // Check that inside phase space limit set by pTmin. + mT34Min = sqrt(m3*m3 + pT2HatMin) + sqrt(m4*m4 + pT2HatMin); + if (mT34Min < mHatMax) { + + // Breit-Wigners and beta factor give total weight. + wtMassNow = 0.; + if (m3 > mLower[3] && m3 < mUpper[3] && m4 > mLower[4] + && m4 < mUpper[4]) { + wtBW3Now = mw[3] / ( pow2(m3*m3 - sPeak[3]) + pow2(mw[3]) ); + wtBW4Now = mw[4] / ( pow2(m4*m4 - sPeak[4]) + pow2(mw[4]) ); + beta34Now = sqrt( pow2(mHatMax*mHatMax - m3*m3 - m4*m4) + - pow2(2. * m3 * m4) ) / (mHatMax*mHatMax); + wtMassNow = wtBW3Now * wtBW4Now * beta34Now; + } + + // Store new maximum, if any. + if (wtMassNow > wtMassXbin) wtMassXbin = wtMassNow; + if (wtMassNow > wtMassMax) { + foundNonZero = true; + wtMassMax = wtMassNow; + m3WtMax = m3; + m4WtMax = m4; + } + } + + // Study point where m4 as close as possible to on-shell. + m4 = min( mUpper[4], m34 - mLower[3]); + if (m4 > mPeak[4]) m4 = max( mLower[4], mPeak[4]); + m3 = m34 - m4; + if (m3 < mLower[3]) {m3 = mLower[3]; m4 = m34 - m3;} + + // Check that inside phase space limit set by pTmin. + mT34Min = sqrt(m3*m3 + pT2HatMin) + sqrt(m4*m4 + pT2HatMin); + if (mT34Min < mHatMax) { + + // Breit-Wigners and beta factor give total weight. + wtMassNow = 0.; + if (m3 > mLower[3] && m3 < mUpper[3] && m4 > mLower[4] + && m4 < mUpper[4]) { + wtBW3Now = mw[3] / ( pow2(m3*m3 - sPeak[3]) + pow2(mw[3]) ); + wtBW4Now = mw[4] / ( pow2(m4*m4 - sPeak[4]) + pow2(mw[4]) ); + beta34Now = sqrt( pow2(mHatMax*mHatMax - m3*m3 - m4*m4) + - pow2(2. * m3 * m4) ) / (mHatMax*mHatMax); + wtMassNow = wtBW3Now * wtBW4Now * beta34Now; + } + + // Store new maximum, if any. + if (wtMassNow > wtMassXbin) wtMassXbin = wtMassNow; + if (wtMassNow > wtMassMax) { + foundNonZero = true; + wtMassMax = wtMassNow; + m3WtMax = m3; + m4WtMax = m4; + } + } + + // Continue stepping if increasing trend and more x range available. + } while ( (!foundNonZero || wtMassXbin > wtMassMaxOld) + && xNow < xMax - xStep); + + // Restore best values for subsequent maximization. Return. + m3 = m3WtMax; + m4 = m4WtMax; + return foundNonZero; + +} + +//********* + +// Special choice of m3 when mHatMax pushes it off mass shell. +// Vary x in expression m3 = mHatMax - m4 - x * Gamma3. +// Maximize BW_3 * beta_34, where latter approximate phase space. + +bool PhaseSpace2to2tauyz::constrainedM3() { + + // Initial values. + bool foundNonZero = false; + double wtMassMax = 0.; + double m3WtMax = 0.; + double mT4Min = sqrt(m4*m4 + pT2HatMin); + double xMax = (mHatMax - mLower[3] - m4) / mWidth[3]; + double xStep = THRESHOLDSTEP * min(1., xMax); + double xNow = 0.; + double wtMassNow, mT34Min, wtBW3Now, beta34Now; + + // Step through increasing x values; gives m3 unambiguously. + do { + xNow += xStep; + wtMassNow = 0.; + m3 = mHatMax - m4 - xNow * mWidth[3]; + + // Check that inside phase space limit set by pTmin. + mT34Min = sqrt(m3*m3 + pT2HatMin) + mT4Min; + if (mT34Min < mHatMax) { + + // Breit-Wigner and beta factor give total weight. + wtBW3Now = mw[3] / ( pow2(m3*m3 - sPeak[3]) + pow2(mw[3]) ); + beta34Now = sqrt( pow2(mHatMax*mHatMax - m3*m3 - m4*m4) + - pow2(2. * m3 * m4) ) / (mHatMax*mHatMax); + wtMassNow = wtBW3Now * beta34Now; + + // Store new maximum, if any. + if (wtMassNow > wtMassMax) { + foundNonZero = true; + wtMassMax = wtMassNow; + m3WtMax = m3; + } + } + + // Continue stepping if increasing trend and more x range available. + } while ( (!foundNonZero || wtMassNow > wtMassMax) + && xNow < xMax - xStep); + + // Restore best value for subsequent maximization. Return. + m3 = m3WtMax; + return foundNonZero; + +} + +//********* + +// Special choice of m4 when mHatMax pushes it off mass shell. +// Vary x in expression m4 = mHatMax - m3 - x * Gamma4. +// Maximize BW_4 * beta_34, where latter approximate phase space. + +bool PhaseSpace2to2tauyz::constrainedM4() { + + // Initial values. + bool foundNonZero = false; + double wtMassMax = 0.; + double m4WtMax = 0.; + double mT3Min = sqrt(m3*m3 + pT2HatMin); + double xMax = (mHatMax - mLower[4] - m3) / mWidth[4]; + double xStep = THRESHOLDSTEP * min(1., xMax); + double xNow = 0.; + double wtMassNow, mT34Min, wtBW4Now, beta34Now; + + // Step through increasing x values; gives m4 unambiguously. + do { + xNow += xStep; + wtMassNow = 0.; + m4 = mHatMax - m3 - xNow * mWidth[4]; + + // Check that inside phase space limit set by pTmin. + mT34Min = mT3Min + sqrt(m4*m4 + pT2HatMin); + if (mT34Min < mHatMax) { + + // Breit-Wigner and beta factor give total weight. + wtBW4Now = mw[4] / ( pow2(m4*m4 - sPeak[4]) + pow2(mw[4]) ); + beta34Now = sqrt( pow2(mHatMax*mHatMax - m3*m3 - m4*m4) + - pow2(2. * m3 * m4) ) / (mHatMax*mHatMax); + wtMassNow = wtBW4Now * beta34Now; + + // Store new maximum, if any. + if (wtMassNow > wtMassMax) { + foundNonZero = true; + wtMassMax = wtMassNow; + m4WtMax = m4; + } + } + + // Continue stepping if increasing trend and more x range available. + } while ( (!foundNonZero || wtMassNow > wtMassMax) + && xNow < xMax - xStep); + + // Restore best value for subsequent maximization. + m4 = m4WtMax; + return foundNonZero; + +} + +//************************************************************************** + +// PhaseSpace2to2elastic class. +// 2 -> 2 kinematics set up for elastic scattering. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Maximum positive/negative argument for exponentiation. +const double PhaseSpace2to2elastic::EXPMAX = 50.; + +// Conversion coefficients = 1/(16pi) * (mb <-> GeV^2). +const double PhaseSpace2to2elastic::CONVERTEL = 0.0510925; + +//********* + +// Form of phase space sampling already fixed, so no optimization. +// However, need to read out relevant parameters from SigmaTotal. + +bool PhaseSpace2to2elastic::setupSampling() { + + // Find maximum = value of cross section. + sigmaNw = sigmaProcessPtr->sigmaHatWrap(); + sigmaMx = sigmaNw; + + // Squared masses of particles. + s1 = mA * mA; + s2 = mB * mB; + + // Elastic slope. + bSlope = sigmaTotPtr->bSlopeEl(); + + // Determine maximum possible t range. + lambda12S = pow2(s - s1 - s2) - 4. * s1 * s2 ; + tLow = - lambda12S / s; + tUpp = 0; + + // Production model with Coulomb corrections need more parameters. + useCoulomb = Settings::flag("SigmaTotal:setOwn") + && Settings::flag("SigmaElastic:setOwn"); + if (useCoulomb) { + sigmaTot = sigmaTotPtr->sigmaTot(); + rho = Settings::parm("SigmaElastic:rho"); + lambda = Settings::parm("SigmaElastic:lambda"); + tAbsMin = Settings::parm("SigmaElastic:tAbsMin"); + phaseCst = Settings::parm("SigmaElastic:phaseConst"); + alphaEM0 = Settings::parm("StandardModel:alphaEM0"); + + // Relative rate of nuclear and Coulombic parts in trials. + tUpp = -tAbsMin; + sigmaNuc = CONVERTEL * pow2(sigmaTot) * (1. + rho*rho) / bSlope + * exp(-bSlope * tAbsMin); + sigmaCou = (useCoulomb) ? + pow2(alphaEM0) / (4. * CONVERTEL * tAbsMin) : 0.; + signCou = (idA == idB) ? 1. : -1.; + + // Dummy values. + } else { + sigmaNuc = sigmaNw; + sigmaCou = 0.; + } + + // Calculate coefficient of generation. + tAux = exp( max(-EXPMAX, bSlope * (tLow - tUpp)) ) - 1.; + + // Initialize alphaEM generation. + alphaEM.init( Settings::mode("SigmaProcess:alphaEMorder") ); + + return true; + +} + +//********* + +// Select a trial kinematics phase space point. Perform full +// Monte Carlo acceptance/rejection at this stage. + +bool PhaseSpace2to2elastic::trialKin( bool, bool ) { + + // Select t according to exp(bSlope*t). + if (!useCoulomb || sigmaNuc > Rndm::flat() * (sigmaNuc + sigmaCou)) + tH = tUpp + log(1. + tAux * Rndm::flat()) / bSlope; + + // Select t according to 1/t^2. + else tH = tLow * tUpp / (tUpp + Rndm::flat() * (tLow - tUpp)); + + // Correction factor for ratio full/simulated. + if (useCoulomb) { + double sigmaN = CONVERTEL * pow2(sigmaTot) * (1. + rho*rho) + * exp(bSlope * tH); + double alpEM = alphaEM.alphaEM(-tH); + double sigmaC = pow2(alpEM) / (4. * CONVERTEL * tH*tH); + double sigmaGen = 2. * (sigmaN + sigmaC); + double form2 = pow4(lambda/(lambda - tH)); + double phase = signCou * alpEM + * (-phaseCst - log(-0.5 * bSlope * tH)); + double sigmaCor = sigmaN + pow2(form2) * sigmaC + - signCou * alpEM * sigmaTot * (form2 / (-tH)) + * exp(0.5 * bSlope * tH) * (rho * cos(phase) + sin(phase)); + sigmaNw = sigmaMx * sigmaCor / sigmaGen; + } + + // Careful reconstruction of scattering angle. + double tRat = s * tH / lambda12S; + double cosTheta = min(1., max(-1., 1. + 2. * tRat ) ); + double sinTheta = 2. * sqrtpos( -tRat * (1. + tRat) ); + theta = asin( min(1., sinTheta)); + if (cosTheta < 0.) theta = M_PI - theta; + + return true; + +} + +//********* + +// Construct the four-vector kinematics from the trial values. + +bool PhaseSpace2to2elastic::finalKin() { + + // Particle masses. + mH[1] = mA; + mH[2] = mB; + mH[3] = m3; + mH[4] = m4; + + // Incoming particles along beam axes. + pAbs = 0.5 * sqrtpos(lambda12S) / eCM; + pH[1] = Vec4( 0., 0., pAbs, 0.5 * (s + s1 - s2) / eCM); + pH[2] = Vec4( 0., 0., -pAbs, 0.5 * (s + s2 - s1) / eCM); + + // Outgoing particles initially along beam axes. + pH[3] = Vec4( 0., 0., pAbs, 0.5 * (s + s1 - s2) / eCM); + pH[4] = Vec4( 0., 0., -pAbs, 0.5 * (s + s2 - s1) / eCM); + + // Then rotate them + phi = 2. * M_PI * Rndm::flat(); + pH[3].rot( theta, phi); + pH[4].rot( theta, phi); + + // Set some further info for completeness. + x1H = 1.; + x2H = 1.; + sH = s; + uH = 2. * (s1 + s2) - sH - tH; + mHat = eCM; + p2Abs = pAbs * pAbs; + betaZ = 0.; + pTH = pAbs * sin(theta); + + // Done. + return true; + +} + +//************************************************************************** + +// PhaseSpace2to2diffractive class. +// 2 -> 2 kinematics set up for diffractive scattering. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Number of tries to find acceptable (m^2, t) set. +const int PhaseSpace2to2diffractive::NTRY = 500; + +// Maximum positive/negative argument for exponentiation. +const double PhaseSpace2to2diffractive::EXPMAX = 50.; + +// Safety margin so sum of diffractive masses not too close to eCM. +const double PhaseSpace2to2diffractive::DIFFMASSMAX = 1e-8; + +//********* + +// Form of phase space sampling already fixed, so no optimization. +// However, need to read out relevant parameters from SigmaTotal. + +bool PhaseSpace2to2diffractive::setupSampling() { + + // Find maximum = value of cross section. + sigmaNw = sigmaProcessPtr->sigmaHatWrap(); + sigmaMx = sigmaNw; + + // Masses of particles and minimal masses of diffractive states. + m3ElDiff = (isDiffA) ? sigmaTotPtr->mMinXB() : mA; + m4ElDiff = (isDiffB) ? sigmaTotPtr->mMinAX() : mB; + s1 = mA * mA; + s2 = mB * mB; + s3 = pow2( m3ElDiff); + s4 = pow2( m4ElDiff); + + // Parameters of low-mass-resonance diffractive enhancement. + cRes = sigmaTotPtr->cRes(); + sResXB = pow2( sigmaTotPtr->mResXB()); + sResAX = pow2( sigmaTotPtr->mResAX()); + sProton = sigmaTotPtr->sProton(); + + // Lower limit diffractive slope. + if (!isDiffB) bMin = sigmaTotPtr->bMinSlopeXB(); + else if (!isDiffA) bMin = sigmaTotPtr->bMinSlopeAX(); + else bMin = sigmaTotPtr->bMinSlopeXX(); + + // Determine maximum possible t range and coefficient of generation. + lambda12 = sqrtpos( pow2( s - s1 - s2) - 4. * s1 * s2 ); + lambda34 = sqrtpos( pow2( s - s3 - s4) - 4. * s3 * s4 ); + double tempA = s - (s1 + s2 + s3 + s4) + (s1 - s2) * (s3 - s4) / s; + double tempB = lambda12 * lambda34 / s; + double tempC = (s3 - s1) * (s4 - s2) + (s1 + s4 - s2 - s3) + * (s1 * s4 - s2 * s3) / s; + tLow = -0.5 * (tempA + tempB); + tUpp = tempC / tLow; + tAux = exp( max(-EXPMAX, bMin * (tLow - tUpp)) ) - 1.; + + return true; + +} + +//********* + +// Select a trial kinematics phase space point. Perform full +// Monte Carlo acceptance/rejection at this stage. + +bool PhaseSpace2to2diffractive::trialKin( bool, bool ) { + + // Loop over attempts to set up masses and t consistently. + for (int loop = 0; ; ++loop) { + if (loop == NTRY) { + infoPtr->errorMsg("Error in PhaseSpace2to2diffractive::trialKin: " + " quit after repeated tries"); + return false; + } + + // Select diffractive mass/masses according to dm^2/m^2. + m3 = (isDiffA) ? m3ElDiff * pow( max(mA, eCM - m4ElDiff) / m3ElDiff, + Rndm::flat()) : m3ElDiff; + m4 = (isDiffB) ? m4ElDiff * pow( max(mB, eCM - m3ElDiff) / m4ElDiff, + Rndm::flat()) : m4ElDiff; + s3 = m3 * m3; + s4 = m4 * m4; + + // Additional mass factors, including resonance enhancement. + if (m3 + m4 >= eCM) continue; + if (isDiffA && !isDiffB) { + double facXB = (1. - s3 / s) + * (1. + cRes * sResXB / (sResXB + s3)); + if (facXB < Rndm::flat() * (1. + cRes)) continue; + } else if (isDiffB && !isDiffA) { + double facAX = (1. - s4 / s) + * (1. + cRes * sResAX / (sResAX + s4)); + if (facAX < Rndm::flat() * (1. + cRes)) continue; + } else { + double facXX = (1. - pow2(m3 + m4) / s) + * (s * sProton / (s * sProton + s3 * s4)) + * (1. + cRes * sResXB / (sResXB + s3)) + * (1. + cRes * sResAX / (sResAX + s4)); + if (facXX < Rndm::flat() * pow2(1. + cRes)) continue; + } + + // Select t according to exp(bMin*t) and correct to right slope. + tH = tUpp + log(1. + tAux * Rndm::flat()) / bMin; + double bDiff = 0.; + if (isDiffA && !isDiffB) bDiff = sigmaTotPtr->bSlopeXB(s3) - bMin; + else if (!isDiffA) bDiff = sigmaTotPtr->bSlopeAX(s4) - bMin; + else bDiff = sigmaTotPtr->bSlopeXX(s3, s4) - bMin; + bDiff = max(0., bDiff); + if (exp( max(-50., bDiff * (tH - tUpp)) ) < Rndm::flat()) continue; + + // Check whether m^2 and t choices are consistent. + lambda34 = sqrtpos( pow2( s - s3 - s4) - 4. * s3 * s4 ); + double tempA = s - (s1 + s2 + s3 + s4) + (s1 - s2) * (s3 - s4) / s; + double tempB = lambda12 * lambda34 / s; + if (tempB < DIFFMASSMAX) continue; + double tempC = (s3 - s1) * (s4 - s2) + (s1 + s4 - s2 - s3) + * (s1 * s4 - s2 * s3) / s; + double tLowNow = -0.5 * (tempA + tempB); + double tUppNow = tempC / tLowNow; + if (tH < tLowNow || tH > tUppNow) continue; + + // Careful reconstruction of scattering angle. + double cosTheta = min(1., max(-1., (tempA + 2. * tH) / tempB)); + double sinTheta = 2. * sqrtpos( -(tempC + tempA * tH + tH * tH) ) + / tempB; + theta = asin( min(1., sinTheta)); + if (cosTheta < 0.) theta = M_PI - theta; + + // Found acceptable kinematics, so no more looping. + break; + } + + return true; + +} + +//********* + +// Construct the four-vector kinematics from the trial values. + +bool PhaseSpace2to2diffractive::finalKin() { + + // Particle masses; incoming always on mass shell. + mH[1] = mA; + mH[2] = mB; + mH[3] = m3; + mH[4] = m4; + + // Incoming particles along beam axes. + pAbs = 0.5 * lambda12 / eCM; + pH[1] = Vec4( 0., 0., pAbs, 0.5 * (s + s1 - s2) / eCM); + pH[2] = Vec4( 0., 0., -pAbs, 0.5 * (s + s2 - s1) / eCM); + + // Outgoing particles initially along beam axes. + pAbs = 0.5 * lambda34 / eCM; + pH[3] = Vec4( 0., 0., pAbs, 0.5 * (s + s3 - s4) / eCM); + pH[4] = Vec4( 0., 0., -pAbs, 0.5 * (s + s4 - s3) / eCM); + + // Then rotate them + phi = 2. * M_PI * Rndm::flat(); + pH[3].rot( theta, phi); + pH[4].rot( theta, phi); + + // Set some further info for completeness. + x1H = 1.; + x2H = 1.; + sH = s; + uH = s1 + s2 + s3 + s4 - sH - tH; + mHat = eCM; + p2Abs = pAbs * pAbs; + betaZ = 0.; + pTH = pAbs * sin(theta); + + // Done. + return true; + +} + +//************************************************************************** + +// PhaseSpace2to3tauycyl class. +// 2 -> 3 kinematics for normal subprocesses. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Number of Newton-Raphson iterations of kinematics when masses introduced. +const int PhaseSpace2to3tauycyl::NITERNR = 5; + +//********* + +// Set up for fixed or Breit-Wigner mass selection. + +bool PhaseSpace2to3tauycyl::setupMasses() { + + // Treat Z0 as such or as gamma*/Z0 + gmZmode = gmZmodeGlobal; + int gmZmodeProc = sigmaProcessPtr->gmZmode(); + if (gmZmodeProc >= 0) gmZmode = gmZmodeProc; + + // Set sHat limits - based on global limits only. + mHatMin = mHatGlobalMin; + sHatMin = mHatMin*mHatMin; + mHatMax = eCM; + if (mHatGlobalMax > mHatGlobalMin) mHatMax = min( eCM, mHatGlobalMax); + sHatMax = mHatMax*mHatMax; + + // Masses and widths of resonances. + setupMass1(3); + setupMass1(4); + setupMass1(5); + + // Reduced mass range - do not make it as fancy as in two-body case. + if (useBW[3]) mUpper[3] -= (mPeak[4] + mPeak[5]); + if (useBW[4]) mUpper[4] -= (mPeak[3] + mPeak[5]); + if (useBW[5]) mUpper[5] -= (mPeak[3] + mPeak[4]); + + // If closed phase space then unallowed process. + bool physical = true; + if (useBW[3] && mUpper[3] < mLower[3] + MASSMARGIN) physical = false; + if (useBW[4] && mUpper[4] < mLower[4] + MASSMARGIN) physical = false; + if (useBW[5] && mUpper[5] < mLower[5] + MASSMARGIN) physical = false; + if (!useBW[3] && !useBW[4] && !useBW[5] && mHatMax < mPeak[3] + + mPeak[4] + mPeak[5] + MASSMARGIN) physical = false; + if (!physical) return false; + + // No extra pT precautions in massless limit - assumed fixed by ME's. + pTHatMin = pTHatGlobalMin; + pT2HatMin = pTHatMin * pTHatMin; + pTHatMax = pTHatGlobalMax; + pT2HatMax = pTHatMax * pTHatMax; + + // Prepare to select m3 by BW + flat + 1/s_3. + if (useBW[3]) { + double distToThreshA = (mHatMax - mPeak[3] - mPeak[4] - mPeak[5]) + * mWidth[3] / (pow2(mWidth[3]) + pow2(mWidth[4]) + pow2(mWidth[5])); + double distToThreshB = (mHatMax - mPeak[3] - mMin[4] - mMin[5]) + / mWidth[3]; + double distToThresh = min( distToThreshA, distToThreshB); + setupMass2(3, distToThresh); + } + + // Prepare to select m4 by BW + flat + 1/s_3. + if (useBW[4]) { + double distToThreshA = (mHatMax - mPeak[3] - mPeak[4] - mPeak[5]) + * mWidth[4] / (pow2(mWidth[3]) + pow2(mWidth[4]) + pow2(mWidth[5])); + double distToThreshB = (mHatMax - mPeak[4] - mMin[3] - mMin[5]) + / mWidth[4]; + double distToThresh = min( distToThreshA, distToThreshB); + setupMass2(4, distToThresh); + } + + // Prepare to select m5 by BW + flat + 1/s_3. + if (useBW[5]) { + double distToThreshA = (mHatMax - mPeak[3] - mPeak[4] - mPeak[5]) + * mWidth[5] / (pow2(mWidth[3]) + pow2(mWidth[4]) + pow2(mWidth[5])); + double distToThreshB = (mHatMax - mPeak[5] - mMin[3] - mMin[4]) + / mWidth[5]; + double distToThresh = min( distToThreshA, distToThreshB); + setupMass2(5, distToThresh); + } + + // Initialization masses. For now give up when constrained phase space. + m3 = (useBW[3]) ? min(mPeak[3], mUpper[3]) : mPeak[3]; + m4 = (useBW[4]) ? min(mPeak[4], mUpper[4]) : mPeak[4]; + m5 = (useBW[5]) ? min(mPeak[5], mUpper[5]) : mPeak[5]; + if (m3 + m4 + m5 + MASSMARGIN > mHatMax) physical = false; + s3 = m3*m3; + s4 = m4*m4; + s5 = m5*m5; + + // Correct selected mass-spectrum to running-width Breit-Wigner. + // Extra safety margin for maximum search. + wtBW = 1.; + if (useBW[3]) wtBW *= weightMass(3) * EXTRABWWTMAX; + if (useBW[4]) wtBW *= weightMass(4) * EXTRABWWTMAX; + if (useBW[5]) wtBW *= weightMass(5) * EXTRABWWTMAX; + + // Done. + return physical; + +} + +//********* + +// Select Breit-Wigner-distributed or fixed masses. + +bool PhaseSpace2to3tauycyl::trialMasses() { + + // By default vanishing cross section. + sigmaNw = 0.; + wtBW = 1.; + + // Pick m3, m4 and m5 independently. + trialMass(3); + trialMass(4); + trialMass(5); + + // If outside phase space then reject event. + if (m3 + m4 + m5 + MASSMARGIN > mHatMax) return false; + + // Correct selected mass-spectrum to running-width Breit-Wigner. + if (useBW[3]) wtBW *= weightMass(3); + if (useBW[4]) wtBW *= weightMass(4); + if (useBW[5]) wtBW *= weightMass(5); + + // Done. + return true; + +} + +//********* + +// Construct the four-vector kinematics from the trial values. + +bool PhaseSpace2to3tauycyl::finalKin() { + + // Assign masses to particles assumed massless in matrix elements. + int id3 = sigmaProcessPtr->id(3); + int id4 = sigmaProcessPtr->id(4); + int id5 = sigmaProcessPtr->id(5); + if (idMass[3] == 0) { m3 = ParticleDataTable::m0(id3); s3 = m3*m3; } + if (idMass[4] == 0) { m4 = ParticleDataTable::m0(id4); s4 = m4*m4; } + if (idMass[5] == 0) { m5 = ParticleDataTable::m0(id5); s5 = m5*m5; } + + // Check that phase space still open after new mass assignment. + if (m3 + m4 + m5 + MASSMARGIN > mHat) { + infoPtr->errorMsg("Warning in PhaseSpace2to3tauycyl::finalKin: " + "failed after mass assignment"); + return false; + } + + // Particle masses; incoming always on mass shell. + mH[1] = 0.; + mH[2] = 0.; + mH[3] = m3; + mH[4] = m4; + mH[5] = m5; + + // Incoming partons along beam axes. + pH[1] = Vec4( 0., 0., 0.5 * eCM * x1H, 0.5 * eCM * x1H); + pH[2] = Vec4( 0., 0., -0.5 * eCM * x2H, 0.5 * eCM * x2H); + + // Begin three-momentum rescaling to compensate for masses. + if (idMass[3] == 0 || idMass[4] == 0 || idMass[5] == 0) { + double p3S = p3cm.pAbs2(); + double p4S = p4cm.pAbs2(); + double p5S = p5cm.pAbs2(); + double fac = 1.; + double e3, e4, e5, value, deriv; + + // Iterate rescaling solution five times, using Newton-Raphson. + for (int i = 0; i < NITERNR; ++i) { + e3 = sqrt(s3 + fac * p3S); + e4 = sqrt(s4 + fac * p4S); + e5 = sqrt(s5 + fac * p5S); + value = e3 + e4 + e5 - mHat; + deriv = 0.5 * (p3S / e3 + p4S / e4 + p5S / e5); + fac -= value / deriv; + } + + // Rescale momenta appropriately. + double facRoot = sqrt(fac); + p3cm.rescale3( facRoot ); + p4cm.rescale3( facRoot ); + p5cm.rescale3( facRoot ); + p3cm.e( sqrt(s3 + fac * p3S) ); + p4cm.e( sqrt(s4 + fac * p4S) ); + p5cm.e( sqrt(s5 + fac * p5S) ); + } + + // Outgoing partons initially in collision CM frame along beam axes. + pH[3] = p3cm; + pH[4] = p4cm; + pH[5] = p5cm; + + // Then boost them to overall CM frame + betaZ = (x1H - x2H)/(x1H + x2H); + pH[3].rot( theta, phi); + pH[4].rot( theta, phi); + pH[3].bst( 0., 0., betaZ); + pH[4].bst( 0., 0., betaZ); + pH[5].bst( 0., 0., betaZ); + + // Store average pT of three final particles for documentation. + pTH = (p3cm.pT() + p4cm.pT() + p5cm.pT()) / 3.; + + // Done. + return true; +} + +//************************************************************************** + +// The PhaseSpaceLHA class. +// A derived class for Les Houches events. +// Note: arbitrary subdivision into PhaseSpaceLHA and SigmaLHAProcess tasks. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// LHA convention with cross section in pb forces conversion to mb. +const double PhaseSpaceLHA::CONVERTPB2MB = 1e-9; + +//********* + +// Find maximal cross section for comparison with internal processes. + +bool PhaseSpaceLHA::setupSampling() { + + // Find which strategy Les Houches events are produced with. + strategy = lhaUpPtr->strategy(); + stratAbs = abs(strategy); + if (strategy == 0 || stratAbs > 4) { + ostringstream stratCode; + stratCode << strategy; + infoPtr->errorMsg("Error in PhaseSpaceLHA::setupSampling: unknown " + "Les Houches Accord weighting stategy", stratCode.str()); + return false; + } + + // Number of contributing processes. + nProc = lhaUpPtr->sizeProc(); + + // Loop over all processes. Read out maximum and cross section. + xMaxAbsSum = 0.; + xSecSgnSum = 0.; + int idPr; + double xMax, xSec, xMaxAbs; + for (int iProc = 0 ; iProc < nProc; ++iProc) { + idPr = lhaUpPtr->idProcess(iProc); + xMax = lhaUpPtr->xMax(iProc); + xSec = lhaUpPtr->xSec(iProc); + + // Check for inconsistencies between strategy and stored values. + if ( (strategy == 1 || strategy == 2) && xMax < 0.) { + infoPtr->errorMsg("Error in PhaseSpaceLHA::setupSampling: " + "negative maximum not allowed"); + return false; + } + if ( ( strategy == 2 || strategy == 3) && xSec < 0.) { + infoPtr->errorMsg("Error in PhaseSpaceLHA::setupSampling: " + "negative cross section not allowed"); + return false; + } + + // Store maximal cross sections for later choice. + if (stratAbs == 1) xMaxAbs = abs(xMax); + else if (stratAbs < 4) xMaxAbs = abs(xSec); + else xMaxAbs = 1.; + idProc.push_back( idPr ); + xMaxAbsProc.push_back( xMaxAbs ); + + // Find sum and convert to mb. + xMaxAbsSum += xMaxAbs; + xSecSgnSum += xSec; + } + sigmaMx = xMaxAbsSum * CONVERTPB2MB; + sigmaSgn = xSecSgnSum * CONVERTPB2MB; + + // Done. + return true; + +} + +//********* + +// Construct the next process, by interface to Les Houches class. + +bool PhaseSpaceLHA::trialKin( bool, bool repeatSame ) { + + // Must select process type in some cases. + int idProcNow = 0; + if (repeatSame) idProcNow = idProcSave; + else if (stratAbs <= 2) { + double xMaxAbsRndm = xMaxAbsSum * Rndm::flat(); + int iProc = -1; + do xMaxAbsRndm -= xMaxAbsProc[++iProc]; + while (xMaxAbsRndm > 0. && iProc < nProc - 1); + idProcNow = idProc[iProc]; + } + + // Generate Les Houches event. Return if fail (= end of file). + bool physical = lhaUpPtr->setEvent(idProcNow); + if (!physical) return false; + + // Find which process was generated. + int idPr = lhaUpPtr->idProcess(); + int iProc = 0; + for (int iP = 0; iP < int(idProc.size()); ++iP) + if (idProc[iP] == idPr) iProc = iP; + idProcSave = idPr; + + // Extract cross section and rescale according to strategy. + double wtPr = lhaUpPtr->weight(); + if (stratAbs == 1) sigmaNw = wtPr * CONVERTPB2MB + * xMaxAbsSum / xMaxAbsProc[iProc]; + else if (stratAbs == 2) sigmaNw = (wtPr / abs(lhaUpPtr->xMax(iProc))) + * sigmaMx; + else if (strategy == 3) sigmaNw = sigmaMx; + else if (strategy == -3 && wtPr > 0.) sigmaNw = sigmaMx; + else if (strategy == -3) sigmaNw = -sigmaMx; + else if (stratAbs == 4) sigmaNw = wtPr * CONVERTPB2MB; + + // Done. + return true; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/ProcessContainer.cxx b/PYTHIA8/pythia8130/src/ProcessContainer.cxx new file mode 100644 index 00000000000..d0ab1cd25bf --- /dev/null +++ b/PYTHIA8/pythia8130/src/ProcessContainer.cxx @@ -0,0 +1,1622 @@ +// ProcessContainer.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// ProcessContainer and SetupContainers classes. + +#include "ProcessContainer.h" + +// Internal headers for special processes. +#include "SigmaCompositeness.h" +#include "SigmaEW.h" +#include "SigmaExtraDim.h" +#include "SigmaHiggs.h" +#include "SigmaLeftRightSym.h" +#include "SigmaLeptoquark.h" +#include "SigmaNewGaugeBosons.h" +#include "SigmaOnia.h" +#include "SigmaQCD.h" +#include "SigmaSUSY.h" + +namespace Pythia8 { + +//************************************************************************** + +// ProcessContainer class. +// Information allowing the generation of a specific process. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Number of event tries to check maximization finding reliability. +const int ProcessContainer::N12SAMPLE = 100; + +// Ditto, but increased for 2 -> 3 processes. +const int ProcessContainer::N3SAMPLE = 1000; + +//********* + +// Initialize phase space and counters. + +bool ProcessContainer::init(Info* infoPtrIn, BeamParticle* beamAPtr, + BeamParticle* beamBPtr, AlphaStrong* alphaSPtr, AlphaEM* alphaEMPtr, + SigmaTotal* sigmaTotPtr, ResonanceDecays* resDecaysPtrIn, + SusyLesHouches* slhaPtr, UserHooks* userHooksPtr) { + + // Extract info about current process from SigmaProcess object. + isLHA = sigmaProcessPtr->isLHA(); + isMinBias = sigmaProcessPtr->isMinBias(); + isResolved = sigmaProcessPtr->isResolved(); + isDiffA = sigmaProcessPtr->isDiffA(); + isDiffB = sigmaProcessPtr->isDiffB(); + int nFin = sigmaProcessPtr->nFinal(); + lhaStrat = (isLHA) ? lhaUpPtr->strategy() : 0; + lhaStratAbs = abs(lhaStrat); + allowNegSig = sigmaProcessPtr->allowNegativeSigma(); + + // Pick and create phase space generator. Send pointers where required. + if (isLHA) phaseSpacePtr = new PhaseSpaceLHA(); + else if (isMinBias) phaseSpacePtr = new PhaseSpace2to2minbias(); + else if (!isResolved && !isDiffA && !isDiffB ) + phaseSpacePtr = new PhaseSpace2to2elastic(); + else if (!isResolved) phaseSpacePtr = new PhaseSpace2to2diffractive( + isDiffA, isDiffB); + else if (nFin == 1) phaseSpacePtr = new PhaseSpace2to1tauy(); + else if (nFin == 2) phaseSpacePtr = new PhaseSpace2to2tauyz(); + else phaseSpacePtr = new PhaseSpace2to3tauycyl(); + + // Store pointers and perform simple initialization. + infoPtr = infoPtrIn; + resDecaysPtr = resDecaysPtrIn; + if (isLHA) { + sigmaProcessPtr->setLHAPtr(lhaUpPtr); + phaseSpacePtr->setLHAPtr(lhaUpPtr); + } + sigmaProcessPtr->init(infoPtr, beamAPtr, beamBPtr, alphaSPtr, + alphaEMPtr, sigmaTotPtr, slhaPtr); + phaseSpacePtr->init( sigmaProcessPtr, infoPtr, beamAPtr, + beamBPtr, sigmaTotPtr, userHooksPtr); + + // Reset cross section statistics. + nTry = 0; + nSel = 0; + nAcc = 0; + nTryStat = 0; + sigmaMx = 0.; + sigmaSum = 0.; + sigma2Sum = 0.; + sigmaNeg = 0.; + sigmaAvg = 0.; + sigmaFin = 0.; + deltaFin = 0.; + + // Initialize process and allowed incoming partons. + sigmaProcessPtr->initProc(); + if (!sigmaProcessPtr->initFlux()) return false; + + // Find maximum of differential cross section * phasespace. + bool physical = phaseSpacePtr->setupSampling(); + sigmaMx = phaseSpacePtr->sigmaMax(); + double sigmaHalfWay = sigmaMx; + + // Separate signed maximum needed for LHA with negative weight. + sigmaSgn = phaseSpacePtr->sigmaSumSigned(); + + // Check maximum by a few events, and extrapolate a further increase. + if (physical & !isLHA) { + int nSample = (nFin < 3) ? N12SAMPLE : N3SAMPLE; + for (int iSample = 0; iSample < nSample; ++iSample) + while (!phaseSpacePtr->trialKin(false)) { + if (iSample == nSample/2) sigmaHalfWay = phaseSpacePtr->sigmaMax(); + } + sigmaMx = pow2(phaseSpacePtr->sigmaMax()) / sigmaHalfWay; + phaseSpacePtr->setSigmaMax(sigmaMx); + } + + // Done. + return physical; +} + +//********* + +// Generate a trial event; selected or not. + +bool ProcessContainer::trialProcess() { + + // Loop over tries only occurs for Les Houches strategy = +-2. + for (int iTry = 0; ; ++iTry) { + + // Generate a trial phase space point, if meaningful. + if (sigmaMx == 0.) return false; + infoPtr->setEndOfFile(false); + bool repeatSame = (iTry > 0); + bool physical = phaseSpacePtr->trialKin(true, repeatSame); + + // Possibly fail, e.g. if at end of Les Houches file, else cross section. + if (isLHA && !physical) infoPtr->setEndOfFile(true); + else ++nTry; + if (!physical) return false; + double sigmaNow = phaseSpacePtr->sigmaNow(); + + // Tell if this event comes with negative weight, or weight at all. + double weight = 1.; + if ( lhaStrat < 0 && sigmaNow < 0.) weight = -1.; + if ( lhaStratAbs == 4) weight = sigmaNow; + infoPtr->setWeight( weight); + + // Check that not negative cross section when not allowed. + if (!allowNegSig) { + if (sigmaNow < sigmaNeg) { + infoPtr->errorMsg("Warning in ProcessContainer::trialProcess: neg" + "ative cross section set 0", "for " + sigmaProcessPtr->name() ); + sigmaNeg = sigmaNow; + } + if (sigmaNow < 0.) sigmaNow = 0.; + } + + // Update statistics. Check if maximum violated. + double sigmaAdd = sigmaNow; + if (lhaStratAbs == 2 || lhaStratAbs == 3) sigmaAdd = sigmaSgn; + sigmaSum += sigmaAdd; + sigma2Sum += pow2(sigmaAdd); + newSigmaMx = phaseSpacePtr->newSigmaMax(); + if (newSigmaMx) sigmaMx = phaseSpacePtr->sigmaMax(); + + // Select or reject trial point. + bool select = true; + if (lhaStratAbs < 3) select + = (newSigmaMx || Rndm::flat() * abs(sigmaMx) < abs(sigmaNow)); + if (select) ++nSel; + if (select || lhaStratAbs !=2) return select; + } + +} + +//********* + +// Give the hard subprocess. + +bool ProcessContainer::constructProcess( Event& process, bool isHardest) { + + // Construct flavour and colours for selected event. + if (isResolved && !isMinBias) sigmaProcessPtr->pickInState(); + sigmaProcessPtr->setIdColAcol(); + + // Construct kinematics from selected phase space point. + if (!phaseSpacePtr->finalKin()) return false; + int nFin = sigmaProcessPtr->nFinal(); + + // Basic info on process. + if (isHardest) infoPtr->setType( name(), code(), nFin, isMinBias, + isResolved, isDiffA, isDiffB, isLHA); + + // Let hard process record begin with the event as a whole and + // the two incoming beam particles. + process.append( 90, -11, 0, 0, 0, 0, 0, 0, + Vec4(0., 0., 0., infoPtr->eCM()), infoPtr->eCM(), 0. ); + process.append( infoPtr->idA(), -12, 0, 0, 3, 0, 0, 0, + Vec4(0., 0., infoPtr->pzA(), infoPtr->eA()), infoPtr->mA(), 0. ); + process.append( infoPtr->idB(), -12, 0, 0, 4, 0, 0, 0, + Vec4(0., 0., infoPtr->pzB(), infoPtr->eB()), infoPtr->mB(), 0. ); + + // For minbias process no interaction selected so far, so done. + if (isMinBias) return true; + double scale = 0.; + + // Insert the subprocess partons - resolved processes. + if (isResolved && !isLHA) { + + // Find scale from which to begin MI/ISR/FSR evolution. + scale = sqrt(Q2Fac()); + process.scale( scale ); + + // Loop over incoming and outgoing partons. + int colOffset = process.lastColTag(); + for (int i = 1; i <= 2 + nFin; ++i) { + + // Read out particle info from SigmaProcess object. + int id = sigmaProcessPtr->id(i); + int status = (i <= 2) ? -21 : 23; + int mother1 = (i <= 2) ? i : 3; + int mother2 = (i <= 2) ? 0 : 4; + int daughter1 = (i <= 2) ? 5 : 0; + int daughter2 = (i <= 2) ? 4 + nFin : 0; + int col = sigmaProcessPtr->col(i); + if (col > 0) col += colOffset; + int acol = sigmaProcessPtr->acol(i); + if (acol > 0) acol += colOffset; + + // Append to process record. + int iNow = process.append( id, status, mother1, mother2, + daughter1, daughter2, col, acol, phaseSpacePtr->p(i), + phaseSpacePtr->m(i), scale); + + // Pick lifetime where relevant, else not. + if (process[iNow].tau0() > 0.) process[iNow].tau( + process[iNow].tau0() * Rndm::exp() ); + } + } + + // Insert the outgoing particles - unresolved processes. + else if (!isLHA) { + process.append( sigmaProcessPtr->id(3), 23, 1, 0, 0, 0, 0, 0, + phaseSpacePtr->p(3), phaseSpacePtr->m(3)); + process.append( sigmaProcessPtr->id(4), 23, 2, 0, 0, 0, 0, 0, + phaseSpacePtr->p(4), phaseSpacePtr->m(4)); + } + + // Insert the outgoing particles - Les Houches Accord processes. + else { + + // Since LHA partons may be out of order, determine correct one. + // (Recall that zeroth particle is empty.) + vector newPos; + newPos.reserve(lhaUpPtr->sizePart()); + newPos.push_back(0); + for (int iNew = 0; iNew < lhaUpPtr->sizePart(); ++iNew) { + // For iNew == 0 look for the two incoming partons, then for + // partons having them as mothers, and so on layer by layer. + for (int i = 1; i < lhaUpPtr->sizePart(); ++i) + if (lhaUpPtr->mother1(i) == newPos[iNew]) newPos.push_back(i); + if (int(newPos.size()) <= iNew) break; + } + + // Find scale from which to begin MI/ISR/FSR evolution. + scale = lhaUpPtr->scale(); + process.scale( scale); + + // Copy over info from LHA event to process, in proper order. + for (int i = 1; i < lhaUpPtr->sizePart(); ++i) { + int iOld = newPos[i]; + int id = lhaUpPtr->id(iOld); + + // Translate from LHA status codes. + int lhaStatus = lhaUpPtr->status(iOld); + int status = -21; + if (lhaStatus == 2 || lhaStatus == 3) status = -22; + if (lhaStatus == 1) status = 23; + + // Find where mothers have been moved by reordering. + int mother1Old = lhaUpPtr->mother1(iOld); + int mother2Old = lhaUpPtr->mother2(iOld); + int mother1 = 0; + int mother2 = 0; + for (int im = 1; im < i; ++im) { + if (mother1Old == newPos[im]) mother1 = im + 2; + if (mother2Old == newPos[im]) mother2 = im + 2; + } + if (i <= 2) mother1 = i; + + // Ensure that second mother = 0 except for bona fide carbon copies. + if (mother1 > 0 && mother2 == mother1) { + int sister1 = process[mother1].daughter1(); + int sister2 = process[mother1].daughter2(); + if (sister2 != sister1 && sister2 != 0) mother2 = 0; + } + + // Find daughters and where they have been moved by reordering. + // (Values shifted two steps to account for inserted beams.) + int daughter1 = 0; + int daughter2 = 0; + for (int im = i + 1; im < lhaUpPtr->sizePart(); ++im) { + if (lhaUpPtr->mother1(newPos[im]) == iOld + || lhaUpPtr->mother2(newPos[im]) == iOld) { + if (daughter1 == 0 || im + 2 < daughter1) daughter1 = im + 2; + if (daughter2 == 0 || im + 2 > daughter2) daughter2 = im + 2; + } + } + // For 2 -> 1 hard scatterings reset second daughter to 0. + if (daughter2 == daughter1) daughter2 = 0; + + // Colour trivial, except reset irrelevant colour indices. + int colType = ParticleDataTable::colType(id); + int col1 = (colType == 1 || colType == 2) + ? lhaUpPtr->col1(iOld) : 0; + int col2 = (colType == -1 || colType == 2) + ? lhaUpPtr->col2(iOld) : 0; + + // Momentum trivial. + double px = lhaUpPtr->px(iOld); + double py = lhaUpPtr->py(iOld); + double pz = lhaUpPtr->pz(iOld); + double e = lhaUpPtr->e(iOld); + double m = lhaUpPtr->m(iOld); + + // For resonance decay products use resonance mass as scale. + double scaleNow = scale; + if (mother1 > 4) scaleNow = process[mother1].m(); + + // Store Les Houches Accord partons. + int iNow = process.append( id, status, mother1, mother2, daughter1, + daughter2, col1, col2, Vec4(px, py, pz, e), m, scaleNow); + + // Check if need to store lifetime. + double tau = lhaUpPtr->tau(iOld); + if (tau > 0.) process[iNow].tau(tau); + } + } + + // Loop through decay chains and set secondary vertices when needed. + for (int i = 3; i < process.size(); ++i) { + int iMother = process[i].mother1(); + + // If sister to already assigned vertex then assign same. + if ( process[i - 1].mother1() == iMother && process[i - 1].hasVertex() ) + process[i].vProd( process[i - 1].vProd() ); + + // Else if mother already has vertex and/or lifetime then assign. + else if ( process[iMother].hasVertex() || process[iMother].tau() > 0.) + process[i].vProd( process[iMother].vDec() ); + } + + // Further info on process. Reset quantities that may or may not be known. + int id1Now = process[3].id(); + int id2Now = process[4].id(); + double pdf1 = 0.; + double pdf2 = 0.; + double tHat = 0.; + double uHat = 0.; + double pTHat = 0.; + double m3 = 0.; + double m4 = 0.; + double theta = 0.; + double phi = 0.; + double Q2FacNow, alphaEM, alphaS, Q2Ren, x1Now, x2Now, sHat; + + // Internally generated and stored information. + if (!isLHA) { + pdf1 = sigmaProcessPtr->pdf1(); + pdf2 = sigmaProcessPtr->pdf2(); + Q2FacNow = sigmaProcessPtr->Q2Fac(); + alphaEM = sigmaProcessPtr->alphaEMRen(); + alphaS = sigmaProcessPtr->alphaSRen(); + Q2Ren = sigmaProcessPtr->Q2Ren(); + x1Now = phaseSpacePtr->x1(); + x2Now = phaseSpacePtr->x2(); + sHat = phaseSpacePtr->sHat(); + tHat = phaseSpacePtr->tHat(); + uHat = phaseSpacePtr->uHat(); + pTHat = phaseSpacePtr->pTHat(); + m3 = phaseSpacePtr->m(3); + m4 = phaseSpacePtr->m(4); + theta = phaseSpacePtr->thetaHat(); + phi = phaseSpacePtr->phiHat(); + } + + // Les Houches Accord process partly available, partly to be constructed. + else { + Q2FacNow = pow2(scale); + alphaEM = lhaUpPtr->alphaQED(); + alphaS = lhaUpPtr->alphaQCD(); + Q2Ren = Q2FacNow; + x1Now = 2. * process[3].e() / infoPtr->eCM(); + x2Now = 2. * process[4].e() / infoPtr->eCM(); + Vec4 pSum = process[3].p() + process[4].p(); + sHat = pSum * pSum; + + // Read info on parton densities if provided. + if (lhaUpPtr->pdfIsSet()) { + pdf1 = lhaUpPtr->xpdf1(); + pdf2 = lhaUpPtr->xpdf2(); + Q2FacNow = pow2(lhaUpPtr->scalePDF()); + x1Now = lhaUpPtr->x1(); + x2Now = lhaUpPtr->x2(); + } + + // Reconstruct kinematics of 2 -> 2 processes from momenta. + if (nFin == 2) { + Vec4 pDifT = process[3].p() - process[5].p(); + tHat = pDifT * pDifT; + Vec4 pDifU = process[3].p() - process[6].p(); + uHat = pDifU * pDifU; + pTHat = process[5].pT(); + m3 = process[5].m(); + m4 = process[6].m(); + Vec4 p5 = process[5].p(); + p5.bstback(pSum); + theta = p5.theta(); + phi = process[5].phi(); + } + } + + // Store information. + if (isHardest) { + infoPtr->setPDFalpha( id1Now, id2Now, pdf1, pdf2, Q2FacNow, + alphaEM, alphaS, Q2Ren); + infoPtr->setKin( x1Now, x2Now, sHat, tHat, uHat, pTHat, m3, m4, + theta, phi); + } + infoPtr->setTypeMI( code(), pTHat); + + // For Les Houches event store subprocess classification. + if (isLHA) { + int codeSub = lhaUpPtr->idProcess(); + ostringstream nameSub; + nameSub << "user process " << codeSub; + infoPtr->setSubType( nameSub.str(), codeSub, nFin); + } + + // Done. + return true; + +} + +//********* + +// Handle resonance decays. + +bool ProcessContainer::decayResonances( Event& process) { + + // Save current event-record size. + process.saveSize(); + bool physical = true; + bool newFlavours = false; + + // Do sequential chain of uncorrelated isotropic decays. + do { + physical = resDecaysPtr->next( process); + if (!physical) return false; + + // Check whether flavours should be correlated. + // (Currently only relevant for f fbar -> gamma*/Z0 gamma*/Z0.) + newFlavours = ( sigmaProcessPtr->weightDecayFlav( process) + < Rndm::flat() ); + + // Reset the decay chains if have to redo. + if (newFlavours) { + process.restoreSize(); + for (int i = 5; i < process.size(); ++i) process[i].statusPos(); + } + + // Loop back where required to generate new decays with new flavours. + } while (newFlavours); + + // Correct to nonisotropic decays. + phaseSpacePtr->decayKinematics( process); + + // Done. + return true; + +} + +//********* + +// Reset event generation statistics; but NOT maximum of cross section. + +void ProcessContainer::reset() { + + nTry = 0; + nSel = 0; + nAcc = 0; + nTryStat = 0; + sigmaSum = 0.; + sigma2Sum = 0.; + sigmaNeg = 0.; + sigmaAvg = 0.; + sigmaFin = 0.; + deltaFin = 0.; + +} + +//********* + +// Estimate integrated cross section and its uncertainty. + +void ProcessContainer::sigmaDelta() { + + // Initial values. No analysis meaningful unless accepted events. + nTryStat = nTry; + sigmaAvg = 0.; + sigmaFin = 0.; + deltaFin = 0.; + if (nAcc == 0) return; + + // Average value. + double nTryInv = 1. / nTry; + double nSelInv = 1. / nSel; + double nAccInv = 1. / nAcc; + sigmaAvg = sigmaSum * nTryInv ; + double fracAcc = nAcc * nSelInv; + sigmaFin = sigmaAvg * fracAcc; + + // Estimated error. Quadratic sum of cross section term and + // binomial from accept/reject step. + deltaFin = sigmaFin; + if (nAcc == 1) return; + double delta2Sig = (sigma2Sum *nTryInv - pow2(sigmaAvg)) * nTryInv + / pow2(sigmaAvg); + double delta2Veto = (nSel - nAcc) * nAccInv * nSelInv; + double delta2Sum = delta2Sig + delta2Veto; + deltaFin = sqrtpos(delta2Sum) * sigmaFin; + +} + +//************************************************************************** + +// SetupContainer class. +// Turns list of user-desired processes into a vector of containers. + +//********* + +// Main routine to initialize list of processes. + +bool SetupContainers::init(vector& containerPtrs) { + + // Reset process list, if filled in previous subrun. + if (containerPtrs.size() > 0) { + for (int i = 0; i < int(containerPtrs.size()); ++i) + delete containerPtrs[i]; + containerPtrs.clear(); + } + SigmaProcess* sigmaPtr; + + // Set up requested objects for soft QCD processes. + bool softQCD = Settings::flag("SoftQCD:all"); + if (softQCD || Settings::flag("SoftQCD:minBias")) { + sigmaPtr = new Sigma0minBias; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (softQCD || Settings::flag("SoftQCD:elastic")) { + sigmaPtr = new Sigma0AB2AB; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (softQCD || Settings::flag("SoftQCD:singleDiffractive")) { + sigmaPtr = new Sigma0AB2XB; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma0AB2AX; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (softQCD || Settings::flag("SoftQCD:doubleDiffractive")) { + sigmaPtr = new Sigma0AB2XX; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for hard QCD processes. + bool hardQCD = Settings::flag("HardQCD:all"); + if (hardQCD || Settings::flag("HardQCD:gg2gg")) { + sigmaPtr = new Sigma2gg2gg; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (hardQCD || Settings::flag("HardQCD:gg2qqbar")) { + sigmaPtr = new Sigma2gg2qqbar; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (hardQCD || Settings::flag("HardQCD:qg2qg")) { + sigmaPtr = new Sigma2qg2qg; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (hardQCD || Settings::flag("HardQCD:qq2qq")) { + sigmaPtr = new Sigma2qq2qq; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (hardQCD || Settings::flag("HardQCD:qqbar2gg")) { + sigmaPtr = new Sigma2qqbar2gg; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (hardQCD || Settings::flag("HardQCD:qqbar2qqbarNew")) { + sigmaPtr = new Sigma2qqbar2qqbarNew; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for c cbar and b bbar, also hard QCD. + if (hardQCD || Settings::flag("HardQCD:gg2ccbar")) { + sigmaPtr = new Sigma2gg2QQbar(4, 121); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (hardQCD || Settings::flag("HardQCD:qqbar2ccbar")) { + sigmaPtr = new Sigma2qqbar2QQbar(4, 122); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (hardQCD || Settings::flag("HardQCD:gg2bbbar")) { + sigmaPtr = new Sigma2gg2QQbar(5, 123); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (hardQCD || Settings::flag("HardQCD:qqbar2bbbar")) { + sigmaPtr = new Sigma2qqbar2QQbar(5, 124); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for prompt photon processes. + bool promptPhotons = Settings::flag("PromptPhoton:all"); + if (promptPhotons + || Settings::flag("PromptPhoton:qg2qgamma")) { + sigmaPtr = new Sigma2qg2qgamma; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (promptPhotons + || Settings::flag("PromptPhoton:qqbar2ggamma")) { + sigmaPtr = new Sigma2qqbar2ggamma; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (promptPhotons + || Settings::flag("PromptPhoton:gg2ggamma")) { + sigmaPtr = new Sigma2gg2ggamma; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (promptPhotons + || Settings::flag("PromptPhoton:ffbar2gammagamma")) { + sigmaPtr = new Sigma2ffbar2gammagamma; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (promptPhotons + || Settings::flag("PromptPhoton:gg2gammagamma")) { + sigmaPtr = new Sigma2gg2gammagamma; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for weak gauge boson t-channel exchange. + bool weakBosonExchanges = Settings::flag("WeakBosonExchange:all"); + if (weakBosonExchanges + || Settings::flag("WeakBosonExchange:ff2ff(t:gmZ)")) { + sigmaPtr = new Sigma2ff2fftgmZ; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (weakBosonExchanges + || Settings::flag("WeakBosonExchange:ff2ff(t:W)")) { + sigmaPtr = new Sigma2ff2fftW; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for weak gauge boson processes. + bool weakSingleBosons = Settings::flag("WeakSingleBoson:all"); + if (weakSingleBosons + || Settings::flag("WeakSingleBoson:ffbar2gmZ")) { + sigmaPtr = new Sigma1ffbar2gmZ; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (weakSingleBosons + || Settings::flag("WeakSingleBoson:ffbar2W")) { + sigmaPtr = new Sigma1ffbar2W; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested object for s-channel gamma exchange. + // Subset of gamma*/Z0 above, intended for Multiple interactions. + if (Settings::flag("WeakSingleBoson:ffbar2ffbar(s:gm)")) { + sigmaPtr = new Sigma2ffbar2ffbarsgm; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for weak gauge boson pair processes. + bool weakDoubleBosons = Settings::flag("WeakDoubleBoson:all"); + if (weakDoubleBosons + || Settings::flag("WeakDoubleBoson:ffbar2gmZgmZ")) { + sigmaPtr = new Sigma2ffbar2gmZgmZ; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (weakDoubleBosons + || Settings::flag("WeakDoubleBoson:ffbar2ZW")) { + sigmaPtr = new Sigma2ffbar2ZW; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (weakDoubleBosons + || Settings::flag("WeakDoubleBoson:ffbar2WW")) { + sigmaPtr = new Sigma2ffbar2WW; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for weak gauge boson + parton processes. + bool weakBosonAndPartons = Settings::flag("WeakBosonAndParton:all"); + if (weakBosonAndPartons + || Settings::flag("WeakBosonAndParton:qqbar2gmZg")) { + sigmaPtr = new Sigma2qqbar2gmZg; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (weakBosonAndPartons + || Settings::flag("WeakBosonAndParton:qg2gmZq")) { + sigmaPtr = new Sigma2qg2gmZq; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (weakBosonAndPartons + || Settings::flag("WeakBosonAndParton:ffbar2gmZgm")) { + sigmaPtr = new Sigma2ffbar2gmZgm; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (weakBosonAndPartons + || Settings::flag("WeakBosonAndParton:fgm2gmZf")) { + sigmaPtr = new Sigma2fgm2gmZf; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (weakBosonAndPartons + || Settings::flag("WeakBosonAndParton:qqbar2Wg")) { + sigmaPtr = new Sigma2qqbar2Wg; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (weakBosonAndPartons + || Settings::flag("WeakBosonAndParton:qg2Wq")) { + sigmaPtr = new Sigma2qg2Wq; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (weakBosonAndPartons + || Settings::flag("WeakBosonAndParton:ffbar2Wgm")) { + sigmaPtr = new Sigma2ffbar2Wgm; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (weakBosonAndPartons + || Settings::flag("WeakBosonAndParton:fgm2Wf")) { + sigmaPtr = new Sigma2fgm2Wf; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for charmonium production + bool charmoniums = Settings::flag("Charmonium:all"); + if (charmoniums || Settings::flag("Charmonium:gg2QQbar[3S1(1)]g")) { + sigmaPtr = new Sigma2gg2QQbar3S11g(4, 401); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:gg2QQbar[3P0(1)]g")) { + sigmaPtr = new Sigma2gg2QQbar3PJ1g(4, 0, 402); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:gg2QQbar[3P1(1)]g")) { + sigmaPtr = new Sigma2gg2QQbar3PJ1g(4, 1, 403); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:gg2QQbar[3P2(1)]g")) { + sigmaPtr = new Sigma2gg2QQbar3PJ1g(4, 2, 404); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qg2QQbar[3P0(1)]q")) { + sigmaPtr = new Sigma2qg2QQbar3PJ1q(4, 0, 405); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qg2QQbar[3P1(1)]q")) { + sigmaPtr = new Sigma2qg2QQbar3PJ1q(4, 1, 406); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qg2QQbar[3P2(1)]q")) { + sigmaPtr = new Sigma2qg2QQbar3PJ1q(4, 2, 407); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qqbar2QQbar[3P0(1)]g")) { + sigmaPtr = new Sigma2qqbar2QQbar3PJ1g(4, 0, 408); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qqbar2QQbar[3P1(1)]g")) { + sigmaPtr = new Sigma2qqbar2QQbar3PJ1g(4, 1, 409); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qqbar2QQbar[3P2(1)]g")) { + sigmaPtr = new Sigma2qqbar2QQbar3PJ1g(4, 2, 410); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:gg2QQbar[3S1(8)]g")) { + sigmaPtr = new Sigma2gg2QQbarX8g(4, 0, 411); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:gg2QQbar[1S0(8)]g")) { + sigmaPtr = new Sigma2gg2QQbarX8g(4, 1, 412); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:gg2QQbar[3PJ(8)]g")) { + sigmaPtr = new Sigma2gg2QQbarX8g(4, 2, 413); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qg2QQbar[3S1(8)]q")) { + sigmaPtr = new Sigma2qg2QQbarX8q(4, 0, 414); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qg2QQbar[1S0(8)]q")) { + sigmaPtr = new Sigma2qg2QQbarX8q(4, 1, 415); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qg2QQbar[3PJ(8)]q")) { + sigmaPtr = new Sigma2qg2QQbarX8q(4, 2, 416); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qqbar2QQbar[3S1(8)]g")) { + sigmaPtr = new Sigma2qqbar2QQbarX8g(4, 0, 417); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qqbar2QQbar[1S0(8)]g")) { + sigmaPtr = new Sigma2qqbar2QQbarX8g(4, 1, 418); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (charmoniums || Settings::flag("Charmonium:qqbar2QQbar[3PJ(8)]g")) { + sigmaPtr = new Sigma2qqbar2QQbarX8g(4, 2, 419); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for bottomonium production + bool bottomoniums = Settings::flag("Bottomonium:all"); + if (bottomoniums || Settings::flag("Bottomonium:gg2QQbar[3S1(1)]g")) { + sigmaPtr = new Sigma2gg2QQbar3S11g(5, 501); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:gg2QQbar[3P0(1)]g")) { + sigmaPtr = new Sigma2gg2QQbar3PJ1g(5, 0, 502); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:gg2QQbar[3P1(1)]g")) { + sigmaPtr = new Sigma2gg2QQbar3PJ1g(5, 1, 503); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:gg2QQbar[3P2(1)]g")) { + sigmaPtr = new Sigma2gg2QQbar3PJ1g(5, 2, 504); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qg2QQbar[3P0(1)]q")) { + sigmaPtr = new Sigma2qg2QQbar3PJ1q(5, 0, 505); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qg2QQbar[3P1(1)]q")) { + sigmaPtr = new Sigma2qg2QQbar3PJ1q(5, 1, 506); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qg2QQbar[3P2(1)]q")) { + sigmaPtr = new Sigma2qg2QQbar3PJ1q(5, 2, 507); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qqbar2QQbar[3P0(1)]g")) { + sigmaPtr = new Sigma2qqbar2QQbar3PJ1g(5, 0, 508); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qqbar2QQbar[3P1(1)]g")) { + sigmaPtr = new Sigma2qqbar2QQbar3PJ1g(5, 1, 509); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qqbar2QQbar[3P2(1)]g")) { + sigmaPtr = new Sigma2qqbar2QQbar3PJ1g(5, 2, 510); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:gg2QQbar[3S1(8)]g")) { + sigmaPtr = new Sigma2gg2QQbarX8g(5, 0, 511); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:gg2QQbar[1S0(8)]g")) { + sigmaPtr = new Sigma2gg2QQbarX8g(5, 1, 512); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:gg2QQbar[3PJ(8)]g")) { + sigmaPtr = new Sigma2gg2QQbarX8g(5, 2, 513); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qg2QQbar[3S1(8)]q")) { + sigmaPtr = new Sigma2qg2QQbarX8q(5, 0, 514); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qg2QQbar[1S0(8)]q")) { + sigmaPtr = new Sigma2qg2QQbarX8q(5, 1, 515); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qg2QQbar[3PJ(8)]q")) { + sigmaPtr = new Sigma2qg2QQbarX8q(5, 2, 516); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qqbar2QQbar[3S1(8)]g")) { + sigmaPtr = new Sigma2qqbar2QQbarX8g(5, 0, 517); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qqbar2QQbar[1S0(8)]g")) { + sigmaPtr = new Sigma2qqbar2QQbarX8g(5, 1, 518); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bottomoniums || Settings::flag("Bottomonium:qqbar2QQbar[3PJ(8)]g")) { + sigmaPtr = new Sigma2qqbar2QQbarX8g(5, 2, 519); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for top production + bool tops = Settings::flag("Top:all"); + if (tops || Settings::flag("Top:gg2ttbar")) { + sigmaPtr = new Sigma2gg2QQbar(6, 601); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (tops || Settings::flag("Top:qqbar2ttbar")) { + sigmaPtr = new Sigma2qqbar2QQbar(6, 602); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (tops || Settings::flag("Top:qq2tq(t:W)")) { + sigmaPtr = new Sigma2qq2QqtW(6, 603); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (tops || Settings::flag("Top:ffbar2ttbar(s:gmZ)")) { + sigmaPtr = new Sigma2ffbar2FFbarsgmZ(6, 604); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (tops || Settings::flag("Top:ffbar2tqbar(s:W)")) { + sigmaPtr = new Sigma2ffbar2FfbarsW(6, 0, 605); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for fourth-generation b' production + bool bPrimes = Settings::flag("FourthBottom:all"); + if (bPrimes || Settings::flag("FourthBottom:gg2bPrimebPrimebar")) { + sigmaPtr = new Sigma2gg2QQbar(7, 801); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bPrimes || Settings::flag("FourthBottom:qqbar2bPrimebPrimebar")) { + sigmaPtr = new Sigma2qqbar2QQbar(7, 802); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bPrimes || Settings::flag("FourthBottom:qq2bPrimeq(t:W)")) { + sigmaPtr = new Sigma2qq2QqtW(7, 803); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bPrimes || Settings::flag("FourthBottom:ffbar2bPrimebPrimebar(s:gmZ)")) { + sigmaPtr = new Sigma2ffbar2FFbarsgmZ(7, 804); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bPrimes || Settings::flag("FourthBottom:ffbar2bPrimeqbar(s:W)")) { + sigmaPtr = new Sigma2ffbar2FfbarsW(7, 0, 805); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (bPrimes || Settings::flag("FourthBottom:ffbar2bPrimetbar(s:W)")) { + sigmaPtr = new Sigma2ffbar2FfbarsW(7, 6, 806); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for fourth-generation t' production + bool tPrimes = Settings::flag("FourthTop:all"); + if (tPrimes || Settings::flag("FourthTop:gg2tPrimetPrimebar")) { + sigmaPtr = new Sigma2gg2QQbar(8, 821); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (tPrimes || Settings::flag("FourthTop:qqbar2tPrimetPrimebar")) { + sigmaPtr = new Sigma2qqbar2QQbar(8, 822); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (tPrimes || Settings::flag("FourthTop:qq2tPrimeq(t:W)")) { + sigmaPtr = new Sigma2qq2QqtW(8, 823); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (tPrimes || Settings::flag("FourthTop:ffbar2tPrimetPrimebar(s:gmZ)")) { + sigmaPtr = new Sigma2ffbar2FFbarsgmZ(8, 824); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (tPrimes || Settings::flag("FourthTop:ffbar2tPrimeqbar(s:W)")) { + sigmaPtr = new Sigma2ffbar2FfbarsW(8, 0, 825); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for two different fourth-generation fermions. + if (bPrimes || tPrimes + || Settings::flag("FourthPair:ffbar2tPrimebPrimebar(s:W)")) { + sigmaPtr = new Sigma2ffbar2FfbarsW(8, 7, 841); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("FourthPair:ffbar2tauPrimenuPrimebar(s:W)")) { + sigmaPtr = new Sigma2ffbar2FfbarsW(17, 18, 842); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Flag for global choice between SM and BSM Higgses. + bool useBSMHiggses = Settings::flag("Higgs:useBSM"); + + // Set up requested objects for Standard-Model Higgs production. + if (!useBSMHiggses) { + bool HiggsesSM = Settings::flag("HiggsSM:all"); + if (HiggsesSM || Settings::flag("HiggsSM:ffbar2H")) { + sigmaPtr = new Sigma1ffbar2H(0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesSM || Settings::flag("HiggsSM:gg2H")) { + sigmaPtr = new Sigma1gg2H(0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesSM || Settings::flag("HiggsSM:gmgm2H")) { + sigmaPtr = new Sigma1gmgm2H(0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesSM || Settings::flag("HiggsSM:ffbar2HZ")) { + sigmaPtr = new Sigma2ffbar2HZ(0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesSM || Settings::flag("HiggsSM:ffbar2HW")) { + sigmaPtr = new Sigma2ffbar2HW(0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesSM || Settings::flag("HiggsSM:ff2Hff(t:ZZ)")) { + sigmaPtr = new Sigma3ff2HfftZZ(0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesSM || Settings::flag("HiggsSM:ff2Hff(t:WW)")) { + sigmaPtr = new Sigma3ff2HfftWW(0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesSM || Settings::flag("HiggsSM:gg2Httbar")) { + sigmaPtr = new Sigma3gg2HQQbar(6,0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesSM || Settings::flag("HiggsSM:qqbar2Httbar")) { + sigmaPtr = new Sigma3qqbar2HQQbar(6,0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Further Standard-Model Higgs processes, not included in "all". + if (Settings::flag("HiggsSM:qg2Hq")) { + sigmaPtr = new Sigma2qg2Hq(4,0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qg2Hq(5,0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsSM:gg2Hbbbar")) { + sigmaPtr = new Sigma3gg2HQQbar(5,0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsSM:qqbar2Hbbbar")) { + sigmaPtr = new Sigma3qqbar2HQQbar(5,0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsSM:gg2Hg(l:t)")) { + sigmaPtr = new Sigma2gg2Hglt(0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsSM:qg2Hq(l:t)")) { + sigmaPtr = new Sigma2qg2Hqlt(0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsSM:qqbar2Hg(l:t)")) { + sigmaPtr = new Sigma2qqbar2Hglt(0); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + } + + // Common switch for the group of Higgs production BSM. + if (useBSMHiggses) { + bool HiggsesBSM = Settings::flag("HiggsBSM:all"); + + // Set up requested objects for BSM H1 production. + bool HiggsesH1 = Settings::flag("HiggsBSM:allH1"); + if (HiggsesBSM || HiggsesH1 || Settings::flag("HiggsBSM:ffbar2H1")) { + sigmaPtr = new Sigma1ffbar2H(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH1 || Settings::flag("HiggsBSM:gg2H1")) { + sigmaPtr = new Sigma1gg2H(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH1 || Settings::flag("HiggsBSM:gmgm2H1")) { + sigmaPtr = new Sigma1gmgm2H(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH1 || Settings::flag("HiggsBSM:ffbar2H1Z")) { + sigmaPtr = new Sigma2ffbar2HZ(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH1 || Settings::flag("HiggsBSM:ffbar2H1W")) { + sigmaPtr = new Sigma2ffbar2HW(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH1 || Settings::flag("HiggsBSM:ff2H1ff(t:ZZ)")) { + sigmaPtr = new Sigma3ff2HfftZZ(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH1 || Settings::flag("HiggsBSM:ff2H1ff(t:WW)")) { + sigmaPtr = new Sigma3ff2HfftWW(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH1 || Settings::flag("HiggsBSM:gg2H1ttbar")) { + sigmaPtr = new Sigma3gg2HQQbar(6,1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH1 || Settings::flag("HiggsBSM:qqbar2H1ttbar")) { + sigmaPtr = new Sigma3qqbar2HQQbar(6,1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Further BSM H1 processes, not included in "all". + if (Settings::flag("HiggsBSM:qg2H1q")) { + sigmaPtr = new Sigma2qg2Hq(4,1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qg2Hq(5,1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:gg2H1bbbar")) { + sigmaPtr = new Sigma3gg2HQQbar(5,1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:qqbar2H1bbbar")) { + sigmaPtr = new Sigma3qqbar2HQQbar(5,1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:gg2H1g(l:t)")) { + sigmaPtr = new Sigma2gg2Hglt(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:qg2H1q(l:t)")) { + sigmaPtr = new Sigma2qg2Hqlt(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:qqbar2H1g(l:t)")) { + sigmaPtr = new Sigma2qqbar2Hglt(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for BSM H2 production. + bool HiggsesH2 = Settings::flag("HiggsBSM:allH2"); + if (HiggsesBSM || HiggsesH2 || Settings::flag("HiggsBSM:ffbar2H2")) { + sigmaPtr = new Sigma1ffbar2H(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH2 || Settings::flag("HiggsBSM:gg2H2")) { + sigmaPtr = new Sigma1gg2H(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH2 || Settings::flag("HiggsBSM:gmgm2H2")) { + sigmaPtr = new Sigma1gmgm2H(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH2 || Settings::flag("HiggsBSM:ffbar2H2Z")) { + sigmaPtr = new Sigma2ffbar2HZ(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH2 || Settings::flag("HiggsBSM:ffbar2H2W")) { + sigmaPtr = new Sigma2ffbar2HW(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH2 || Settings::flag("HiggsBSM:ff2H2ff(t:ZZ)")) { + sigmaPtr = new Sigma3ff2HfftZZ(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH2 || Settings::flag("HiggsBSM:ff2H2ff(t:WW)")) { + sigmaPtr = new Sigma3ff2HfftWW(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH2 || Settings::flag("HiggsBSM:gg2H2ttbar")) { + sigmaPtr = new Sigma3gg2HQQbar(6,2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesH2 || Settings::flag("HiggsBSM:qqbar2H2ttbar")) { + sigmaPtr = new Sigma3qqbar2HQQbar(6,2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Further BSM H2 processes, not included in "all". + if (Settings::flag("HiggsBSM:qg2H2q")) { + sigmaPtr = new Sigma2qg2Hq(4,2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qg2Hq(5,2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:gg2H2bbbar")) { + sigmaPtr = new Sigma3gg2HQQbar(5,2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:qqbar2H2bbbar")) { + sigmaPtr = new Sigma3qqbar2HQQbar(5,2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:gg2H2g(l:t)")) { + sigmaPtr = new Sigma2gg2Hglt(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:qg2H2q(l:t)")) { + sigmaPtr = new Sigma2qg2Hqlt(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:qqbar2H2g(l:t)")) { + sigmaPtr = new Sigma2qqbar2Hglt(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for BSM A3 production. + bool HiggsesA3 = Settings::flag("HiggsBSM:allA3"); + if (HiggsesBSM || HiggsesA3 || Settings::flag("HiggsBSM:ffbar2A3")) { + sigmaPtr = new Sigma1ffbar2H(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesA3 || Settings::flag("HiggsBSM:gg2A3")) { + sigmaPtr = new Sigma1gg2H(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesA3 || Settings::flag("HiggsBSM:gmgm2A3")) { + sigmaPtr = new Sigma1gmgm2H(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesA3 || Settings::flag("HiggsBSM:ffbar2A3Z")) { + sigmaPtr = new Sigma2ffbar2HZ(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesA3 || Settings::flag("HiggsBSM:ffbar2A3W")) { + sigmaPtr = new Sigma2ffbar2HW(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesA3 || Settings::flag("HiggsBSM:ff2A3ff(t:ZZ)")) { + sigmaPtr = new Sigma3ff2HfftZZ(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesA3 || Settings::flag("HiggsBSM:ff2A3ff(t:WW)")) { + sigmaPtr = new Sigma3ff2HfftWW(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesA3 || Settings::flag("HiggsBSM:gg2A3ttbar")) { + sigmaPtr = new Sigma3gg2HQQbar(6,3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesA3 || Settings::flag("HiggsBSM:qqbar2A3ttbar")) { + sigmaPtr = new Sigma3qqbar2HQQbar(6,3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Further BSM A3 processes, not included in "all". + if (Settings::flag("HiggsBSM:qg2A3q")) { + sigmaPtr = new Sigma2qg2Hq(4,3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qg2Hq(5,3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:gg2A3bbbar")) { + sigmaPtr = new Sigma3gg2HQQbar(5,3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:qqbar2A3bbbar")) { + sigmaPtr = new Sigma3qqbar2HQQbar(5,3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:gg2A3g(l:t)")) { + sigmaPtr = new Sigma2gg2Hglt(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:qg2A3q(l:t)")) { + sigmaPtr = new Sigma2qg2Hqlt(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("HiggsBSM:qqbar2A3g(l:t)")) { + sigmaPtr = new Sigma2qqbar2Hglt(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for Charged Higgs production + bool HiggsesChg = Settings::flag("HiggsBSM:allH+-"); + if (HiggsesBSM || HiggsesChg || Settings::flag("HiggsBSM:ffbar2H+-")) { + sigmaPtr = new Sigma1ffbar2Hchg; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesChg || Settings::flag("HiggsBSM:bg2H+-t")) { + sigmaPtr = new Sigma2qg2Hchgq(6, 1062, "b g -> H+- t"); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for Higgs pair-production + bool HiggsesPairs = Settings::flag("HiggsBSM:allHpair"); + if (HiggsesBSM || HiggsesPairs || Settings::flag("HiggsBSM:ffbar2A3H1")) { + sigmaPtr = new Sigma2ffbar2A3H12(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesPairs || Settings::flag("HiggsBSM:ffbar2A3H2")) { + sigmaPtr = new Sigma2ffbar2A3H12(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesPairs || Settings::flag("HiggsBSM:ffbar2H+-H1")) { + sigmaPtr = new Sigma2ffbar2HchgH12(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesPairs || Settings::flag("HiggsBSM:ffbar2H+-H2")) { + sigmaPtr = new Sigma2ffbar2HchgH12(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (HiggsesBSM || HiggsesPairs || Settings::flag("HiggsBSM:ffbar2H+H-")) { + sigmaPtr = new Sigma2ffbar2HposHneg(); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + } + + // Set up requested objects for neutralino pair processes. + bool SUSYs = Settings::flag("SUSY:all"); + if (SUSYs || Settings::flag("SUSY:qqbar2chi0chi0")) { + sigmaPtr = new Sigma2qqbar2chi0chi0(1, 1, 1201); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2chi0chi0(1, 2, 1202); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2chi0chi0(1, 3, 1203); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2chi0chi0(1, 4, 1204); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2chi0chi0(2, 2, 1205); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2chi0chi0(2, 3, 1206); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2chi0chi0(2, 4, 1207); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2chi0chi0(3, 3, 1208); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2chi0chi0(3, 4, 1209); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2chi0chi0(4, 4, 1210); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for New-Gauge-Boson processes. + if (Settings::flag("NewGaugeBoson:ffbar2gmZZprime")) { + sigmaPtr = new Sigma1ffbar2gmZZprime(); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("NewGaugeBoson:ffbar2Wprime")) { + sigmaPtr = new Sigma1ffbar2Wprime(); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("NewGaugeBoson:ffbar2R0")) { + sigmaPtr = new Sigma1ffbar2Rhorizontal(); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for Left-Right-Symmetry processes. + bool leftrights = Settings::flag("LeftRightSymmmetry:all"); + if (leftrights || Settings::flag("LeftRightSymmmetry:ffbar2ZR")) { + sigmaPtr = new Sigma1ffbar2ZRight(); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:ffbar2WR")) { + sigmaPtr = new Sigma1ffbar2WRight(); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:ll2HL")) { + sigmaPtr = new Sigma1ll2Hchgchg(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:lgm2HLe")) { + sigmaPtr = new Sigma2lgm2Hchgchgl(1, 11); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:lgm2HLmu")) { + sigmaPtr = new Sigma2lgm2Hchgchgl(1, 13); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:lgm2HLtau")) { + sigmaPtr = new Sigma2lgm2Hchgchgl(1, 15); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:ff2HLff")) { + sigmaPtr = new Sigma3ff2HchgchgfftWW(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:ffbar2HLHL")) { + sigmaPtr = new Sigma2ffbar2HchgchgHchgchg(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:ll2HR")) { + sigmaPtr = new Sigma1ll2Hchgchg(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:lgm2HRe")) { + sigmaPtr = new Sigma2lgm2Hchgchgl(2, 11); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:lgm2HRmu")) { + sigmaPtr = new Sigma2lgm2Hchgchgl(2, 13); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:lgm2HRtau")) { + sigmaPtr = new Sigma2lgm2Hchgchgl(2, 15); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:ff2HRff")) { + sigmaPtr = new Sigma3ff2HchgchgfftWW(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leftrights || Settings::flag("LeftRightSymmmetry:ffbar2HRHR")) { + sigmaPtr = new Sigma2ffbar2HchgchgHchgchg(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for leptoquark LQ processes. + bool leptoquarks = Settings::flag("LeptoQuark:all"); + if (leptoquarks || Settings::flag("LeptoQuark:ql2LQ")) { + sigmaPtr = new Sigma1ql2LeptoQuark; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leptoquarks || Settings::flag("LeptoQuark:qg2LQl")) { + sigmaPtr = new Sigma2qg2LeptoQuarkl; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leptoquarks || Settings::flag("LeptoQuark:gg2LQLQbar")) { + sigmaPtr = new Sigma2gg2LQLQbar; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (leptoquarks || Settings::flag("LeptoQuark:qqbar2LQLQbar")) { + sigmaPtr = new Sigma2qqbar2LQLQbar; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for excited-fermion processes. + bool excitedfermions = Settings::flag("ExcitedFermion:all"); + if (excitedfermions || Settings::flag("ExcitedFermion:dg2dStar")) { + sigmaPtr = new Sigma1qg2qStar(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:ug2uStar")) { + sigmaPtr = new Sigma1qg2qStar(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:sg2sStar")) { + sigmaPtr = new Sigma1qg2qStar(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:cg2cStar")) { + sigmaPtr = new Sigma1qg2qStar(4); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:bg2bStar")) { + sigmaPtr = new Sigma1qg2qStar(5); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:egm2eStar")) { + sigmaPtr = new Sigma1lgm2lStar(11); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:mugm2muStar")) { + sigmaPtr = new Sigma1lgm2lStar(13); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:taugm2tauStar")) { + sigmaPtr = new Sigma1lgm2lStar(15); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:qq2dStarq")) { + sigmaPtr = new Sigma2qq2qStarq(1); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:qq2uStarq")) { + sigmaPtr = new Sigma2qq2qStarq(2); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:qq2sStarq")) { + sigmaPtr = new Sigma2qq2qStarq(3); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:qq2cStarq")) { + sigmaPtr = new Sigma2qq2qStarq(4); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:qq2bStarq")) { + sigmaPtr = new Sigma2qq2qStarq(5); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:qqbar2eStare")) { + sigmaPtr = new Sigma2qqbar2lStarlbar(11); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:qqbar2nueStarnue")) { + sigmaPtr = new Sigma2qqbar2lStarlbar(12); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:qqbar2muStarmu")) { + sigmaPtr = new Sigma2qqbar2lStarlbar(13); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:qqbar2numuStarnumu")) { + sigmaPtr = new Sigma2qqbar2lStarlbar(14); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:qqbar2tauStartau")) { + sigmaPtr = new Sigma2qqbar2lStarlbar(15); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (excitedfermions || Settings::flag("ExcitedFermion:qqbar2nutauStarnutau")) { + sigmaPtr = new Sigma2qqbar2lStarlbar(16); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Set up requested objects for extra-dimensional G* processes. + bool extraDimGstars = Settings::flag("ExtraDimensionsG*:all"); + if (extraDimGstars || Settings::flag("ExtraDimensionsG*:gg2G*")) { + sigmaPtr = new Sigma1gg2GravitonStar; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (extraDimGstars || Settings::flag("ExtraDimensionsG*:ffbar2G*")) { + sigmaPtr = new Sigma1ffbar2GravitonStar; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("ExtraDimensionsG*:gg2G*g")) { + sigmaPtr = new Sigma2gg2GravitonStarg; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("ExtraDimensionsG*:qg2G*q")) { + sigmaPtr = new Sigma2qg2GravitonStarq; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + if (Settings::flag("ExtraDimensionsG*:qqbar2G*g")) { + sigmaPtr = new Sigma2qqbar2GravitonStarg; + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Done. + return true; + +} + +//********* + +// Routine to initialize list of second hard processes. + +bool SetupContainers::init2(vector& container2Ptrs) { + + // Reset process list, if filled in previous subrun. + if (container2Ptrs.size() > 0) { + for (int i = 0; i < int(container2Ptrs.size()); ++i) + delete container2Ptrs[i]; + container2Ptrs.clear(); + } + SigmaProcess* sigmaPtr; + + // Two hard QCD jets. + if (Settings::flag("SecondHard:TwoJets")) { + sigmaPtr = new Sigma2gg2gg; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2gg2qqbar; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qg2qg; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qq2qq; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2gg; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2qqbarNew; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2gg2QQbar(4, 121); + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2QQbar(4, 122); + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2gg2QQbar(5, 123); + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2QQbar(5, 124); + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // A prompt photon and a hard jet. + if (Settings::flag("SecondHard:PhotonAndJet")) { + sigmaPtr = new Sigma2qg2qgamma; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2ggamma; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2gg2ggamma; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Two prompt photons. + if (Settings::flag("SecondHard:TwoPhotons")) { + sigmaPtr = new Sigma2ffbar2gammagamma; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2gg2gammagamma; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // A single gamma*/Z0. + if (Settings::flag("SecondHard:SingleGmZ")) { + sigmaPtr = new Sigma1ffbar2gmZ; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // A single W+-. + if (Settings::flag("SecondHard:SingleW")) { + sigmaPtr = new Sigma1ffbar2W; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // A gamma*/Z0 and a hard jet. + if (Settings::flag("SecondHard:GmZAndJet")) { + sigmaPtr = new Sigma2qqbar2gmZg; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qg2gmZq; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // A W+- and a hard jet. + if (Settings::flag("SecondHard:WAndJet")) { + sigmaPtr = new Sigma2qqbar2Wg; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qg2Wq; + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Two b jets - already part of TwoJets sample above. + if (Settings::flag("SecondHard:TwoBJets")) { + sigmaPtr = new Sigma2gg2QQbar(5, 123); + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + sigmaPtr = new Sigma2qqbar2QQbar(5, 124); + container2Ptrs.push_back( new ProcessContainer(sigmaPtr) ); + } + + // Done. + return true; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/ProcessLevel.cxx b/PYTHIA8/pythia8130/src/ProcessLevel.cxx new file mode 100644 index 00000000000..f5c231be4fc --- /dev/null +++ b/PYTHIA8/pythia8130/src/ProcessLevel.cxx @@ -0,0 +1,1069 @@ +// ProcessLevel.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the ProcessLevel class. + +#include "ProcessLevel.h" + +namespace Pythia8 { + +//************************************************************************** + +// The ProcessLevel class. + +//********* + +// Destructor. + +ProcessLevel::~ProcessLevel() { + + // Run through list of first hard processes and delete them. + for (int i = 0; i < int(containerPtrs.size()); ++i) + delete containerPtrs[i]; + + // Run through list of second hard processes and delete them. + for (int i =0; i < int(container2Ptrs.size()); ++i) + delete container2Ptrs[i]; + +} + +//********* + +// Main routine to initialize generation process. + +bool ProcessLevel::init( Info* infoPtrIn, BeamParticle* beamAPtrIn, + BeamParticle* beamBPtrIn, SigmaTotal* sigmaTotPtrIn, bool doLHA, + SusyLesHouches* slhaPtrIn, UserHooks* userHooksPtrIn, + vector& sigmaPtrs, ostream& os) { + + // Store input pointers for future use. + infoPtr = infoPtrIn; + beamAPtr = beamAPtrIn; + beamBPtr = beamBPtrIn; + sigmaTotPtr = sigmaTotPtrIn; + userHooksPtr = userHooksPtrIn; + slhaPtr = slhaPtrIn; + + // Send on some input pointers. + resonanceDecays.init( infoPtr); + + // Options to allow second hard interaction and resonance decays. + doSecondHard = Settings::flag("SecondHard:generate"); + doResDecays = Settings::flag("ProcessLevel:resonanceDecays"); + + // Set up SigmaTotal. Store sigma_nondiffractive for future use. + sigmaTotPtr->init( infoPtr); + int idA = infoPtr->idA(); + int idB = infoPtr->idB(); + double eCM = infoPtr->eCM(); + sigmaTotPtr->calc( idA, idB, eCM); + sigmaND = sigmaTotPtr->sigmaND(); + + // Initialize SUSY Les Houches Accord data + if (!initSLHA()) return false; + + // Set up containers for all the internal hard processes. + SetupContainers setupContainers; + setupContainers.init(containerPtrs); + + // Append containers for external hard processes, if any. + if (sigmaPtrs.size() > 0) { + for (int iSig = 0; iSig < int(sigmaPtrs.size()); ++iSig) + containerPtrs.push_back( new ProcessContainer(sigmaPtrs[iSig]) ); + } + + // Append single container for Les Houches processes, if any. + if (doLHA) { + SigmaProcess* sigmaPtr = new SigmaLHAProcess(); + containerPtrs.push_back( new ProcessContainer(sigmaPtr) ); + + // Store location of this container, and send in LHA pointer. + iLHACont = containerPtrs.size() - 1; + containerPtrs[iLHACont]->setLHAPtr(lhaUpPtr); + } + + // If no processes found then refuse to do anything. + if ( int(containerPtrs.size()) == 0) { + infoPtr->errorMsg("Error in ProcessLevel::init: " + "no process switched on"); + return false; + } + + // Initialize alphaStrong generation for SigmaProcess. + double alphaSvalue = Settings::parm("SigmaProcess:alphaSvalue"); + int alphaSorder = Settings::mode("SigmaProcess:alphaSorder"); + alphaS.init( alphaSvalue, alphaSorder); + + // Initialize alphaEM generation for SigmaProcess. + int alphaEMorder = Settings::mode("SigmaProcess:alphaEMorder"); + alphaEM.init( alphaEMorder); + + // Initialize each process. + int numberOn = 0; + for (int i = 0; i < int(containerPtrs.size()); ++i) + if (containerPtrs[i]->init(infoPtr, beamAPtr, beamBPtr, &alphaS, + &alphaEM, sigmaTotPtr, &resonanceDecays, slhaPtr, userHooksPtr)) + ++numberOn; + + // Sum maxima for Monte Carlo choice. + sigmaMaxSum = 0.; + for (int i = 0; i < int(containerPtrs.size()); ++i) + sigmaMaxSum += containerPtrs[i]->sigmaMax(); + + // Option to pick a second hard interaction: repeat as above. + int number2On = 0; + if (doSecondHard) { + setupContainers.init2(container2Ptrs); + if ( int(container2Ptrs.size()) == 0) { + infoPtr->errorMsg("Error in ProcessLevel::init: " + "no second hard process switched on"); + return false; + } + for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) + if (container2Ptrs[i2]->init(infoPtr, beamAPtr, beamBPtr, &alphaS, + &alphaEM, sigmaTotPtr, &resonanceDecays, slhaPtr, userHooksPtr)) + ++number2On; + sigma2MaxSum = 0.; + for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) + sigma2MaxSum += container2Ptrs[i2]->sigmaMax(); + } + + // Construct string with incoming beams and for cm energy. + string collision = "We collide " + ParticleDataTable::name(idA) + + " with " + ParticleDataTable::name(idB) + " at a CM energy of "; + string pad( 51 - collision.length(), ' '); + + // Print initialization information: header. + os << "\n *------- PYTHIA Process Initialization ---------" + << "-----------------*\n" + << " | " + << " |\n" + << " | " << collision << scientific << setprecision(3)<< setw(9) << eCM + << " GeV" << pad << " |\n" + << " | " + << " |\n" + << " |---------------------------------------------------" + << "---------------|\n" + << " | " + << " | |\n" + << " | Subprocess Code" + << " | Estimated |\n" + << " | " + << " | max (mb) |\n" + << " | " + << " | |\n" + << " |---------------------------------------------------" + << "---------------|\n" + << " | " + << " | |\n"; + + + // Loop over existing processes: print individual process info. + for (int i = 0; i < int(containerPtrs.size()); ++i) + os << " | " << left << setw(45) << containerPtrs[i]->name() + << right << setw(5) << containerPtrs[i]->code() << " | " + << scientific << setprecision(3) << setw(11) + << containerPtrs[i]->sigmaMax() << " |\n"; + + // Loop over second hard processes, if any, and repeat as above. + if (doSecondHard) { + os << " | " + << " | |\n" + << " |---------------------------------------------------" + <<"---------------|\n" + << " | " + <<" | |\n"; + for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) + os << " | " << left << setw(45) << container2Ptrs[i2]->name() + << right << setw(5) << container2Ptrs[i2]->code() << " | " + << scientific << setprecision(3) << setw(11) + << container2Ptrs[i2]->sigmaMax() << " |\n"; + } + + // Listing finished. + os << " | " + << " |\n" + << " *------- End PYTHIA Process Initialization ----------" + <<"-------------*" << endl; + + // If sum of maxima vanishes then refuse to do anything. + if ( numberOn == 0 || sigmaMaxSum <= 0.) { + infoPtr->errorMsg("Error in ProcessLevel::init: " + "all processes have vanishing cross sections"); + return false; + } + if ( doSecondHard && (number2On == 0 || sigma2MaxSum <= 0.) ) { + infoPtr->errorMsg("Error in ProcessLevel::init: " + "all second hard processes have vanishing cross sections"); + return false; + } + + // If two hard processes then check whether some (but not all) agree. + allHardSame = true; + noneHardSame = true; + if (doSecondHard) { + bool foundMatch = false; + + // Check for each first process if matched in second. + for (int i = 0; i < int(containerPtrs.size()); ++i) { + foundMatch = false; + for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) + if (container2Ptrs[i2]->code() == containerPtrs[i]->code()) + foundMatch = true; + containerPtrs[i]->isSame( foundMatch ); + if (!foundMatch) allHardSame = false; + if ( foundMatch) noneHardSame = false; + } + + // Check for each second process if matched in first. + for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) { + foundMatch = false; + for (int i = 0; i < int(containerPtrs.size()); ++i) + if (containerPtrs[i]->code() == container2Ptrs[i2]->code()) + foundMatch = true; + container2Ptrs[i2]->isSame( foundMatch ); + if (!foundMatch) allHardSame = false; + if ( foundMatch) noneHardSame = false; + } + } + someHardSame = !allHardSame && !noneHardSame; + + // Reset counters for average impact-parameter enhancement. + nImpact = 0; + sumImpactFac = 0.; + sum2ImpactFac = 0.; + + // Statistics for LHA events. + codeLHA.resize(0); + nEvtLHA.resize(0); + + // Done. + return true; +} + +//********* + +// Main routine to generate the hard process. + +bool ProcessLevel::next( Event& process) { + + // Generate the next event with two or one hard interactions. + bool physical = (doSecondHard) ? nextTwo( process) : nextOne( process); + + // Check that colour assignments make sense. + if (physical) physical = checkColours( process); + + // Done. + return physical; +} + +//********* + +// Accumulate and update statistics (after possible user veto). + +void ProcessLevel::accumulate() { + + // Increase number of accepted events. + containerPtrs[iContainer]->accumulate(); + + // Provide current generated cross section estimate. + long nTrySum = 0; + long nSelSum = 0; + long nAccSum = 0; + double sigmaSum = 0.; + double delta2Sum = 0.; + double sigSelSum = 0.; + for (int i = 0; i < int(containerPtrs.size()); ++i) + if (containerPtrs[i]->sigmaMax() != 0.) { + nTrySum += containerPtrs[i]->nTried(); + nSelSum += containerPtrs[i]->nSelected(); + nAccSum += containerPtrs[i]->nAccepted(); + sigmaSum += containerPtrs[i]->sigmaMC(); + delta2Sum += pow2(containerPtrs[i]->deltaMC()); + sigSelSum += containerPtrs[i]->sigmaSelMC(); + } + + // For Les Houches events find subprocess type and update counter. + if (infoPtr->isLHA()) { + int codeLHANow = infoPtr->codeSub(); + int iFill = -1; + for (int i = 0; i < int(codeLHA.size()); ++i) + if (codeLHANow == codeLHA[i]) iFill = i; + if (iFill >= 0) ++nEvtLHA[iFill]; + + // Add new process when new code and then arrange in order. + else { + codeLHA.push_back(codeLHANow); + nEvtLHA.push_back(1); + for (int i = int(codeLHA.size()) - 1; i > 0; --i) { + if (codeLHA[i] < codeLHA[i - 1]) { + swap(codeLHA[i], codeLHA[i - 1]); + swap(nEvtLHA[i], nEvtLHA[i - 1]); + } + else break; + } + } + } + + // Normally only one hard interaction. Then store info and done. + if (!doSecondHard) { + double deltaSum = sqrtpos(delta2Sum); + infoPtr->setSigma( nTrySum, nSelSum, nAccSum, sigmaSum, deltaSum); + return; + } + + // Increase counter for a second hard interaction. + container2Ptrs[i2Container]->accumulate(); + + // Update statistics on average impact factor. + ++nImpact; + sumImpactFac += infoPtr->enhanceMI(); + sum2ImpactFac += pow2(infoPtr->enhanceMI()); + + // Cross section estimate for second hard process. + double sigma2Sum = 0.; + double sig2SelSum = 0.; + for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) + if (container2Ptrs[i2]->sigmaMax() != 0.) { + nTrySum += container2Ptrs[i2]->nTried(); + sigma2Sum += container2Ptrs[i2]->sigmaMC(); + sig2SelSum += container2Ptrs[i2]->sigmaSelMC(); + } + + // Average impact-parameter factor and error. + double invN = 1. / max(1, nImpact); + double impactFac = max( 1., sumImpactFac * invN); + double impactErr2 = ( sum2ImpactFac * invN / pow2(impactFac) - 1.) * invN; + + // Cross section estimate for combination of first and second process. + // Combine two possible ways and take average. + double sigmaComb = 0.5 * (sigmaSum * sig2SelSum + sigSelSum * sigma2Sum); + sigmaComb *= impactFac / sigmaND; + if (allHardSame) sigmaComb *= 0.5; + double deltaComb = sqrtpos(2. / nAccSum + impactErr2) * sigmaComb; + + // Store info and done. + infoPtr->setSigma( nTrySum, nSelSum, nAccSum, sigmaComb, deltaComb); + +} + +//********* + +// Print statistics on cross sections and number of events. + +void ProcessLevel::statistics(bool reset, ostream& os) { + + // Special processing if two hard interactions selected. + if (doSecondHard) { + statistics2(reset, os); + return; + } + + // Header. + os << "\n *------- PYTHIA Event and Cross Section Statistics ------" + << "-------------------------------------------------------*\n" + << " | " + << " |\n" + << " | Subprocess Code | " + << " Number of events | sigma +- delta |\n" + << " | | " + << "Tried Selected Accepted | (estimated) (mb) |\n" + << " | | " + << " | |\n" + << " |------------------------------------------------------------" + << "-----------------------------------------------------|\n" + << " | | " + << " | |\n"; + + // Reset sum counters. + long nTrySum = 0; + long nSelSum = 0; + long nAccSum = 0; + double sigmaSum = 0.; + double delta2Sum = 0.; + + // Loop over existing processes. + for (int i = 0; i < int(containerPtrs.size()); ++i) + if (containerPtrs[i]->sigmaMax() != 0.) { + + // Read info for process. Sum counters. + long nTry = containerPtrs[i]->nTried(); + long nSel = containerPtrs[i]->nSelected(); + long nAcc = containerPtrs[i]->nAccepted(); + double sigma = containerPtrs[i]->sigmaMC(); + double delta = containerPtrs[i]->deltaMC(); + nTrySum += nTry; + nSelSum += nSel; + nAccSum += nAcc; + sigmaSum += sigma; + delta2Sum += pow2(delta); + + // Print individual process info. + os << " | " << left << setw(45) << containerPtrs[i]->name() + << right << setw(5) << containerPtrs[i]->code() << " | " + << setw(11) << nTry << " " << setw(10) << nSel << " " + << setw(10) << nAcc << " | " << scientific << setprecision(3) + << setw(11) << sigma << setw(11) << delta << " |\n"; + + // Print subdivision by user code for Les Houches process. + if (containerPtrs[i]->code() == 9999) + for (int j = 0; j < int(codeLHA.size()); ++j) + os << " | ... whereof user classification code " << setw(10) + << codeLHA[j] << " | " << setw(10) + << nEvtLHA[j] << " | | \n"; + } + + // Print summed process info. + os << " | | " + << " | |\n" + << " | " << left << setw(50) << "sum" << right << " | " << setw(11) + << nTrySum << " " << setw(10) << nSelSum << " " << setw(10) + << nAccSum << " | " << scientific << setprecision(3) << setw(11) + << sigmaSum << setw(11) << sqrtpos(delta2Sum) << " |\n"; + + // Listing finished. + os << " | " + << " |\n" + << " *------- End PYTHIA Event and Cross Section Statistics -----" + << "-----------------------------------------------------*" << endl; + + // Optionally reset statistics contants. + if (reset) for (int i = 0; i < int(containerPtrs.size()); ++i) + containerPtrs[i]->reset(); + +} + +//********* + +// Initialize SUSY Les Houches Accord data. + +bool ProcessLevel::initSLHA() { + + // Check whether SUSY is on. + if ( !Settings::flag("SUSY") ) return true; + + // Read SUSY Les Houches Accord File. + string slhaFile = Settings::word("SUSY:SusyLesHouchesFile"); + int ifail = slhaPtr->readFile(slhaFile); + + // In case of problems, print error and fail init. + if (ifail != 0) { + infoPtr->errorMsg("Error from Pythia::initSLHA: " + "problem reading SLHA file", slhaFile); + return false; + }; + + // Update particle data. + int id = slhaPtr->mass.first(); + for (int i = 1; i <= slhaPtr->mass.size() ; i++) { + double mass = abs(slhaPtr->mass(id)); + ParticleDataTable::m0(id,mass); + id = slhaPtr->mass.next(); + }; + + // Check spectrum for consistency. Switch off SUSY if necessary. + ifail = slhaPtr->checkSpectrum(); + if (ifail != 0) { + infoPtr->errorMsg("Warning from Pythia::initSLHA: " + "Problem with SLHA spectrum.", + "\n Only using masses and switching off SUSY."); + Settings::flag("SUSY", false); + slhaPtr->printSpectrum(); + return true; + }; + + // Print spectrum. Done. + slhaPtr->printSpectrum(); + return true; + +} + +//********* + +// Generate the next event with one interaction. + +bool ProcessLevel::nextOne( Event& process) { + + // Update CM energy for phase space selection. + double eCM = infoPtr->eCM(); + for (int i = 0; i < int(containerPtrs.size()); ++i) + containerPtrs[i]->newECM(eCM); + + // Loop over tries until trial event succeeds. + for ( ; ; ) { + + // Pick one of the subprocesses. + double sigmaMaxNow = sigmaMaxSum * Rndm::flat(); + int iMax = containerPtrs.size() - 1; + iContainer = -1; + do sigmaMaxNow -= containerPtrs[++iContainer]->sigmaMax(); + while (sigmaMaxNow > 0. && iContainer < iMax); + + // Do a trial event of this subprocess; accept or not. + if (containerPtrs[iContainer]->trialProcess()) break; + + // Check for end-of-file condition for Les Houches events. + if (infoPtr->atEndOfFile()) return false; + } + + // Update sum of maxima if current maximum violated. + if (containerPtrs[iContainer]->newSigmaMax()) { + sigmaMaxSum = 0.; + for (int i = 0; i < int(containerPtrs.size()); ++i) + sigmaMaxSum += containerPtrs[i]->sigmaMax(); + } + + // Construct kinematics of acceptable process. + if ( !containerPtrs[iContainer]->constructProcess( process) ) return false; + + // Do all resonance decays. + if ( doResDecays && !containerPtrs[iContainer]->decayResonances( + process) ) return false; + + // Add any junctions to the process event record list. + findJunctions( process); + + // Done. + return true; +} + +//********* + +// Generate the next event with two hard interactions. + +bool ProcessLevel::nextTwo( Event& process) { + + // Update CM energy for phase space selection. + double eCM = infoPtr->eCM(); + for (int i = 0; i < int(containerPtrs.size()); ++i) + containerPtrs[i]->newECM(eCM); + for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) + container2Ptrs[i2]->newECM(eCM); + + // Loop over both hard processes to find consistent common kinematics. + for ( ; ; ) { + + // Loop internally over tries for hardest process until succeeds. + for ( ; ; ) { + + // Pick one of the subprocesses. + double sigmaMaxNow = sigmaMaxSum * Rndm::flat(); + int iMax = containerPtrs.size() - 1; + iContainer = -1; + do sigmaMaxNow -= containerPtrs[++iContainer]->sigmaMax(); + while (sigmaMaxNow > 0. && iContainer < iMax); + + // Do a trial event of this subprocess; accept or not. + if (containerPtrs[iContainer]->trialProcess()) break; + + // Check for end-of-file condition for Les Houches events. + if (infoPtr->atEndOfFile()) return false; + } + + // Update sum of maxima if current maximum violated. + if (containerPtrs[iContainer]->newSigmaMax()) { + sigmaMaxSum = 0.; + for (int i = 0; i < int(containerPtrs.size()); ++i) + sigmaMaxSum += containerPtrs[i]->sigmaMax(); + } + + // Loop internally over tries for second hardest process until succeeds. + for ( ; ; ) { + + // Pick one of the subprocesses. + double sigma2MaxNow = sigma2MaxSum * Rndm::flat(); + int i2Max = container2Ptrs.size() - 1; + i2Container = -1; + do sigma2MaxNow -= container2Ptrs[++i2Container]->sigmaMax(); + while (sigma2MaxNow > 0. && i2Container < i2Max); + + // Do a trial event of this subprocess; accept or not. + if (container2Ptrs[i2Container]->trialProcess()) break; + } + + // Update sum of maxima if current maximum violated. + if (container2Ptrs[i2Container]->newSigmaMax()) { + sigma2MaxSum = 0.; + for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) + sigma2MaxSum += container2Ptrs[i2]->sigmaMax(); + } + + // Check whether common set of x values is kinematically possible. + double xA1 = containerPtrs[iContainer]->x1(); + double xB1 = containerPtrs[iContainer]->x2(); + double xA2 = container2Ptrs[i2Container]->x1(); + double xB2 = container2Ptrs[i2Container]->x2(); + if (xA1 + xA2 >= 1. || xB1 + xB2 >= 1.) continue; + + // Reset beam contents. Naive parton densities for second interaction. + // (Subsequent procedure could be symmetrized, but would be overkill.) + beamAPtr->clear(); + beamBPtr->clear(); + int idA1 = containerPtrs[iContainer]->id1(); + int idB1 = containerPtrs[iContainer]->id2(); + int idA2 = container2Ptrs[i2Container]->id1(); + int idB2 = container2Ptrs[i2Container]->id2(); + double Q2Fac1 = containerPtrs[iContainer]->Q2Fac(); + double Q2Fac2 = container2Ptrs[i2Container]->Q2Fac(); + double pdfA2Raw = beamAPtr->xf( idA2, xA2,Q2Fac2); + double pdfB2Raw = beamBPtr->xf( idB2, xB2,Q2Fac2); + + // Remove partons in first interaction from beams. + beamAPtr->append( 3, idA1, xA1); + beamAPtr->xfISR( 0, idA1, xA1, Q2Fac1); + beamAPtr->pickValSeaComp(); + beamBPtr->append( 4, idB1, xB1); + beamBPtr->xfISR( 0, idB1, xB1, Q2Fac1); + beamBPtr->pickValSeaComp(); + + // Reevaluate pdf's for second interaction and weight by reduction. + double pdfA2Mod = beamAPtr->xfMI( idA2, xA2,Q2Fac2); + double pdfB2Mod = beamBPtr->xfMI( idB2, xB2,Q2Fac2); + double wtPdfMod = (pdfA2Mod * pdfB2Mod) / (pdfA2Raw * pdfB2Raw); + if (wtPdfMod < Rndm::flat()) continue; + + // Reduce by a factor of 2 for identical processes when others not. + if ( someHardSame && containerPtrs[iContainer]->isSame() + && container2Ptrs[i2Container]->isSame() && Rndm::flat() > 0.5) + continue; + + // If come this far then acceptable event. + break; + } + + // Construct kinematics of acceptable processes. + Event process2; + process2.initColTag(); + startColTag2 = process2.lastColTag(); + if ( !containerPtrs[iContainer]->constructProcess( process) ) return false; + if ( !container2Ptrs[i2Container]->constructProcess( process2, false) ) + return false; + + // Do all resonance decays. + if ( doResDecays && !containerPtrs[iContainer]->decayResonances( + process) ) return false; + if ( doResDecays && !container2Ptrs[i2Container]->decayResonances( + process2) ) return false; + + // Append second hard interaction to normal process object. + combineProcessRecords( process, process2); + + // Add any junctions to the process event record list. + findJunctions( process); + + // Done. + return true; +} + +//********* + +// Append second hard interaction to normal process object. +// Complication: all resonance decay chains must be put at the end. + +void ProcessLevel::combineProcessRecords( Event& process, Event& process2) { + + // Find first event record size, excluding resonances. + int nSize = process.size(); + int nHard = 5; + while (nHard < nSize && process[nHard].mother1() == 3) ++nHard; + + // Save resonance products temporarily elsewhere. + vector resProd; + if (nSize > nHard) { + for (int i = nHard; i < nSize; ++i) resProd.push_back( process[i] ); + process.popBack(nSize - nHard); + } + + // Find second event record size, excluding resonances. + int nSize2 = process2.size(); + int nHard2 = 5; + while (nHard2 < nSize2 && process2[nHard2].mother1() == 3) ++nHard2; + + // Find amount of necessary position and colour offset for second process. + int addPos = nHard - 3; + int addCol = process.lastColTag() - startColTag2; + + // Loop over all particles (except beams) from second process. + for (int i = 3; i < nSize2; ++i) { + + // Offset mother and daughter pointers and colour tags of particle. + process2[i].offsetHistory( 2, addPos, 2, addPos); + process2[i].offsetCol( addCol); + + // Append hard-process particles from process2 to process. + if (i < nHard2) process.append( process2[i] ); + } + + // Reinsert resonance decay chains of first hard process. + int addPos2 = nHard2 - 3; + if (nHard < nSize) { + + // Offset daughter pointers of unmoved mothers. + for (int i = 5; i < nHard; ++i) + process[i].offsetHistory( 0, 0, nHard - 1, addPos2); + + // Modify history of resonance products when restoring. + for (int i = 0; i < int(resProd.size()); ++i) { + resProd[i].offsetHistory( nHard - 1, addPos2, nHard - 1, addPos2); + process.append( resProd[i] ); + } + } + + // Insert resonance decay chains of second hard process. + if (nHard2 < nSize2) { + int nHard3 = nHard + nHard2 - 3; + int addPos3 = nSize - nHard; + + // Offset daughter pointers of second-process mothers. + for (int i = nHard + 2; i < nHard3; ++i) + process[i].offsetHistory( 0, 0, nHard3 - 1, addPos3); + + // Modify history of second-process resonance products and insert. + for (int i = nHard2; i < nSize2; ++i) { + process2[i].offsetHistory( nHard3 - 1, addPos3, nHard3 - 1, addPos3); + process.append( process2[i] ); + } + } + + // Store PDF scale for second interaction. + process.scaleSecond( process2.scale() ); + +} + +//********* + +// Add any junctions to the process event record list. +// First try, so still incomplete. ?? +// Also check that do not doublebook if called repeatedly. + +void ProcessLevel::findJunctions( Event& junEvent) { + + // Loop though event; isolate all uncoloured particles. + for (int i = 0; i < junEvent.size(); ++i) + if ( junEvent[i].col() == 0 && junEvent[i].acol() == 0) { + + // Find all daughters and store daughter colours and anticolours. + vector daughters = junEvent.daughterList(i); + vector cols, acols; + for (int j = 0; j < int(daughters.size()); ++j) { + int colDau = junEvent[ daughters[j] ].col(); + int acolDau = junEvent[ daughters[j] ].acol(); + if (colDau > 0) cols.push_back( colDau); + if (acolDau > 0) acols.push_back( acolDau); + } + + // Remove all matching colour-anticolour pairs. + bool foundPair = true; + while (foundPair && cols.size() > 0 && acols.size() > 0) { + foundPair = false; + for (int j = 0; j < int(cols.size()); ++j) { + for (int k = 0; k < int(acols.size()); ++k) { + if (acols[k] == cols[j]) { + cols[j] = cols.back(); + cols.pop_back(); + acols[k] = acols.back(); + acols.pop_back(); + foundPair = true; + break; + } + } if (foundPair) break; + } + } + + // Store an (anti)junction when three (anti)coloured daughters. + if (cols.size() == 3 && acols.size() == 0) + junEvent.appendJunction( 1, cols[0], cols[1], cols[2]); + if (acols.size() == 3 && cols.size() == 0) + junEvent.appendJunction( 2, acols[0], acols[1], acols[2]); + } + + // Done. +} + +//********* + +// Check that colours match up. + +bool ProcessLevel::checkColours( Event& process) { + + // Variables and arrays for common usage. + bool physical = true; + bool match; + int colType, col, acol, iPos, iNow, iNowA; + vector colTags, colPos, acolPos; + + // Check that each particle has the kind of colours expected of it. + for (int i = 0; i < process.size(); ++i) { + colType = process[i].colType(); + col = process[i].col(); + acol = process[i].acol(); + if (colType == 0 && (col != 0 || acol != 0)) physical = false; + else if (colType == 1 && (col <= 0 || acol != 0)) physical = false; + else if (colType == -1 && (col != 0 || acol <= 0)) physical = false; + else if (colType == 2 && (col <= 0 || acol <= 0)) physical = false; + else if (colType < -1 || colType > 2) physical = false; + + // Add to the list of colour tags. + if (col > 0) { + match = false; + for (int ic = 0; ic < int(colTags.size()) ; ++ic) + if (col == colTags[ic]) match = true; + if (!match) colTags.push_back(col); + } else if (acol > 0) { + match = false; + for (int ic = 0; ic < int(colTags.size()) ; ++ic) + if (acol == colTags[ic]) match = true; + if (!match) colTags.push_back(acol); + } + } + + // Warn and give up if particles did not have the expected colours. + if (!physical) { + infoPtr->errorMsg("Error in ProcessLevel::checkColours: " + "incorrect colour assignment"); + return false; + } + + // Loop through all colour tags and find their positions (by sign). + for (int ic = 0; ic < int(colTags.size()); ++ic) { + col = colTags[ic]; + colPos.resize(0); + acolPos.resize(0); + for (int i = 0; i < process.size(); ++i) { + if (process[i].col() == col) colPos.push_back(i); + if (process[i].acol() == col) acolPos.push_back(i); + } + + // Trace colours back through decays; remove daughters. + while (colPos.size() > 1) { + iPos = colPos.size() - 1; + iNow = colPos[iPos]; + if ( process[iNow].mother1() == colPos[iPos - 1] + && process[iNow].mother2() == 0) colPos.pop_back(); + else break; + } + while (acolPos.size() > 1) { + iPos = acolPos.size() - 1; + iNow = acolPos[iPos]; + if ( process[iNow].mother1() == acolPos[iPos - 1] + && process[iNow].mother2() == 0) acolPos.pop_back(); + else break; + } + + // Now colour should exist in only 2 copies. + if (colPos.size() + acolPos.size() != 2) physical = false; + + // If both colours or both anticolours then one mother of the other. + else if (colPos.size() == 2) { + iNow = colPos[1]; + if ( process[iNow].mother1() != colPos[0] + && process[iNow].mother2() != colPos[0] ) physical = false; + } + else if (acolPos.size() == 2) { + iNowA = acolPos[1]; + if ( process[iNowA].mother1() != acolPos[0] + && process[iNowA].mother2() != acolPos[0] ) physical = false; + } + + // If one of each then should have same mother(s), or point to beams. + else { + iNow = colPos[0]; + iNowA = acolPos[0]; + if ( process[iNow].status() == -21 && process[iNowA].status() == -21 ); + else if ( (process[iNow].mother1() != process[iNowA].mother1()) + || (process[iNow].mother2() != process[iNowA].mother2()) ) + physical = false; + } + + } + + // Error message if problem found. Done. + if (!physical) infoPtr->errorMsg("Error in ProcessLevel::checkColours: " + "unphysical colour flow"); + return physical; + +} + +//********* + +// Print statistics when two hard processes allowed. + +void ProcessLevel::statistics2(bool reset, ostream& os) { + + // Average impact-parameter factor and error. + double invN = 1. / max(1, nImpact); + double impactFac = max( 1., sumImpactFac * invN); + double impactErr2 = ( sum2ImpactFac * invN / pow2(impactFac) - 1.) * invN; + + // Derive scaling factor to be applied to first set of processes. + double sigma2SelSum = 0.; + int n2SelSum = 0; + for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) { + sigma2SelSum += container2Ptrs[i2]->sigmaSelMC(); + n2SelSum += container2Ptrs[i2]->nSelected(); + } + double factor1 = impactFac * sigma2SelSum / sigmaND; + double rel1Err = sqrt(1. / max(1, n2SelSum) + impactErr2); + if (allHardSame) factor1 *= 0.5; + + // Derive scaling factor to be applied to second set of processes. + double sigma1SelSum = 0.; + int n1SelSum = 0; + for (int i = 0; i < int(containerPtrs.size()); ++i) { + sigma1SelSum += containerPtrs[i]->sigmaSelMC(); + n1SelSum += containerPtrs[i]->nSelected(); + } + double factor2 = impactFac * sigma1SelSum / sigmaND; + if (allHardSame) factor2 *= 0.5; + double rel2Err = sqrt(1. / max(1, n1SelSum) + impactErr2); + + // Header. + os << "\n *------- PYTHIA Event and Cross Section Statistics ------" + << "--------------------------------------------------*\n" + << " | " + << " |\n" + << " | Subprocess Code | " + << "Number of events | sigma +- delta |\n" + << " | | Tried" + << " Selected Accepted | (estimated) (mb) |\n" + << " | | " + << " | |\n" + << " |------------------------------------------------------------" + << "------------------------------------------------|\n" + << " | | " + << " | |\n" + << " | First hard process: | " + << " | |\n" + << " | | " + << " | |\n"; + + // Reset sum counters. + long nTrySum = 0; + long nSelSum = 0; + long nAccSum = 0; + double sigmaSum = 0.; + double delta2Sum = 0.; + + // Loop over existing first processes. + for (int i = 0; i < int(containerPtrs.size()); ++i) + if (containerPtrs[i]->sigmaMax() != 0.) { + + // Read info for process. Sum counters. + long nTry = containerPtrs[i]->nTried(); + long nSel = containerPtrs[i]->nSelected(); + long nAcc = containerPtrs[i]->nAccepted(); + double sigma = containerPtrs[i]->sigmaMC() * factor1; + double delta2 = pow2( containerPtrs[i]->deltaMC() * factor1 ); + nTrySum += nTry; + nSelSum += nSel; + nAccSum += nAcc; + sigmaSum += sigma; + delta2Sum += delta2; + delta2 += pow2( sigma * rel1Err ); + + // Print individual process info. + os << " | " << left << setw(40) << containerPtrs[i]->name() + << right << setw(5) << containerPtrs[i]->code() << " | " + << setw(11) << nTry << " " << setw(10) << nSel << " " + << setw(10) << nAcc << " | " << scientific << setprecision(3) + << setw(11) << sigma << setw(11) << sqrtpos(delta2) << " |\n"; + } + + // Print summed info for first processes. + delta2Sum += pow2( sigmaSum * rel1Err ); + os << " | | " + << " | |\n" + << " | " << left << setw(45) << "sum" << right << " | " << setw(11) + << nTrySum << " " << setw(10) << nSelSum << " " << setw(10) + << nAccSum << " | " << scientific << setprecision(3) << setw(11) + << sigmaSum << setw(11) << sqrtpos(delta2Sum) << " |\n"; + + + // Separation lines to second hard processes. + os << " | | " + << " | |\n" + << " |------------------------------------------------------------" + << "------------------------------------------------|\n" + << " | | " + << " | |\n" + << " | Second hard process: | " + << " | |\n" + << " | | " + << " | |\n"; + + // Reset sum counters. + nTrySum = 0; + nSelSum = 0; + nAccSum = 0; + sigmaSum = 0.; + delta2Sum = 0.; + + // Loop over existing second processes. + for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) + if (container2Ptrs[i2]->sigmaMax() != 0.) { + + // Read info for process. Sum counters. + long nTry = container2Ptrs[i2]->nTried(); + long nSel = container2Ptrs[i2]->nSelected(); + long nAcc = container2Ptrs[i2]->nAccepted(); + double sigma = container2Ptrs[i2]->sigmaMC() * factor2; + double delta2 = pow2( container2Ptrs[i2]->deltaMC() * factor2 ); + nTrySum += nTry; + nSelSum += nSel; + nAccSum += nAcc; + sigmaSum += sigma; + delta2Sum += delta2; + delta2 += pow2( sigma * rel2Err ); + + // Print individual process info. + os << " | " << left << setw(40) << container2Ptrs[i2]->name() + << right << setw(5) << container2Ptrs[i2]->code() << " | " + << setw(11) << nTry << " " << setw(10) << nSel << " " + << setw(10) << nAcc << " | " << scientific << setprecision(3) + << setw(11) << sigma << setw(11) << sqrtpos(delta2) << " |\n"; + } + + // Print summed info for second processes. + delta2Sum += pow2( sigmaSum * rel2Err ); + os << " | | " + << " | |\n" + << " | " << left << setw(45) << "sum" << right << " | " << setw(11) + << nTrySum << " " << setw(10) << nSelSum << " " << setw(10) + << nAccSum << " | " << scientific << setprecision(3) << setw(11) + << sigmaSum << setw(11) << sqrtpos(delta2Sum) << " |\n"; + + // Print information on how the two processes were combined. + os << " | | " + << " | |\n" + << " |------------------------------------------------------------" + << "------------------------------------------------|\n" + << " | " + << " |\n" + << " | Uncombined cross sections for the two event sets were " + << setw(10) << sigma1SelSum << " and " << sigma2SelSum << " mb, " + << "respectively, combined |\n" + << " | using a sigma(nonDiffractive) of " << setw(10) << sigmaND + << " mb and an impact-parameter enhancement factor of " + << setw(10) << impactFac << ". |\n"; + + // Listing finished. + os << " | " + << " |\n" + << " *------- End PYTHIA Event and Cross Section Statistics -----" + << "------------------------------------------------*" << endl; + + // Optionally reset statistics contants. + if (reset) { + for (int i = 0; i < int(containerPtrs.size()); ++i) + containerPtrs[i]->reset(); + for (int i2 = 0; i2 < int(container2Ptrs.size()); ++i2) + container2Ptrs[i2]->reset(); + } + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/Pythia.cxx b/PYTHIA8/pythia8130/src/Pythia.cxx new file mode 100644 index 00000000000..562266464b2 --- /dev/null +++ b/PYTHIA8/pythia8130/src/Pythia.cxx @@ -0,0 +1,1346 @@ +// Pythia.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the Pythia class. + +#include "Pythia.h" + +// Access time information. +#include + +// Allow string and character manipulation. +#include + +namespace Pythia8 { + +//************************************************************************** + +// The Pythia class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Maximum number of tries to produce parton level from given input. +const int Pythia::NTRY = 10; + +// Negative integer to denote that no subrun has been set. +const int Pythia::SUBRUNDEFAULT = -999; + +//********* + +// Constructor. + +Pythia::Pythia(string xmlDir) { + + // Initial values for pointers to PDF's. + useNewPdfA = false; + useNewPdfB = false; + useNewPdfHard = false; + pdfAPtr = 0; + pdfBPtr = 0; + pdfHardAPtr = 0; + pdfHardBPtr = 0; + + // Initial values for pointers to Les Houches Event objects. + doLHA = false; + useNewLHA = false; + lhaUpPtr = 0; + + // Initial value for pointer to external decay handler. + decayHandlePtr = 0; + + // Initial value for pointer to user hooks. + userHooksPtr = 0; + + // Initial value for pointer to beam shape. + useNewBeamShape = false; + beamShapePtr = 0; + + // Initial values for pointers to timelike and spacelike showers. + useNewTimes = false; + useNewSpace = false; + timesDecPtr = 0; + timesPtr = 0; + spacePtr = 0; + + // Send Info pointer to handle error printout/counting correctly. + settings.initPtr( &info); + ParticleDataEntry::initPtr( &info); + particleData.initPtr( &info); + + // Find path to data files, i.e. xmldoc directory location. + // Environment variable takes precedence, else use constructor input. + string path = ""; + const char* PYTHIA8DATA = "PYTHIA8DATA"; + char* envPath = getenv(PYTHIA8DATA); + if (envPath != 0 && *envPath != '\0') { + int i = 0; + while (*(envPath+i) != '\0') path += *(envPath+(i++)); + } + else path = xmlDir; + if (path[ path.length() - 1 ] != '/') path += "/"; + + // Read in files with all flags, modes, parms and words. + string initFile = path + "Index.xml"; + isConstructed = settings.init( initFile); + if (!isConstructed) { + info.errorMsg("Abort from Pythia::Pythia: settings unavailable"); + return; + } + + // Read in files with all particle data. + string dataFile = path + "ParticleData.xml"; + isConstructed = particleData.init( dataFile); + if (!isConstructed) { + info.errorMsg("Abort from Pythia::Pythia: particle data unavailable"); + return; + } + + // Write the Pythia banner to output. + banner(); + + // Set headers to distinguish the two event listing kinds. + process.init("(hard process)"); + event.init("(complete event)"); + + // Not initialized until at the end of initInternal. + isInit = false; + +} + +//********* + +// Destructor. + +Pythia::~Pythia() { + + // Delete the PDF's created with new. + if (useNewPdfHard && pdfHardAPtr != pdfAPtr) delete pdfHardAPtr; + if (useNewPdfHard && pdfHardBPtr != pdfBPtr) delete pdfHardBPtr; + if (useNewPdfA) delete pdfAPtr; + if (useNewPdfB) delete pdfBPtr; + + // Delete the Les Houches object created with new. + if (useNewLHA) delete lhaUpPtr; + + // Delete the BeamShape object created with new. + if (useNewBeamShape) delete beamShapePtr; + + // Delete the timelike and spacelike showers created with new. + if (useNewTimes) delete timesPtr; + if (useNewSpace) delete spacePtr; + +} + +//********* + +// Read in one update for a setting or particle data from a single line. + +bool Pythia::readString(string line, bool warn) { + + // Check that constructor worked. + if (!isConstructed) return false; + + // If empty line then done. + if (line.find_first_not_of(" ") == string::npos) return true; + + // If first character is not a letter/digit, then taken to be a comment. + int firstChar = line.find_first_not_of(" "); + if (!isalnum(line[firstChar])) return true; + + // Send on particle data to the ParticleData database. + if (isdigit(line[firstChar])) + return particleData.readString(line, warn); + + // Everything else sent on to Settings. + return settings.readString(line, warn); + +} + +//********* + +// Read in updates for settings or particle data from user-defined file. + +bool Pythia::readFile(string fileName, bool warn, int subrun) { + + // Check that constructor worked. + if (!isConstructed) return false; + + // Open file with updates. + const char* cstring = fileName.c_str(); + ifstream is(cstring); + if (!is) { + info.errorMsg("Error in Pythia::readFile: did not find file", fileName); + return false; + } + + // Read in one line at a time. + string line; + bool accepted = true; + int subrunNow = SUBRUNDEFAULT; + while ( getline(is, line) ) { + + // Check whether entered new subrun. + int subrunLine = readSubrun( line, warn); + if (subrunLine >= 0) subrunNow = subrunLine; + + // Process the line if in correct subrun. + if ( (subrunNow == subrun || subrunNow == SUBRUNDEFAULT) + && !readString( line, warn) ) accepted = false; + + // Reached end of input file. + }; + return accepted; +} + +//********* + +// Routine to pass in pointers to PDF's. Usage optional. + +bool Pythia::setPDFPtr( PDF* pdfAPtrIn, PDF* pdfBPtrIn, PDF* pdfHardAPtrIn, + PDF* pdfHardBPtrIn) { + + // The routine can have no effect if PDF's already assigned. + if (pdfAPtr != 0 || pdfBPtr != 0) return false; + + // The two PDF objects cannot be one and the same, or unassigned. + if (pdfAPtrIn == pdfBPtrIn || pdfAPtrIn == 0 || pdfBPtrIn == 0) return false; + + // Save pointers. + pdfAPtr = pdfAPtrIn; + pdfBPtr = pdfBPtrIn; + + // By default same pointers for hard-process PDF's. + pdfHardAPtr = pdfAPtrIn; + pdfHardBPtr = pdfBPtrIn; + + // Optionally allow separate pointers for hard process. + if (pdfHardAPtrIn == 0 || pdfHardBPtrIn == 0) return true; + if (pdfHardAPtrIn == pdfHardBPtrIn) return false; + pdfHardAPtr = pdfHardAPtrIn; + pdfHardBPtr = pdfHardBPtrIn; + + // Done. + return true; +} + +//********* + +// Routine to initialize with CM energy. + +bool Pythia::init( int idAin, int idBin, double eCMin) { + + // Read in and set values. + idA = idAin; + idB = idBin; + frameType = 1; + eCM = eCMin; + doLHA = false; + + // Send on to common initialization. + bool status = initInternal(); + if (!status) info.errorMsg("Abort from Pythia::init: initialization failed"); + return status; + +} + +//********* + +// Routine to initialize with two collinear beams, energies specified. + +bool Pythia::init( int idAin, int idBin, double eAin, double eBin) { + + // Read in and set values. + idA = idAin; + idB = idBin; + frameType = 2; + eA = eAin; + eB = eBin; + doLHA = false; + + // Send on to common initialization. + bool status = initInternal(); + if (!status) info.errorMsg("Abort from Pythia::init: initialization failed"); + return status; + +} + +//********* + +// Routine to initialize with two beams specified by three-momenta. + +bool Pythia::init( int idAin, int idBin, double pxAin, double pyAin, + double pzAin, double pxBin, double pyBin, double pzBin) { + + // Read in and set values. + idA = idAin; + idB = idBin; + frameType = 3; + pxA = pxAin; + pyA = pyAin; + pzA = pzAin; + pxB = pxBin; + pyB = pyBin; + pzB = pzBin; + doLHA = false; + + // Send on to common initialization. + bool status = initInternal(); + if (!status) info.errorMsg("Abort from Pythia::init: initialization failed"); + return status; + +} + +//********* + +// Routine to initialize when all info is given in a Les Houches Event File. + +bool Pythia::init( string LesHouchesEventFile, bool skipInit) { + + // Destroy any previous LHAup object. + if (useNewLHA) delete lhaUpPtr; + + // Create LHAup object. Send in pointer to info. + const char* cstring = LesHouchesEventFile.c_str(); + lhaUpPtr = new LHAupLHEF(cstring); + lhaUpPtr->setPtr( &info); + doLHA = true; + useNewLHA = true; + + // Store or replace LHA pointer in other classes. + processLevel.setLHAPtr( lhaUpPtr); + + // If second time around, only with new file, then simplify. + if (skipInit) return true; + + // Set LHAinit information (in some external program). + if (!lhaUpPtr->setInit()) { + info.errorMsg("Abort from Pythia::init: " + "Les Houches initialization failed"); + return false; + } + + // Extract beams from values set in an LHAinit object. + idA = lhaUpPtr->idBeamA(); + idB = lhaUpPtr->idBeamB(); + eA = lhaUpPtr->eBeamA(); + eB = lhaUpPtr->eBeamB(); + frameType = 2; + + // Now do normal initialization. List info if there. + bool status = initInternal(); + lhaUpPtr->listInit(); + if (!status) info.errorMsg("Abort from Pythia::init: initialization failed"); + return status; + +} + +//********* + +// Routine to initialize with the variable values of the Beams kind. + +bool Pythia::init() { + + // Check if to read from Les Houches Event File set, and is so send on. + if (mode("Beams:frameType") == 4) { + string lhef = word("Beams:LHEF"); + bool skipInit = flag("Main:LHEFskipInit"); + return init( lhef, skipInit); + } + + // Read in and set values. + idA = mode("Beams:idA"); + idB = mode("Beams:idB"); + frameType = mode("Beams:frameType"); + eCM = parm("Beams:eCM"); + eA = parm("Beams:eA"); + eB = parm("Beams:eB"); + pxA = parm("Beams:pxA"); + pyA = parm("Beams:pyA"); + pzA = parm("Beams:pzA"); + pxB = parm("Beams:pxB"); + pyB = parm("Beams:pyB"); + pzB = parm("Beams:pzB"); + doLHA = false; + + // Send on to common initialization. + bool status = initInternal(); + if (!status) info.errorMsg("Abort from Pythia::init: initialization failed"); + return status; + +} + +//********* + +// Routine to initialize when beam info is given in an LHAup object. + +bool Pythia::init( LHAup* lhaUpPtrIn) { + + // Save and set flag for subsequent usage of LHAup object. + lhaUpPtr = lhaUpPtrIn; + doLHA = true; + + // Store LHA pointer in other classes. + processLevel.setLHAPtr( lhaUpPtr); + + // Set LHAinit information (in some external program). + if (!lhaUpPtr->setInit()) { + info.errorMsg("Abort from Pythia::init: " + "Les Houches initialization failed"); + return false; + } + + // Extract beams from values set in an LHAinit object. + idA = lhaUpPtr->idBeamA(); + idB = lhaUpPtr->idBeamB(); + eA = lhaUpPtr->eBeamA(); + eB = lhaUpPtr->eBeamB(); + frameType = 2; + + // Now do normal initialization. List info if there. + bool status = initInternal(); + lhaUpPtr->listInit(); + if (!status) info.errorMsg("Abort from Pythia::init: initialization failed"); + return status; + +} + +//********* + +// Main routine to initialize the generation process. +// (The alternative init forms end up in this one.) + +bool Pythia::initInternal() { + + // Check that constructor worked. + isInit = false; + if (!isConstructed) return false; + + // Reset error counters. + nErrEvent = 0; + info.errorReset(); + + // Initialize data members extracted from database. + doProcessLevel = settings.flag("ProcessLevel:all"); + doPartonLevel = settings.flag("PartonLevel:all") && doProcessLevel; + doHadronLevel = settings.flag("HadronLevel:all"); + doMomentumSpread = settings.flag("Beams:allowMomentumSpread"); + doVertexSpread = settings.flag("Beams:allowVertexSpread"); + checkEvent = settings.flag("Check:event"); + nErrList = settings.mode("Check:nErrList"); + epTolErr = settings.parm("Check:epTolErr"); + epTolWarn = settings.parm("Check:epTolWarn"); + + // Initialize the random number generator. + if ( settings.flag("Random:setSeed") ) + Rndm::init( settings.mode("Random:seed") ); + + // Initialize tunes to e+e- and pp/ppbar data. + initTunes(); + + // Initialize couplings (needed to initialize resonances). + AlphaEM::initStatic(); + CoupEW::initStatic(); + VCKM::initStatic(); + + // Initialize some aspects of particle data, including resonances. + ParticleDataEntry::initStatic(); + particleData.initBWmass(); + particleData.initResonances(resonancePtrs); + + // Set up values related to user hooks. + hasUserHooks = (userHooksPtr > 0); + doVetoProcess = (hasUserHooks) + ? userHooksPtr->canVetoProcessLevel() : false; + doVetoPartons = (hasUserHooks) + ? userHooksPtr->canVetoPartonLevel() : false; + + // Set up values related to beam shape. + if (beamShapePtr == 0) { + beamShapePtr = new BeamShape(); + useNewBeamShape = true; + } + beamShapePtr->init(); + + // Set up objects for timelike and spacelike showers. + if (timesDecPtr == 0 || timesPtr == 0) { + TimeShower* timesNow = new TimeShower(); + if (timesDecPtr == 0) timesDecPtr = timesNow; + if (timesPtr == 0) timesPtr = timesNow; + useNewTimes = true; + } + if (spacePtr == 0) { + spacePtr = new SpaceShower(); + useNewSpace = true; + } + + // Initialize showers, especially for simple showers in decays. + timesPtr->initPtr( &info); + timesDecPtr->initPtr( &info); + spacePtr->initPtr( &info); + timesDecPtr->init( 0, 0); + + // Check that beams and beam combination can be handled. + // Only allow neutrinos as beams when leptons unresolved. + bool canHandleBeams = false; + int idAabs = abs(idA); + int idBabs = abs(idB); + if (doProcessLevel) { + if (idAabs == 2212 && idBabs == 2212) canHandleBeams = true; + else if ( idAabs == idBabs && (idAabs == 11 || idAabs == 13 + || idAabs == 15) ) canHandleBeams = true; + else if ( idAabs > 10 && idAabs < 17 && idA * idB < 0 + && !settings.flag("PDF:lepton") ) { + if (idAabs == idBabs) canHandleBeams = true; + int idMax = max(idAabs, idBabs); + int idMin = min(idAabs, idBabs); + if (idMax - idMin == 1 && idMax%2 == 0) canHandleBeams = true; + } + if (!canHandleBeams) { + info.errorMsg("Error in Pythia::init: " + "cannot handle this beam combination"); + return false; + } + } + + // Do not set up beam kinematics when no process level. + if (!doProcessLevel) frameType = 1; + else { + + // Set up beam kinematics. + if (!initKinematics()) return false; + + // Set up the PDF's, if not already done. + if (pdfAPtr == 0) { + pdfAPtr = getPDFPtr(idA); + if (!pdfAPtr->isSetup()) return false; + pdfHardAPtr = pdfAPtr; + useNewPdfA = true; + } + if (pdfBPtr == 0) { + pdfBPtr = getPDFPtr(idB); + if (!pdfBPtr->isSetup()) return false; + pdfHardBPtr = pdfBPtr; + useNewPdfB = true; + } + + // Optionally set up separate PDF's for hard process. + if (settings.flag("PDF:useHard")) { + pdfHardAPtr = getPDFPtr(idA, 2); + if (!pdfHardAPtr->isSetup()) return false; + pdfHardBPtr = getPDFPtr(idB, 2); + if (!pdfHardBPtr->isSetup()) return false; + useNewPdfHard = true; + } + + // Set up the two beams and the common remnant system. + StringFlav* flavSel = hadronLevel.getStringFlavPtr(); + bool isUnresolvedA = ( ParticleDataTable::isLepton(idA) + && !settings.flag("PDF:lepton") ); + bool isUnresolvedB = ( ParticleDataTable::isLepton(idB) + && !settings.flag("PDF:lepton") ); + beamA.init( idA, pzAcm, eA, mA, &info, pdfAPtr, pdfHardAPtr, + isUnresolvedA, flavSel); + beamB.init( idB, pzBcm, eB, mB, &info, pdfBPtr, pdfHardBPtr, + isUnresolvedB, flavSel); + } + + // Send info/pointers to process level for initialization. + if ( doProcessLevel && !processLevel.init( &info, &beamA, &beamB, + &sigmaTot, doLHA, &slha, userHooksPtr, sigmaPtrs) ) return false; + + // Send info/pointers to parton level for initialization. + if ( doPartonLevel && !partonLevel.init( &info, &beamA, &beamB, + &sigmaTot, timesDecPtr, timesPtr, spacePtr, userHooksPtr) ) + return false; + + // Send info/pointers to hadron level for initialization. + // Note: forceHadronLevel() can come, so we must always initialize. + if ( !hadronLevel.init( &info, timesDecPtr, decayHandlePtr, + handledParticles) ) return false; + + // Optionally check particle data table for inconsistencies. + if ( settings.flag("Check:particleData") ) + particleData.checkTable( settings.mode("Check:levelParticleData") ); + + // Succeeded. + isInit = true; + return true; +} + +//********* + +// Calculate kinematics at initialization. Store beam four-momenta. + +bool Pythia::initKinematics() { + + // Find masses. Initial guess that we are in CM frame. + mA = ParticleDataTable::m0(idA); + mB = ParticleDataTable::m0(idB); + betaZ = 0.; + gammaZ = 1.; + + // Collinear beams not in CM frame: find CM energy. + if (frameType == 2) { + eA = max(eA, mA); + eB = max(eB, mB); + pzA = sqrt(eA*eA - mA*mA); + pzB = -sqrt(eB*eB - mB*mB); + pAinit = Vec4( 0., 0., pzA, eA); + pBinit = Vec4( 0., 0., pzB, eB); + eCM = sqrt( pow2(eA + eB) - pow2(pzA + pzB) ); + + // Find boost to rest frame. + betaZ = (pzA + pzB) / (eA + eB); + gammaZ = (eA + eB) / eCM; + if (abs(betaZ) < 1e-10) frameType = 1; + } + + // Completely general beam directions: find CM energy. + else if (frameType == 3) { + eA = sqrt( pxA*pxA + pyA*pyA + pzA*pzA + mA*mA); + eB = sqrt( pxB*pxB + pyB*pyB + pzB*pzB + mB*mB); + pAinit = Vec4( pxA, pyA, pzA, eA); + pBinit = Vec4( pxB, pyB, pzB, eB); + eCM = (pAinit + pBinit).mCalc(); + + // Find boost+rotation needed to move from/to CM frame. + MfromCM.reset(); + MfromCM.fromCMframe( pAinit, pBinit); + MtoCM = MfromCM; + MtoCM.invert(); + } + + // Fail if CM energy below beam masses. + if (eCM < mA + mB) return false; + + // Set up CM-frame kinematics with beams along +-z axis. + pzAcm = 0.5 * sqrtpos( (eCM + mA + mB) * (eCM - mA - mB) + * (eCM - mA + mB) * (eCM + mA - mB) ) / eCM; + pzBcm = -pzAcm; + eA = sqrt(mA*mA + pzAcm*pzAcm); + eB = sqrt(mB*mB + pzBcm*pzBcm); + + // If in CM frame then store beam four-vectors (else already done above). + if (frameType != 2 && frameType != 3) { + pAinit = Vec4( 0., 0., pzAcm, eA); + pBinit = Vec4( 0., 0., pzBcm, eB); + } + + // Store main info for access in process generation. + info.setBeamA( idA, pzAcm, eA, mA); + info.setBeamB( idB, pzBcm, eB, mB); + info.setECM( eCM); + + // Must allow for generic boost+rotation when beam momentum spread. + if (doMomentumSpread) frameType = 3; + + // Done. + return true; + +} + +//********* + +// Initialize tunes to e+e- and pp/ppbar data. + +void Pythia::initTunes() { + + // Modes to use. Fast return if all is default. + int eeTune = settings.mode("Tune:ee"); + int ppTune = settings.mode("Tune:pp"); + if (eeTune == 0 && ppTune == 0) return; + + // Marc Montull's tune to particle composition at LEP1. + if (eeTune == 101) { + settings.parm("StringZ:aLund", 0.76 ); + settings.parm("StringZ:bLund", 0.58 ); // default + settings.parm("StringFlav:probStoUD", 0.22 ); + settings.parm("StringFlav:probQQtoQ", 0.08 ); + settings.parm("StringFlav:probSQtoQQ", 0.75 ); + settings.parm("StringFlav:probQQ1toQQ0", 0.025 ); + settings.parm("StringFlav:mesonUDvector", 0.5 ); + settings.parm("StringFlav:mesonSvector", 0.6 ); + settings.parm("StringFlav:mesonCvector", 1.5 ); + settings.parm("StringFlav:mesonBvector", 2.5 ); + settings.parm("StringFlav:etaSup", 0.60 ); + settings.parm("StringFlav:etaPrimeSup", 0.15 ); + settings.parm("StringFlav:popcornSpair", 1.0 ); + settings.parm("StringFlav:popcornSmeson", 1.0 ); + } + +} + +//********* + +// Main routine to generate the next event, using internal machinery. + +bool Pythia::next() { + + // Simpler option when only HadronLevel to be generated. + if (!doProcessLevel) { + + // Set correct energy for system. + Vec4 pSum = 0.; + for (int i = 1; i < event.size(); ++i) + if (event[i].isFinal()) pSum += event[i].p(); + event[0].p( pSum ); + event[0].m( pSum.mCalc() ); + + // Generate hadronization and decays. + return forceHadronLevel(); + } + + // Reset arrays. + info.clear(); + process.clear(); + event.clear(); + + // Can only generate event if initialization worked. + if (!isInit) { + info.errorMsg("Abort from Pythia::next: " + "not properly initialized so cannot generate events"); + return false; + } + + // Pick beam momentum spread and beam vertex. + if (doMomentumSpread || doVertexSpread) beamShapePtr->pick(); + + // Recalculate kinematics when beam momentum spread. + if (doMomentumSpread) nextKinematics(); + + // Outer loop over hard processes; only relevant for user-set vetoes. + for ( ; ; ) { + bool hasVetoed = false; + + // Provide the hard process that starts it off. Only one try. + info.clear(); + process.clear(); + if ( !processLevel.next( process) ) { + info.errorMsg("Abort from Pythia::next: " + "processLevel failed; giving up"); + return false; + } + + // Possibility for a user veto of the process-level event. + if (doVetoProcess) { + hasVetoed = userHooksPtr->doVetoProcessLevel( process); + if (hasVetoed) continue; + } + + // Possibility to stop the generation at this stage. + if (!doPartonLevel) { + boostAndVertex( true, true); + processLevel.accumulate(); + return true; + } + + // Allow up to ten tries for parton- and hadron-level processing. + bool physical = true; + bool hasBoosted = false; + for (int iTry = 0; iTry < NTRY; ++ iTry) { + + physical = true; + + // Restore process record to CM frame if it was boosted. + if (hasBoosted) { + boostAndVertex( false, false); + hasBoosted = false; + } + + // Reset event record and (extracted partons from) beam remnants. + event.clear(); + beamA.clear(); + beamB.clear(); + + // Parton-level evolution: ISR, FSR, MI. + if ( !partonLevel.next( process, event) ) { + // Skip to next hard process for failure owing to deliberate veto. + hasVetoed = partonLevel.hasVetoed(); + if (hasVetoed) break; + // Else make a new try for other failures. + info.errorMsg("Error in Pythia::next: " + "partonLevel failed; try again"); + physical = false; + continue; + } + + // Possibility for a user veto of the parton-level event. + if (doVetoPartons) { + hasVetoed = userHooksPtr->doVetoPartonLevel( event); + if (hasVetoed) break; + } + + // Boost to lab frame (before decays, for vertices). + boostAndVertex( true, true); + if (frameType == 2 || frameType == 3) hasBoosted = true; + + // Possibility to stop the generation at this stage. + if (!doHadronLevel) { + processLevel.accumulate(); + partonLevel.accumulate(); + + // Optionally check final event for problems. + if (checkEvent && !check()) { + info.errorMsg("Abort from Pythia::next: " + "check of event revealed problems"); + return false; + } + return true; + } + + // Hadron-level: hadronization, decays. + if ( !hadronLevel.next( event) ) { + info.errorMsg("Error in Pythia::next: " + "hadronLevel failed; try again"); + physical = false; + continue; + } + + // Stop parton- and hadron-level looping if you got this far. + break; + } + + // If event vetoed then to make a new try. + if (hasVetoed) continue; + + // If event failed any other way (after ten tries) then give up. + if (!physical) { + info.errorMsg("Abort from Pythia::next: " + "parton+hadronLevel failed; giving up"); + return false; + } + + // Process- and parton-level statistics. + processLevel.accumulate(); + partonLevel.accumulate(); + + // End of outer loop over hard processes. Done with normal option. + break; + } + + // Optionally check final event for problems. + if (checkEvent && !check()) { + info.errorMsg("Abort from Pythia::next: " + "check of event revealed problems"); + return false; + } + + // Done. + return true; + +} + +//********* + +// Generate only the hadronization/decay stage, using internal machinery. +// The "event" instance should already contain a parton-level configuration. + +bool Pythia::forceHadronLevel() { + + // Can only generate event if initialization worked. + if (!isInit) { + info.errorMsg("Abort from Pythia::forceHadronLevel: " + "not properly initialized so cannot generate events"); + return false; + } + + // Check whether any junctions in system. (Normally done in ProcessLevel.) + event.clearJunctions(); + processLevel.findJunctions( event); + + // Save spare copy of event in case of failure. + Event spareEvent = event; + + // Allow up to ten tries for hadron-level processing. + bool physical = true; + for (int iTry = 0; iTry < NTRY; ++ iTry) { + physical = true; + + // Hadron-level: hadronization, decays. + if (hadronLevel.next( event)) break; + + // If failure then warn, restore original configuration and try again. + info.errorMsg("Error in Pythia::forceHadronLevel: " + "hadronLevel failed; try again"); + physical = false; + event = spareEvent; + } + + // Done for simpler option. + if (!physical) { + info.errorMsg("Abort from Pythia::forceHadronLevel: " + "hadronLevel failed; giving up"); + return false; + } + + // Optionally check final event for problems. + if (checkEvent && !check()) { + info.errorMsg("Abort from Pythia::forceHadronLevel: " + "check of event revealed problems"); + return false; + } + + // Done. + return true; + +} + +//********* + +// Recalculate kinematics for each event when beam momentum has a spread. + +void Pythia::nextKinematics() { + + // Read out momentum shift to give current beam momenta. + pAnow = pAinit + beamShapePtr->deltaPA(); + pAnow.e( sqrt(pAnow.pAbs2() + mA * mA) ); + pBnow = pBinit + beamShapePtr->deltaPB(); + pBnow.e( sqrt(pBnow.pAbs2() + mB * mB) ); + + // Construct CM frame kinematics. + eCM = (pAnow + pBnow).mCalc(); + pzAcm = 0.5 * sqrtpos( (eCM + mA + mB) * (eCM - mA - mB) + * (eCM - mA + mB) * (eCM + mA - mB) ) / eCM; + pzBcm = -pzAcm; + eA = sqrt(mA*mA + pzAcm*pzAcm); + eB = sqrt(mB*mB + pzBcm*pzBcm); + + // Set relevant info for other classes to use. + info.setBeamA( idA, pzAcm, eA, mA); + info.setBeamB( idB, pzBcm, eB, mB); + info.setECM( eCM); + beamA.newPzE( pzAcm, eA); + beamB.newPzE( pzBcm, eB); + + // Set boost/rotation matrices from/to CM frame. + MfromCM.reset(); + MfromCM.fromCMframe( pAnow, pBnow); + MtoCM = MfromCM; + MtoCM.invert(); + +} + +//********* + +// Boost from CM frame to lab frame, or inverse. Set production vertex. + +void Pythia::boostAndVertex( bool toLab, bool setVertex) { + + // Boost process from CM frame to lab frame. + if (toLab) { + if (frameType == 2) process.bst(0., 0., betaZ, gammaZ); + else if (frameType == 3) process.rotbst(MfromCM); + + // Boost nonempty event from CM frame to lab frame. + if (event.size() > 0) { + if (frameType == 2) event.bst(0., 0., betaZ, gammaZ); + else if (frameType == 3) event.rotbst(MfromCM); + } + + // Boost process from lab frame to CM frame. + } else { + if (frameType == 2) process.bst(0., 0., -betaZ, gammaZ); + else if (frameType == 3) process.rotbst(MtoCM); + + // Boost nonempty event from lab frame to CM frame. + if (event.size() > 0) { + if (frameType == 2) event.bst(0., 0., -betaZ, gammaZ); + else if (frameType == 3) event.rotbst(MtoCM); + } + } + + // Set production vertex; assumes particles are in lab frame and at origin + if (setVertex && doVertexSpread) { + Vec4 vertex = beamShapePtr->vertex(); + for (int i = 0; i < process.size(); ++i) process[i].vProd( vertex); + for (int i = 0; i < event.size(); ++i) event[i].vProd( vertex); + } + +} + +//********* + +// Print statistics on event generation. + +void Pythia::statistics(bool all, bool reset) { + + // Statistics on cross section and number of events. + if (doProcessLevel) processLevel.statistics(reset); + + // Statistics from other classes, e.g. multiple interactions. + if (all) partonLevel.statistics(reset); + + // Summary of which and how many warnings/errors encountered. + info.errorStatistics(); + if (reset) info.errorReset(); + +} + +//********* + +// Write the Pythia banner, with symbol and version information. + +void Pythia::banner(ostream& os) { + + // Read in version number and last date of change. + double versionNumber = Settings::parm("Pythia:versionNumber"); + int versionDate = Settings::mode("Pythia:versionDate"); + string month[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + // Get date and time. + time_t t = time(0); + char dateNow[12]; + strftime(dateNow,12,"%d %b %Y",localtime(&t)); + char timeNow[9]; + strftime(timeNow,9,"%H:%M:%S",localtime(&t)); + + + os << "\n" + << " *-------------------------------------------" + << "-----------------------------------------* \n" + << " | " + << " | \n" + << " | *----------------------------------------" + << "--------------------------------------* | \n" + << " | | " + << " | | \n" + << " | | " + << " | | \n" + << " | | PPP Y Y TTTTT H H III A " + << " Welcome to the Lund Monte Carlo! | | \n" + << " | | P P Y Y T H H I A A " + << " This is PYTHIA version " << fixed << setprecision(3) + << setw(5) << versionNumber << " | | \n" + << " | | PPP Y T HHHHH I AAAAA" + << " Last date of change: " << setw(2) << versionDate%100 + << " " << month[ (versionDate/100)%100 - 1 ] + << " " << setw(4) << versionDate/10000 << " | | \n" + << " | | P Y T H H I A A" + << " | | \n" + << " | | P Y T H H III A A" + << " Now is " << dateNow << " at " << timeNow << " | | \n" + << " | | " + << " | | \n" + << " | | Main author: Torbjorn Sjostrand; CERN" + << "/PH, CH-1211 Geneva, Switzerland, | | \n" + << " | | and Department of Theoretical Physi" + << "cs, Lund University, Lund, Sweden; | | \n" + << " | | phone: + 41 - 22 - 767 82 27; e-mai" + << "l: torbjorn@thep.lu.se | | \n" + << " | | Author: Stephen Mrenna; Computing Div" + << "ision, Simulations Group, | | \n" + << " | | Fermi National Accelerator Laborato" + << "ry, MS 234, Batavia, IL 60510, USA; | | \n" + << " | | phone: + 1 - 630 - 840 - 2556; e-ma" + << "il: mrenna@fnal.gov | | \n" + << " | | Author: Peter Skands; CERN/PH, CH-121" + << "1 Geneva, Switzerland, | | \n" + << " | | and Theoretical Physics Department," + << " | | \n" + << " | | Fermi National Accelerator Laborato" + << "ry, MS 106, Batavia, IL 60510, USA; | | \n" + << " | | phone: + 41 - 22 - 767 24 59; e-mai" + << "l: skands@fnal.gov | | \n" + << " | | " + << " | | \n" + << " | | The main program reference is the 'Br" + << "ief Introduction to PYTHIA 8.1', | | \n" + << " | | T. Sjostrand, S. Mrenna and P. Skands" + << ", arXiv:0710.3820 | | \n" + << " | | " + << " | | \n" + << " | | The main physics reference is the 'PY" + << "THIA 6.4 Physics and Manual', | | \n" + << " | | T. Sjostrand, S. Mrenna and P. Skands" + << ", JHEP05 (2006) 026 [hep-ph/0603175]. | | \n" + << " | | " + << " | | \n" + << " | | An archive of program versions and do" + << "cumentation is found on the web: | | \n" + << " | | http://www.thep.lu.se/~torbjorn/Pythi" + << "a.html | | \n" + << " | | " + << " | | \n" + << " | | This program is released under the GN" + << "U General Public Licence version 2. | | \n" + << " | | Please respect the MCnet Guidelines f" + << "or Event Generator Authors and Users. | | \n" + << " | | " + << " | | \n" + << " | | Disclaimer: this program comes withou" + << "t any guarantees. | | \n" + << " | | Beware of errors and use common sense" + << " when interpreting results. | | \n" + << " | | " + << " | | \n" + << " | | Copyright (C) 2008 Torbjorn Sjostrand" + << " | | \n" + << " | | " + << " | | \n" + << " | | " + << " | | \n" + << " | *----------------------------------------" + << "--------------------------------------* | \n" + << " | " + << " | \n" + << " *-------------------------------------------" + << "-----------------------------------------* \n" << endl; + +} + +//********* + +// Check for lines in file that mark the beginning of new subrun. + +int Pythia::readSubrun(string line, bool warn, ostream& os) { + + // If empty line then done. + int subrunLine = SUBRUNDEFAULT; + if (line.find_first_not_of(" ") == string::npos) return subrunLine; + + // If first character is not a letter, then done. + string lineNow = line; + int firstChar = lineNow.find_first_not_of(" "); + if (!isalpha(lineNow[firstChar])) return subrunLine; + + // Replace an equal sign by a blank to make parsing simpler. + while (lineNow.find("=") != string::npos) { + int firstEqual = lineNow.find_first_of("="); + lineNow.replace(firstEqual, 1, " "); + } + + // Get first word of a line. + istringstream splitLine(lineNow); + string name; + splitLine >> name; + + // Replace two colons by one (:: -> :) to allow for such mistakes. + while (name.find("::") != string::npos) { + int firstColonColon = name.find_first_of("::"); + name.replace(firstColonColon, 2, ":"); + } + + // Convert to lowercase. + for (int i = 0; i < int(name.length()); ++i) + name[i] = std::tolower(name[i]); + + // If no match then done. + if (name != "main:subrun") return subrunLine; + + // Else find new subrun number and return it. + splitLine >> subrunLine; + if (!splitLine) { + if (warn) os << "\n PYTHIA Warning: Main:subrun number not" + << " recognized; skip:\n " << line << endl; + subrunLine = SUBRUNDEFAULT; + } + return subrunLine; + +} + +//********* + +// Check that the final event makes sense: no unknown id codes; +// charge and energy-momentum conserved. + +bool Pythia::check(ostream& os) { + + // Reset. + bool physical = true; + iErrId.resize(0); + iErrCol.resize(0); + iErrNan.resize(0); + Vec4 pSum; + double chargeSum = 0.; + + // Incoming beams counted with negative momentum and charge. + if (doProcessLevel) { + pSum = - (event[1].p() + event[2].p()); + chargeSum = - (event[1].charge() + event[2].charge()); + + // If no ProcessLevel then sum momentum and charge in initial state. + } else { + pSum = - event[0].p(); + for (int i = 0; i < process.size(); ++i) + if (process[i].isFinal()) chargeSum -= process[i].charge(); + } + double eLab = abs(pSum.e()); + + // Loop over particles in the event. + for (int i = 0; i < event.size(); ++i) { + + // Look for any unrecognized particle codes. + int id = event[i].id(); + if (id == 0 || !ParticleDataTable::isParticle(id)) { + ostringstream errCode; + errCode << ", id = " << id; + info.errorMsg("Error in Pythia::check: " + "unknown particle code", errCode.str()); + physical = false; + iErrId.push_back(i); + + // Check that colour assignments are the expected ones. + } else { + int colType = event[i].colType(); + int col = event[i].col(); + int acol = event[i].acol(); + if ( (colType == 0 && (col > 0 || acol > 0)) + || (colType == 1 && (col <= 0 || acol > 0)) + || (colType == -1 && (col > 0 || acol <= 0)) + || (colType == 2 && (col <= 0 || acol <= 0)) ) { + ostringstream errCode; + errCode << ", id = " << id << " cols = " << col << " " << acol; + info.errorMsg("Error in Pythia::check: " + "incorrect colours", errCode.str()); + physical = false; + iErrCol.push_back(i); + } + } + + // Look for particles with not-a-number energy/momentum/mass. + if (abs(event[i].px()) >= 0. && abs(event[i].py()) >= 0. + && abs(event[i].pz()) >= 0. && abs(event[i].e()) >= 0. + && abs(event[i].m()) >= 0.) ; + else { + info.errorMsg("Error in Pythia::check: " + "not-a-number energy/momentum/mass"); + physical = false; + iErrNan.push_back(i); + } + + // Add final-state four-momentum and charge. + if (event[i].isFinal()) { + pSum += event[i].p(); + chargeSum += event[i].charge(); + } + + // End of particle loop. + } + + // Check energy-momentum/charge conservation. + double epDev = abs(pSum.e()) + abs(pSum.px()) + abs(pSum.py()) + + abs(pSum.pz()); + if (epDev > epTolErr * eLab) { + info.errorMsg("Error in Pythia::check: energy-momentum not conserved"); + physical = false; + } else if (epDev > epTolWarn * eLab) { + info.errorMsg("Warning in Pythia::check: " + "energy-momentum not quite conserved"); + } + if (abs(chargeSum) > 0.1) { + info.errorMsg("Error in Pythia::check: charge not conserved"); + physical = false; + } + + // Done for sensible events. + if (physical) return true; + + // Print (the first few) flawed events. + if (nErrEvent < nErrList) { + os << " PYTHIA erroneous event info: \n"; + if (iErrId.size() > 0) { + os << " unknown particle codes in lines "; + for (int i = 0; i < int(iErrId.size()); ++i) + os << iErrId[i] << " "; + os << "\n"; + } + if (iErrCol.size() > 0) { + os << " incorrect colour assignments in lines "; + for (int i = 0; i < int(iErrCol.size()); ++i) + os << iErrCol[i] << " "; + os << "\n"; + } + if (iErrNan.size() > 0) { + os << " not-a-number energy/momentum/mass in lines "; + for (int i = 0; i < int(iErrNan.size()); ++i) + os << iErrNan[i] << " "; + os << "\n"; + } + if (epDev > epTolErr * eLab) os << scientific << setprecision(3) + << " total energy-momentum non-conservation = " << epDev << "\n"; + if (abs(chargeSum) > 0.1) os << fixed << setprecision(2) + << " total charge non-conservation = " << chargeSum << "\n"; + info.list(); + event.list(); + } + + // Update error counter. Done also for flawed event. + ++nErrEvent; + return false; + +} + +//********* + +// Routine to set up a PDF pointer. + +PDF* Pythia::getPDFPtr(int idIn, int sequence) { + + PDF* tempPDFPtr; + + // Proton beam, normal choice. + if (abs(idIn) == 2212 && sequence == 1) { + int pSet = settings.mode("PDF:pSet"); + bool useLHAPDF = settings.flag("PDF:useLHAPDF"); + + // Use internal sets. + if (!useLHAPDF) { + if (pSet == 1) tempPDFPtr = new GRV94L(idIn); + else tempPDFPtr = new CTEQ5L(idIn); + } + + // Use sets from LHAPDF. + else { + string LHAPDFset = settings.word("PDF:LHAPDFset"); + int LHAPDFmember = settings.mode("PDF:LHAPDFmember"); + tempPDFPtr = new LHAPDF(idIn, LHAPDFset, LHAPDFmember, 1, &info); + + // Optionally allow extrapolation beyond x and Q2 limits. + tempPDFPtr->setExtrapolate( settings.flag("PDF:extrapolateLHAPDF") ); + } + } + + // Proton beam, special choice for the hard process.. + else if (abs(idIn) == 2212) { + int pSet = settings.mode("PDF:pHardSet"); + bool useLHAPDF = settings.flag("PDF:useHardLHAPDF"); + + // Use internal sets. + if (!useLHAPDF) { + if (pSet == 1) tempPDFPtr = new GRV94L(idIn); + else tempPDFPtr = new CTEQ5L(idIn); + } + + // Use sets from LHAPDF. + else { + string LHAPDFset = settings.word("PDF:hardLHAPDFset"); + int LHAPDFmember = settings.mode("PDF:hardLHAPDFmember"); + tempPDFPtr = new LHAPDF(idIn, LHAPDFset, LHAPDFmember, 2, &info); + + // Optionally allow extrapolation beyond x and Q2 limits. + tempPDFPtr->setExtrapolate( settings.flag("PDF:extrapolateLHAPDF") ); + } + } + + // Lepton beam; resolved or not. + else { + if (settings.flag("PDF:lepton") && abs(idIn)%2 == 1) + tempPDFPtr = new Lepton(idIn); + else tempPDFPtr = new LeptonPoint(idIn); + } + + // Done. + return tempPDFPtr; +} + +//********* + +} // end namespace Pythia8 + + diff --git a/PYTHIA8/pythia8130/src/ResonanceDecays.cxx b/PYTHIA8/pythia8130/src/ResonanceDecays.cxx new file mode 100644 index 00000000000..6bc0531618e --- /dev/null +++ b/PYTHIA8/pythia8130/src/ResonanceDecays.cxx @@ -0,0 +1,798 @@ +// ResonanceDecays.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for +// the ResonanceDecays class. + +#include "ResonanceDecays.h" + +namespace Pythia8 { + +//************************************************************************** + +// The ResonanceDecays class. +// Do all resonance decays sequentially. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Number of tries to pick a decay channel. +const int ResonanceDecays::NTRYCHANNEL = 10; + +// Number of tries to pick a set of daughter masses. +const int ResonanceDecays::NTRYMASSES = 10000; + +// Mass above threshold for allowed decays. +const double ResonanceDecays::MSAFETY = 0.1; + +// When constrainted kinematics cut high-mass tail of Breit-Wigner. +const double ResonanceDecays::WIDTHCUT = 5.; + +// Small number (relative to 1) to protect against roundoff errors. +const double ResonanceDecays::TINY = 1e-10; + +// These numbers are hardwired empirical parameters, +// intended to speed up the M-generator. +const double ResonanceDecays::WTCORRECTION[11] = { 1., 1., 1., + 2., 5., 15., 60., 250., 1250., 7000., 50000. }; + +//********* + +bool ResonanceDecays::next( Event& process) { + + // Loop over all entries to find resonances that should decay. + int iDec = 0; + do { + Particle& decayer = process[iDec]; + if (decayer.isFinal() && decayer.canDecay() && decayer.mayDecay() + && decayer.isResonance() ) { + + // Fill the decaying particle in slot 0 of arrays. + id0 = decayer.id(); + m0 = decayer.m(); + idProd.resize(0); + mProd.resize(0); + idProd.push_back( id0 ); + mProd.push_back( m0 ); + + // Mother flavour - relevant for gamma*/Z0 mixing. (Not always??) + int idIn = process[decayer.mother1()].id(); + + // Prepare decay selection. + decayer.particleData().preparePick(id0, m0, idIn); + + // Pick a decay channel; allow up to ten tries. + bool foundChannel = false; + for (int iTryChannel = 0; iTryChannel < NTRYCHANNEL; ++iTryChannel) { + + // Pick decay channel. Find multiplicity. + DecayChannel& channel = decayer.particleData().pickChannel(); + mult = channel.multiplicity(); + + // Read out flavours. + idProd.resize(1); + int idNow; + for (int i = 1; i <= mult; ++i) { + idNow = channel.product(i - 1); + if (id0 < 0 && ParticleDataTable::hasAnti(idNow)) idNow = -idNow; + idProd.push_back( idNow); + } + + // Pick masses. Pick new channel if fail. + if (!pickMasses()) continue; + foundChannel = true; + break; + } + + // Failed to find acceptable decays. + if (!foundChannel) { + infoPtr->errorMsg("Error in ResonanceDecays::next:" + " failed to find workable decay channel"); + return false; + } + + // Select colours in decay. + if (!pickColours(iDec, process)) return false; + + // Select four-momenta in decay, boosted to lab frame. + pProd.resize(0); + pProd.push_back( decayer.p() ); + if (!pickKinematics()) return false; + + // Append decay products to the process event record. + int iFirst = process.size(); + for (int i = 1; i <= mult; ++i) { + process.append( idProd[i], 23, iDec, 0, 0, 0, cols[i], acols[i], + pProd[i], mProd[i], m0); + } + int iLast = process.size() - 1; + + // Modify mother status and daughters. + decayer.status(-22); + decayer.daughters(iFirst, iLast); + + // End of loop over all entries. + } + } while (++iDec < process.size()); + + // Done. + return true; + +} + +// Select masses of decay products. + +bool ResonanceDecays::pickMasses() { + + // Arrays with properties of particles. Fill with dummy values for mother. + vector useBW; + vector m0BW, mMinBW, mMaxBW, widthBW; + double mMother = mProd[0]; + double m2Mother = mMother * mMother; + useBW.push_back( false ); + m0BW.push_back( mMother ); + mMinBW.push_back( mMother ); + mMaxBW.push_back( mMother ); + widthBW.push_back( 0. ); + + // Loop throught products for masses and widths. Set nominal mass. + bool useBWNow; + double m0Now, mMinNow, mMaxNow, widthNow; + for (int i = 1; i <= mult; ++i) { + useBWNow = ParticleDataTable::useBreitWigner( idProd[i] ); + m0Now = ParticleDataTable::m0( idProd[i] ); + mMinNow = ParticleDataTable::m0Min( idProd[i] ); + mMaxNow = ParticleDataTable::m0Max( idProd[i] ); + if (useBWNow && mMaxNow < mMinNow) mMaxNow = mMother; + widthNow = ParticleDataTable::mWidth( idProd[i] ); + useBW.push_back( useBWNow ); + m0BW.push_back( m0Now ); + mMinBW.push_back( mMinNow ); + mMaxBW.push_back( mMaxNow ); + widthBW.push_back( widthNow ); + mProd.push_back( m0Now ); + } + + // Find number of Breit-Wigners and summed (minimal) masses. + int nBW = 0; + double mSum = 0.; + double mSumMin = 0.; + for (int i = 1; i <= mult; ++i) { + if (useBW[i]) ++nBW; + mSum += max( m0BW[i], mMinBW[i]); + mSumMin += mMinBW[i]; + } + + // If sum of minimal masses above mother mass then give up. + if (mSumMin + MSAFETY > mMother) return false; + + // If sum of masses below and no Breit-Wigners then done. + if (mSum + 0.5 * MSAFETY < mMother && nBW == 0) return true; + + // Else if below then retry Breit-Wigners, with simple treshold. + if (mSum + MSAFETY < mMother) { + double wtMax = 2. * sqrtpos(1. - mSum*mSum / m2Mother); + double wt; + for (int iTryMasses = 0; iTryMasses <= NTRYMASSES; ++ iTryMasses) { + if (iTryMasses == NTRYMASSES) return false; + mSum = 0.; + for (int i = 1; i <= mult; ++i) { + if (useBW[i]) mProd[i] = ParticleDataTable::mass( idProd[i] ); + mSum += mProd[i]; + } + wt = (mSum + 0.5 * MSAFETY < mMother) + ? sqrtpos(1. - mSum*mSum / m2Mother) : 0.; + if (wt > Rndm::flat() * wtMax) break; + } + return true; + } + + // From now on some particles will have to be forced off shell. + + // Order Breit-Wigners in decreasing widths. Sum of other masses. + vector iBW; + double mSum0 = 0.; + for (int i = 1; i <= mult; ++i) { + if (useBW[i]) iBW.push_back(i); + else mSum0 += mProd[i]; + } + for (int i = 1; i < nBW; ++i) { + for (int j = i - 1; j >= 0; --j) { + if (widthBW[iBW[j+1]] > widthBW[iBW[j]]) swap (iBW[j+1], iBW[j]); + else break; + } + } + + // Do all but broadest two in increasing-width order. Includes only one. + if (nBW != 2) { + int iMin = (nBW == 1) ? 0 : 2; + for (int i = nBW - 1; i >= iMin; --i) { + int iBWi = iBW[i]; + + // Find allowed mass range of current resonance. + double mMax = mMother - mSum0 - MSAFETY; + if (nBW != 1) for (int j = 0; j < i; ++j) mMax -= mMinBW[iBW[j]]; + mMax = min( mMaxBW[iBWi], mMax ); + double mMin = min( mMinBW[iBWi], mMax - MSAFETY); + if (mMin < 0.) return false; + + // Parameters for Breit-Wigner choice, with constrained mass range. + double m2Nom = pow2( m0BW[iBWi] ); + double m2Max = mMax * mMax; + double m2Min = mMin * mMin; + double mmWid = m0BW[iBWi] * widthBW[iBWi]; + double atanMin = atan( (m2Min - m2Nom) / mmWid ); + double atanMax = atan( (m2Max - m2Nom) / mmWid ); + double atanDif = atanMax - atanMin; + + // Retry mass according to Breit-Wigner, with simple threshold factor. + double mr1 = mSum0*mSum0 / m2Mother; + double mr2 = m2Min / m2Mother; + double wtMax = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 ); + double m2Now, wt; + for (int iTryMasses = 0; iTryMasses <= NTRYMASSES; ++ iTryMasses) { + if (iTryMasses == NTRYMASSES) return false; + m2Now = m2Nom + mmWid * tan(atanMin + Rndm::flat() * atanDif); + mr2 = m2Now / m2Mother; + wt = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 ); + if (wt > Rndm::flat() * wtMax) break; + } + + // Prepare to iterate for more. Done for one Breit-Wigner. + mProd[iBWi] = sqrt(m2Now); + mSum0 += mProd[iBWi]; + } + if (nBW == 1) return true; + } + + // Left to do two broadest Breit-Wigners correlated, i.e. more realistic. + int iBW1 = iBW[0]; + int iBW2 = iBW[1]; + int idMother = abs(idProd[0]); + int idDau1 = abs(idProd[iBW1]); + int idDau2 = abs(idProd[iBW2]); + + // In some cases known phase-space behaviour; else simple beta factor. + int psMode = 1 ; + if ( (idMother == 25 || idMother == 35) && idDau1 < 19 + && idDau2 == idDau1 ) psMode = 3; + if ( (idMother == 25 || idMother == 35 || idMother == 36) + && (idDau1 == 23 || idDau1 == 24) && idDau2 == idDau1 ) psMode = 5; + + // Find allowed mass ranges + double mRem = mMother - mSum0 - MSAFETY; + double mMax1 = min( mMaxBW[iBW1], mRem - mMinBW[iBW2] ); + double mMin1 = min( mMinBW[iBW1], mMax1 - MSAFETY); + double mMax2 = min( mMaxBW[iBW2], mRem - mMinBW[iBW1] ); + double mMin2 = min( mMinBW[iBW2], mMax2 - MSAFETY); + + // At least one range must extend below half remaining mass. + double mMid = 0.5 * mRem; + bool hasMid1 = (mMin1 < 0.5 * mRem); + bool hasMid2 = (mMin2 < 0.5 * mRem); + if (!hasMid1 && !hasMid2) return false; + + // Parameters for Breit-Wigner choice, with constrained mass range. + double m2Nom1 = pow2( m0BW[iBW1] ); + double m2Max1 = mMax1 * mMax1; + double m2Min1 = mMin1 * mMin1; + double mmWid1 = m0BW[iBW1] * widthBW[iBW1]; + double atanMin1 = atan( (m2Min1 - m2Nom1) / mmWid1 ); + double atanMax1 = atan( (m2Max1 - m2Nom1) / mmWid1 ); + double atanMid1 = (hasMid1) ? atan( (mMid*mMid - m2Nom1) / mmWid1 ) : 0.; + double m2Nom2 = pow2( m0BW[iBW2] ); + double m2Max2 = mMax1 * mMax2; + double m2Min2 = mMin1 * mMin2; + double mmWid2 = m0BW[iBW2] * widthBW[iBW2]; + double atanMin2 = atan( (m2Min2 - m2Nom2) / mmWid2 ); + double atanMax2 = atan( (m2Max2 - m2Nom2) / mmWid2 ); + double atanMid2 = (hasMid2) ? atan( (mMid*mMid - m2Nom2) / mmWid2 ) : 0.; + + // Relative weight to pick either below half remaining mass. + double probLow1 = (hasMid1) ? 1. : 0.; + if (hasMid1 && hasMid2) probLow1 = (atanMid1 - atanMin1) + / ( (atanMid1 - atanMin1) + (atanMid2 - atanMin1) ); + + // Maximum matrix element times phase space weight. + double m2Rem = mRem * mRem; + double mr1 = m2Min1 / m2Rem; + double mr2 = m2Min2 / m2Rem; + double psMax = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 ); + double wtMax = 1.; + if (psMode == 1) wtMax = psMax; + else if (psMode == 2) wtMax = psMax * psMax; + else if (psMode == 3) wtMax = pow3(psMax); + else if (psMode == 5) wtMax = psMax + * (pow2(1. - mr1 - mr2) + 8. * mr1 * mr2); + + // Retry mass according to Breit-Wigners, with simple threshold factor. + double atanDif1, atanDif2, m2Now1, m2Now2, mNow1, mNow2, ps, wt; + for (int iTryMasses = 0; iTryMasses <= NTRYMASSES; ++ iTryMasses) { + if (iTryMasses == NTRYMASSES) return false; + + // Pick either below half remaining mass. + if (Rndm::flat() < probLow1) { + atanDif1 = atanMid1 - atanMin1; + atanDif2 = atanMax2 - atanMin2; + } else { + atanDif1 = atanMax1 - atanMin1; + atanDif2 = atanMid2 - atanMin2; + } + m2Now1 = m2Nom1 + mmWid1 * tan(atanMin1 + Rndm::flat() * atanDif1); + m2Now2 = m2Nom2 + mmWid2 * tan(atanMin2 + Rndm::flat() * atanDif2); + mNow1 = sqrt(m2Now1); + mNow2 = sqrt(m2Now2); + + // Threshold weight. + mr1 = m2Now1 / m2Rem; + mr2 = m2Now2 / m2Rem; + wt = 0.; + if (mNow1 + mNow2 + MSAFETY < mMother) { + ps = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 ); + wt = 1.; + if (psMode == 1) wt = ps; + else if (psMode == 2) wt = ps * ps; + else if (psMode == 3) wt = pow3(ps); + else if (psMode == 5) wt = ps + * (pow2(1. - mr1 - mr2) + 8. * mr1 * mr2); + } + if (wt > Rndm::flat() * wtMax) break; + } + mProd[iBW1] = mNow1; + mProd[iBW2] = mNow2; + + // Done. + return true; + +} + +//********* + +// Select colours of decay products. + +bool ResonanceDecays::pickColours(int iDec, Event& process) { + + // Reset or create arrays with colour info. + cols.resize(0); + acols.resize(0); + vector iTriplet, iAtriplet, iOctet, iDipCol, iDipAcol; + + // Mother colours already known. + int col0 = process[iDec].col(); + int acol0 = process[iDec].acol(); + cols.push_back( col0); + acols.push_back(acol0); + + // Loop through all daughters. + int colTypeNow; + for (int i = 1; i <= mult; ++i) { + // Daughter colours initially empty, so that all is set for singlet. + cols.push_back(0); + acols.push_back(0); + // Find character (singlet, triplet, antitriplet, octet) of daughters. + colTypeNow = ParticleDataTable::colType( idProd[i] ); + if (colTypeNow == 0); + else if (colTypeNow == 1) iTriplet.push_back(i); + else if (colTypeNow == -1) iAtriplet.push_back(i); + else if (colTypeNow == 2) iOctet.push_back(i); + else { + infoPtr->errorMsg("Error in ResonanceDecays::pickColours:" + " unknown colour type encountered"); + return false; + } + } + + // Check excess of colours and anticolours in final over initial state. + int nCol = iTriplet.size(); + if (col0 != 0) --nCol; + int nAcol = iAtriplet.size(); + if (acol0 != 0) --nAcol; + + // If net creation of three colours then find junction kind: + // mother is 1 = singlet, 3 = antitriplet, 5 = octet. + if (nCol - nAcol == 3) { + int kindJun = (col0 == 0) ? ((acol0 == 0) ? 1 : 3) : 5; + + // Set colours in three junction legs and store junction. + int colJun[3]; + colJun[0] = (kindJun == 1) ? process.nextColTag() : acol0; + colJun[1] = process.nextColTag(); + colJun[2] = process.nextColTag(); + process.appendJunction( kindJun, colJun[0], colJun[1], colJun[2]); + + // Loop over three legs. Remove an incoming anticolour on first leg. + for (int leg = 0; leg < 3; ++leg) { + if (leg == 0 && kindJun != 1) acol0 = 0; + + // Pick final-state triplets to carry these new colours. + else { + int pickT = (iTriplet.size() == 1) ? 0 + : int( TINY + Rndm::flat() * (iTriplet.size() - TINY) ); + int iPickT = iTriplet[pickT]; + cols[iPickT] = colJun[leg]; + + // Remove matched triplet and store new colour dipole ends. + iTriplet[pickT] = iTriplet.back(); + iTriplet.pop_back(); + iDipCol.push_back(iPickT); + iDipAcol.push_back(0); + } + } + + // Update colour counter. Done with junction. + nCol -= 3; + } + + // If net creation of three anticolours then find antijunction kind: + // mother is 2 = singlet, 4 = triplet, 6 = octet. + if (nAcol - nCol == 3) { + int kindJun = (acol0 == 0) ? ((col0 == 0) ? 2 : 4) : 6; + + // Set anticolours in three antijunction legs and store antijunction. + int acolJun[3]; + acolJun[0] = (kindJun == 2) ? process.nextColTag() : col0; + acolJun[1] = process.nextColTag(); + acolJun[2] = process.nextColTag(); + process.appendJunction( kindJun, acolJun[0], acolJun[1], acolJun[2]); + + // Loop over three legs. Remove an incoming colour on first leg. + for (int leg = 0; leg < 3; ++leg) { + if (leg == 0 && kindJun != 2) col0 = 0; + + // Pick final-state antitriplets to carry these new anticolours. + else { + int pickA = (iAtriplet.size() == 1) ? 0 + : int( TINY + Rndm::flat() * (iAtriplet.size() - TINY) ); + int iPickA = iAtriplet[pickA]; + acols[iPickA] = acolJun[leg]; + + // Remove matched antitriplet and store new colour dipole ends. + iAtriplet[pickA] = iAtriplet.back(); + iAtriplet.pop_back(); + iDipCol.push_back(0); + iDipAcol.push_back(iPickA); + } + } + + // Update anticolour counter. Done with antijunction. + nAcol -= 3; + } + + // If colours and anticolours do not match now then unphysical. + if (nCol != nAcol) { + infoPtr->errorMsg("Error in ResonanceDecays::pickColours:" + " inconsistent colour tags"); + return false; + } + + // Pick final-state triplet (if any) to carry initial colour. + if (col0 != 0 && iTriplet.size() > 0) { + int pickT = (iTriplet.size() == 1) ? 0 + : int( TINY + Rndm::flat() * (iTriplet.size() - TINY) ); + int iPickT = iTriplet[pickT]; + cols[iPickT] = col0; + + // Remove matched triplet and store new colour dipole ends. + col0 = 0; + iTriplet[pickT] = iTriplet.back(); + iTriplet.pop_back(); + iDipCol.push_back(iPickT); + iDipAcol.push_back(0); + } + + // Pick final-state antitriplet (if any) to carry initial anticolour. + if (acol0 != 0 && iAtriplet.size() > 0) { + int pickA = (iAtriplet.size() == 1) ? 0 + : int( TINY + Rndm::flat() * (iAtriplet.size() - TINY) ); + int iPickA = iAtriplet[pickA]; + acols[iPickA] = acol0; + + // Remove matched antitriplet and store new colour dipole ends. + acol0 = 0; + iAtriplet[pickA] = iAtriplet.back(); + iAtriplet.pop_back(); + iDipCol.push_back(0); + iDipAcol.push_back(iPickA); + } + + // Error checks that amount of leftover colours and anticolours match. + if ( (iTriplet.size() != iAtriplet.size()) + || (col0 != 0 && acol0 == 0) || (col0 == 0 && acol0 != 0) ) { + infoPtr->errorMsg("Error in ResonanceDecays::pickColours:" + " inconsistent colour tags"); + return false; + } + + // Match triplets to antitriplets in the final state. + for (int pickT = 0; pickT < int(iTriplet.size()); ++pickT) { + int iPickT = iTriplet[pickT]; + int pickA = (iAtriplet.size() == 1) ? 0 + : int( TINY + Rndm::flat() * (iAtriplet.size() - TINY) ); + int iPickA = iAtriplet[pickA]; + + // Connect pair with new colour tag. + cols[iPickT] = process.nextColTag(); + acols[iPickA] = cols[iPickT]; + + // Remove matched antitriplet and store new colour dipole ends. + iAtriplet[pickT] = iAtriplet.back(); + iAtriplet.pop_back(); + iDipCol.push_back(iPickT); + iDipAcol.push_back(iPickA); + } + + // If no octets are around then matching is done. + if (col0 == 0 && acol0 == 0 && iOctet.size() == 0) return true; + + // If initial-state octet remains then store as (first!) new dipole. + if (col0 != 0) { + iDipCol.push_back(0); + iDipAcol.push_back(0); + } + + // Now attach all final-state octets at random to existing dipoles. + for (int i = 0; i < int(iOctet.size()); ++i) { + int iOct = iOctet[i]; + + // If no dipole then start new one. (Happens for singlet -> octets.) + if (iDipCol.size() == 0) { + cols[iOct] = process.nextColTag(); + acols[iOct] = cols[iOct] ; + iDipCol.push_back(iOct); + iDipAcol.push_back(iOct); + } + + // Else attach to existing dipole picked at random. + else { + int pickDip = (iDipCol.size() == 1) ? 0 + : int( TINY + Rndm::flat() * (iDipCol.size() - TINY) ); + + // Case with dipole in initial state: reattach existing colours. + if (iDipCol[pickDip] == 0 && iDipAcol[pickDip] == 0) { + cols[iOct] = col0; + acols[iOct] = acol0; + iDipAcol[pickDip] = iOct; + iDipCol.push_back(iOct); + iDipAcol.push_back(0); + + // Case with dipole from colour in initial state: also new colour. + } else if (iDipAcol[pickDip] == 0) { + int iPickCol = iDipCol[pickDip]; + cols[iOct] = cols[iPickCol]; + acols[iOct] = process.nextColTag(); + cols[iPickCol] = acols[iOct]; + iDipCol[pickDip] = iOct; + iDipCol.push_back(iPickCol); + iDipAcol.push_back(iOct); + + // Remaining cases with dipole from anticolour in initial state + // or dipole inside final state: also new colour. + } else { + int iPickAcol = iDipAcol[pickDip]; + acols[iOct] = acols[iPickAcol]; + cols[iOct] = process.nextColTag(); + acols[iPickAcol] = cols[iOct]; + iDipAcol[pickDip] = iOct; + iDipCol.push_back(iOct); + iDipAcol.push_back(iPickAcol); + } + } + } + + // Must now have at least two dipoles (no 1 -> 8 or 8 -> 1). + if (iDipCol.size() < 2) { + infoPtr->errorMsg("Error in ResonanceDecays::pickColours:" + " inconsistent colour tags"); + return false; + } + + // Done. + return true; + +} + +//********* + +// Select decay products momenta isotropically in phase space. +// Process-dependent angular distributions may be imposed in SigmaProcess. + +bool ResonanceDecays::pickKinematics() { + + // Description of two-body decays as simple special case. + if (mult == 2) { + + // Masses. + m0 = mProd[0]; + double m1 = mProd[1]; + double m2 = mProd[2]; + + // Energies and absolute momentum in the rest frame. + double e1 = 0.5 * (m0*m0 + m1*m1 - m2*m2) / m0; + double e2 = 0.5 * (m0*m0 + m2*m2 - m1*m1) / m0; + double pAbs = 0.5 * sqrtpos( (m0 - m1 - m2) * (m0 + m1 + m2) + * (m0 + m1 - m2) * (m0 - m1 + m2) ) / m0; + + // Pick isotropic angles to give three-momentum. + double cosTheta = 2. * Rndm::flat() - 1.; + double sinTheta = sqrt(1. - cosTheta*cosTheta); + double phi = 2. * M_PI * Rndm::flat(); + double pX = pAbs * sinTheta * cos(phi); + double pY = pAbs * sinTheta * sin(phi); + double pZ = pAbs * cosTheta; + + // Fill four-momenta in mother rest frame and then boost to lab frame. + pProd.push_back( Vec4( pX, pY, pZ, e1) ); + pProd.push_back( Vec4( -pX, -pY, -pZ, e2) ); + pProd[1].bst( pProd[0] ); + pProd[2].bst( pProd[0] ); + + // Done for two-body decay. + return true; + } + + // Description of three-body decays as semi-simple special case. + if (mult == 3) { + + // Masses. + m0 = mProd[0]; + double m1 = mProd[1]; + double m2 = mProd[2]; + double m3 = mProd[3]; + double mDiff = m0 - (m1 + m2 + m3); + + // Kinematical limits for 2+3 mass. Maximum phase-space weight. + double m23Min = m2 + m3; + double m23Max = m0 - m1; + double p1Max = 0.5 * sqrtpos( (m0 - m1 - m23Min) * (m0 + m1 + m23Min) + * (m0 + m1 - m23Min) * (m0 - m1 + m23Min) ) / m0; + double p23Max = 0.5 * sqrtpos( (m23Max - m2 - m3) * (m23Max + m2 + m3) + * (m23Max + m2 - m3) * (m23Max - m2 + m3) ) / m23Max; + double wtPSmax = 0.5 * p1Max * p23Max; + + // Pick an intermediate mass m23 flat in the allowed range. + double wtPS, m23, p1Abs, p23Abs; + do { + m23 = m23Min + Rndm::flat() * mDiff; + + // Translate into relative momenta and find phase-space weight. + p1Abs = 0.5 * sqrtpos( (m0 - m1 - m23) * (m0 + m1 + m23) + * (m0 + m1 - m23) * (m0 - m1 + m23) ) / m0; + p23Abs = 0.5 * sqrtpos( (m23 - m2 - m3) * (m23 + m2 + m3) + * (m23 + m2 - m3) * (m23 - m2 + m3) ) / m23; + wtPS = p1Abs * p23Abs; + + // If rejected, try again with new invariant masses. + } while ( wtPS < Rndm::flat() * wtPSmax ); + + // Set up m23 -> m2 + m3 isotropic in its rest frame. + double cosTheta = 2. * Rndm::flat() - 1.; + double sinTheta = sqrt(1. - cosTheta*cosTheta); + double phi = 2. * M_PI * Rndm::flat(); + double pX = p23Abs * sinTheta * cos(phi); + double pY = p23Abs * sinTheta * sin(phi); + double pZ = p23Abs * cosTheta; + double e2 = sqrt( m2*m2 + p23Abs*p23Abs); + double e3 = sqrt( m3*m3 + p23Abs*p23Abs); + Vec4 p2( pX, pY, pZ, e2); + Vec4 p3( -pX, -pY, -pZ, e3); + + // Set up 0 -> 1 + 23 isotropic in its rest frame. + cosTheta = 2. * Rndm::flat() - 1.; + sinTheta = sqrt(1. - cosTheta*cosTheta); + phi = 2. * M_PI * Rndm::flat(); + pX = p1Abs * sinTheta * cos(phi); + pY = p1Abs * sinTheta * sin(phi); + pZ = p1Abs * cosTheta; + double e1 = sqrt( m1*m1 + p1Abs*p1Abs); + double e23 = sqrt( m23*m23 + p1Abs*p1Abs); + pProd.push_back( Vec4( pX, pY, pZ, e1) ); + + // Boost 2 + 3 to the 0 rest frame and then boost to lab frame. + Vec4 p23( -pX, -pY, -pZ, e23); + p2.bst( p23 ); + p3.bst( p23 ); + pProd.push_back( p2 ); + pProd.push_back( p3 ); + pProd[1].bst( pProd[0] ); + pProd[2].bst( pProd[0] ); + pProd[3].bst( pProd[0] ); + + // Done for three-body decay. + return true; + } + + // Do a multibody decay using the M-generator algorithm. + + // Mother and sum daughter masses. + m0 = mProd[0]; + double mSum = mProd[1]; + for (int i = 2; i <= mult; ++i) mSum += mProd[i]; + double mDiff = m0 - mSum; + + // Begin setup of intermediate invariant masses. + vector mInv; + for (int i = 0; i <= mult; ++i) mInv.push_back( mProd[i]); + + // Calculate the maximum weight in the decay. + double wtPSmax = 1. / WTCORRECTION[mult]; + double mMax = mDiff + mProd[mult]; + double mMin = 0.; + for (int i = mult - 1; i > 0; --i) { + mMax += mProd[i]; + mMin += mProd[i+1]; + double mNow = mProd[i]; + wtPSmax *= 0.5 * sqrtpos( (mMax - mMin - mNow) * (mMax + mMin + mNow) + * (mMax + mMin - mNow) * (mMax - mMin + mNow) ) / mMax; + } + + // Begin loop to find the set of intermediate invariant masses. + vector rndmOrd; + double wtPS; + do { + wtPS = 1.; + + // Find and order random numbers in descending order. + rndmOrd.resize(0); + rndmOrd.push_back(1.); + for (int i = 1; i < mult - 1; ++i) { + double rndm = Rndm::flat(); + rndmOrd.push_back(rndm); + for (int j = i - 1; j > 0; --j) { + if (rndm > rndmOrd[j]) swap( rndmOrd[j], rndmOrd[j+1] ); + else break; + } + } + rndmOrd.push_back(0.); + + // Translate into intermediate masses and find weight. + for (int i = mult - 1; i > 0; --i) { + mInv[i] = mInv[i+1] + mProd[i] + (rndmOrd[i-1] - rndmOrd[i]) * mDiff; + wtPS *= 0.5 * sqrtpos( (mInv[i] - mInv[i+1] - mProd[i]) + * (mInv[i] + mInv[i+1] + mProd[i]) * (mInv[i] + mInv[i+1] - mProd[i]) + * (mInv[i] - mInv[i+1] + mProd[i]) ) / mInv[i]; + } + + // If rejected, try again with new invariant masses. + } while ( wtPS < Rndm::flat() * wtPSmax ); + + // Perform two-particle decays in the respective rest frame. + vector pInv; + pInv.resize(mult + 1); + for (int i = 1; i < mult; ++i) { + double pAbs = 0.5 * sqrtpos( (mInv[i] - mInv[i+1] - mProd[i]) + * (mInv[i] + mInv[i+1] + mProd[i]) * (mInv[i] + mInv[i+1] - mProd[i]) + * (mInv[i] - mInv[i+1] + mProd[i]) ) / mInv[i]; + + // Isotropic angles give three-momentum. + double cosTheta = 2. * Rndm::flat() - 1.; + double sinTheta = sqrt(1. - cosTheta*cosTheta); + double phi = 2. * M_PI * Rndm::flat(); + double pX = pAbs * sinTheta * cos(phi); + double pY = pAbs * sinTheta * sin(phi); + double pZ = pAbs * cosTheta; + + // Calculate energies, fill four-momenta. + double eHad = sqrt( mProd[i]*mProd[i] + pAbs*pAbs); + double eInv = sqrt( mInv[i+1]*mInv[i+1] + pAbs*pAbs); + pProd.push_back( Vec4( pX, pY, pZ, eHad) ); + pInv[i+1].p( -pX, -pY, -pZ, eInv); + } + pProd.push_back( pInv[mult] ); + + // Boost decay products to the mother rest frame and on to lab frame. + pInv[1] = pProd[0]; + for (int iFrame = mult - 1; iFrame > 0; --iFrame) + for (int i = iFrame; i <= mult; ++i) pProd[i].bst(pInv[iFrame]); + + // Done for multibody decay. + return true; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/ResonanceWidths.cxx b/PYTHIA8/pythia8130/src/ResonanceWidths.cxx new file mode 100644 index 00000000000..e03f43fc5ad --- /dev/null +++ b/PYTHIA8/pythia8130/src/ResonanceWidths.cxx @@ -0,0 +1,2084 @@ +// ResonanceWidths.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for +// the ResonanceWidths class and classes derived from it. + +#include "ResonanceWidths.h" +#include "PythiaComplex.h" + +namespace Pythia8 { + +//************************************************************************** + +// The ResonanceWidths class. +// Base class for the various resonances. + +//********* + +// Definitions of static variables and functions. +// (Values will be overwritten in initStatic call, so are purely dummy.) + +int ResonanceWidths::alphaSorder = 1; +int ResonanceWidths::alphaEMorder = 1; +double ResonanceWidths::alphaSvalue = 0.1265; +double ResonanceWidths::minWidth = 1e-20; +double ResonanceWidths::minThreshold = 0.1; +AlphaStrong ResonanceWidths::alphaS; +AlphaEM ResonanceWidths::alphaEM; + +// Static copy of Info - not optimal solution?? +Info* ResonanceWidths::infoPtr = 0; + +// Number of points in integration direction for numInt routines. +const int ResonanceWidths::NPOINT = 100; + +// The sum of product masses must not be too close to the resonance mass. +const double ResonanceWidths::MASSMARGIN = 0.1; + +//********* + +// Initialize static data members. + +void ResonanceWidths::initStatic(Info* infoPtrIn) { + + // Save pointer. + infoPtr = infoPtrIn; + + // Parameters of alphaStrong generation . + alphaSvalue = Settings::parm("SigmaProcess:alphaSvalue"); + alphaSorder = Settings::mode("SigmaProcess:alphaSorder"); + + // Initialize alphaStrong generation. + alphaS.init( alphaSvalue, alphaSorder); + + // Parameters of alphaEM generation. + alphaEMorder = Settings::mode("SigmaProcess:alphaEMorder"); + + // Initialize alphaEM generation. + alphaEM.init( alphaEMorder); + + // Minimal decaying-resonance width. Minimal phase space for meMode = 103. + minWidth = Settings::parm("ResonanceWidths:minWidth"); + minThreshold = Settings::parm("ResonanceWidths:minThreshold"); + +} + +//********* + +// Initialize data members. +// Calculate and store partial and total widths at the nominal mass. + +void ResonanceWidths::init() { + + // Initialize constants used for a resonance. + initConstants(); + + // Calculate various common prefactors for the current mass. + mHat = mRes; + calcPreFac(true); + + // Reset quantities to sum. Declare variables inside loop. + double widTot = 0.; + double widPos = 0.; + double widNeg = 0.; + int idNow, idAnti; + double openSecPos, openSecNeg; + + // Loop over all decay channels. Basic properties of channel. + for (int i = 0; i < particlePtr->decay.size(); ++i) { + iChannel = i; + onMode = particlePtr->decay[i].onMode(); + meMode = particlePtr->decay[i].meMode(); + mult = particlePtr->decay[i].multiplicity(); + widNow = 0.; + + // Channels with meMode < 100 must be implemented in derived classes. + if (meMode < 100) { + + // Read out information on channel: primarily use first two. + id1 = particlePtr->decay[i].product(0); + id2 = particlePtr->decay[i].product(1); + id1Abs = abs(id1); + id2Abs = abs(id2); + + // Order first two in descending order of absolute values. + if (id2Abs > id1Abs) {swap( id1, id2); swap( id1Abs, id2Abs);} + + // Allow for third product to be treated in derived classes. + if (mult > 2) { + id3 = particlePtr->decay[i].product(2); + id3Abs = abs(id3); + + // Also order third into descending order of absolute values. + if (id3Abs > id2Abs) {swap( id2, id3); swap( id2Abs, id3Abs);} + if (id2Abs > id1Abs) {swap( id1, id2); swap( id1Abs, id2Abs);} + } + + // Read out masses. Calculate two-body phase space. + mf1 = ParticleDataTable::m0(id1Abs); + mf2 = ParticleDataTable::m0(id2Abs); + mr1 = pow2(mf1 / mHat); + mr2 = pow2(mf2 / mHat); + ps = (mHat < mf1 + mf2 + MASSMARGIN) ? 0. + : sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 ); + if (mult > 2) { + mf3 = ParticleDataTable::m0(id3Abs); + mr3 = pow2(mf3 / mHat); + } + + // Let derived class calculate width for channel provided. + calcWidth(true); + } + + // Channels with meMode >= 100 are caculated based on stored values. + else widNow = GammaRes * particlePtr->decay[i].bRatio(); + + // Find secondary open fractions of partial width. + openSecPos = 1.; + openSecNeg = 1.; + for (int j = 0; j < mult; ++j) { + idNow = particlePtr->decay[i].product(j); + idAnti = (ParticleDataTable::hasAnti(idNow)) ? -idNow : idNow; + openSecPos *= ParticleDataTable::resOpenFrac(idNow); + openSecNeg *= ParticleDataTable::resOpenFrac(idAnti); + } + + // Store partial widths and secondary open fractions. + particlePtr->decay[i].onShellWidth(widNow); + particlePtr->decay[i].openSec( idRes, openSecPos); + particlePtr->decay[i].openSec(-idRes, openSecNeg); + + // Update sum over all channnels and over open channels only. + widTot += widNow; + if (onMode == 1 || onMode == 2) widPos += widNow * openSecPos; + if (onMode == 1 || onMode == 3) widNeg += widNow * openSecNeg; + } + + // If no decay channels are open then set particle stable and done. + if (widTot < minWidth) { + particlePtr->setMayDecay(false, false); + particlePtr->setMWidth(0., false); + for (int i = 0; i < particlePtr->decay.size(); ++i) + particlePtr->decay[i].bRatio( 0., false); + return; + } + + // Normalize branching ratios to unity. + double bRatio; + for (int i = 0; i < particlePtr->decay.size(); ++i) { + bRatio = particlePtr->decay[i].onShellWidth() / widTot; + particlePtr->decay[i].bRatio( bRatio, false); + } + + // Optionally force total width by rescaling of all partial ones. + if (doForceWidth) { + forceFactor = GammaRes / widTot; + for (int i = 0; i < particlePtr->decay.size(); ++i) + particlePtr->decay[i].onShellWidthFactor( forceFactor); + } + + // Else update newly calculated partial width. + else { + particlePtr->setMWidth(widTot, false); + GammaRes = widTot; + } + + // Updated width-to-mass ratio. Secondary widths for open. + GamMRat = GammaRes / mRes; + openPos = widPos / widTot; + openNeg = widNeg / widTot; + +} + +//********* + +// Calculate the total width and store phase-space-weighted coupling sums. + +double ResonanceWidths::width(int idSgn, double mHatIn, int idInFlavIn, + bool openOnly, bool setBR, int idOutFlav1, int idOutFlav2) { + + // Calculate various prefactors for the current mass. + mHat = mHatIn; + idInFlav = idInFlavIn; + calcPreFac(false); + + // Reset quantities to sum. Declare variables inside loop. + double widSum = 0.; + double mfSum, psOnShell; + + // Loop over all decay channels. Basic properties of channel. + for (int i = 0; i < particlePtr->decay.size(); ++i) { + iChannel = i; + onMode = particlePtr->decay[i].onMode(); + meMode = particlePtr->decay[i].meMode(); + mult = particlePtr->decay[i].multiplicity(); + + // Initially assume vanishing branching ratio. + widNow = 0.; + if (setBR) particlePtr->decay[i].currentBR(widNow); + + // Optionally only consider specific (two-body) decay channel. + // Currently only used for Higgs -> q qbar, g g or gamma gamma. + if (idOutFlav1 > 0 || idOutFlav2 > 0) { + if (mult > 2) continue; + if (particlePtr->decay[i].product(0) != idOutFlav1) continue; + if (particlePtr->decay[i].product(1) != idOutFlav2) continue; + } + + // Optionally only consider open channels. + if (openOnly) { + if (idSgn > 0 && onMode !=1 && onMode != 2) continue; + if (idSgn < 0 && onMode !=1 && onMode != 3) continue; + } + + // Channels with meMode < 100 must be implemented in derived classes. + if (meMode < 100) { + + // Read out information on channel: primarily use first two. + id1 = particlePtr->decay[i].product(0); + id2 = particlePtr->decay[i].product(1); + id1Abs = abs(id1); + id2Abs = abs(id2); + + // Order first two in descending order of absolute values. + if (id2Abs > id1Abs) {swap( id1, id2); swap( id1Abs, id2Abs);} + + // Allow for third product to be treated in derived classes. + if (mult > 2) { + id3 = particlePtr->decay[i].product(2); + id3Abs = abs(id3); + + // Also order third into descending order of absolute values. + if (id3Abs > id2Abs) {swap( id2, id3); swap( id2Abs, id3Abs);} + if (id2Abs > id1Abs) {swap( id1, id2); swap( id1Abs, id2Abs);} + } + + // Read out masses. Calculate two-body phase space. + mf1 = ParticleDataTable::m0(id1Abs); + mf2 = ParticleDataTable::m0(id2Abs); + mr1 = pow2(mf1 / mHat); + mr2 = pow2(mf2 / mHat); + ps = (mHat < mf1 + mf2 + MASSMARGIN) ? 0. + : sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 ); + if (mult > 2) { + mf3 = ParticleDataTable::m0(id3Abs); + mr3 = pow2(mf3 / mHat); + } + + // Let derived class calculate width for channel provided. + calcWidth(false); + } + + // Now on to meMode >= 100. First case: no correction at all. + else if (meMode == 100) + widNow = GammaRes * particlePtr->decay[i].bRatio(); + + // Correction by step at threshold. + else if (meMode == 101) { + mfSum = 0.; + for (int j = 0; j < mult; ++j) mfSum + += ParticleDataTable::m0( particlePtr->decay[i].product(j) ); + if (mfSum + MASSMARGIN < mHat) + widNow = GammaRes * particlePtr->decay[i].bRatio(); + } + + // Correction by a phase space factor for two-body decays. + else if ( (meMode == 102 || meMode == 103) && mult == 2) { + mf1 = ParticleDataTable::m0( particlePtr->decay[i].product(0) ); + mf2 = ParticleDataTable::m0( particlePtr->decay[i].product(1) ); + mr1 = pow2(mf1 / mHat); + mr2 = pow2(mf2 / mHat); + ps = (mHat < mf1 + mf2 + MASSMARGIN) ? 0. + : sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 ); + mr1 = pow2(mf1 / mRes); + mr2 = pow2(mf2 / mRes); + psOnShell = (meMode == 102) ? 1. : max( minThreshold, + sqrtpos( pow2(1.- mr1 - mr2) - 4. * mr1 * mr2) ); + widNow = GammaRes * particlePtr->decay[i].bRatio() * ps / psOnShell; + } + + // Correction by simple threshold factor for multibody decay. + else if (meMode == 102 || meMode == 103) { + mfSum = 0.; + for (int j = 0; j < mult; ++j) mfSum + += ParticleDataTable::m0( particlePtr->decay[i].product(j) ); + ps = sqrtpos(1. - mfSum / mHat); + psOnShell = (meMode == 102) ? 1. : max( minThreshold, + sqrtpos(1. - mfSum / mRes) ); + widNow = GammaRes * particlePtr->decay[i].bRatio() * ps / psOnShell; + } + + // Optionally multiply by secondary widths. + if (openOnly) widNow *= particlePtr->decay[i].openSec(idSgn); + + // Optionally include factor to force to fixed width?? + // Optionally multiply by current/nominal resonance mass?? + + // Sum back up. + widSum += widNow; + + // Optionally store partial widths for later decay channel choice. + if (setBR) particlePtr->decay[i].currentBR(widNow); + } + + // Done. + return widSum; + +} + +//********* + +// Initialize particle properties always present. + +bool ResonanceWidths::initBasic(int idResIn) { + + // Resonance identity code and pointer to/from particle species. + idRes = idResIn; + particlePtr = ParticleDataTable::particleDataPtr(idRes); + if (particlePtr == 0) { + infoPtr->errorMsg("Error in ResonanceWidths::initBasic:" + " unknown resonance identity code"); + return false; + } + particlePtr->setResonancePtr(this); + + // Resonance properties: antiparticle, mass, width + hasAntiRes = particlePtr->hasAnti(); + mRes = particlePtr->m0(); + GammaRes = particlePtr->mWidth(); + m2Res = mRes*mRes; + + // For very narrow resonances assign fictitious small width. + if (GammaRes < minWidth) GammaRes = 0.1 * minWidth; + GamMRat = GammaRes / mRes; + + // Secondary decay chains by default all on. + openPos = 1.; + openNeg = 1.; + + // Allow option where on-shell width is forced to current value. + doForceWidth = particlePtr->doForceWidth(); + forceFactor = 1.; + + // Done. + return true; + +} + +//********* + +// Numerical integration of matrix-element in two-body decay, +// where one particle is described by a Breit-Wigner mass distribution. +// Normalization to unit integral if matrix element is unity +// and there are no phase-space restrictions. + +double ResonanceWidths::numInt1BW(double mHatIn, double m1, double Gamma1, + double mMin1, double m2, int psMode) { + + // Check that phase space is open for integration. + if (mMin1 + m2 > mHatIn) return 0.; + + // Precalculate coefficients for Breit-Wigner selection. + double s1 = m1 * m1; + double mG1 = m1 * Gamma1; + double mMax1 = mHatIn - m2; + double atanMin1 = atan( (mMin1 * mMin1 - s1) / mG1 ); + double atanMax1 = atan( (mMax1 * mMax1 - s1) / mG1 ); + double atanDif1 = atanMax1 - atanMin1; + double wtDif1 = atanDif1 / (M_PI * NPOINT); + + // Step size in atan-mapped variable. + double xStep = 1. / NPOINT; + + // Variables used in loop over integration points. + double sum = 0.; + double mrNow2 = pow2(m2 / mHatIn); + double xNow1, sNow1, mNow1, mrNow1, psNow, value; + + // Loop with first-particle mass selection. + for (int ip1 = 0; ip1 < NPOINT; ++ip1) { + xNow1 = xStep * (ip1 + 0.5); + sNow1 = s1 + mG1 * tan(atanMin1 + xNow1 * atanDif1); + mNow1 = min( mMax1, max( mMin1, sqrtpos(sNow1) ) ); + mrNow1 = pow2(mNow1 / mHatIn); + + // Evaluate value and add to sum. Different matrix elements. + psNow = sqrtpos( pow2(1. - mrNow1 - mrNow2) + - 4. * mrNow1 * mrNow2); + value = 1.; + if (psMode == 1) value = psNow; + if (psMode == 2) value = psNow * psNow; + if (psMode == 3) value = pow3(psNow); + if (psMode == 5) value = psNow * + (pow2(1. - mrNow1 - mrNow2) + 8. * mrNow1 * mrNow2); + sum += value; + + // End of loop over integration points. Overall normalization. + } + sum *= wtDif1; + + // Done. + return sum; +} + +//********* + +// Numerical integration of matrix-element in two-body decay, +// where both particles are described by Breit-Wigner mass distributions. +// Normalization to unit integral if matrix element is unity +// and there are no phase-space restrictions. + +double ResonanceWidths::numInt2BW(double mHatIn, double m1, double Gamma1, + double mMin1, double m2, double Gamma2, double mMin2, int psMode) { + + // Check that phase space is open for integration. + if (mMin1 + mMin2 > mHatIn) return 0.; + + // Precalculate coefficients for Breit-Wigner selection. + double s1 = m1 * m1; + double mG1 = m1 * Gamma1; + double mMax1 = mHatIn - mMin2; + double atanMin1 = atan( (mMin1 * mMin1 - s1) / mG1 ); + double atanMax1 = atan( (mMax1 * mMax1 - s1) / mG1 ); + double atanDif1 = atanMax1 - atanMin1; + double wtDif1 = atanDif1 / (M_PI * NPOINT); + double s2 = m2 * m2; + double mG2 = m2 * Gamma2; + double mMax2 = mHatIn - mMin1; + double atanMin2 = atan( (mMin2 * mMin2 - s2) / mG2 ); + double atanMax2 = atan( (mMax2 * mMax2 - s2) / mG2 ); + double atanDif2 = atanMax2 - atanMin2; + double wtDif2 = atanDif2 / (M_PI * NPOINT); + + // If on-shell decay forbidden then split integration range + // to ensure that low-mass region is not forgotten. + bool mustDiv = false; + double mDiv1 = 0.; + double atanDiv1 = 0.; + double atanDLo1 = 0.; + double atanDHi1 = 0.; + double wtDLo1 = 0.; + double wtDHi1 = 0.; + double mDiv2 = 0.; + double atanDiv2 = 0.; + double atanDLo2 = 0.; + double atanDHi2 = 0.; + double wtDLo2 = 0.; + double wtDHi2 = 0.; + if (m1 + m2 > mHatIn) { + mustDiv = true; + double tmpDiv = (mHatIn - m1 - m2) / (Gamma1 + Gamma2); + mDiv1 = m1 + Gamma1 * tmpDiv; + atanDiv1 = atan( (mDiv1 * mDiv1 - s1) / mG1 ); + atanDLo1 = atanDiv1 - atanMin1; + atanDHi1 = atanMax1 - atanDiv1; + wtDLo1 = atanDLo1 / (M_PI * NPOINT); + wtDHi1 = atanDHi1 / (M_PI * NPOINT); + mDiv2 = m2 + Gamma2 * tmpDiv; + atanDiv2 = atan( (mDiv2 * mDiv2 - s2) / mG2 ); + atanDLo2 = atanDiv2 - atanMin2; + atanDHi2 = atanMax2 - atanDiv2; + wtDLo2 = atanDLo2 / (M_PI * NPOINT); + wtDHi2 = atanDHi2 / (M_PI * NPOINT); + } + + // Step size in atan-mapped variable. + double xStep = 1. / NPOINT; + int nIter = (mustDiv) ? 2 * NPOINT : NPOINT; + + // Variables used in loop over integration points. + double sum = 0.; + double xNow1, sNow1, mNow1, mrNow1, xNow2, sNow2, mNow2, mrNow2, psNow, + value; + double wtNow1 = wtDif1; + double wtNow2 = wtDif2; + + // Outer loop with first-particle mass selection. + for (int ip1 = 0; ip1 < nIter; ++ip1) { + if (!mustDiv) { + xNow1 = xStep * (ip1 + 0.5); + sNow1 = s1 + mG1 * tan(atanMin1 + xNow1 * atanDif1); + } else if (ip1 < NPOINT) { + xNow1 = xStep * (ip1 + 0.5); + sNow1 = s1 + mG1 * tan(atanMin1 + xNow1 * atanDLo1); + wtNow1 = wtDLo1; + } else { + xNow1 = xStep * (ip1 - NPOINT + 0.5); + sNow1 = s1 + mG1 * tan(atanDiv1 + xNow1 * atanDHi1); + wtNow1 = wtDHi1; + } + mNow1 = min( mMax1, max( mMin1, sqrtpos(sNow1) ) ); + mrNow1 = pow2(mNow1 / mHatIn); + + // Inner loop with second-particle mass selection. + for (int ip2 = 0; ip2 < nIter; ++ip2) { + if (!mustDiv) { + xNow2 = xStep * (ip2 + 0.5); + sNow2 = s2 + mG2 * tan(atanMin2 + xNow2 * atanDif2); + } else if (ip2 < NPOINT) { + xNow2 = xStep * (ip2 + 0.5); + sNow2 = s2 + mG2 * tan(atanMin2 + xNow2 * atanDLo2); + wtNow2 = wtDLo2; + } else { + xNow2 = xStep * (ip2 - NPOINT + 0.5); + sNow2 = s2 + mG2 * tan(atanDiv2 + xNow2 * atanDHi2); + wtNow2 = wtDHi2; + } + mNow2 = min( mMax2, max( mMin2, sqrtpos(sNow2) ) ); + mrNow2 = pow2(mNow2 / mHatIn); + + // Check that point is inside phase space. + if (mNow1 + mNow2 > mHatIn) break; + + // Evaluate value and add to sum. Different matrix elements. + psNow = sqrtpos( pow2(1. - mrNow1 - mrNow2) + - 4. * mrNow1 * mrNow2); + value = 1.; + if (psMode == 1) value = psNow; + else if (psMode == 2) value = psNow * psNow; + else if (psMode == 3) value = pow3(psNow); + else if (psMode == 5) value = psNow + * (pow2(1. - mrNow1 - mrNow2) + 8. * mrNow1 * mrNow2); + sum += value * wtNow1 * wtNow2; + + // End of second and first loop over integration points. + } + } + + // Done. + return sum; +} + +//************************************************************************** + +// The ResonanceGmZ class. +// Derived class for gamma*/Z0 properties. + +//********* + +// Initialize constants. + +void ResonanceGmZ::initConstants() { + + // Locally stored properties and couplings. + gmZmode = Settings::mode("WeakZ0:gmZmode"); + thetaWRat = 1. / (16. * CoupEW::sin2thetaW() * CoupEW::cos2thetaW()); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceGmZ::calcPreFac(bool calledFromInit) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = 3. * (1. + alpS / M_PI); + preFac = alpEM * thetaWRat * mHat / 3.; + + // When call for incoming flavour need to consider gamma*/Z0 mix. + if (!calledFromInit) { + + // Couplings when an incoming fermion is specified; elso only pure Z0. + ei2 = 0.; + eivi = 0.; + vi2ai2 = 1.; + int idInFlavAbs = abs(idInFlav); + if (idInFlavAbs > 0 && idInFlavAbs < 19) { + ei2 = CoupEW::ef2(idInFlavAbs); + eivi = CoupEW::efvf(idInFlavAbs); + vi2ai2 = CoupEW::vf2af2(idInFlavAbs); + } + + // Calculate prefactors for gamma/interference/Z0 terms. + double sH = mHat * mHat; + gamNorm = ei2; + intNorm = 2. * eivi * thetaWRat * sH * (sH - m2Res) + / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + resNorm = vi2ai2 * pow2(thetaWRat * sH) + / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + + // Rescale Z0 height normalization to compensate for a width one?? + //if (doForceWidth) { + // intNorm *= forceFactor; + // resNorm *= forceFactor; + //} + + // Optionally only keep gamma* or Z0 term. + if (gmZmode == 1) {intNorm = 0.; resNorm = 0.;} + if (gmZmode == 2) {gamNorm = 0.; intNorm = 0.;} + } + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceGmZ::calcWidth(bool calledFromInit) { + + // Check that above threshold. + if (ps == 0.) return; + + // Only contributions from three fermion generations, except top. + if ( (id1Abs > 5 && id1Abs < 11) || id1Abs > 16 ) return; + + // At initialization only the pure Z0 should be considered. + if (calledFromInit) { + + // Combine kinematics with colour factor and couplings. + widNow = preFac * ps * (CoupEW::vf2(id1Abs) * (1. + 2. * mr1) + + CoupEW::af2(id1Abs) * ps*ps); + if (id1Abs < 6) widNow *= colQ; + } + + // When call for incoming flavour need to consider gamma*/Z0 mix. + else { + + // Kinematical factors and couplings. + double kinFacV = ps * (1. + 2. * mr1); + double ef2 = CoupEW::ef2(id1Abs) * kinFacV; + double efvf = CoupEW::efvf(id1Abs) * kinFacV; + double vf2af2 = CoupEW::vf2(id1Abs) * kinFacV + + CoupEW::af2(id1Abs) * pow3(ps); + + // Relative outwidths: combine instate, propagator and outstate. + widNow = gamNorm * ef2 + intNorm * efvf + resNorm * vf2af2; + + // Colour factor. + if (id1Abs < 6) widNow *= colQ; + } + +} + +//************************************************************************** + +// The ResonanceW class. +// Derived class for W+- properties. + +//********* + +// Initialize constants. + +void ResonanceW::initConstants() { + + // Locally stored properties and couplings. + thetaWRat = 1. / (12. * CoupEW::sin2thetaW()); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceW::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = 3. * (1. + alpS / M_PI); + preFac = alpEM * thetaWRat * mHat; + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceW::calcWidth(bool) { + + // Check that above threshold. + if (ps == 0.) return; + + // Only contributions from three fermion generations, except top. + if ( (id1Abs > 5 && id1Abs < 11) || id1Abs > 16 ) return; + + + // Combine kinematics with colour factor and couplings. + widNow = preFac * ps + * (1. - 0.5 * (mr1 + mr2) - 0.5 * pow2(mr1 - mr2)); + if (id1Abs < 6) widNow *= colQ * VCKM::V2id(id1Abs, id2Abs); + +} + +//************************************************************************** + +// The ResonanceTop class. +// Derived class for top/antitop properties. + +//********* + +// Initialize constants. + +void ResonanceTop::initConstants() { + + // Locally stored properties and couplings. + thetaWRat = 1. / (16. * CoupEW::sin2thetaW()); + m2W = pow2(ParticleDataTable::m0(24)); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceTop::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = 1. - 2.5 * alpS / M_PI; + preFac = alpEM * thetaWRat * pow3(mHat) / m2W; + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceTop::calcWidth(bool) { + + // Only contributions from W + quark. + if (id1Abs != 24 || id2Abs > 5) return; + + // Check that above threshold. Kinematical factor. + if (ps == 0.) return; + widNow = preFac * ps + * ( pow2(1. - mr2) + (1. + mr2) * mr1 - 2. * mr1 * mr1 ); + + // Combine with colour factor and CKM couplings. + widNow *= colQ * VCKM::V2id(6, id2Abs); + +} + +//************************************************************************** + +// The ResonanceFour class. +// Derived class for fourth-generation properties. + +//********* + +// Initialize constants. + +void ResonanceFour::initConstants() { + + // Locally stored properties and couplings. + thetaWRat = 1. / (16. * CoupEW::sin2thetaW()); + m2W = pow2(ParticleDataTable::m0(24)); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceFour::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = (idRes < 9) ? 1. - 2.5 * alpS / M_PI : 1.; + preFac = alpEM * thetaWRat * pow3(mHat) / m2W; + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceFour::calcWidth(bool) { + + // Only contributions from W + fermion. + if (id1Abs != 24 || id2Abs > 18) return; + + // Check that above threshold. Kinematical factor. + if (ps == 0.) return; + widNow = preFac * ps + * ( pow2(1. - mr2) + (1. + mr2) * mr1 - 2. * mr1 * mr1 ); + + // Combine with colour factor and CKM couplings. + if (idRes < 9) widNow *= colQ * VCKM::V2id(idRes, id2Abs); + +} + +//************************************************************************** + +// The ResonanceH class. +// Derived class for SM and BSM Higgs properties. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Minimal mass for W, Z, top in integration over respective Breit-Wigner. +const double ResonanceH::MASSMIN = 10.; + +// Number of widths above threshold where B-W integration not needed. +const double ResonanceH::GAMMAMARGIN = 10.; + +//********* + +// Initialize constants. + +void ResonanceH::initConstants() { + + // Locally stored properties and couplings. + useCubicWidth = Settings::flag("Higgs:cubicWidth"); + useRunLoopMass = Settings::flag("Higgs:runningLoopMass"); + sin2tW = CoupEW::sin2thetaW(); + cos2tW = 1. - sin2tW; + mT = ParticleDataTable::m0(6); + mZ = ParticleDataTable::m0(23); + mW = ParticleDataTable::m0(24); + mHchg = ParticleDataTable::m0(37); + GammaT = ParticleDataTable::mWidth(6); + GammaZ = ParticleDataTable::mWidth(23); + GammaW = ParticleDataTable::mWidth(24); + + // Couplings to fermions, Z and W, depending on Higgs type. + coup2d = 1.; + coup2u = 1.; + coup2l = 1.; + coup2Z = 1.; + coup2W = 1.; + coup2Hchg = 0.; + coup2H1H1 = 0.; + coup2A3A3 = 0.; + coup2H1Z = 0.; + coup2A3Z = 0.; + coup2A3H1 = 0.; + coup2HchgW = 0.; + if (higgsType == 1) { + coup2d = Settings::parm("HiggsH1:coup2d"); + coup2u = Settings::parm("HiggsH1:coup2u"); + coup2l = Settings::parm("HiggsH1:coup2l"); + coup2Z = Settings::parm("HiggsH1:coup2Z"); + coup2W = Settings::parm("HiggsH1:coup2W"); + coup2Hchg = Settings::parm("HiggsH1:coup2Hchg"); + } else if (higgsType == 2) { + coup2d = Settings::parm("HiggsH2:coup2d"); + coup2u = Settings::parm("HiggsH2:coup2u"); + coup2l = Settings::parm("HiggsH2:coup2l"); + coup2Z = Settings::parm("HiggsH2:coup2Z"); + coup2W = Settings::parm("HiggsH2:coup2W"); + coup2Hchg = Settings::parm("HiggsH2:coup2Hchg"); + coup2H1H1 = Settings::parm("HiggsH2:coup2H1H1"); + coup2A3A3 = Settings::parm("HiggsH2:coup2A3A3"); + coup2H1Z = Settings::parm("HiggsH2:coup2H1Z"); + coup2A3Z = Settings::parm("HiggsA3:coup2H2Z"); + coup2A3H1 = Settings::parm("HiggsH2:coup2A3H1"); + coup2HchgW = Settings::parm("HiggsH2:coup2HchgW"); + } else if (higgsType == 3) { + coup2d = Settings::parm("HiggsA3:coup2d"); + coup2u = Settings::parm("HiggsA3:coup2u"); + coup2l = Settings::parm("HiggsA3:coup2l"); + coup2Z = Settings::parm("HiggsA3:coup2Z"); + coup2W = Settings::parm("HiggsA3:coup2W"); + coup2Hchg = Settings::parm("HiggsA3:coup2Hchg"); + coup2H1H1 = Settings::parm("HiggsA3:coup2H1H1"); + coup2H1Z = Settings::parm("HiggsA3:coup2H1Z"); + coup2HchgW = Settings::parm("HiggsA3:coup2Hchg"); + } + + // Initialization of threshold kinematical factor by stepwise + // numerical integration of H -> t tbar, Z0 Z0 and W+ W-. + int psMode = (higgsType < 3) ? 3 : 1; + for (int i = 0; i <= 100; ++i) { + kinFacT[i] = numInt2BW( (0.5 + 0.025 * i) * mT, + mT, GammaT, MASSMIN, mT, GammaT, MASSMIN, psMode); + kinFacZ[i] = numInt2BW( (0.5 + 0.025 * i) * mZ, + mZ, GammaZ, MASSMIN, mZ, GammaZ, MASSMIN, 5); + kinFacW[i] = numInt2BW( (0.5 + 0.025 * i) * mW, + mW, GammaW, MASSMIN, mW, GammaW, MASSMIN, 5); + } + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceH::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = 3. * (1. + alpS / M_PI); + preFac = (alpEM / (8. * sin2tW)) * pow3(mHat) / pow2(mW); +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceH::calcWidth(bool) { + + // Widths of decays Higgs -> f + fbar. + if ( id2Abs == id1Abs && ( (id1Abs > 0 && id1Abs < 7) + || (id1Abs > 10 && id1Abs < 17) ) ) { + kinFac = 0.; + + // Check that above threshold (well above for top). Kinematical factor. + if ( (id1Abs != 6 && mHat > 2. * mf1 + MASSMARGIN) + || (id1Abs == 6 && mHat > 3. * mT ) ) { + // A0 behaves like beta, h0 and H0 like beta**3. + kinFac = (higgsType < 3) ? pow3(ps) : ps; + } + + // Top near or below threshold: interpolate in table or extrapolate below. + else if (id1Abs == 6 && mHat > 0.5 * mT) { + double xTab = 40. * (mHat / mT - 0.5); + int iTab = max( 0, min( 99, int(xTab) ) ); + kinFac = kinFacT[iTab] + * pow( kinFacT[iTab + 1] / kinFacT[iTab], xTab - iTab); + } + else if (id1Abs == 6) kinFac = kinFacT[0] + * 2. / (1. + pow6(0.5 * mT / mHat)); + + // Coupling from mass and from BSM deviation from SM. + double coupFac = pow2(ParticleDataTable::mRun(id1Abs, mHat) / mHat); + if (id1Abs < 7 && id1Abs%2 == 1) coupFac *= coup2d * coup2d; + else if (id1Abs < 7) coupFac *= coup2u * coup2u; + else coupFac *= coup2l * coup2l; + + // Combine couplings and phase space with colour factor. + widNow = preFac * coupFac * kinFac; + if (id1Abs < 7) widNow *= colQ; + } + + // Widths of decays Higgs -> g + g. + else if (id1Abs == 21 && id2Abs == 21) + widNow = preFac * pow2(alpS / M_PI) * eta2gg(); + + // Widths of decays Higgs -> gamma + gamma. + else if (id1Abs == 22 && id2Abs == 22) + widNow = preFac * pow2(alpEM / M_PI) * 0.5 * eta2gaga(); + + // Widths of decays Higgs -> Z0 + gamma0. + else if (id1Abs == 23 && id2Abs == 22) + widNow = preFac * pow2(alpEM / M_PI) * pow3(ps) * eta2gaZ(); + + // Widths of decays Higgs (h0, H0) -> Z0 + Z0. + else if (id1Abs == 23 && id2Abs == 23) { + // If Higgs heavy use on-shell expression, else interpolation in table + if (mHat > 3. * mZ) kinFac = (1. - 4. * mr1 + 12. * mr1 * mr1) * ps; + else if (mHat > 0.5 * mZ) { + double xTab = 40. * (mHat / mZ - 0.5); + int iTab = max( 0, min( 99, int(xTab) ) ); + kinFac = kinFacZ[iTab] + * pow( kinFacZ[iTab + 1] / kinFacZ[iTab], xTab - iTab ); + } + else kinFac = kinFacZ[0] * 2. / (1. + pow6(0.5 * mZ / mHat)); + // Prefactor, normally rescaled to mRes^2 * mHat rather than mHat^3. + widNow = 0.25 * preFac * pow2(coup2Z) * kinFac; + if (!useCubicWidth) widNow *= pow2(mRes / mHat); + } + + // Widths of decays Higgs (h0, H0) -> W+ + W-. + else if (id1Abs == 24 && id2Abs == 24) { + // If Higgs heavy use on-shell expression, else interpolation in table. + if (mHat > 3. * mW) kinFac = (1. - 4. * mr1 + 12. * mr1 * mr1) * ps; + else if (mHat > 0.5 * mW) { + double xTab = 40. * (mHat / mW - 0.5); + int iTab = max( 0, min( 99, int(xTab) ) ); + kinFac = kinFacW[iTab] + * pow( kinFacW[iTab + 1] / kinFacW[iTab], xTab - iTab); + } + else kinFac = kinFacW[0] * 2. / (1. + pow6(0.5 * mW / mHat)); + // Prefactor, normally rescaled to mRes^2 * mHat rather than mHat^3. + widNow = 0.5 * preFac * pow2(coup2W) * kinFac; + if (!useCubicWidth) widNow *= pow2(mRes / mHat); + } + + // Widths of decays Higgs (H0) -> h0 + h0. + else if (id1Abs == 25 && id2Abs == 25) + widNow = 0.25 * preFac * pow4(mZ / mHat) * ps * pow2(coup2H1H1); + + // Widths of decays Higgs (H0) -> A0 + A0. + else if (id1Abs == 36 && id2Abs == 36) + widNow = 0.5 * preFac * pow4(mZ / mHat) * ps * pow2(coup2A3A3); + + // Widths of decays Higgs (A0) -> h0 + Z0. + else if (id1Abs == 25 && id2Abs == 23) + widNow = 0.5 * preFac * pow3(ps) * pow2(coup2H1Z); + + // Widths of decays Higgs (H0) -> A0 + Z0. + else if (id1Abs == 36 && id2Abs == 23) + widNow = 0.5 * preFac * pow3(ps) * pow2(coup2A3Z); + + // Widths of decays Higgs (H0) -> A0 + h0. + else if (id1Abs == 36 && id2Abs == 25) + widNow = 0.25 * preFac * pow4(mZ / mHat) * ps * pow2(coup2A3H1); + + // Widths of decays Higgs -> H+- + W-+. + else if (id1Abs == 37 && id2Abs == 24) + widNow = 0.5 * preFac * pow3(ps) * pow2(coup2HchgW); + +} + +//********* + +// Sum up quark loop contributions in Higgs -> g + g. +// Note: running quark masses are used, unlike Pythia6 (not negligible shift). + +double ResonanceH::eta2gg() { + + // Initial values. + complex eta = complex(0., 0.); + double mLoop, epsilon, root, rootLog; + complex phi, etaNow; + + // Loop over s, c, b, t quark flavours. + for (int idNow = 3; idNow < 7; ++idNow) { + mLoop = (useRunLoopMass) ? ParticleDataTable::mRun(idNow, mHat) + : ParticleDataTable::m0(idNow); + epsilon = pow2(2. * mLoop / mHat); + + // Value of loop integral. + if (epsilon <= 1.) { + root = sqrt(1. - epsilon); + rootLog = (epsilon < 1e-4) ? log(4. / epsilon - 2.) + : log( (1. + root) / (1. - root) ); + phi = complex( -0.25 * (pow2(rootLog) - pow2(M_PI)), + 0.5 * M_PI * rootLog ); + } + else phi = complex( pow2( asin(1. / sqrt(epsilon)) ), 0.); + + // Factors that depend on Higgs and flavour type. + if (higgsType < 3) etaNow = -0.5 * epsilon + * (complex(1., 0.) + (1. - epsilon) * phi); + else etaNow = -0.5 * epsilon * phi; + if (idNow%2 == 1) etaNow *= coup2d; + else etaNow *= coup2u; + + // Sum up contribution and return square of absolute value. + eta += etaNow; + } + return (pow2(eta.real()) + pow2(eta.imag())); + +} + +//********* + +// Sum up quark, lepton, W+- and (for BSM) H+- loop contributions +// in Higgs -> gamma + gamma. + +double ResonanceH::eta2gaga() { + + // Initial values. + complex eta = complex(0., 0.); + int idNow; + double ef, mLoop, epsilon, root, rootLog; + complex phi, etaNow; + + // Loop over s, c, b, t, mu, tau, W+-, H+- flavours. + for (int idLoop = 0; idLoop < 8; ++idLoop) { + if (idLoop < 4) idNow = idLoop + 3; + else if (idLoop < 6) idNow = 2 * idLoop + 5; + else if (idLoop < 7) idNow = 24; + else idNow = 37; + if (idNow == 37 && higgsType == 0) continue; + + // Charge and loop integral parameter. + ef = (idNow < 20) ? CoupEW::ef(idNow) : 1.; + mLoop = (useRunLoopMass) ? ParticleDataTable::mRun(idNow, mHat) + : ParticleDataTable::m0(idNow); + epsilon = pow2(2. * mLoop / mHat); + + // Value of loop integral. + if (epsilon <= 1.) { + root = sqrt(1. - epsilon); + rootLog = (epsilon < 1e-4) ? log(4. / epsilon - 2.) + : log( (1. + root) / (1. - root) ); + phi = complex( -0.25 * (pow2(rootLog) - pow2(M_PI)), + 0.5 * M_PI * rootLog ); + } + else phi = complex( pow2( asin(1. / sqrt(epsilon)) ), 0.); + + // Expressions for quarks and leptons that depend on Higgs type. + if (idNow < 17) { + if (higgsType < 3) etaNow = -0.5 * epsilon + * (complex(1., 0.) + (1. - epsilon) * phi); + else etaNow = -0.5 * epsilon * phi; + if (idNow < 7 && idNow%2 == 1) etaNow *= 3. * pow2(ef) * coup2d; + else if (idNow < 7 ) etaNow *= 3. * pow2(ef) * coup2u; + else etaNow *= pow2(ef) * coup2l; + } + + // Expression for W+-. + else if (idNow == 24) etaNow = (complex(0.5 + 0.75 * epsilon, 0.) + + 0.75 * epsilon * (2. - epsilon) * phi) * coup2W; + + // Expression for H+-. + else etaNow = (complex(epsilon, 0.) - epsilon * epsilon * phi) + * pow2(mW / mHchg) * coup2Hchg; + + // Sum up contribution and return square of absolute value. + eta += etaNow; + } + return (pow2(eta.real()) + pow2(eta.imag())); + +} + +//********* + +// Sum up quark, lepton, W+- and (for BSM) H+- loop contributions +// in Higgs -> gamma + Z0. + +double ResonanceH::eta2gaZ() { + + // Initial values. + complex eta = complex(0., 0.); + int idNow; + double ef, vf, mLoop, epsilon, epsPrime, root, rootLog, asinEps; + complex phi, psi, phiPrime, psiPrime, fXY, f1, etaNow; + + // Loop over s, c, b, t, mu , tau, W+-, H+- flavours. + for (int idLoop = 0; idLoop < 7; ++idLoop) { + if (idLoop < 4) idNow = idLoop + 3; + else if (idLoop < 6) idNow = 2 * idLoop + 5; + else if (idLoop < 7) idNow = 24; + else idNow = 37; + + // Electroweak charges and loop integral parameters. + ef = (idNow < 20) ? CoupEW::ef(idNow) : 1.; + vf = (idNow < 20) ? CoupEW::vf(idNow) : 0.; + mLoop = (useRunLoopMass) ? ParticleDataTable::mRun(idNow, mHat) + : ParticleDataTable::m0(idNow); + epsilon = pow2(2. * mLoop / mHat); + epsPrime = pow2(2. * mLoop / mZ); + + // Value of loop integral for epsilon = 4 m^2 / sHat. + if (epsilon <= 1.) { + root = sqrt(1. - epsilon); + rootLog = (epsilon < 1e-4) ? log(4. / epsilon - 2.) + : log( (1. + root) / (1. - root) ); + phi = complex( -0.25 * (pow2(rootLog) - pow2(M_PI)), + 0.5 * M_PI * rootLog ); + psi = 0.5 * root * complex( rootLog, -M_PI); + } else { + asinEps = asin(1. / sqrt(epsilon)); + phi = complex( pow2(asinEps), 0.); + psi = complex( sqrt(epsilon - 1.) * asinEps, 0.); + } + + // Value of loop integral for epsilonPrime = 4 m^2 / m_Z^2. + if (epsPrime <= 1.) { + root = sqrt(1. - epsPrime); + rootLog = (epsPrime < 1e-4) ? log(4. / epsPrime - 2.) + : log( (1. + root) / (1. - root) ); + phiPrime = complex( -0.25 * (pow2(rootLog) - pow2(M_PI)), + 0.5 * M_PI * rootLog ); + psiPrime = 0.5 * root * complex( rootLog, -M_PI); + } else { + asinEps = asin(1. / sqrt(epsPrime)); + phiPrime = complex( pow2(asinEps), 0.); + psiPrime = complex( sqrt(epsPrime - 1.) * asinEps, 0.); + } + + // Combine the two loop integrals. + fXY = (epsilon * epsPrime / (8. * pow2(epsilon - epsPrime))) + * ( complex(epsilon - epsPrime, 0) + + epsilon * epsPrime * (phi - phiPrime) + + 2. * epsilon * (psi - psiPrime) ); + f1 = - (epsilon * epsPrime / (2. * (epsilon - epsPrime))) + * (phi - phiPrime); + + // Expressions for quarks and leptons that depend on Higgs type. + if (idNow < 17) { + etaNow = (higgsType < 3) ? -fXY + 0.25 * f1 : 0.25 * f1; + if (idNow < 7 && idNow%2 == 1) etaNow *= 3. * ef * vf * coup2d; + else if (idNow < 7) etaNow *= 3. * ef * vf * coup2u; + else etaNow *= ef * vf * coup2l; + + // Expression for W+-. + } else if (idNow == 24) { + double coef1 = 3. - sin2tW / cos2tW; + double coefXY = (1. + 2. / epsilon) * sin2tW / cos2tW + - (5. + 2. / epsilon); + etaNow = -cos2tW * (coef1 * f1 + coefXY * fXY) * coup2W; + + // Expression for H+-. + } else etaNow = (1. - 2. * sin2tW) * fXY * pow2(mW / mHchg) + * coup2Hchg; + + // Sum up contribution and return square of absolute value. + eta += etaNow; + } + return ( (pow2(eta.real()) + pow2(eta.imag())) / (sin2tW * cos2tW) ); + +} + +//************************************************************************** + +// The ResonanceHchg class. +// Derived class for H+- properties. + +//********* + +// Initialize constants. + +void ResonanceHchg::initConstants() { + + // Locally stored properties and couplings. + useCubicWidth = Settings::flag("Higgs:cubicWidth"); + thetaWRat = 1. / (8. * CoupEW::sin2thetaW()); + mW = ParticleDataTable::m0(24); + tanBeta = Settings::parm("HiggsHchg:tanBeta"); + tan2Beta = tanBeta * tanBeta; + coup2H1W = Settings::parm("HiggsHchg:coup2H1W"); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceHchg::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = 3. * (1. + alpS / M_PI); + preFac = alpEM * thetaWRat * pow3(mHat) / pow2(mW); + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceHchg::calcWidth(bool) { + + // Check that above threshold. + if (ps == 0.) return; + + // H+- decay to fermions involves running masses. + if (id1Abs < 17 && (id1Abs < 7 || id1Abs > 10)) { + double mRun1 = ParticleDataTable::mRun(id1Abs, mHat); + double mRun2 = ParticleDataTable::mRun(id2Abs, mHat); + double mrRunDn = pow2(mRun1 / mHat); + double mrRunUp = pow2(mRun2 / mHat); + if (id1Abs%2 == 0) swap( mrRunDn, mrRunUp); + + // Width to fermions: couplings, kinematics, colour factor. + widNow = preFac * max( 0., (mrRunDn * tan2Beta + mrRunUp / tan2Beta) + * (1. - mrRunDn - mrRunUp) - 4. *mrRunDn * mrRunUp ) * ps; + if (id1Abs < 7) widNow *= colQ; + } + + // H+- decay to h0 + W+-. + else if (id1Abs == 25 && id2Abs == 24) + widNow = 0.5 * preFac * pow3(ps) * pow2(coup2H1W); + +} + +//************************************************************************** + +// The ResonanceZprime class. +// Derived class for gamma*/Z0/Z'^0 properties. + +//********* + +// Initialize constants. + +void ResonanceZprime::initConstants() { + + // Locally stored properties and couplings. + gmZmode = Settings::mode("Zprime:gmZmode"); + sin2tW = CoupEW::sin2thetaW(); + cos2tW = 1. - sin2tW; + thetaWRat = 1. / (16. * sin2tW * cos2tW); + + // Properties of Z resonance. + mZ = ParticleDataTable::m0(23); + GammaZ = ParticleDataTable::mWidth(23); + m2Z = mZ*mZ; + GamMRatZ = GammaZ / mZ; + + // Ensure that arrays initially empty. + for (int i = 0; i < 20; ++i) afZp[i] = 0.; + for (int i = 0; i < 20; ++i) vfZp[i] = 0.; + + // Store first-generation axial and vector couplings. + afZp[1] = Settings::parm("Zprime:ad"); + afZp[2] = Settings::parm("Zprime:au"); + afZp[11] = Settings::parm("Zprime:ae"); + afZp[12] = Settings::parm("Zprime:anue"); + vfZp[1] = Settings::parm("Zprime:vd"); + vfZp[2] = Settings::parm("Zprime:vu"); + vfZp[11] = Settings::parm("Zprime:ve"); + vfZp[12] = Settings::parm("Zprime:vnue"); + + // Second and third generation could be carbon copy of this... + if (Settings::flag("Zprime:universality")) { + for (int i = 3; i <= 6; ++i) { + afZp[i] = afZp[i-2]; + vfZp[i] = vfZp[i-2]; + afZp[i+10] = afZp[i+8]; + vfZp[i+10] = vfZp[i+8]; + } + + // ... or could have different couplings. + } else { + afZp[3] = Settings::parm("Zprime:as"); + afZp[4] = Settings::parm("Zprime:ac"); + afZp[5] = Settings::parm("Zprime:ab"); + afZp[6] = Settings::parm("Zprime:at"); + afZp[13] = Settings::parm("Zprime:amu"); + afZp[14] = Settings::parm("Zprime:anumu"); + afZp[15] = Settings::parm("Zprime:atau"); + afZp[16] = Settings::parm("Zprime:anutau"); + vfZp[3] = Settings::parm("Zprime:vs"); + vfZp[4] = Settings::parm("Zprime:vc"); + vfZp[5] = Settings::parm("Zprime:vb"); + vfZp[6] = Settings::parm("Zprime:vt"); + vfZp[13] = Settings::parm("Zprime:vmu"); + vfZp[14] = Settings::parm("Zprime:vnumu"); + vfZp[15] = Settings::parm("Zprime:vtau"); + vfZp[16] = Settings::parm("Zprime:vnutau"); + } + + // Coupling for Z' -> W+ W-. + coupZpWW = Settings::parm("Zprime:coup2WW"); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceZprime::calcPreFac(bool calledFromInit) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = 3. * (1. + alpS / M_PI); + preFac = alpEM * thetaWRat * mHat / 3.; + + // When call for incoming flavour need to consider gamma*/Z0 mix. + if (!calledFromInit) { + + // Couplings when an incoming fermion is specified; elso only pure Z'0. + ei2 = 0.; + eivi = 0.; + vai2 = 0.; + eivpi = 0.; + vaivapi = 0., + vapi2 = 1.; + int idInFlavAbs = abs(idInFlav); + if (idInFlavAbs > 0 && idInFlavAbs < 19) { + double ei = CoupEW::ef(idInFlavAbs); + double ai = CoupEW::af(idInFlavAbs); + double vi = CoupEW::vf(idInFlavAbs); + double api = afZp[idInFlavAbs]; + double vpi = vfZp[idInFlavAbs]; + ei2 = ei * ei; + eivi = ei * vi; + vai2 = vi * vi + ai * ai; + eivpi = ei * vpi; + vaivapi = vi * vpi + ai * api;; + vapi2 = vpi * vpi + api * api; + } + + // Calculate prefactors for gamma/interference/Z0 terms. + double sH = mHat * mHat; + double propZ = sH / ( pow2(sH - m2Z) + pow2(sH * GamMRatZ) ); + double propZp = sH / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + gamNorm = ei2; + gamZNorm = 2. * eivi * thetaWRat * (sH - m2Z) * propZ; + ZNorm = vai2 * pow2(thetaWRat) * sH * propZ; + gamZpNorm = 2. * eivpi * thetaWRat * (sH - m2Res) * propZp; + ZZpNorm = 2. * vaivapi * pow2(thetaWRat) * ((sH - m2Res) * (sH - m2Z) + + sH * GamMRat * sH * GamMRatZ) * propZ * propZp; + ZpNorm = vapi2 * pow2(thetaWRat) * sH * propZp; + + // Rescale Z0 height normalization to compensate for a width one?? + //if (doForceWidth) { + // intNorm *= forceFactor; + // resNorm *= forceFactor; + //} + + // Optionally only keep some of gamma*, Z0 and Z' terms. + if (gmZmode == 1) {gamZNorm = 0; ZNorm = 0.; gamZpNorm = 0.; + ZZpNorm = 0.; ZpNorm = 0.;} + if (gmZmode == 2) {gamNorm = 0.; gamZNorm = 0.; gamZpNorm = 0.; + ZZpNorm = 0.; ZpNorm = 0.;} + if (gmZmode == 3) {gamNorm = 0.; gamZNorm = 0.; ZNorm = 0.; + gamZpNorm = 0.; ZZpNorm = 0.;} + if (gmZmode == 4) {gamZpNorm = 0.; ZZpNorm = 0.; ZpNorm = 0.;} + if (gmZmode == 5) {gamZNorm = 0.; ZNorm = 0.; ZZpNorm = 0.;} + if (gmZmode == 6) {gamNorm = 0.; gamZNorm = 0.; gamZpNorm = 0.;} + } + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceZprime::calcWidth(bool calledFromInit) { + + // Check that above threshold. + if (ps == 0.) return; + + // At initialization only the pure Z'0 should be considered. + if (calledFromInit) { + + // Contributions from three fermion generations. + if ( id1Abs < 7 || (id1Abs > 10 && id1Abs < 17) ) { + double apf = afZp[id1Abs]; + double vpf = vfZp[id1Abs]; + widNow = preFac * ps * (vpf*vpf * (1. + 2. * mr1) + + apf*apf * ps*ps); + if (id1Abs < 7) widNow *= colQ; + + // Contribution from Z'0 -> W^+ W^-. + } else if (id1Abs == 24) { + widNow = preFac * pow2(coupZpWW * cos2tW) * pow3(ps) + * (1. + mr1*mr1 + mr2*mr2 + 10. * (mr1 + mr2 + mr1 * mr2)); + } + } + + // When call for incoming flavour need to consider full mix. + else { + + // Contributions from three fermion generations. + if ( id1Abs < 7 || (id1Abs > 10 && id1Abs < 17) ) { + + // Couplings of gamma^*/Z^0/Z'^0 to final flavour + double ef = CoupEW::ef(id1Abs); + double af = CoupEW::af(id1Abs); + double vf = CoupEW::vf(id1Abs); + double apf = afZp[id1Abs]; + double vpf = vfZp[id1Abs]; + + // Combine couplings with kinematical factors. + double kinFacA = pow3(ps); + double kinFacV = ps * (1. + 2. * mr1); + double ef2 = ef * ef * kinFacV; + double efvf = ef * vf * kinFacV; + double vaf2 = vf * vf * kinFacV + af * af * kinFacA; + double efvpf = ef * vpf * kinFacV; + double vafvapf = vf * vpf * kinFacV + af * apf * kinFacA; + double vapf2 = vpf * vpf * kinFacV + apf * apf * kinFacA; + + // Relative outwidths: combine instate, propagator and outstate. + widNow = gamNorm * ef2 + gamZNorm * efvf + ZNorm * vaf2 + + gamZpNorm * efvpf + ZZpNorm * vafvapf + ZpNorm * vapf2; + if (id1Abs < 7) widNow *= colQ; + + // Contribution from Z'0 -> W^+ W^-. + } else if (id1Abs == 24) { + widNow = ZpNorm * pow2(coupZpWW * cos2tW) * pow3(ps) + * (1. + mr1*mr1 + mr2*mr2 + 10. * (mr1 + mr2 + mr1 * mr2)); + } + } + +} + +//************************************************************************** + +// The ResonanceWprime class. +// Derived class for W'+- properties. + +//********* + +// Initialize constants. + +void ResonanceWprime::initConstants() { + + // Locally stored properties and couplings. + thetaWRat = 1. / (12. * CoupEW::sin2thetaW()); + cos2tW = CoupEW::cos2thetaW(); + + // Axial and vector couplings of fermions. + aqWp = Settings::parm("Wprime:aq"); + vqWp = Settings::parm("Wprime:vq"); + alWp = Settings::parm("Wprime:al"); + vlWp = Settings::parm("Wprime:vl"); + + // Coupling for W' -> W Z. + coupWpWZ = Settings::parm("Wprime:coup2WZ"); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceWprime::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = 3. * (1. + alpS / M_PI); + preFac = alpEM * thetaWRat * mHat; + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceWprime::calcWidth(bool) { + + // Check that above threshold. + if (ps == 0.) return; + + // Decay to quarks involves colour factor and CKM matrix. + if (id1Abs > 0 && id1Abs < 7) widNow + = preFac * ps * 0.5 * (aqWp*aqWp + vqWp * vqWp) + * (1. - 0.5 * (mr1 + mr2) - 0.5 * pow2(mr1 - mr2)) + * colQ * VCKM::V2id(id1Abs, id2Abs); + + // Decay to leptons simpler. + else if (id1Abs > 10 && id1Abs < 17) widNow + = preFac * ps * 0.5 * (alWp*aqWp + vlWp * vqWp) + * (1. - 0.5 * (mr1 + mr2) - 0.5 * pow2(mr1 - mr2)); + + // Decay to W^+- Z^0. + else if (id1Abs == 24 && id2Abs == 23) widNow + = preFac * 0.25 * pow2(coupWpWZ) * cos2tW * (mr1 / mr2) * pow3(ps) + * (1. + mr1*mr1 + mr2*mr2 + 10. * (mr1 + mr2 + mr1 * mr2)); + +} + +//************************************************************************** + +// The ResonanceRhorizontal class. +// Derived class for R^0 (horizontal gauge boson) properties. + +//********* + +// Initialize constants. + +void ResonanceRhorizontal::initConstants() { + + // Locally stored properties and couplings. + thetaWRat = 1. / (12. * CoupEW::sin2thetaW()); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceRhorizontal::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = 3. * (1. + alpS / M_PI); + preFac = alpEM * thetaWRat * mHat; + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceRhorizontal::calcWidth(bool) { + + // Check that above threshold. + if (ps == 0.) return; + + // R -> f fbar. Colour factor for quarks. + widNow = preFac * ps * (2. - mr1 - mr2 - pow2(mr1 - mr2)); + if (id1Abs < 9) widNow *= colQ; + +} + +//************************************************************************** + +// The ResonanceExcited class. +// Derived class for excited-fermion properties. + +//********* + +// Initialize constants. + +void ResonanceExcited::initConstants() { + + // Locally stored properties and couplings. + Lambda = Settings::parm("ExcitedFermion:Lambda"); + coupF = Settings::parm("ExcitedFermion:coupF"); + coupFprime = Settings::parm("ExcitedFermion:coupFprime"); + coupFcol = Settings::parm("ExcitedFermion:coupFcol"); + sin2tW = CoupEW::sin2thetaW(); + cos2tW = 1. - sin2tW; + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceExcited::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + preFac = pow3(mHat) / pow2(Lambda); + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceExcited::calcWidth(bool) { + + // Check that above threshold. + if (ps == 0.) return; + + // f^* -> f g. + if (id1Abs == 21) widNow = preFac * alpS * pow2(coupFcol) / 3.; + + // f^* -> f gamma. + else if (id1Abs == 22) { + double chgI3 = (id2Abs%2 == 0) ? 0.5 : -0.5; + double chgY = (id2Abs < 9) ? 1. / 6. : -0.5; + double chg = chgI3 * coupF + chgY * coupFprime; + widNow = preFac * alpEM * pow2(chg) / 4.; + } + + // f^* -> f Z^0. + else if (id1Abs == 23) { + double chgI3 = (id2Abs%2 == 0) ? 0.5 : -0.5; + double chgY = (id2Abs < 9) ? 1. / 6. : -0.5; + double chg = chgI3 * cos2tW * coupF - chgY * sin2tW * coupFprime; + widNow = preFac * (alpEM * pow2(chg) / (8. * sin2tW * cos2tW)) + * ps*ps * (2. + mr1); + } + + // f^* -> f' W^+-. + else if (id1Abs == 24) widNow = preFac * (alpEM * pow2(coupF) + / (16. * sin2tW)) * ps*ps * (2. + mr1); + +} + +//************************************************************************** + +// The ResonanceGraviton class. +// Derived class for excited Graviton properties. + +//********* + +// Initialize constants. + +void ResonanceGraviton::initConstants() { + + // Locally stored properties and couplings: kappa * m_G*. + kappaMG = Settings::parm("ExtraDimensionsG*:kappaMG"); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceGraviton::calcPreFac(bool) { + + // Common coupling factors. + alpS = alphaS.alphaS(mHat * mHat); + colQ = 3. * (1. + alpS / M_PI); + preFac = pow2(kappaMG) * mHat / M_PI; + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceGraviton::calcWidth(bool) { + + // Check that above threshold. + if (ps == 0.) return; + + // Widths to fermion pairs. + if (id1Abs < 19) { + widNow = preFac * pow3(ps) * (1. + 8. * mr1 / 3.) / 320.; + if (id1Abs < 9) widNow *= colQ; + } + + // Widths to gluon and photon pair. + else if (id1Abs == 21) widNow = preFac / 20.; + else if (id1Abs == 22) widNow = preFac / 160.; + + // Widths to Z0 Z0 and W+ W- pair. + else if (id1Abs == 23 || id1Abs == 24) { + widNow = preFac * ps * (13. / 12. + 14. * mr1 / 3. + 4. * mr1 * mr1) + / 80.; + if (id1Abs == 23) widNow *= 0.5; + } + +} + +//************************************************************************** + +// The ResonanceLeptoquark class. +// Derived class for leptoquark properties. + +//********* + +// Initialize constants. + +void ResonanceLeptoquark::initConstants() { + + // Locally stored properties and couplings. + kCoup = Settings::parm("LeptoQuark:kCoup"); + + // Check that flavour info in decay channel is correctly set. + int id1Now = particlePtr->decay[0].product(0); + int id2Now = particlePtr->decay[0].product(1); + if (id1Now < 1 || id1Now > 5) { + infoPtr->errorMsg("Error in ResonanceLeptoquark::init:" + " unallowed input quark flavour reset to u"); + id1Now = 2; + particlePtr->decay[0].product(0, id1Now); + } + if (abs(id2Now) < 11 || abs(id2Now) > 16) { + infoPtr->errorMsg("Error in ResonanceLeptoquark::init:" + " unallowed input lepton flavour reset to e-"); + id2Now = 11; + particlePtr->decay[0].product(1, id2Now); + } + + // Set/overwrite charge and name of particle. + bool changed = particlePtr->hasChanged(); + int chargeLQ = ParticleDataTable::chargeType(id1Now) + + ParticleDataTable::chargeType(id2Now); + particlePtr->setChargeType(chargeLQ); + string nameLQ = "LQ_" + ParticleDataTable::name(id1Now) + "," + + ParticleDataTable::name(id2Now); + particlePtr->setNames(nameLQ, nameLQ + "bar"); + if (!changed) particlePtr->setHasChanged(false); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceLeptoquark::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + preFac = 0.25 * alpEM * kCoup * mHat; + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceLeptoquark::calcWidth(bool) { + + // Check that above threshold. + if (ps == 0.) return; + + // Width into lepton plus quark. + if (id1Abs > 10 && id1Abs < 17 && id2Abs < 7) widNow = preFac * pow3(ps); + +} + +//************************************************************************** + +// The ResonanceNuRight class. +// Derived class for righthanded Majorana neutrino properties. + +//********* + +// Initialize constants. + +void ResonanceNuRight::initConstants() { + + // Locally stored properties and couplings: righthanded W mass. + thetaWRat = 1. / (768. * M_PI * pow2(CoupEW::sin2thetaW())); + mWR = ParticleDataTable::m0(9900024); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceNuRight::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = 3. * (1. + alpS / M_PI); + preFac = pow2(alpEM) * thetaWRat * pow5(mHat) / pow4(max(mHat, mWR)); + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceNuRight::calcWidth(bool) { + + // Check that above threshold. + if (mHat < mf1 + mf2 + mf3 + MASSMARGIN) return; + + // Coupling part of widths to l- q qbar', l- l'+ nu_lR' and c.c. + widNow = (id2Abs < 9 && id3Abs < 9) + ? preFac * colQ * VCKM::V2id(id2, id3) : preFac; + + // Phase space corrections in decay. Must have y < 1. + double x = (mf1 + mf2 + mf3) / mHat; + double x2 = x * x; + double fx = 1. - 8. * x2 + 8. * pow3(x2) - pow4(x2) + - 24. * pow2(x2) * log(x); + double y = min( 0.999, pow2(mHat / mWR) ); + double fy = ( 12. * (1. - y) * log(1. - y) + 12. * y - 6. * y*y + - 2.* pow3(y) ) / pow4(y); + widNow *= fx * fy; + +} + +//************************************************************************** + +// The ResonanceZRight class. +// Derived class for Z_R^0 properties. + +//********* + +// Initialize constants. + +void ResonanceZRight::initConstants() { + + // Locally stored properties and couplings: righthanded W mass. + sin2tW = CoupEW::sin2thetaW(); + thetaWRat = 1. / (48. * sin2tW * (1. - sin2tW) * (1. - 2. * sin2tW) ); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceZRight::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = 3. * (1. + alpS / M_PI); + preFac = alpEM * thetaWRat * mHat; + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceZRight::calcWidth(bool) { + + // Check that above threshold. + if (ps == 0.) return; + + // Couplings to q qbar and l+ l-. + double vf = 0.; + double af = 0.; + double symMaj = 1.; + if (id1Abs < 9 && id1Abs%2 == 1) { + af = -1. + 2. * sin2tW; + vf = -1. + 4. * sin2tW / 3.; + } else if (id1Abs < 9) { + af = 1. - 2. * sin2tW; + vf = 1. - 8. * sin2tW / 3.; + } else if (id1Abs < 19 && id1Abs%2 == 1) { + af = -1. + 2. * sin2tW; + vf = -1. + 4. * sin2tW; + + // Couplings to nu_L nu_Lbar and nu_R nu_Rbar, both assumed Majoranas. + } else if (id1Abs < 19) { + af = -2. * sin2tW; + vf = 0.; + symMaj = 0.5; + } else { + af = 2. * (1. - sin2tW); + vf = 0.; + symMaj = 0.5; + } + + // Width expression, including phase space and colour factor. + widNow = preFac * (vf*vf * (1. + 2. * mr1) + af*af * ps*ps) * ps + * symMaj; + if (id1Abs < 9) widNow *= colQ; + +} + +//************************************************************************** + +// The ResonanceWRight class. +// Derived class for W_R+- properties. + +//********* + +// Initialize constants. + +void ResonanceWRight::initConstants() { + + // Locally stored properties and couplings. + thetaWRat = 1. / (12. * CoupEW::sin2thetaW()); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceWRight::calcPreFac(bool) { + + // Common coupling factors. + alpEM = alphaEM.alphaEM(mHat * mHat); + alpS = alphaS.alphaS(mHat * mHat); + colQ = 3. * (1. + alpS / M_PI); + preFac = alpEM * thetaWRat * mHat; + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceWRight::calcWidth(bool) { + + // Check that above threshold. + if (ps == 0.) return; + + // Combine kinematics with colour factor and CKM couplings. + widNow = preFac * (1. - 0.5 * (mr1 + mr2) - 0.5 * pow2(mr1 - mr2)) + * ps; + if (id1Abs < 9) widNow *= colQ * VCKM::V2id(id1Abs, id2Abs); + +} + +//************************************************************************** + +// The ResonanceHchgchgLeft class. +// Derived class for H++/H-- (left) properties. + +//********* + +// Initialize constants. + +void ResonanceHchgchgLeft::initConstants() { + + // Read in Yukawa matrix for couplings to a lepton pair. + yukawa[1][1] = Settings::parm("LeftRightSymmmetry:coupHee"); + yukawa[2][1] = Settings::parm("LeftRightSymmmetry:coupHmue"); + yukawa[2][2] = Settings::parm("LeftRightSymmmetry:coupHmumu"); + yukawa[3][1] = Settings::parm("LeftRightSymmmetry:coupHtaue"); + yukawa[3][2] = Settings::parm("LeftRightSymmmetry:coupHtaumu"); + yukawa[3][3] = Settings::parm("LeftRightSymmmetry:coupHtautau"); + + // Locally stored properties and couplings. + gL = Settings::parm("LeftRightSymmmetry:gL"); + vL = Settings::parm("LeftRightSymmmetry:vL"); + mW = ParticleDataTable::m0(24); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceHchgchgLeft::calcPreFac(bool) { + + // Common coupling factors. + preFac = mHat / (8. * M_PI); + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceHchgchgLeft::calcWidth(bool) { + + // Check that above threshold. + if (ps == 0.) return; + + // H++-- width to a pair of leptons. Combinatorial factor of 2. + if (id1Abs < 17 && id2Abs < 17) { + widNow = preFac * pow2(yukawa[(id1Abs-9)/2][(id2Abs-9)/2]) * ps; + if (id2Abs != id1Abs) widNow *= 2.; + } + + // H++-- width to a pair of lefthanded W's. + else if (id1Abs == 24 && id2Abs == 24) + widNow = preFac * 0.5 * pow2(gL*gL * vL / mW) + * (3. * mr1 + 0.25 / mr1 - 1.) * ps; + +} + +//************************************************************************** + +// The ResonanceHchgchgRight class. +// Derived class for H++/H-- (right) properties. + +//********* + +// Initialize constants. + +void ResonanceHchgchgRight::initConstants() { + + // Read in Yukawa matrix for couplings to a lepton pair. + yukawa[1][1] = Settings::parm("LeftRightSymmmetry:coupHee"); + yukawa[2][1] = Settings::parm("LeftRightSymmmetry:coupHmue"); + yukawa[2][2] = Settings::parm("LeftRightSymmmetry:coupHmumu"); + yukawa[3][1] = Settings::parm("LeftRightSymmmetry:coupHtaue"); + yukawa[3][2] = Settings::parm("LeftRightSymmmetry:coupHtaumu"); + yukawa[3][3] = Settings::parm("LeftRightSymmmetry:coupHtautau"); + + // Locally stored properties and couplings. + idWR = 9000024; + gR = Settings::parm("LeftRightSymmmetry:gR"); + +} + +//********* + +// Calculate various common prefactors for the current mass. + +void ResonanceHchgchgRight::calcPreFac(bool) { + + // Common coupling factors. + preFac = mHat / (8. * M_PI); + +} + +//********* + +// Calculate width for currently considered channel. + +void ResonanceHchgchgRight::calcWidth(bool) { + + // Check that above threshold. + if (ps == 0.) return; + + // H++-- width to a pair of leptons. Combinatorial factor of 2. + if (id1Abs < 17 && id2Abs < 17) { + widNow = preFac * pow2(yukawa[(id1Abs-9)/2][(id2Abs-9)/2]) * ps; + if (id2Abs != id1Abs) widNow *= 2.; + } + + // H++-- width to a pair of lefthanded W's. + else if (id1Abs == idWR && id2Abs == idWR) + widNow = preFac * pow2(yukawa[(id1Abs-9)/2][(id2Abs-9)/2]) * ps; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/Settings.cxx b/PYTHIA8/pythia8130/src/Settings.cxx new file mode 100644 index 00000000000..c0211402069 --- /dev/null +++ b/PYTHIA8/pythia8130/src/Settings.cxx @@ -0,0 +1,687 @@ +// Settings.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the Settings class. + +#include "Settings.h" + +// Allow string and character manipulation. +#include + +namespace Pythia8 { + +//************************************************************************** + +// Settings class. +// This class contains flags, modes, parms and words used in generation. + +//********* + +// Definitions of static variables. +map Settings::flags; +map Settings::modes; +map Settings::parms; +map Settings::words; +bool Settings::isInit = false; + +// Static copy of Info - not optimal solution?? +Info* Settings::infoPtr = 0; + +//********* + +// Read in database from specific file. + +bool Settings::init(string startFile, bool append, ostream& os) { + + // Don't initialize if it has already been done and not in append mode. + if (isInit && !append) return true; + int nError = 0; + + // List of files to be checked. Start with input file. + vector files; + files.push_back(startFile); + + // If nontrivial startfile path, then use that for other files as well. + string pathName = ""; + if (startFile.rfind("/") != string::npos) + pathName = startFile.substr(0, startFile.rfind("/") + 1); + + // Loop over files. Open them for read. + for (int i = 0; i < int(files.size()); ++i) { + const char* cstring = files[i].c_str(); + ifstream is(cstring); + + // Check that instream is OK. + if (!is) { + os << "\n PYTHIA Error: settings file " << files[i] + << " not found" << endl; + return false; + } + + // Read in one line at a time. + string line; + while ( getline(is, line) ) { + + // Get first word of a line, to interpret it as tag. + istringstream getfirst(line); + string tag; + getfirst >> tag; + + // Skip ahead if not interesting. Only look for new files in startfile. + if (tag != ". + while (line.find(">") == string::npos) { + string addLine; + getline(is, addLine); + line += " " + addLine; + } + + // Remove extra blanks before an = sign. + while (line.find(" =") != string::npos) line.erase( line.find(" ="), 1); + + // Add file also to be read. + if (tag == "> name; + + // Replace two colons by one (:: -> :) to allow for such mistakes. + while (name.find("::") != string::npos) { + int firstColonColon = name.find_first_of("::"); + name.replace(firstColonColon, 2, ":"); + } + + // Check whether this is in the database. Done if not. + int inDataBase = 0; + if (isFlag(name)) inDataBase = 1; + else if (isMode(name)) inDataBase = 2; + else if (isParm(name)) inDataBase = 3; + else if (isWord(name)) inDataBase = 4; + if (inDataBase == 0) { + if (warn) os << "\n PYTHIA Warning: input string not found in settings" + << " databases; skip:\n " << line << endl; + return false; + } + + // Find value. Warn if none found. + string valueString; + splitLine >> valueString; + if (!splitLine) { + if (warn) os << "\n PYTHIA Warning: variable recognized, but its value" + << " not meaningful; skip:\n " << line << endl; + return false; + } + + // Update flag map; allow many ways to say yes. + if (inDataBase == 1) { + bool value = boolString(valueString); + flag(name, value); + + // Update mode map. + } else if (inDataBase == 2) { + istringstream modeData(valueString); + int value; + modeData >> value; + if (!modeData) { + if (warn) os << "\n PYTHIA Warning: variable recognized, but its value" + << " not meaningful; skip:\n " << line << endl; + return false; + } + mode(name, value); + + // Update parm map. + } else if (inDataBase == 3) { + istringstream parmData(valueString); + double value; + parmData >> value; + if (!parmData) { + if (warn) os << "\n PYTHIA Warning: variable recognized, but its value" + << " not meaningful; skip:\n " << line << endl; + return false; + } + parm(name, value); + + // Update word map. + } else { + word(name, valueString); + } + + // Done. + return true; +} + +//********* + +// Write updates or everything to user-defined file. + +bool Settings::writeFile(string toFile, bool writeAll) { + + // Open file for writing. + const char* cstring = toFile.c_str(); + ofstream os(cstring); + if (!os) { + infoPtr->errorMsg("Error in Settings::writeFile:" + " could not open file", toFile); + return false; + } + return writeFile( os, writeAll); + +} + +//********* + +// Write updates or everything to user-defined file. + +bool Settings::writeFile(ostream& os, bool writeAll) { + + // Write simple header as comment. + if (writeAll) os << "! List of all current PYTHIA "; + else os << "! List of all modified PYTHIA "; + os << fixed << setprecision(3) << parm("Pythia:versionNumber") + << " settings.\n"; + + // Iterators for the flag, mode and parm tables. + map::iterator flagEntry = flags.begin(); + map::iterator modeEntry = modes.begin(); + map::iterator parmEntry = parms.begin(); + map::iterator wordEntry = words.begin(); + + // Loop while there is something left to do. + while (flagEntry != flags.end() || modeEntry != modes.end() + || parmEntry != parms.end() || wordEntry != words.end()) { + + // Check if a flag is next in lexigraphical order; if so print it. + if ( flagEntry != flags.end() + && ( modeEntry == modes.end() || flagEntry->first < modeEntry->first ) + && ( parmEntry == parms.end() || flagEntry->first < parmEntry->first ) + && ( wordEntry == words.end() || flagEntry->first < wordEntry->first ) + ) { + string state[2] = {"off", "on"}; + bool valNow = flagEntry->second.valNow; + bool valDefault = flagEntry->second.valDefault; + if ( writeAll || valNow != valDefault ) + os << flagEntry->second.name << " = " << state[valNow] << "\n"; + ++flagEntry; + + // Else check if mode is next, and if so print it. + } else if ( modeEntry != modes.end() + && ( parmEntry == parms.end() || modeEntry->first < parmEntry->first ) + && ( wordEntry == words.end() || modeEntry->first < wordEntry->first ) + ) { + int valNow = modeEntry->second.valNow; + int valDefault = modeEntry->second.valDefault; + if ( writeAll || valNow != valDefault ) + os << modeEntry->second.name << " = " << valNow << "\n"; + ++modeEntry; + + // Else check if parm is next, and if so print it; + // fixed or scientific depending on value. + } else if ( parmEntry != parms.end() + && ( wordEntry == words.end() || parmEntry->first < wordEntry->first ) + ) { + double valNow = parmEntry->second.valNow; + double valDefault = parmEntry->second.valDefault; + if ( writeAll || valNow != valDefault ) { + os << parmEntry->second.name << " = "; + if ( valNow == 0. ) os << fixed << setprecision(1); + else if ( abs(valNow) < 0.001 ) os << scientific << setprecision(4); + else if ( abs(valNow) < 0.1 ) os << fixed << setprecision(7); + else if ( abs(valNow) < 1000. ) os << fixed << setprecision(5); + else if ( abs(valNow) < 1000000. ) os << fixed << setprecision(3); + else os << scientific << setprecision(4); + os << valNow << "\n"; + } + ++parmEntry; + + // Else print word. + } else { + string valNow = wordEntry->second.valNow; + string valDefault = wordEntry->second.valDefault; + if ( writeAll || valNow != valDefault ) + os << wordEntry->second.name << " = " << valNow << "\n"; + ++wordEntry; + } + } ; + + // Done. + return true; +} + +//********* + +// Print out table of database in lexigraphical order. + +void Settings::list(bool listAll, bool listString, string match, + ostream& os) { + + // Table header; output for bool as off/on. + if (listAll) + os << "\n *------- PYTHIA Flag + Mode + Parm + Word Settings (all) " + << " -------------------------------------------------------* \n"; + else if (!listString) + os << "\n *------- PYTHIA Flag + Mode + Parm + Word Settings (chang" + << "es only) ----------------------------------------------* \n" ; + else + os << "\n *------- PYTHIA Flag + Mode + Parm + Word Settings (with " + << "requested string) -------------------------------------* \n" ; + os << " | " + << " | \n" + << " | Name | " + << " Now | Default Min Max | \n" + << " | | " + << " | | \n"; + + // Convert input string to lowercase for match. + match = toLower(match); + if (match == "") match = " "; + + // Iterators for the flag, mode and parm tables. + map::iterator flagEntry = flags.begin(); + map::iterator modeEntry = modes.begin(); + map::iterator parmEntry = parms.begin(); + map::iterator wordEntry = words.begin(); + + // Loop while there is something left to do. + while (flagEntry != flags.end() || modeEntry != modes.end() + || parmEntry != parms.end() || wordEntry != words.end()) { + + // Check if a flag is next in lexigraphical order; if so print it. + if ( flagEntry != flags.end() + && ( modeEntry == modes.end() || flagEntry->first < modeEntry->first ) + && ( parmEntry == parms.end() || flagEntry->first < parmEntry->first ) + && ( wordEntry == words.end() || flagEntry->first < wordEntry->first ) + ) { + string state[2] = {"off", "on"}; + bool valNow = flagEntry->second.valNow; + bool valDefault = flagEntry->second.valDefault; + if ( listAll || (!listString && valNow != valDefault) + || (listString && flagEntry->first.find(match) != string::npos) ) + os << " | " << setw(45) << left + << flagEntry->second.name << " | " << setw(24) << right + << state[valNow] << " | " << setw(12) << state[valDefault] + << " | \n"; + ++flagEntry; + + // Else check if mode is next, and if so print it. + } else if ( modeEntry != modes.end() + && ( parmEntry == parms.end() || modeEntry->first < parmEntry->first ) + && ( wordEntry == words.end() || modeEntry->first < wordEntry->first ) + ) { + int valNow = modeEntry->second.valNow; + int valDefault = modeEntry->second.valDefault; + if ( listAll || (!listString && valNow != valDefault) + || (listString && modeEntry->first.find(match) != string::npos) ) { + os << " | " << setw(45) << left + << modeEntry->second.name << " | " << setw(24) << right + << valNow << " | " << setw(12) << valDefault; + if (modeEntry->second.hasMin) + os << setw(12) << modeEntry->second.valMin; + else os << " "; + if (modeEntry->second.hasMax) + os << setw(12) << modeEntry->second.valMax; + else os << " "; + os << " | \n"; + } + ++modeEntry; + + // Else check if parm is next, and if so print it; + // fixed or scientific depending on value. + } else if ( parmEntry != parms.end() + && ( wordEntry == words.end() || parmEntry->first < wordEntry->first ) + ) { + double valNow = parmEntry->second.valNow; + double valDefault = parmEntry->second.valDefault; + if ( listAll || (!listString && valNow != valDefault ) + || (listString && parmEntry->first.find(match) != string::npos) ) { + os << " | " << setw(45) << left + << parmEntry->second.name << right << " | "; + for (int i = 0; i < 4; ++i) { + if (i == 1) valNow = valDefault; + if (i == 2) valNow = parmEntry->second.valMin; + if (i == 3) valNow = parmEntry->second.valMax; + if ( (i == 2 && !parmEntry->second.hasMin) + || (i == 3 && !parmEntry->second.hasMax) ) + os << " "; + else if ( valNow == 0. ) + os << fixed << setprecision(1) << setw(12) << valNow; + else if ( abs(valNow) < 0.001 ) + os << scientific << setprecision(4) << setw(12) << valNow; + else if ( abs(valNow) < 0.1 ) + os << fixed << setprecision(7) << setw(12) << valNow; + else if ( abs(valNow) < 1000. ) + os << fixed << setprecision(5) << setw(12) << valNow; + else if ( abs(valNow) < 1000000. ) + os << fixed << setprecision(3) << setw(12) << valNow; + else + os << scientific << setprecision(4) << setw(12) << valNow; + if (i == 0) os << " | "; + } + os << " | \n"; + } + ++parmEntry; + + // Else print word. + } else { + string valNow = wordEntry->second.valNow; + string valDefault = wordEntry->second.valDefault; + int blankLeft = max(0, 60 - max(24, int(valNow.length()) ) + - max(12, int(valDefault.length()) ) ); + string blankPad( blankLeft, ' '); + if ( listAll || (!listString && valNow != valDefault) + || (listString && wordEntry->first.find(match) != string::npos) ) + os << " | " << setw(45) << left + << wordEntry->second.name << " | " << setw(24) << right + << valNow << " | " << setw(12) << valDefault << blankPad + << " | \n"; + ++wordEntry; + } + } ; + + // End of loop over database contents. + os << " | " + << " | \n" + << " *------- End PYTHIA Flag + Mode + Parm + Word Settings ---" + << "------------------------------------------------------* " << endl; + +} + +//********* + +// Reset all values to their defaults. + +void Settings::resetAll() { + + // Loop through the flags table, resetting all entries. + for (map::iterator flagEntry = flags.begin(); + flagEntry != flags.end(); ++flagEntry) { + string name = flagEntry->first; + resetFlag(name); + } + + // Loop through the modes table, resetting all entries. + for (map::iterator modeEntry = modes.begin(); + modeEntry != modes.end(); ++modeEntry) { + string name = modeEntry->first; + resetMode(name); + } + + // Loop through the parms table, resetting all entries. + for (map::iterator parmEntry = parms.begin(); + parmEntry != parms.end(); ++parmEntry) { + string name = parmEntry->first; + resetParm(name); + } + + // Loop through the words table, resetting all entries. + for (map::iterator wordEntry = words.begin(); + wordEntry != words.end(); ++wordEntry) { + string name = wordEntry->first; + resetWord(name); + } + +} + +//********* + +// Give back current value, with check that key exists. + +bool Settings::flag(string keyIn) { + if (isFlag(keyIn)) return flags[toLower(keyIn)].valNow; + infoPtr->errorMsg("Error in Settings::flag: unknown key", keyIn); + return false; +} + +int Settings::mode(string keyIn) { + if (isMode(keyIn)) return modes[toLower(keyIn)].valNow; + infoPtr->errorMsg("Error in Settings::mode: unknown key", keyIn); + return 0; +} + +double Settings::parm(string keyIn) { + if (isParm(keyIn)) return parms[toLower(keyIn)].valNow; + infoPtr->errorMsg("Error in Settings::parm: unknown key", keyIn); + return 0.; +} + +string Settings::word(string keyIn) { + if (isWord(keyIn)) return words[toLower(keyIn)].valNow; + infoPtr->errorMsg("Error in Settings::word: unknown key", keyIn); + return " "; +} + +//********* + +// Change current value, respecting limits. + +void Settings::flag(string keyIn, bool nowIn) { + if (isFlag(keyIn)) flags[toLower(keyIn)].valNow = nowIn; +} + +void Settings:: mode(string keyIn, int nowIn) { + if (isMode(keyIn)) { + Mode& modeNow = modes[toLower(keyIn)]; + if (modeNow.hasMin && nowIn < modeNow.valMin) + modeNow.valNow = modeNow.valMin; + else if (modeNow.hasMax && nowIn > modeNow.valMax) + modeNow.valNow = modeNow.valMax; + else modeNow.valNow = nowIn; + } +} + +void Settings::parm(string keyIn, double nowIn) { + if (isParm(keyIn)) { + Parm& parmNow = parms[toLower(keyIn)]; + if (parmNow.hasMin && nowIn < parmNow.valMin) + parmNow.valNow = parmNow.valMin; + else if (parmNow.hasMax && nowIn > parmNow.valMax) + parmNow.valNow = parmNow.valMax; + else parmNow.valNow = nowIn; + } +} + +void Settings::word(string keyIn, string nowIn) { + if (isWord(keyIn)) words[toLower(keyIn)].valNow = nowIn; +} + +//********* + +// Convert string to lowercase for case-insensitive comparisons. +// Also remove initial and trailing blanks, if any. + +string Settings::toLower(const string& name) { + + // Copy string without initial and trailing blanks. + if (name.find_first_not_of(" ") == string::npos) return ""; + int firstChar = name.find_first_not_of(" "); + int lastChar = name.find_last_not_of(" "); + string temp = name.substr( firstChar, lastChar + 1 - firstChar); + + // Convert to lowercase letter by letter. + for (int i = 0; i < int(temp.length()); ++i) + temp[i] = std::tolower(temp[i]); + return temp; + +} + +//********* + +// Allow several alternative inputs for true/false. + +bool Settings::boolString(string tag) { + + string tagLow = toLower(tag); + return ( tagLow == "true" || tagLow == "1" || tagLow == "on" + || tagLow == "yes" || tagLow == "ok" ); + +} + +//********* + +// Extract XML value string following XML attribute. + +string Settings::attributeValue(string line, string attribute) { + + if (line.find(attribute) == string::npos) return ""; + int iBegAttri = line.find(attribute); + int iBegQuote = line.find("\"", iBegAttri + 1); + int iEndQuote = line.find("\"", iBegQuote + 1); + return line.substr(iBegQuote + 1, iEndQuote - iBegQuote - 1); + +} + +//********* + +// Extract XML bool value following XML attribute. + +bool Settings::boolAttributeValue(string line, string attribute) { + + string valString = attributeValue(line, attribute); + if (valString == "") return false; + return boolString(valString); + +} + +//********* + +// Extract XML int value following XML attribute. + +int Settings::intAttributeValue(string line, string attribute) { + string valString = attributeValue(line, attribute); + if (valString == "") return 0; + istringstream valStream(valString); + int intVal; + valStream >> intVal; + return intVal; + +} + +//********* + +// Extract XML double value following XML attribute. + +double Settings::doubleAttributeValue(string line, string attribute) { + string valString = attributeValue(line, attribute); + if (valString == "") return 0.; + istringstream valStream(valString); + double doubleVal; + valStream >> doubleVal; + return doubleVal; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SigmaCompositeness.cxx b/PYTHIA8/pythia8130/src/SigmaCompositeness.cxx new file mode 100644 index 00000000000..b54fe623594 --- /dev/null +++ b/PYTHIA8/pythia8130/src/SigmaCompositeness.cxx @@ -0,0 +1,436 @@ +// SigmaCompositeness.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// compositeness simulation classes. + +#include "SigmaCompositeness.h" + +namespace Pythia8 { + +//************************************************************************** + +// Sigma1qg2qStar class. +// Cross section for q g -> q^* (excited quark state). +// Note: for simplicity decay is assumed isotropic. + +//********* + +// Initialize process. + +void Sigma1qg2qStar::initProc() { + + // Set up process properties from the chosen quark flavour. + idRes = 4000000 + idq; + codeSave = 4000 + idq; + if (idq == 1) nameSave = "d g -> d^*"; + else if (idq == 2) nameSave = "u g -> u^*"; + else if (idq == 3) nameSave = "s g -> s^*"; + else if (idq == 4) nameSave = "c g -> c^*"; + else nameSave = "b g -> b^*"; + + // Store q* mass and width for propagator. + mRes = ParticleDataTable::m0(idRes); + GammaRes = ParticleDataTable::mWidth(idRes); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Locally stored properties and couplings. + Lambda = Settings::parm("ExcitedFermion:Lambda"); + coupFcol = Settings::parm("ExcitedFermion:coupFcol"); + + // Set pointer to particle properties and decay table. + qStarPtr = ParticleDataTable::particleDataPtr(idRes); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1qg2qStar::sigmaKin() { + + // Incoming width for correct quark. + widthIn = pow3(mH) * alpS * pow2(coupFcol) / (3. * pow2(Lambda)); + + // Set up Breit-Wigner. + sigBW = M_PI/ ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + +} + +//********* + +// Evaluate sigmaHat(sHat) for specific incoming flavours. + +double Sigma1qg2qStar::sigmaHat() { + + // Identify whether correct incoming flavours. + int idqNow = (id2 == 21) ? id1 : id2; + if (abs(idqNow) != idq) return 0.; + + // Outgoing width and total sigma. Done. + return widthIn * sigBW * qStarPtr->resWidthOpen(idqNow, mH); + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1qg2qStar::setIdColAcol() { + + // Flavours. + int idqNow = (id2 == 21) ? id1 : id2; + int idqStar = (idqNow > 0) ? idRes : -idRes; + setId( id1, id2, idqStar); + + // Colour flow topology. + if (id1 == idqNow) setColAcol( 1, 0, 2, 1, 2, 0); + else setColAcol( 2, 1, 1, 0, 2, 0); + if (idqNow < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for q* decay angle. + +double Sigma1qg2qStar::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // q* should sit in entry 5. Sequential Z/W decay assumed isotropic. + if (iResBeg != 5 || iResEnd != 5) return 1.; + + // Sign of asymmetry. + int sideIn = (process[3].idAbs() < 20) ? 1 : 2; + int sideOut = (process[6].idAbs() < 20) ? 1 : 2; + double eps = (sideIn == sideOut) ? 1. : -1.; + + // Phase space factors. + double mr1 = pow2(process[6].m()) / sH; + double mr2 = pow2(process[7].m()) / sH; + double betaf = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2); + + // Reconstruct decay angle. Default isotropic decay. + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * betaf); + double wt = 1.; + double wtMax = 1.; + + // Decay q* -> q (g/gamma) or q (Z^0/W^+-). + int idBoson = (sideOut == 1) ? process[7].idAbs() : process[6].idAbs(); + if (idBoson == 21 || idBoson == 22) { + wt = 1. + eps * cosThe; + wtMax = 2.; + } else if (idBoson == 23 || idBoson == 24) { + double mrB = (sideOut == 1) ? mr2 : mr1; + double ratB = (1. - 0.5 * mrB) / (1 + 0.5 * mrB); + wt = 1. + eps * cosThe * ratB; + wtMax = 1. + ratB; + } + + // Done. + return (wt / wtMax); + +} + +//************************************************************************** + +// Sigma1lgm2lStar class. +// Cross section for l gamma -> l^* (excited lepton state). +// Note: for simplicity decay is assumed isotropic. + +//********* + +// Initialize process. + +void Sigma1lgm2lStar::initProc() { + + // Set up process properties from the chosen lepton flavour. + idRes = 4000000 + idl; + codeSave = 4000 + idl; + if (idl == 11) nameSave = "e gamma -> e^*"; + else if (idl == 13) nameSave = "mu gamma -> mu^*"; + else nameSave = "tau gamma -> tau^*"; + + // Store l* mass and width for propagator. + mRes = ParticleDataTable::m0(idRes); + GammaRes = ParticleDataTable::mWidth(idRes); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Locally stored properties and couplings. + Lambda = Settings::parm("ExcitedFermion:Lambda"); + double coupF = Settings::parm("ExcitedFermion:coupF"); + double coupFp = Settings::parm("ExcitedFermion:coupFprime"); + coupChg = -0.5 * coupF - 0.5 * coupFp; + + // Set pointer to particle properties and decay table. + qStarPtr = ParticleDataTable::particleDataPtr(idRes); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1lgm2lStar::sigmaKin() { + + // Incoming width for correct lepton. + widthIn = pow3(mH) * alpEM * pow2(coupChg) / pow2(Lambda); + + // Set up Breit-Wigner. + sigBW = M_PI/ ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + +} + +//********* + +// Evaluate sigmaHat(sHat) for specific incoming flavours. + +double Sigma1lgm2lStar::sigmaHat() { + + // Identify whether correct incoming flavours. + int idlNow = (id2 == 22) ? id1 : id2; + if (abs(idlNow) != idl) return 0.; + + // Outgoing width and total sigma. Done. + return widthIn * sigBW * qStarPtr->resWidthOpen(idlNow, mH); + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1lgm2lStar::setIdColAcol() { + + // Flavours. + int idlNow = (id2 == 22) ? id1 : id2; + int idlStar = (idlNow > 0) ? idRes : -idRes; + setId( id1, id2, idlStar); + + // No colour flow. + setColAcol( 0, 0, 0, 0, 0, 0); + +} + +//********* + +// Evaluate weight for l* decay angle. + +double Sigma1lgm2lStar::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // l* should sit in entry 5. Sequential Z/W decay assumed isotropic. + if (iResBeg != 5 || iResEnd != 5) return 1.; + + // Sign of asymmetry. + int sideIn = (process[3].idAbs() < 20) ? 1 : 2; + int sideOut = (process[6].idAbs() < 20) ? 1 : 2; + double eps = (sideIn == sideOut) ? 1. : -1.; + + // Phase space factors. + double mr1 = pow2(process[6].m()) / sH; + double mr2 = pow2(process[7].m()) / sH; + double betaf = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2); + + // Reconstruct decay angle. Default isotropic decay. + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * betaf); + double wt = 1.; + double wtMax = 1.; + + // Decay l* -> l gamma or l (Z^0/W^+-). + int idBoson = (sideOut == 1) ? process[7].idAbs() : process[6].idAbs(); + if (idBoson == 22) { + wt = 1. + eps * cosThe; + wtMax = 2.; + } else if (idBoson == 23 || idBoson == 24) { + double mrB = (sideOut == 1) ? mr2 : mr1; + double ratB = (1. - 0.5 * mrB) / (1 + 0.5 * mrB); + wt = 1. + eps * cosThe * ratB; + wtMax = 1. + ratB; + } + + // Done. + return (wt / wtMax); + +} + +//************************************************************************** + +// Sigma2qq2qStarq class. +// Cross section for q q' -> q^* q' (excited quark state). +// Note: for simplicity decay is assumed isotropic. + +//********* + +// Initialize process. + +void Sigma2qq2qStarq::initProc() { + + // Set up process properties from the chosen quark flavour. + idRes = 4000000 + idq; + codeSave = 4020 + idq; + if (idq == 1) nameSave = "q q -> d^* q"; + else if (idq == 2) nameSave = "q q -> u^* q"; + else if (idq == 3) nameSave = "q q -> s^* q"; + else if (idq == 4) nameSave = "q q -> c^* q"; + else nameSave = "q q -> b^* q"; + + // Locally stored properties and couplings. + Lambda = Settings::parm("ExcitedFermion:Lambda"); + preFac = M_PI / pow4(Lambda); + + // Secondary open width fractions. + openFracPos = ParticleDataTable::resOpenFrac( idRes); + openFracNeg = ParticleDataTable::resOpenFrac(-idRes); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2qq2qStarq::sigmaKin() { + + // Two possible expressions, for like or unlike sign. + sigmaA = preFac * (1. - s3 / sH); + sigmaB = preFac * (-uH) * (sH + tH) / sH2; + +} + +//********* + +// Evaluate sigmaHat(sHat) for specific incoming flavours. + +double Sigma2qq2qStarq::sigmaHat() { + + // Identify different allowed incoming flavour combinations. + int id1Abs = abs(id1); + int id2Abs = abs(id2); + double open1 = (id1 > 0) ? openFracPos : openFracNeg; + double open2 = (id2 > 0) ? openFracPos : openFracNeg; + double sigma = 0.; + if (id1 * id2 > 0) { + if (id1Abs == idq) sigma += (4./3.) * sigmaA * open1; + if (id2Abs == idq) sigma += (4./3.) * sigmaA * open2; + } else if (id1Abs == idq && id2 == -id1) + sigma = (8./3.) * sigmaB * (open1 + open2); + else if (id2 == -id1) sigma = sigmaB * (open1 + open2); + else if (id1Abs == idq) sigma = sigmaB * open1; + else if (id2Abs == idq) sigma = sigmaB * open2; + + // Done. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qq2qStarq::setIdColAcol() { + + // Flavours: either side may have been excited. + double open1 = 0.; + double open2 = 0.; + if (abs(id1) == idq) open1 = (id1 > 0) ? openFracPos : openFracNeg; + if (abs(id2) == idq) open2 = (id2 > 0) ? openFracPos : openFracNeg; + if (open1 == 0. && open2 == 0.) { + open1 = (id1 > 0) ? openFracPos : openFracNeg; + open2 = (id2 > 0) ? openFracPos : openFracNeg; + } + bool excite1 = (open1 > 0.); + if (open1 > 0. && open2 > 0.) excite1 + = (Rndm::flat() * (open1 + open2) < open1); + + // Always excited quark in slot 3 so colour flow flipped or not. + if (excite1) { + id3 = (id1 > 0) ? idq : -idq; + id4 = id2; + if (id1 * id2 > 0) setColAcol( 1, 0, 2, 0, 1, 0, 2, 0); + else setColAcol( 1, 0, 0, 2, 1, 0, 0, 2); + if (id1 < 0) swapColAcol(); + } else { + id3 = (id2 > 0) ? idq : -idq; + id4 = id1; + swapTU = true; + if (id1 * id2 > 0) setColAcol( 1, 0, 2, 0, 2, 0, 1, 0); + else setColAcol( 1, 0, 0, 2, 0, 2, 1, 0); + if (id1 < 0) swapColAcol(); + } + setId( id1, id2, id3, id4); + +} + +//************************************************************************** + +// Sigma2qqbar2lStarlbar class. +// Cross section for q qbar -> l^* lbar (excited lepton state). +// Note: for simplicity decay is assumed isotropic. + +//********* + +// Initialize process. + +void Sigma2qqbar2lStarlbar::initProc() { + + // Set up process properties from the chosen lepton flavour. + idRes = 4000000 + idl; + codeSave = 4020 + idl; + if (idl == 11) nameSave = "q qbar -> e^*+- e^-+"; + else if (idl == 12) nameSave = "q qbar -> nu_e^* nu_ebar"; + else if (idl == 13) nameSave = "q qbar -> mu^*+- mu^-+"; + else if (idl == 14) nameSave = "q qbar -> nu_mu^* nu_mubar"; + else if (idl == 15) nameSave = "q qbar -> tau^*+- tau^-+"; + else nameSave = "q qbar -> nu_tau^* nu_taubar"; + + // Secondary open width fractions. + openFracPos = ParticleDataTable::resOpenFrac( idRes); + openFracNeg = ParticleDataTable::resOpenFrac(-idRes); + + // Locally stored properties and couplings. + Lambda = Settings::parm("ExcitedFermion:Lambda"); + preFac = (M_PI / pow4(Lambda)) * (openFracPos + openFracNeg) / 3.; + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2qqbar2lStarlbar::sigmaKin() { + + // Only one possible expressions + sigma = preFac * (-uH) * (sH + tH) / sH2; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2lStarlbar::setIdColAcol() { + + // Flavours: either lepton or antilepton may be excited. + if (Rndm::flat() * (openFracPos + openFracNeg) < openFracPos) { + setId( id1, id2, idRes, -idl); + if (id1 < 0) swapTU = true; + } else { + setId( id1, id2, -idRes, idl); + if (id1 > 0) swapTU = true; + } + + // Colour flow trivial. + if (id1 > 0) setColAcol( 1, 0, 0, 1, 0, 0, 0, 0); + else setColAcol( 0, 1, 1, 0, 0, 0, 0, 0); + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SigmaEW.cxx b/PYTHIA8/pythia8130/src/SigmaEW.cxx new file mode 100644 index 00000000000..a2ead707532 --- /dev/null +++ b/PYTHIA8/pythia8130/src/SigmaEW.cxx @@ -0,0 +1,2732 @@ +// SigmaEW.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// electroweak simulation classes (including photon processes). + +#include "SigmaEW.h" + +namespace Pythia8 { + +//************************************************************************** + +// Sigma2qg2qgamma class. +// Cross section for q g -> q gamma. + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2qg2qgamma::sigmaKin() { + + // Calculate kinematics dependence. + sigUS = (1./3.) * (sH2 + uH2) / (-sH * uH); + + // Answer. + sigma0 = (M_PI/sH2) * alpS * alpEM * sigUS; + + } + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2qg2qgamma::sigmaHat() { + + // Incoming flavour gives charge factor. + int idNow = (id2 == 21) ? id1 : id2; + double eNow = CoupEW::ef( abs(idNow) ); + return sigma0 * pow2(eNow); + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qg2qgamma::setIdColAcol() { + + // Construct outgoing flavours. + id3 = (id1 == 21) ? 22 : id1; + id4 = (id2 == 21) ? 22 : id2; + setId( id1, id2, id3, id4); + + // Colour flow topology. Swap if first is gluon, or when antiquark. + setColAcol( 1, 0, 2, 1, 2, 0, 0, 0); + if (id1 == 21) swapCol1234(); + if (id1 < 0 || id2 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2qqbar2ggamma class. +// Cross section for q qbar -> g gamma. + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2qqbar2ggamma::sigmaKin() { + + // Calculate kinematics dependence. + double sigTU = (8./9.) * (tH2 + uH2) / (tH * uH); + + // Answer. + sigma0 = (M_PI/sH2) * alpS * alpEM * sigTU; + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2qqbar2ggamma::sigmaHat() { + + // Incoming flavour gives charge factor. + double eNow = CoupEW::ef( abs(id1) ); + return sigma0 * pow2(eNow); + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2ggamma::setIdColAcol() { + + // Outgoing flavours trivial. + setId( id1, id2, 21, 22); + + // One colour flow topology. Swap if first is antiquark. + setColAcol( 1, 0, 0, 2, 1, 2, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2gg2ggamma class. +// Cross section for g g -> g gamma. +// Proceeds through a quark box, by default using 5 massless quarks. + +//********* + +// Initialize process, especially parton-flux object. + +void Sigma2gg2ggamma::initProc() { + + // Maximum quark flavour in loop. + int nQuarkLoop = Settings::mode("PromptPhoton:nQuarkLoop"); + + // Calculate charge factor from the allowed quarks in the box. + chargeSum = - 1./3. + 2./3. - 1./3.; + if (nQuarkLoop >= 4) chargeSum += 2./3.; + if (nQuarkLoop >= 5) chargeSum -= 1./3.; + if (nQuarkLoop >= 6) chargeSum += 2./3.; + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat). + +void Sigma2gg2ggamma::sigmaKin() { + + // Logarithms of Mandelstam variable ratios. + double logST = log( -sH / tH ); + double logSU = log( -sH / uH ); + double logTU = log( tH / uH ); + + // Real and imaginary parts of separate amplitudes. + double b0stuRe = 1. + (tH - uH) / sH * logTU + + 0.5 * (tH2 + uH2) / sH2 * (pow2(logTU) + pow2(M_PI)); + double b0stuIm = 0.; + double b0tsuRe = 1. + (sH - uH) / tH * logSU + + 0.5 * (sH2 + uH2) / tH2 * pow2(logSU); + double b0tsuIm = -M_PI * ( (sH - uH) / tH + (sH2 + uH2) / tH2 * logSU); + double b0utsRe = 1. + (sH - tH) / uH * logST + + 0.5 * (sH2 + tH2) / uH2 * pow2(logST); + double b0utsIm = -M_PI * ( (sH - tH) / uH + (sH2 + tH2) / uH2 * logST); + double b1stuRe = -1.; + double b1stuIm = 0.; + double b2stuRe = -1.; + double b2stuIm = 0.; + + // Calculate kinematics dependence. + double sigBox = pow2(b0stuRe) + pow2(b0stuIm) + pow2(b0tsuRe) + + pow2(b0tsuIm) + pow2(b0utsRe) + pow2(b0utsIm) + 4. * pow2(b1stuRe) + + 4. * pow2(b1stuIm) + pow2(b2stuRe) + pow2(b2stuIm); + + // Answer. + sigma = (5. / (192. * M_PI * sH2)) * pow2(chargeSum) + * pow3(alpS) * alpEM * sigBox; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2gg2ggamma::setIdColAcol() { + + // Flavours and colours are trivial. + setId( id1, id2, 21, 22); + setColAcol( 1, 2, 2, 3, 1, 3, 0, 0); + if (Rndm::flat() > 0.5) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2ffbar2gammagamma class. +// Cross section for q qbar -> gamma gamma. + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2ffbar2gammagamma::sigmaKin() { + + // Calculate kinematics dependence. + sigTU = 2. * (tH2 + uH2) / (tH * uH); + + // Answer contains factor 1/2 from identical photons. + sigma0 = (M_PI/sH2) * pow2(alpEM) * 0.5 * sigTU; + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ffbar2gammagamma::sigmaHat() { + + // Incoming flavour gives charge and colour factors. + double eNow = CoupEW::ef( abs(id1) ); + double colFac = (abs(id1) < 9) ? 1. / 3. : 1.; + return sigma0 * pow4(eNow) * colFac; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2gammagamma::setIdColAcol() { + + // Outgoing flavours trivial. + setId( id1, id2, 22, 22); + + // No colours at all or one flow topology. Swap if first is antiquark. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2gg2gammagamma class. +// Cross section for g g -> gamma gamma. +// Proceeds through a quark box, by default using 5 massless quarks. + +//********* + +// Initialize process. + +void Sigma2gg2gammagamma::initProc() { + + // Maximum quark flavour in loop. + int nQuarkLoop = Settings::mode("PromptPhoton:nQuarkLoop"); + + // Calculate charge factor from the allowed quarks in the box. + charge2Sum = 1./9. + 4./9. + 1./9.; + if (nQuarkLoop >= 4) charge2Sum += 4./9.; + if (nQuarkLoop >= 5) charge2Sum += 1./9.; + if (nQuarkLoop >= 6) charge2Sum += 4./9.; + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat). + +void Sigma2gg2gammagamma::sigmaKin() { + + // Logarithms of Mandelstam variable ratios. + double logST = log( -sH / tH ); + double logSU = log( -sH / uH ); + double logTU = log( tH / uH ); + + // Real and imaginary parts of separate amplitudes. + double b0stuRe = 1. + (tH - uH) / sH * logTU + + 0.5 * (tH2 + uH2) / sH2 * (pow2(logTU) + pow2(M_PI)); + double b0stuIm = 0.; + double b0tsuRe = 1. + (sH - uH) / tH * logSU + + 0.5 * (sH2 + uH2) / tH2 * pow2(logSU); + double b0tsuIm = -M_PI * ( (sH - uH) / tH + (sH2 + uH2) / tH2 * logSU); + double b0utsRe = 1. + (sH - tH) / uH * logST + + 0.5 * (sH2 + tH2) / uH2 * pow2(logST); + double b0utsIm = -M_PI * ( (sH - tH) / uH + (sH2 + tH2) / uH2 * logST); + double b1stuRe = -1.; + double b1stuIm = 0.; + double b2stuRe = -1.; + double b2stuIm = 0.; + + // Calculate kinematics dependence. + double sigBox = pow2(b0stuRe) + pow2(b0stuIm) + pow2(b0tsuRe) + + pow2(b0tsuIm) + pow2(b0utsRe) + pow2(b0utsIm) + 4. * pow2(b1stuRe) + + 4. * pow2(b1stuIm) + pow2(b2stuRe) + pow2(b2stuIm); + + // Answer contains factor 1/2 from identical photons. + sigma = (0.5 / (16. * M_PI * sH2)) * pow2(charge2Sum) + * pow2(alpS) * pow2(alpEM) * sigBox; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2gg2gammagamma::setIdColAcol() { + + // Flavours and colours are trivial. + setId( id1, id2, 22, 22); + setColAcol( 1, 2, 2, 1, 0, 0, 0, 0); + +} + +//************************************************************************** + +// Sigma2ff2fftgmZ class. +// Cross section for f f' -> f f' via t-channel gamma*/Z0 exchange +// (f is quark or lepton). + +//********* + +// Initialize process. + +void Sigma2ff2fftgmZ::initProc() { + + // Store Z0 mass for propagator. Common coupling factor. + gmZmode = Settings::mode("WeakZ0:gmZmode"); + mZ = ParticleDataTable::m0(23); + mZS = mZ*mZ; + thetaWRat = 1. / (16. * CoupEW::sin2thetaW() * CoupEW::cos2thetaW()); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2ff2fftgmZ::sigmaKin() { + + // Cross section part common for all incoming flavours. + double sigma0 = (M_PI / sH2) * pow2(alpEM); + + // Kinematical functions for gamma-gamma, gamma-Z and Z-Z parts. + sigmagmgm = sigma0 * 2. * (sH2 + uH2) / tH2; + sigmagmZ = sigma0 * 4. * thetaWRat * sH2 / (tH * (tH - mZS)); + sigmaZZ = sigma0 * 2. * pow2(thetaWRat) * sH2 / pow2(tH - mZS); + if (gmZmode == 1) {sigmagmZ = 0.; sigmaZZ = 0.;} + if (gmZmode == 2) {sigmagmgm = 0.; sigmagmZ = 0.;} + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ff2fftgmZ::sigmaHat() { + + // Couplings for current flavour combination. + int id1Abs = abs(id1); + double e1 = CoupEW::ef(id1Abs); + double v1 = CoupEW::vf(id1Abs); + double a1 = CoupEW::af(id1Abs); + int id2Abs = abs(id2); + double e2 = CoupEW::ef(id2Abs); + double v2 = CoupEW::vf(id2Abs); + double a2 = CoupEW::af(id2Abs); + + // Distinguish same-sign and opposite-sign fermions. + double epsi = (id1 * id2 > 0) ? 1. : -1.; + + // Flavour-dependent cross section. + double sigma = sigmagmgm * pow2(e1 * e2) + + sigmagmZ * e1 * e2 * (v1 * v2 * (1. + uH2 / sH2) + + a1 * a2 * epsi * (1. - uH2 / sH2)) + + sigmaZZ * ((v1*v1 + a1*a1) * (v2*v2 + a2*a2) * (1. + uH2 / sH2) + + 4. * v1 * a1 * v2 * a2 * epsi * (1. - uH2 / sH2)); + + // Spin-state extra factor 2 per incoming neutrino. + if (id1Abs == 12 || id1Abs == 14 || id1Abs == 16) sigma *= 2.; + if (id2Abs == 12 || id2Abs == 14 || id2Abs == 16) sigma *= 2.; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ff2fftgmZ::setIdColAcol() { + + // Trivial flavours: out = in. + setId( id1, id2, id1, id2); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9 && abs(id2) < 9 && id1*id2 > 0) + setColAcol( 1, 0, 2, 0, 1, 0, 2, 0); + else if (abs(id1) < 9 && abs(id2) < 9) + setColAcol( 1, 0, 0, 2, 1, 0, 0, 2); + else if (abs(id1) < 9) setColAcol( 1, 0, 0, 0, 1, 0, 0, 0); + else if (abs(id2) < 9) setColAcol( 0, 0, 1, 0, 0, 0, 1, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if ( (abs(id1) < 9 && id1 < 0) || (abs(id1) > 10 && id2 < 0) ) + swapColAcol(); + +} + +//************************************************************************** + +// Sigma2ff2fftW class. +// Cross section for f_1 f_2 -> f_3 f_4 via t-channel W+- exchange +// (f is quark or lepton). + +//********* + +// Initialize process. + +void Sigma2ff2fftW::initProc() { + + // Store W+- mass for propagator. Common coupling factor. + mW = ParticleDataTable::m0(24); + mWS = mW*mW; + thetaWRat = 1. / (4. * CoupEW::sin2thetaW()); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2ff2fftW::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * pow2(alpEM * thetaWRat) + * 4. * sH2 / pow2(tH - mWS); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ff2fftW::sigmaHat() { + + // Some flavour combinations not possible. + int id1Abs = abs(id1); + int id2Abs = abs(id2); + if ( (id1Abs%2 == id2Abs%2 && id1 * id2 > 0) + || (id1Abs%2 != id2Abs%2 && id1 * id2 < 0) ) return 0.; + + // Basic cross section. + double sigma = sigma0; + if (id1 * id2 < 0) sigma *= uH2 / sH2; + + // CKM factors for final states. + sigma *= VCKM::V2sum(id1Abs) * VCKM::V2sum(id2Abs); + + // Spin-state extra factor 2 per incoming neutrino. + if (id1Abs == 12 || id1Abs == 14 || id1Abs == 16) sigma *= 2.; + if (id2Abs == 12 || id2Abs == 14 || id2Abs == 16) sigma *= 2.; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ff2fftW::setIdColAcol() { + + // Pick out-flavours by relative CKM weights. + id3 = VCKM::V2pick(id1); + id4 = VCKM::V2pick(id2); + setId( id1, id2, id3, id4); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9 && abs(id2) < 9 && id1*id2 > 0) + setColAcol( 1, 0, 2, 0, 1, 0, 2, 0); + else if (abs(id1) < 9 && abs(id2) < 9) + setColAcol( 1, 0, 0, 2, 1, 0, 0, 2); + else if (abs(id1) < 9) setColAcol( 1, 0, 0, 0, 1, 0, 0, 0); + else if (abs(id2) < 9) setColAcol( 0, 0, 1, 0, 0, 0, 1, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if ( (abs(id1) < 9 && id1 < 0) || (abs(id1) > 10 && id2 < 0) ) + swapColAcol(); + +} + + +//************************************************************************** + +// Sigma2qq2QqtW class. +// Cross section for q q' -> Q q" via t-channel W+- exchange. +// Related to Sigma2ff2ffViaW class, but with massive matrix elements. + +//********* + +// Initialize process. + +void Sigma2qq2QqtW::initProc() { + + // Process name. + nameSave = "q q -> Q q (t-channel W+-)"; + if (idNew == 4) nameSave = "q q -> c q (t-channel W+-)"; + if (idNew == 5) nameSave = "q q -> b q (t-channel W+-)"; + if (idNew == 6) nameSave = "q q -> t q (t-channel W+-)"; + if (idNew == 7) nameSave = "q q -> b' q (t-channel W+-)"; + if (idNew == 8) nameSave = "q q -> t' q (t-channel W+-)"; + + // Store W+- mass for propagator. Common coupling factor. + mW = ParticleDataTable::m0(24); + mWS = mW*mW; + thetaWRat = 1. / (4. * CoupEW::sin2thetaW()); + + // Secondary open width fractions, relevant for top (or heavier). + openFracPos = ParticleDataTable::resOpenFrac(idNew); + openFracNeg = ParticleDataTable::resOpenFrac(-idNew); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2qq2QqtW::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * pow2(alpEM * thetaWRat) * 4. / pow2(tH - mWS); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2qq2QqtW::sigmaHat() { + + // Some flavour combinations not possible. + int id1Abs = abs(id1); + int id2Abs = abs(id2); + bool diff12 = (id1Abs%2 != id2Abs%2); + if ( (!diff12 && id1 * id2 > 0) + || ( diff12 && id1 * id2 < 0) ) return 0.; + + // Basic cross section. + double sigma = sigma0; + sigma *= (id1 * id2 > 0) ? sH * (sH - s3) : uH * (uH - s3); + + // Secondary width if t or tbar produced on either side. + double openFrac1 = (id1 > 0) ? openFracPos : openFracNeg; + double openFrac2 = (id2 > 0) ? openFracPos : openFracNeg; + + // CKM factors for final states; further impossible case. + bool diff1N = (id1Abs%2 != idNew%2); + bool diff2N = (id2Abs%2 != idNew%2); + if (diff1N && diff2N) + sigma *= ( VCKM::V2id(id1Abs, idNew) * openFrac1 * VCKM::V2sum(id2Abs) + + VCKM::V2sum(id1Abs) * VCKM::V2id(id2Abs, idNew) * openFrac2 ); + else if (diff1N) + sigma *= VCKM::V2id(id1Abs, idNew) * openFrac1 * VCKM::V2sum(id2Abs); + else if (diff2N) + sigma *= VCKM::V2sum(id1Abs) * VCKM::V2id(id2Abs, idNew) * openFrac2; + else sigma = 0.; + + // Spin-state extra factor 2 per incoming neutrino. + if (id1Abs == 12 || id1Abs == 14 || id1Abs == 16) sigma *= 2.; + if (id2Abs == 12 || id2Abs == 14 || id2Abs == 16) sigma *= 2.; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qq2QqtW::setIdColAcol() { + + // For topologies like d dbar -> (t/c/u) (t/c/u)bar pick side. + int id1Abs = abs(id1); + int id2Abs = abs(id2); + int side = 1; + if ( (id1Abs + idNew)%2 == 1 && (id2Abs + idNew)%2 == 1 ) { + double prob1 = VCKM::V2id(id1Abs, idNew) * VCKM::V2sum(id2Abs); + prob1 *= (id1 > 0) ? openFracPos : openFracNeg; + double prob2 = VCKM::V2id(id2Abs, idNew) * VCKM::V2sum(id1Abs); + prob2 *= (id2 > 0) ? openFracPos : openFracNeg; + if (prob2 > Rndm::flat() * (prob1 + prob2)) side = 2; + } + else if ((id2Abs + idNew)%2 == 1) side = 2; + + // Pick out-flavours by relative CKM weights. + if (side == 1) { + // q q' -> t q" : correct order from start. + id3 = (id1 > 0) ? idNew : -idNew; + id4 = VCKM::V2pick(id2); + setId( id1, id2, id3, id4); + } else { + // q q' -> q" t : stored as t q" so swap tHat <-> uHat. + swapTU = true; + id3 = VCKM::V2pick(id1); + id4 = (id2 > 0) ? idNew : -idNew; + setId( id1, id2, id4, id3); + } + + // Colour flow topologies. Swap when antiquarks on side 1. + if (side == 1 && id1 * id2 > 0) setColAcol( 1, 0, 2, 0, 1, 0, 2, 0); + else if (id1 * id2 > 0) setColAcol( 1, 0, 2, 0, 2, 0, 1, 0); + else if (side == 1) setColAcol( 1, 0, 0, 2, 1, 0, 0, 2); + else setColAcol( 1, 0, 0, 2, 0, 2, 1, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles of W in top decay. + +double Sigma2qq2QqtW::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // For top decay hand over to standard routine, else done. + if (idNew == 6 && process[process[iResBeg].mother1()].idAbs() == 6) + return weightTopDecay( process, iResBeg, iResEnd); + else return 1.; + +} + +//************************************************************************** + +// Sigma1ffbar2gmZ class. +// Cross section for f fbar -> gamma*/Z0 (f is quark or lepton). + +//********* + +// Initialize process. + +void Sigma1ffbar2gmZ::initProc() { + + // Allow to pick only gamma* or Z0 part of full gamma*/Z0 expression. + gmZmode = Settings::mode("WeakZ0:gmZmode"); + + // Store Z0 mass and width for propagator. + mRes = ParticleDataTable::m0(23); + GammaRes = ParticleDataTable::mWidth(23); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + thetaWRat = 1. / (16. * CoupEW::sin2thetaW() * CoupEW::cos2thetaW()); + + // Set pointer to particle properties and decay table. + particlePtr = ParticleDataTable::particleDataPtr(23); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1ffbar2gmZ::sigmaKin() { + + // Common coupling factors. + double colQ = 3. * (1. + alpS / M_PI); + + // Reset quantities to sum. Declare variables in loop. + gamSum = 0.; + intSum = 0.; + resSum = 0.; + int idAbs, onMode; + double mf, mr, psvec, psaxi, betaf, ef2, efvf, vf2af2, colf; + + // Loop over all Z0 decay channels. + for (int i = 0; i < particlePtr->decay.size(); ++i) { + idAbs = abs( particlePtr->decay[i].product(0) ); + + // Only contributions from three fermion generations, except top. + if ( (idAbs > 0 && idAbs < 6) || ( idAbs > 10 && idAbs < 17)) { + mf = ParticleDataTable::m0(idAbs); + + // Check that above threshold. Phase space. + if (mH > 2. * mf + MASSMARGIN) { + mr = pow2(mf / mH); + betaf = sqrtpos(1. - 4. * mr); + psvec = betaf * (1. + 2. * mr); + psaxi = pow3(betaf); + + // Combine phase space with couplings. + ef2 = CoupEW::ef2(idAbs) * psvec; + efvf = CoupEW::efvf(idAbs) * psvec; + vf2af2 = CoupEW::vf2(idAbs) * psvec + CoupEW::af2(idAbs) * psaxi; + colf = (idAbs < 6) ? colQ : 1.; + + // Store sum of combinations. For outstate only open channels. + onMode = particlePtr->decay[i].onMode(); + if (onMode == 1 || onMode == 2) { + gamSum += colf * ef2; + intSum += colf * efvf; + resSum += colf * vf2af2; + } + + // End loop over fermions. + } + } + } + + // Calculate prefactors for gamma/interference/Z0 cross section terms. + gamProp = 4. * M_PI * pow2(alpEM) / (3. * sH); + intProp = gamProp * 2. * thetaWRat * sH * (sH - m2Res) + / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + resProp = gamProp * pow2(thetaWRat * sH) + / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + + // Optionally only keep gamma* or Z0 term. + if (gmZmode == 1) {intProp = 0.; resProp = 0.;} + if (gmZmode == 2) {gamProp = 0.; intProp = 0.;} + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma1ffbar2gmZ::sigmaHat() { + + // Combine gamma, interference and Z0 parts. + int idAbs = abs(id1); + double sigma = CoupEW::ef2(idAbs) * gamProp * gamSum + + CoupEW::efvf(idAbs) * intProp * intSum + + CoupEW::vf2af2(idAbs) * resProp * resSum; + + // Colour factor. Answer. + if (idAbs < 9) sigma /= 3.; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ffbar2gmZ::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, 23); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for gamma*/Z0 decay angle. + +double Sigma1ffbar2gmZ::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Z should sit in entry 5. + if (iResBeg != 5 || iResEnd != 5) return 1.; + + // Couplings for in- and out-flavours. + int idInAbs = process[3].idAbs(); + double ei = CoupEW::ef(idInAbs); + double vi = CoupEW::vf(idInAbs); + double ai = CoupEW::af(idInAbs); + int idOutAbs = process[6].idAbs(); + double ef = CoupEW::ef(idOutAbs); + double vf = CoupEW::vf(idOutAbs); + double af = CoupEW::af(idOutAbs); + + // Phase space factors. (One power of beta left out in formulae.) + double mf = process[6].m(); + double mr = mf*mf / sH; + double betaf = sqrtpos(1. - 4. * mr); + + // Coefficients of angular expression. + double coefTran = ei*ei * gamProp * ef*ef + ei * vi * intProp * ef * vf + + (vi*vi + ai*ai) * resProp * (vf*vf + pow2(betaf) * af*af); + double coefLong = 4. * mr * ( ei*ei * gamProp * ef*ef + + ei * vi * intProp * ef * vf + (vi*vi + ai*ai) * resProp * vf*vf ); + double coefAsym = betaf * ( ei * ai * intProp * ef * af + + 4. * vi * ai * resProp * vf * af ); + + // Flip asymmetry for in-fermion + out-antifermion. + if (process[3].id() * process[6].id() < 0) coefAsym = -coefAsym; + + // Reconstruct decay angle and weight for it. + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * betaf); + double wtMax = 2. * (coefTran + abs(coefAsym)); + double wt = coefTran * (1. + pow2(cosThe)) + + coefLong * (1. - pow2(cosThe)) + 2. * coefAsym * cosThe; + + // Done. + return (wt / wtMax); + +} + +//************************************************************************** + +// Sigma1ffbar2W class. +// Cross section for f fbar' -> W+- (f is quark or lepton). + +//********* + +// Initialize process. + +void Sigma1ffbar2W::initProc() { + + // Store W+- mass and width for propagator. + mRes = ParticleDataTable::m0(24); + GammaRes = ParticleDataTable::mWidth(24); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + thetaWRat = 1. / (12. * CoupEW::sin2thetaW()); + + // Set pointer to particle properties and decay table. + particlePtr = ParticleDataTable::particleDataPtr(24); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1ffbar2W::sigmaKin() { + + // Set up Breit-Wigner. Cross section for W+ and W- separately. + double sigBW = 12. * M_PI / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + double preFac = alpEM * thetaWRat * mH; + sigma0Pos = preFac * sigBW * particlePtr->resWidthOpen(34, mH); + sigma0Neg = preFac * sigBW * particlePtr->resWidthOpen(-34, mH); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma1ffbar2W::sigmaHat() { + + // Secondary width for W+ or W-. CKM and colour factors. + int idUp = (abs(id1)%2 == 0) ? id1 : id2; + double sigma = (idUp > 0) ? sigma0Pos : sigma0Neg; + if (abs(id1) < 9) sigma *= VCKM::V2id(abs(id1), abs(id2)) / 3.; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ffbar2W::setIdColAcol() { + + // Sign of outgoing W. + int sign = 1 - 2 * (abs(id1)%2); + if (id1 < 0) sign = -sign; + setId( id1, id2, 24 * sign); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for W decay angle. + +double Sigma1ffbar2W::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // W should sit in entry 5. + if (iResBeg != 5 || iResEnd != 5) return 1.; + + // Phase space factors. + double mr1 = pow2(process[6].m()) / sH; + double mr2 = pow2(process[7].m()) / sH; + double betaf = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2); + + // Sign of asymmetry. + double eps = (process[3].id() * process[6].id() > 0) ? 1. : -1.; + + // Reconstruct decay angle and weight for it. + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * betaf); + double wtMax = 4.; + double wt = pow2(1. + betaf * eps * cosThe) - pow2(mr1 - mr2); + + // Done. + return (wt / wtMax); + +} + +//************************************************************************** + +// Sigma2ffbar2ffbarsgm class. +// Cross section f fbar -> gamma* -> f' fbar', for multiple interactions. + + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2ffbar2ffbarsgm::sigmaKin() { + + // Pick new flavour. Allow three leptons and five quarks. + double colQ = 1. + (alpS / M_PI); + double flavWt = 3. + colQ * 11. / 3.; + double flavRndm = Rndm::flat() * flavWt; + if (flavRndm < 3.) { + if (flavRndm < 1.) idNew = 11; + else if (flavRndm < 2.) idNew = 13; + else idNew = 15; + } else { + flavRndm = 3. * (flavWt - 3.) / colQ; + if (flavRndm < 4.) idNew = 2; + else if (flavRndm < 8.) idNew = 4; + else if (flavRndm < 9.) idNew = 1; + else if (flavRndm < 10.) idNew = 3; + else idNew = 5; + } + double mNew = ParticleDataTable::m0(idNew); + double m2New = mNew*mNew; + + // Calculate kinematics dependence. Give correct mass factors for + // tHat, uHat defined as if massless kinematics, d(sigma)/d(Omega) + // = beta (1 + cos^2(theta) + (1 - beta^2) sin^2(theta)). + // Special case related to phase space form in multiple interactions. + double sigS = 0.; + if (sH > 4. * m2New) { + double beta = sqrt(1. - 4. * m2New / sH); + sigS = beta * (2.* (tH2 + uH2) + 4. * (1. - beta * beta) * tH * uH) + / sH2; + } + + // Answer is proportional to number of outgoing flavours. + sigma0 = (M_PI/sH2) * pow2(alpEM) * sigS * flavWt; + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ffbar2ffbarsgm::sigmaHat() { + + // Charge and colour factors. + double eNow = CoupEW::ef( abs(id1) ); + double sigma = sigma0 * pow2(eNow); + if (abs(id1) < 9) sigma /= 3.; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2ffbarsgm::setIdColAcol() { + + // Set outgoing flavours. + id3 = (id1 > 0) ? idNew : -idNew; + setId( id1, id2, id3, -id3); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9 && idNew < 9) setColAcol( 1, 0, 0, 1, 2, 0, 0, 2); + else if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0, 0, 0); + else if (idNew < 9) setColAcol( 0, 0, 0, 0, 1, 0, 0, 1); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2ffbar2FFbarsgmZ class. +// Cross section f fbar -> gamma*/Z0 -> F Fbar. + +//********* + +// Initialize process. + +void Sigma2ffbar2FFbarsgmZ::initProc() { + + // Process name. + nameSave = "f fbar -> F Fbar (s-channel gamma*/Z0)"; + if (idNew == 4) nameSave = "f fbar -> c cbar (s-channel gamma*/Z0)"; + if (idNew == 5) nameSave = "f fbar -> b bbar (s-channel gamma*/Z0)"; + if (idNew == 6) nameSave = "f fbar -> t tbar (s-channel gamma*/Z0)"; + if (idNew == 7) nameSave = "f fbar -> b' b'bar (s-channel gamma*/Z0)"; + if (idNew == 8) nameSave = "f fbar -> t' t'bar (s-channel gamma*/Z0)"; + if (idNew == 15) nameSave = "f fbar -> tau+ tau- (s-channel gamma*/Z0)"; + if (idNew == 17) nameSave = "f fbar -> tau'+ tau'- (s-channel gamma*/Z0)"; + if (idNew == 18) + nameSave = "f fbar -> nu'_tau nu'bar_tau (s-channel gamma*/Z0)"; + + // Allow to pick only gamma* or Z0 part of full gamma*/Z0 expression. + gmZmode = Settings::mode("WeakZ0:gmZmode"); + + // Store Z0 mass and width for propagator. + mRes = ParticleDataTable::m0(23); + GammaRes = ParticleDataTable::mWidth(23); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + thetaWRat = 1. / (16. * CoupEW::sin2thetaW() * CoupEW::cos2thetaW()); + + // Store couplings of F. + ef = CoupEW::ef(idNew); + vf = CoupEW::vf(idNew); + af = CoupEW::af(idNew); + + // Secondary open width fraction, relevant for top (or heavier). + openFracPair = ParticleDataTable::resOpenFrac(idNew, -idNew); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2ffbar2FFbarsgmZ::sigmaKin() { + + // Check that above threshold. + isPhysical = true; + if (mH < m3 + m4 + MASSMARGIN) { + isPhysical = false; + return; + } + + // Define average F, Fbar mass so same beta. Phase space. + double s34Avg = 0.5 * (s3 + s4) - 0.25 * pow2(s3 - s4) / sH; + mr = s34Avg / sH; + betaf = sqrtpos(1. - 4. * mr); + + // Final-state colour factor. + double colF = (idNew < 9) ? 3. * (1. + alpS / M_PI) : 1.; + + // Reconstruct decay angle so can reuse 2 -> 1 cross section. + cosThe = (tH - uH) / (betaf * sH); + + // Calculate prefactors for gamma/interference/Z0 cross section terms. + gamProp = colF * M_PI * pow2(alpEM) / sH2; + intProp = gamProp * 2. * thetaWRat * sH * (sH - m2Res) + / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + resProp = gamProp * pow2(thetaWRat * sH) + / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + + // Optionally only keep gamma* or Z0 term. + if (gmZmode == 1) {intProp = 0.; resProp = 0.;} + if (gmZmode == 2) {gamProp = 0.; intProp = 0.;} + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ffbar2FFbarsgmZ::sigmaHat() { + + // Fail if below threshold. + if (!isPhysical) return 0.; + + // Couplings for in-flavours. + int idAbs = abs(id1); + double ei = CoupEW::ef(idAbs); + double vi = CoupEW::vf(idAbs); + double ai = CoupEW::af(idAbs); + + // Coefficients of angular expression. + double coefTran = ei*ei * gamProp * ef*ef + ei * vi * intProp * ef * vf + + (vi*vi + ai*ai) * resProp * (vf*vf + pow2(betaf) * af*af); + double coefLong = 4. * mr * ( ei*ei * gamProp * ef*ef + + ei * vi * intProp * ef * vf + (vi*vi + ai*ai) * resProp * vf*vf ); + double coefAsym = betaf * ( ei * ai * intProp * ef * af + + 4. * vi * ai * resProp * vf * af ); + + // Combine gamma, interference and Z0 parts. + double sigma = coefTran * (1. + pow2(cosThe)) + + coefLong * (1. - pow2(cosThe)) + 2. * coefAsym * cosThe; + + // Top: corrections for closed decay channels. + sigma *= openFracPair; + + // Initial-state colour factor. Answer. + if (idAbs < 9) sigma /= 3.; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2FFbarsgmZ::setIdColAcol() { + + // Set outgoing flavours. + id3 = (id1 > 0) ? idNew : -idNew; + setId( id1, id2, id3, -id3); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9 && idNew < 9) setColAcol( 1, 0, 0, 1, 2, 0, 0, 2); + else if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0, 0, 0); + else if (idNew < 9) setColAcol( 0, 0, 0, 0, 1, 0, 0, 1); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles of W in top decay. + +double Sigma2ffbar2FFbarsgmZ::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // For top decay hand over to standard routine, else done. + if (idNew == 6 && process[process[iResBeg].mother1()].idAbs() == 6) + return weightTopDecay( process, iResBeg, iResEnd); + else return 1.; + +} + +//************************************************************************** + +// Sigma2ffbar2FfbarsW class. +// Cross section f fbar' -> W+- -> F fbar". + +//********* + +// Initialize process. + +void Sigma2ffbar2FfbarsW::initProc() { + + // Process name. + nameSave = "f fbar -> F fbar (s-channel W+-)"; + if (idNew == 4) nameSave = "f fbar -> c qbar (s-channel W+-)"; + if (idNew == 5) nameSave = "f fbar -> b qbar (s-channel W+-)"; + if (idNew == 6) nameSave = "f fbar -> t qbar (s-channel W+-)"; + if (idNew == 7) nameSave = "f fbar -> b' qbar (s-channel W+-)"; + if (idNew == 8) nameSave = "f fbar -> t' qbar (s-channel W+-)"; + if (idNew == 7 && idNew2 == 6) + nameSave = "f fbar -> b' tbar (s-channel W+-)"; + if (idNew == 8 && idNew2 == 7) + nameSave = "f fbar -> t' b'bar (s-channel W+-)"; + if (idNew == 15 || idNew == 16) + nameSave = "f fbar -> tau nu_taubar (s-channel W+-)"; + if (idNew == 17 || idNew == 18) + nameSave = "f fbar -> tau' nu'_taubar (s-channel W+-)"; + + // Store W+- mass and width for propagator. + mRes = ParticleDataTable::m0(24); + GammaRes = ParticleDataTable::mWidth(24); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + thetaWRat = 1. / (12. * CoupEW::sin2thetaW()); + + // For t/t' want to use at least b mass. + idPartner = idNew2; + if ( (idNew == 6 || idNew == 8) && idNew2 == 0 ) idPartner = 5; + + // Sum of CKM weights for quarks. + V2New = (idNew < 9) ? VCKM::V2sum(idNew) : 1.; + if (idNew2 != 0) V2New = VCKM::V2id(idNew, idNew2); + + // Secondary open width fractions, relevant for top or heavier. + openFracPos = ParticleDataTable::resOpenFrac( idNew, -idNew2); + openFracNeg = ParticleDataTable::resOpenFrac(-idNew, idNew2); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2ffbar2FfbarsW::sigmaKin() { + + // Check that above threshold. + isPhysical = true; + if (mH < m3 + m4 + MASSMARGIN) { + isPhysical = false; + return; + } + + // Phase space factors. + double mr1 = s3 / sH; + double mr2 = s4 / sH; + double betaf = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2); + + // Reconstruct decay angle so can reuse 2 -> 1 cross section. + double cosThe = (tH - uH) / (betaf * sH); + + // Set up Breit-Wigner and in- and out-widths. + double sigBW = 9. * M_PI * pow2(alpEM * thetaWRat) + / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + + // Initial-state colour factor. + double colF = (idNew < 9) ? 3. * (1. + alpS / M_PI) * V2New : 1.; + + // Angular dependence. + double wt = pow2(1. + betaf * cosThe) - pow2(mr1 - mr2); + + // Temporary answer. + sigma0 = sigBW * colF * wt; + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ffbar2FfbarsW::sigmaHat() { + + // Fail if below threshold. + if (!isPhysical) return 0.; + + // CKM and colour factors. + double sigma = sigma0; + if (abs(id1) < 9) sigma *= VCKM::V2id(abs(id1), abs(id2)) / 3.; + + // Correction for secondary width in top (or heavier) decay. + int idSame = ((abs(id1) + idNew)%2 == 0) ? id1 : id2; + sigma *= (idSame > 0) ? openFracPos : openFracNeg; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2FfbarsW::setIdColAcol() { + + // Set outgoing flavours. + id3 = idNew; + id4 = (idNew2 != 0) ? idNew2 : VCKM::V2pick(idNew); + if (idNew%2 == 0) { + int idInUp = (abs(id1)%2 == 0) ? id1 : id2; + if (idInUp > 0) id4 = -id4; + else id3 = -id3; + } else { + int idInDn = (abs(id1)%2 == 1) ? id1 : id2; + if (idInDn > 0) id4 = -id4; + else id3 = -id3; + } + setId( id1, id2, id3, id4); + + // Swap tHat and uHat for fbar' f -> F f". + if (id1 * id3 < 0) swapTU = true; + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9 && idNew < 9) setColAcol( 1, 0, 0, 1, 2, 0, 0, 2); + else if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0, 0, 0); + else if (idNew < 9) setColAcol( 0, 0, 0, 0, 1, 0, 0, 1); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapCol12(); + if (id3 < 0) swapCol34(); + +} + +//********* + +// Evaluate weight for decay angles of W in top decay. + +double Sigma2ffbar2FfbarsW::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // For top decay hand over to standard routine, else done. + if (idNew == 6 && process[process[iResBeg].mother1()].idAbs() == 6) + return weightTopDecay( process, iResBeg, iResEnd); + else return 1.; + +} + +//************************************************************************** + +// Sigma2ffbargmZWgmZW class. +// Collects common methods for f fbar -> gamma*/Z0/W+- gamma*/Z0/W-+. + +//********* + +// Calculate and store internal products. + +void Sigma2ffbargmZWgmZW::setupProd( Event& process, int i1, int i2, + int i3, int i4, int i5, int i6) { + + // Store incoming and outgoing momenta, + pRot[1] = process[i1].p(); + pRot[2] = process[i2].p(); + pRot[3] = process[i3].p(); + pRot[4] = process[i4].p(); + pRot[5] = process[i5].p(); + pRot[6] = process[i6].p(); + + // Do random rotation to avoid accidental zeroes in HA expressions. + bool smallPT = false; + do { + smallPT = false; + double thetaNow = acos(2. * Rndm::flat() - 1.); + double phiNow = 2. * M_PI * Rndm::flat(); + for (int i = 1; i <= 6; ++i) { + pRot[i].rot( thetaNow, phiNow); + if (pRot[i].pT2() < 1e-4 * pRot[i].pAbs2()) smallPT = true; + } + } while (smallPT); + + // Calculate internal products. + for (int i = 1; i < 6; ++i) { + for (int j = i + 1; j <= 6; ++j) { + hA[i][j] = + sqrt( (pRot[i].e() - pRot[i].pz()) * (pRot[j].e() + pRot[j].pz()) + / pRot[i].pT2() ) * complex( pRot[i].px(), pRot[i].py() ) + - sqrt( (pRot[i].e() + pRot[i].pz()) * (pRot[j].e() - pRot[j].pz()) + / pRot[j].pT2() ) * complex( pRot[j].px(), pRot[j].py() ); + hC[i][j] = conj( hA[i][j] ); + if (i <= 2) { + hA[i][j] *= complex( 0., 1.); + hC[i][j] *= complex( 0., 1.); + } + hA[j][i] = - hA[i][j]; + hC[j][i] = - hC[i][j]; + } + } + +} + +//********* + +// Evaluate the F function of Gunion and Kunszt. + +complex Sigma2ffbargmZWgmZW::fGK(int j1, int j2, int j3, int j4, int j5, + int j6) { + + return 4. * hA[j1][j3] * hC[j2][j6] + * ( hA[j1][j5] * hC[j1][j4] + hA[j3][j5] * hC[j3][j4] ); + +} + +//********* + +// Evaluate the Xi function of Gunion and Kunszt. + +double Sigma2ffbargmZWgmZW::xiGK( double tHnow, double uHnow) { + + return - 4. * s3 * s4 + tHnow * (3. * tHnow + 4. * uHnow) + + tHnow * tHnow * ( tHnow * uHnow / (s3 * s4) + - 2. * (1. / s3 + 1./s4) * (tHnow + uHnow) + + 2. * (s3 / s4 + s4 / s3) ); + +} + +//********* + +// Evaluate the Xj function of Gunion and Kunszt. + +double Sigma2ffbargmZWgmZW::xjGK( double tHnow, double uHnow) { + + return 8. * pow2(s3 + s4) - 8. * (s3 + s4) * (tHnow + uHnow) + - 6. * tHnow * uHnow - 2. * tHnow * uHnow * ( tHnow * uHnow + / (s3 * s4) - 2. * (1. / s3 + 1. / s4) * (tHnow + uHnow) + + 2. * (s3 / s4 + s4 / s3) ); + +} + +//************************************************************************** + +// Sigma2ffbar2gmZgmZ class. +// Cross section for f fbar -> gamma*/Z0 gamma*/Z0 (f is quark or lepton). + +//********* + +// Initialize process. + +void Sigma2ffbar2gmZgmZ::initProc() { + + // Allow to pick only gamma* or Z0 part of full gamma*/Z0 expression. + gmZmode = Settings::mode("WeakZ0:gmZmode"); + + // Store Z0 mass and width for propagator. + mRes = ParticleDataTable::m0(23); + GammaRes = ParticleDataTable::mWidth(23); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + thetaWRat = 1. / (16. * CoupEW::sin2thetaW() * CoupEW::cos2thetaW()); + + // Set pointer to particle properties and decay table. + particlePtr = ParticleDataTable::particleDataPtr(23); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2ffbar2gmZgmZ::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * pow2(alpEM) * 0.5 + * ( (tH2 + uH2 + 2. * (s3 + s4) * sH) / (tH * uH) + - s3 * s4 * (1./tH2 + 1./uH2) ); + + // Common coupling factors at the resonance masses + double alpEM3 = alphaEMPtr->alphaEM(s3); + double alpS3 = alphaSPtr->alphaS(s3); + double colQ3 = 3. * (1. + alpS3 / M_PI); + double alpEM4 = alphaEMPtr->alphaEM(s4); + double alpS4 = alphaSPtr->alphaS(s4); + double colQ4 = 3. * (1. + alpS4 / M_PI); + + // Reset quantities to sum. Declare variables in loop. + gamSum3 = 0.; + intSum3 = 0.; + resSum3 = 0.; + gamSum4 = 0.; + intSum4 = 0.; + resSum4 = 0.; + int onMode; + double mf, mr, psvec, psaxi, betaf, ef2, efvf, vf2af2, colf; + + // Loop over all Z0 decay channels. + for (int i = 0; i < particlePtr->decay.size(); ++i) { + int idAbs = abs( particlePtr->decay[i].product(0) ); + + // Only contributions from three fermion generations, except top. + if ( (idAbs > 0 && idAbs < 6) || ( idAbs > 10 && idAbs < 17)) { + mf = ParticleDataTable::m0(idAbs); + onMode = particlePtr->decay[i].onMode(); + + // First Z0: check that above threshold. Phase space. + if (m3 > 2. * mf + MASSMARGIN) { + mr = pow2(mf / m3); + betaf = sqrtpos(1. - 4. * mr); + psvec = betaf * (1. + 2. * mr); + psaxi = pow3(betaf); + + // First Z0: combine phase space with couplings. + ef2 = CoupEW::ef2(idAbs) * psvec; + efvf = CoupEW::efvf(idAbs) * psvec; + vf2af2 = CoupEW::vf2(idAbs) * psvec + CoupEW::af2(idAbs) * psaxi; + colf = (idAbs < 6) ? colQ3 : 1.; + + // First Z0: store sum of combinations for open outstate channels. + if (onMode == 1 || onMode == 2) { + gamSum3 += colf * ef2; + intSum3 += colf * efvf; + resSum3 += colf * vf2af2; + } + } + + // Second Z0: check that above threshold. Phase space. + if (m4 > 2. * mf + MASSMARGIN) { + mr = pow2(mf / m4); + betaf = sqrtpos(1. - 4. * mr); + psvec = betaf * (1. + 2. * mr); + psaxi = pow3(betaf); + + // Second Z0: combine phase space with couplings. + ef2 = CoupEW::ef2(idAbs) * psvec; + efvf = CoupEW::efvf(idAbs) * psvec; + vf2af2 = CoupEW::vf2(idAbs) * psvec + CoupEW::af2(idAbs) * psaxi; + colf = (idAbs < 6) ? colQ4 : 1.; + + // Second Z0: store sum of combinations for open outstate channels. + if (onMode == 1 || onMode == 2) { + gamSum4 += colf * ef2; + intSum4 += colf * efvf; + resSum4 += colf * vf2af2; + } + } + + // End loop over fermions. + } + } + + // First Z0: calculate prefactors for gamma/interference/Z0 terms. + gamProp3 = 4. * alpEM3 / (3. * M_PI * s3); + intProp3 = gamProp3 * 2. * thetaWRat * s3 * (s3 - m2Res) + / ( pow2(s3 - m2Res) + pow2(s3 * GamMRat) ); + resProp3 = gamProp3 * pow2(thetaWRat * s3) + / ( pow2(s3 - m2Res) + pow2(s3 * GamMRat) ); + + // First Z0: optionally only keep gamma* or Z0 term. + if (gmZmode == 1) {intProp3 = 0.; resProp3 = 0.;} + if (gmZmode == 2) {gamProp3 = 0.; intProp3 = 0.;} + + // Second Z0: calculate prefactors for gamma/interference/Z0 terms. + gamProp4 = 4. * alpEM4 / (3. * M_PI * s4); + intProp4 = gamProp4 * 2. * thetaWRat * s4 * (s4 - m2Res) + / ( pow2(s4 - m2Res) + pow2(s4 * GamMRat) ); + resProp4 = gamProp4 * pow2(thetaWRat * s4) + / ( pow2(s4 - m2Res) + pow2(s4 * GamMRat) ); + + // Second Z0: optionally only keep gamma* or Z0 term. + if (gmZmode == 1) {intProp4 = 0.; resProp4 = 0.;} + if (gmZmode == 2) {gamProp4 = 0.; intProp4 = 0.;} + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ffbar2gmZgmZ::sigmaHat() { + + // Charge/2, left- and righthanded couplings for in-fermion. + int idAbs = abs(id1); + double ei = 0.5 * CoupEW::ef(idAbs); + double li = CoupEW::lf(idAbs); + double ri = CoupEW::rf(idAbs); + + // Combine left/right gamma, interference and Z0 parts for each Z0. + double left3 = ei * ei * gamProp3 * gamSum3 + + ei * li * intProp3 * intSum3 + + li * li * resProp3 * resSum3; + double right3 = ei * ei * gamProp3 * gamSum3 + + ei * ri * intProp3 * intSum3 + + ri * ri * resProp3 * resSum3; + double left4 = ei * ei * gamProp4 * gamSum4 + + ei * li * intProp4 * intSum4 + + li * li * resProp4 * resSum4; + double right4 = ei * ei * gamProp4 * gamSum4 + + ei * ri * intProp4 * intSum4 + + ri * ri * resProp4 * resSum4; + + // Combine left- and right-handed couplings for the two Z0's. + double sigma = sigma0 * (left3 * left4 + right3 * right4); + + // Correct for the running-width Z0 propagators weight in PhaseSpace. + sigma /= (runBW3 * runBW4); + + // Initial-state colour factor. Answer. + if (idAbs < 9) sigma /= 3.; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2gmZgmZ::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, 23, 23); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate correlated decay flavours of the two gamma*/Z0. +// Unique complication, caused by gamma*/Z0 mix different left/right. + +double Sigma2ffbar2gmZgmZ::weightDecayFlav( Event& process) { + + // Order so that fbar(1) f(2) -> f'(3) fbar'(4) f"(5) fbar"(6). + i1 = (process[3].id() < 0) ? 3 : 4; + i2 = 7 - i1; + i3 = (process[7].id() > 0) ? 7 : 8; + i4 = 15 - i3; + i5 = (process[9].id() > 0) ? 9 : 10; + i6 = 19 - i5; + + // Charge/2, left- and righthanded couplings for in- and out-fermions. + int idAbs = process[i1].idAbs(); + double ei = 0.5 * CoupEW::ef(idAbs); + double li = CoupEW::lf(idAbs); + double ri = CoupEW::rf(idAbs); + idAbs = process[i3].idAbs(); + double e3 = 0.5 * CoupEW::ef(idAbs); + double l3 = CoupEW::lf(idAbs); + double r3 = CoupEW::rf(idAbs); + idAbs = process[i5].idAbs(); + double e4 = 0.5 * CoupEW::ef(idAbs); + double l4 = CoupEW::lf(idAbs); + double r4 = CoupEW::rf(idAbs); + + // Left- and righthanded couplings combined with propagators. + c3LL = ei * ei * gamProp3 * e3 * e3 + + ei * li * intProp3 * e3 * l3 + + li * li * resProp3 * l3 * l3; + c3LR = ei * ei * gamProp3 * e3 * e3 + + ei * li * intProp3 * e3 * r3 + + li * li * resProp3 * r3 * r3; + c3RL = ei * ei * gamProp3 * e3 * e3 + + ei * ri * intProp3 * e3 * l3 + + ri * ri * resProp3 * l3 * l3; + c3RR = ei * ei * gamProp3 * e3 * e3 + + ei * ri * intProp3 * e3 * r3 + + ri * ri * resProp3 * r3 * r3; + c4LL = ei * ei * gamProp4 * e4 * e4 + + ei * li * intProp4 * e4 * l4 + + li * li * resProp4 * l4 * l4; + c4LR = ei * ei * gamProp4 * e4 * e4 + + ei * li * intProp4 * e4 * r4 + + li * li * resProp4 * r4 * r4; + c4RL = ei * ei * gamProp4 * e4 * e4 + + ei * ri * intProp4 * e4 * l4 + + ri * ri * resProp4 * l4 * l4; + c4RR = ei * ei * gamProp4 * e4 * e4 + + ei * ri * intProp4 * e4 * r4 + + ri * ri * resProp4 * r4 * r4; + + // Flavour weight and maximum. + flavWt = (c3LL + c3LR) * (c4LL + c4LR) + (c3RL + c3RR) * (c4RL + c4RR); + double flavWtMax = (c3LL + c3LR + c3RL + c3RR) * (c4LL + c4LR + c4RL + c4RR); + + // Done. + return flavWt / flavWtMax; + +} + +//********* + +// Evaluate weight for decay angles of the two gamma*/Z0. + +double Sigma2ffbar2gmZgmZ::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Two resonance decays, but with common weight. + if (iResBeg != 5 || iResEnd != 6) return 1.; + + // Set up four-products and internal products. + setupProd( process, i1, i2, i3, i4, i5, i6); + + // Flip tHat and uHat if first incoming is fermion. + double tHres = tH; + double uHres = uH; + if (process[3].id() > 0) swap( tHres, uHres); + + // Kinematics factors (norm(x) = |x|^2). + double fGK135 = norm( fGK( 1, 2, 3, 4, 5, 6) / tHres + + fGK( 1, 2, 5, 6, 3, 4) / uHres ); + double fGK145 = norm( fGK( 1, 2, 4, 3, 5, 6) / tHres + + fGK( 1, 2, 5, 6, 4, 3) / uHres ); + double fGK136 = norm( fGK( 1, 2, 3, 4, 6, 5) / tHres + + fGK( 1, 2, 6, 5, 3, 4) / uHres ); + double fGK146 = norm( fGK( 1, 2, 4, 3, 6, 5) / tHres + + fGK( 1, 2, 6, 5, 4, 3) / uHres ); + double fGK253 = norm( fGK( 2, 1, 5, 6, 3, 4) / tHres + + fGK( 2, 1, 3, 4, 5, 6) / uHres ); + double fGK263 = norm( fGK( 2, 1, 6, 5, 3, 4) / tHres + + fGK( 2, 1, 3, 4, 6, 5) / uHres ); + double fGK254 = norm( fGK( 2, 1, 5, 6, 4, 3) / tHres + + fGK( 2, 1, 4, 3, 5, 6) / uHres ); + double fGK264 = norm( fGK( 2, 1, 6, 5, 4, 3) / tHres + + fGK( 2, 1, 4, 3, 6, 5) / uHres ); + + // Weight and maximum. + double wt = c3LL * c4LL * fGK135 + c3LR * c4LL * fGK145 + + c3LL * c4LR * fGK136 + c3LR * c4LR * fGK146 + + c3RL * c4RL * fGK253 + c3RR * c4RL * fGK263 + + c3RL * c4RR * fGK254 + c3RR * c4RR * fGK264; + double wtMax = 16. * s3 * s4 * flavWt + * ( (tHres*tHres + uHres*uHres + 2. * sH * (s3 + s4)) / (tHres * uHres) + - s3 * s4 * (1. / (tHres*tHres) + 1. / (uHres*uHres)) ); + + // Done. + return wt / wtMax; + +} + +//************************************************************************** + +// Sigma2ffbar2ZW class. +// Cross section for f fbar' -> W+ W- (f is quark or lepton). + +//********* + +// Initialize process. + +void Sigma2ffbar2ZW::initProc() { + + // Store W+- mass and width for propagator. + mW = ParticleDataTable::m0(24); + widW = ParticleDataTable::mWidth(24); + mWS = mW*mW; + mwWS = pow2(mW * widW); + + // Left-handed couplings for up/nu- and down/e-type quarks. + lun = (hasLeptonBeams) ? CoupEW::lf(12) : CoupEW::lf(2); + lde = (hasLeptonBeams) ? CoupEW::lf(11) : CoupEW::lf(1); + + // Common weak coupling factor. + sin2thetaW = CoupEW::sin2thetaW(); + cos2thetaW = CoupEW::cos2thetaW(); + thetaWRat = 1. / (4. * cos2thetaW); + thetaWpt = (9. - 8. * sin2thetaW) / 4.; + thetaWmm = (8. * sin2thetaW - 6.) / 4.; + + // Secondary open width fractions. + openFracPos = ParticleDataTable::resOpenFrac(23, 24); + openFracNeg = ParticleDataTable::resOpenFrac(23, -24); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2ffbar2ZW::sigmaKin() { + + // Evaluate cross section. + double resBW = 1. / (pow2(sH - mWS) + mwWS); + sigma0 = (M_PI / sH2) * 0.5 * pow2(alpEM / sin2thetaW); + sigma0 *= sH * resBW * (thetaWpt * pT2 + thetaWmm * (s3 + s4)) + + (sH - mWS) * resBW * sH * (pT2 - s3 - s4) * (lun / tH - lde / uH) + + thetaWRat * sH * pT2 * ( lun*lun / tH2 + lde*lde / uH2 ) + + 2. * thetaWRat * sH * (s3 + s4) * lun * lde / (tH * uH); + + // Protect against slightly negative cross sections, + // probably caused by addition of width to the W propagator. + sigma0 = max(0., sigma0); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ffbar2ZW::sigmaHat() { + + // CKM and colour factors. + double sigma = sigma0; + if (abs(id1) < 9) sigma *= VCKM::V2id(abs(id1), abs(id2)) / 3.; + + // Corrections for secondary widths in Z0 and W+- decays. + int idUp = (abs(id1)%2 == 0) ? id1 : id2; + sigma *= (idUp > 0) ? openFracPos : openFracNeg; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2ZW::setIdColAcol() { + + // Sign of outgoing W. + int sign = 1 - 2 * (abs(id1)%2); + if (id1 < 0) sign = -sign; + setId( id1, id2, 23, 24 * sign); + + // tHat is defined between (f, W-) or (fbar, W+), + // so OK for u/ubar on side 1, but must swap tHat <-> uHat if d/dbar. + if (abs(id1)%2 == 1) swapTU = true; + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for Z0 and W+- decay angles. + +double Sigma2ffbar2ZW::weightDecay( Event& process, int iResBeg, int iResEnd) { + + // Two resonance decays, but with common weight. + if (iResBeg != 5 || iResEnd != 6) return 1.; + + // Order so that fbar(1) f(2) -> f'(3) fbar'(4) f"(5) fbar"(6) + // with f' fbar' from W+- and f" fbar" from Z0 (note flip Z0 <-> W+-). + int i1 = (process[3].id() < 0) ? 3 : 4; + int i2 = 7 - i1; + int i3 = (process[9].id() > 0) ? 9 : 10; + int i4 = 19 - i3; + int i5 = (process[7].id() > 0) ? 7 : 8; + int i6 = 15 - i5; + + // Set up four-products and internal products. + setupProd( process, i1, i2, i3, i4, i5, i6); + + // Swap tHat and uHat if incoming fermion is downtype. + double tHres = tH; + double uHres = uH; + if (process[i2].id()%2 == 1) swap( tHres, uHres); + + // Couplings of incoming (anti)fermions and outgoing from Z0. + int idAbs = process[i1].idAbs(); + double ai = CoupEW::af(idAbs); + double li1 = CoupEW::lf(idAbs); + idAbs = process[i2].idAbs(); + double li2 = CoupEW::lf(idAbs); + idAbs = process[i5].idAbs(); + double l4 = CoupEW::lf(idAbs); + double r4 = CoupEW::rf(idAbs); + + // W propagator/interference factor. + double Wint = cos2thetaW * (sH - mWS) / (pow2(sH - mWS) + mwWS); + + // Combinations of couplings and kinematics (norm(x) = |x|^2). + double aWZ = li2 / tHres - 2. * Wint * ai; + double bWZ = li1 / uHres + 2. * Wint * ai; + double fGK135 = norm( aWZ * fGK( 1, 2, 3, 4, 5, 6) + + bWZ * fGK( 1, 2, 5, 6, 3, 4) ); + double fGK136 = norm( aWZ * fGK( 1, 2, 3, 4, 6, 5) + + bWZ * fGK( 1, 2, 6, 5, 3, 4) ); + double xiT = xiGK( tHres, uHres); + double xiU = xiGK( uHres, tHres); + double xjTU = xjGK( tHres, uHres); + + // Weight and maximum weight. + double wt = l4*l4 * fGK135 + r4*r4 * fGK136; + double wtMax = 4. * s3 * s4 * (l4*l4 + r4*r4) + * (aWZ * aWZ * xiT + bWZ * bWZ * xiU + aWZ * bWZ * xjTU); + + // Done. + return wt / wtMax; + +} + +//************************************************************************** + +// Sigma2ffbar2WW class. +// Cross section for f fbar -> W- W+ (f is quark or lepton). + +//********* + +// Initialize process. + +void Sigma2ffbar2WW::initProc() { + + // Store Z0 mass and width for propagator. Common coupling factor. + mZ = ParticleDataTable::m0(23); + widZ = ParticleDataTable::mWidth(23); + mZS = mZ*mZ; + mwZS = pow2(mZ * widZ); + thetaWRat = 1. / (4. * CoupEW::sin2thetaW()); + + // Secondary open width fraction. + openFracPair = ParticleDataTable::resOpenFrac(24, -24); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2ffbar2WW::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * pow2(alpEM); + + // Z0 propagator and gamma*/Z0 interference. + double Zprop = sH2 / (pow2(sH - mZS) + mwZS); + double Zint = Zprop * (1. - mZS / sH); + + // Common coupling factors (g = gamma*, Z = Z0, f = t-channel fermion). + cgg = 0.5; + cgZ = thetaWRat * Zint; + cZZ = 0.5 * pow2(thetaWRat) * Zprop; + cfg = thetaWRat; + cfZ = pow2(thetaWRat) * Zint; + cff = pow2(thetaWRat); + + // Kinematical functions. + double rat34 = sH * (2. * (s3 + s4) + pT2) / (s3 * s4); + double lambdaS = pow2(sH - s3 - s4) - 4. * s3 * s4; + double intA = (sH - s3 - s4) * rat34 / sH; + double intB = 4. * (s3 + s4 - pT2); + gSS = (lambdaS * rat34 + 12. * sH * pT2) / sH2; + gTT = rat34 + 4. * sH * pT2 / tH2; + gST = intA + intB / tH; + gUU = rat34 + 4. * sH * pT2 / uH2; + gSU = intA + intB / uH; + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ffbar2WW::sigmaHat() { + + // Flavour-specific couplings. + int idAbs = abs(id1); + double ei = CoupEW::ef(idAbs); + double vi = CoupEW::vf(idAbs); + double ai = CoupEW::af(idAbs); + + // Combine, with different cases for up- and down-type in-flavours. + double sigma = sigma0; + sigma *= (idAbs%2 == 1) + ? (cgg * ei*ei + cgZ * ei * vi + cZZ * (vi*vi + ai*ai)) * gSS + + (cfg * ei + cfZ * (vi + ai)) * gST + cff * gTT + : (cgg * ei*ei + cgZ * ei * vi + cZZ * (vi*vi + ai*ai)) * gSS + - (cfg * ei + cfZ * (vi + ai)) * gSU + cff * gUU; + + // Initial-state colour factor. Correction for secondary widths. Answer. + if (idAbs < 9) sigma /= 3.; + sigma *= openFracPair; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2WW::setIdColAcol() { + + // Always order W- W+, i.e. W- first. + setId( id1, id2, -24, 24); + + // tHat is defined between (f, W-) or (fbar, W+), + if (id1 < 0) swapTU = true; + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for W+ and W- decay angles. + +double Sigma2ffbar2WW::weightDecay( Event& process, int iResBeg, int iResEnd) { + + // Two resonance decays, but with common weight. + if (iResBeg != 5 || iResEnd != 6) return 1.; + + // Order so that fbar(1) f(2) -> f'(3) fbar'(4) f"(5) fbar"(6). + // with f' fbar' from W- and f" fbar" from W+. + int i1 = (process[3].id() < 0) ? 3 : 4; + int i2 = 7 - i1; + int i3 = (process[7].id() > 0) ? 7 : 8; + int i4 = 15 - i3; + int i5 = (process[9].id() > 0) ? 9 : 10; + int i6 = 19 - i5; + + // Set up four-products and internal products. + setupProd( process, i1, i2, i3, i4, i5, i6); + + // tHat and uHat of fbar f -> W- W+ opposite to previous convention. + double tHres = uH; + double uHres = tH; + + // Couplings of incoming (anti)fermion. + int idAbs = process[i1].idAbs(); + double ai = CoupEW::af(idAbs); + double li = CoupEW::lf(idAbs); + double ri = CoupEW::rf(idAbs); + + // gamma*/Z0 propagator/interference factor. + double Zint = mZS * (sH - mZS) / (pow2(sH - mZS) + mwZS); + + // Combinations of couplings and kinematics (norm(x) = |x|^2). + double dWW = (li * Zint + ai) / sH; + double aWW = dWW + 0.5 * (ai + 1.) / tHres; + double bWW = dWW + 0.5 * (ai - 1.) / uHres; + double cWW = ri * Zint / sH; + double fGK135 = norm( aWW * fGK( 1, 2, 3, 4, 5, 6) + - bWW * fGK( 1, 2, 5, 6, 3, 4) ); + double fGK253 = norm( cWW * ( fGK( 2, 1, 5, 6, 3, 4) + - fGK( 2, 1, 3, 4, 5, 6) ) ); + double xiT = xiGK( tHres, uHres); + double xiU = xiGK( uHres, tHres); + double xjTU = xjGK( tHres, uHres); + + // Weight and maximum weight. + double wt = fGK135 + fGK253; + double wtMax = 4. * s3 * s4 + * ( aWW * aWW * xiT + bWW * bWW * xiU - aWW * bWW * xjTU + + cWW * cWW * (xiT + xiU - xjTU) ); + + // Done. + return wt / wtMax; +} + +//************************************************************************** + +// Sigma2ffbargmZggm class. +// Collects common methods for f fbar -> gamma*/Z0 g/gamma and permutations. + +//********* + +// Initialize process. + +void Sigma2ffbargmZggm::initProc() { + + // Allow to pick only gamma* or Z0 part of full gamma*/Z0 expression. + gmZmode = Settings::mode("WeakZ0:gmZmode"); + + // Store Z0 mass and width for propagator. + mRes = ParticleDataTable::m0(23); + GammaRes = ParticleDataTable::mWidth(23); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + thetaWRat = 1. / (16. * CoupEW::sin2thetaW() * CoupEW::cos2thetaW()); + + // Set pointer to particle properties and decay table. + particlePtr = ParticleDataTable::particleDataPtr(23); + +} + +//********* + +// Evaluate sum of flavour couplings times phase space. + +void Sigma2ffbargmZggm::flavSum() { + + // Coupling factors for Z0 subsystem. + double alpSZ = alphaSPtr->alphaS(s3); + double colQZ = 3. * (1. + alpSZ / M_PI); + + // Reset quantities to sum. Declare variables in loop. + gamSum = 0.; + intSum = 0.; + resSum = 0.; + int onMode; + double mf, mr, psvec, psaxi, betaf, ef2, efvf, vf2af2, colf; + + // Loop over all Z0 decay channels. + for (int i = 0; i < particlePtr->decay.size(); ++i) { + int idAbs = abs( particlePtr->decay[i].product(0) ); + + // Only contributions from three fermion generations, except top. + if ( (idAbs > 0 && idAbs < 6) || ( idAbs > 10 && idAbs < 17)) { + mf = ParticleDataTable::m0(idAbs); + + // Check that above threshold. Phase space. + if (m3 > 2. * mf + MASSMARGIN) { + mr = pow2(mf / m3); + betaf = sqrtpos(1. - 4. * mr); + psvec = betaf * (1. + 2. * mr); + psaxi = pow3(betaf); + + // Combine phase space with couplings. + ef2 = CoupEW::ef2(idAbs) * psvec; + efvf = CoupEW::efvf(idAbs) * psvec; + vf2af2 = CoupEW::vf2(idAbs) * psvec + CoupEW::af2(idAbs) * psaxi; + colf = (idAbs < 6) ? colQZ : 1.; + + // Store sum of combinations. For outstate only open channels. + onMode = particlePtr->decay[i].onMode(); + if (onMode == 1 || onMode == 2) { + gamSum += colf * ef2; + intSum += colf * efvf; + resSum += colf * vf2af2; + } + + // End loop over fermions. + } + } + } + + // Done. Return values in gamSum, intSum and resSum. + +} + +//********* + +// Calculate common parts of gamma/interference/Z0 propagator terms. + +void Sigma2ffbargmZggm::propTerm() { + + // Calculate prefactors for gamma/interference/Z0 cross section terms. + gamProp = 4. * alpEM / (3. * M_PI * s3); + intProp = gamProp * 2. * thetaWRat * s3 * (s3 - m2Res) + / ( pow2(s3 - m2Res) + pow2(s3 * GamMRat) ); + resProp = gamProp * pow2(thetaWRat * s3) + / ( pow2(s3 - m2Res) + pow2(s3 * GamMRat) ); + + // Optionally only keep gamma* or Z0 term. + if (gmZmode == 1) {intProp = 0.; resProp = 0.;} + if (gmZmode == 2) {gamProp = 0.; intProp = 0.;} + +} + +//********* + +// Evaluate weight for gamma*/Z0 decay angle. + +double Sigma2ffbargmZggm::weightDecay( Event& process, int iResBeg, int iResEnd) { + + // Z should sit in entry 5 and one more parton in entry 6. + if (iResBeg != 5 || iResEnd != 6) return 1.; + + // In an outgoing sense fermions are labelled f(1) fbar(2) f'(3) fbar'(4) + // where f' fbar' come from gamma*/Z0 decay. + int i1, i2; + int i3 = (process[7].id() > 0) ? 7 : 8; + int i4 = 15 - i3; + + // Order so that fbar(1) f(2) -> gamma*/Z0 g/gamma. + if (process[3].idAbs() < 20 && process[4].idAbs() < 20) { + i1 = (process[3].id() < 0) ? 3 : 4; + i2 = 7 - i1; + + // Order so that f(2)/fbar(1) g/gamma -> f(1)/fbar(2) f'(3) gamma*/Z0. + } else if (process[3].idAbs() < 20) { + i1 = (process[3].id() < 0) ? 3 : 6; + i2 = 9 - i1; + } else { + i1 = (process[4].id() < 0) ? 4 : 6; + i2 = 10 - i1; + } + + // Charge/2, left- and righthanded couplings for in- and out-fermion. + int id1Abs = process[i1].idAbs(); + double ei = 0.5 * CoupEW::ef(id1Abs); + double li = CoupEW::lf(id1Abs); + double ri = CoupEW::rf(id1Abs); + int id3Abs = process[i3].idAbs(); + double ef = 0.5 * CoupEW::ef(id3Abs); + double lf = CoupEW::lf(id3Abs); + double rf = CoupEW::rf(id3Abs); + + // Combinations of left/right for in/out, gamma*/interference/Z0. + double clilf = ei*ei * gamProp * ef*ef + ei*li * intProp * ef*lf + + li*li * resProp * lf*lf; + double clirf = ei*ei * gamProp * ef*ef + ei*li * intProp * ef*rf + + li*li * resProp * rf*rf; + double crilf = ei*ei * gamProp * ef*ef + ei*ri * intProp * ef*lf + + ri*ri * resProp * lf*lf; + double crirf = ei*ei * gamProp * ef*ef + ei*ri * intProp * ef*rf + + ri*ri * resProp * rf*rf; + + // Evaluate four-vector products. + double p13 = process[i1].p() * process[i3].p(); + double p14 = process[i1].p() * process[i4].p(); + double p23 = process[i2].p() * process[i3].p(); + double p24 = process[i2].p() * process[i4].p(); + + // Calculate weight and its maximum. + double wt = (clilf + crirf) * (p13*p13 + p24*p24) + + (clirf + crilf) * (p14*p14 + p23*p23) ; + double wtMax = (clilf + clirf + crilf + crirf) + * (pow2(p13 + p14) + pow2(p23 + p24)); + + // Done. + return (wt / wtMax); + +} + +//************************************************************************** + +// Sigma2qqbar2gmZg class. +// Cross section for q qbar -> gamma*/Z0 g. + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2qqbar2gmZg::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * (alpEM * alpS) + * (2./9.) * (tH2 + uH2 + 2. * sH * s3) / (tH * uH); + + // Calculate flavour sums for final state. + flavSum(); + + // Calculate prefactors for gamma/interference/Z0 cross section terms. + propTerm(); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2qqbar2gmZg::sigmaHat() { + + // Combine gamma, interference and Z0 parts. + int idAbs = abs(id1); + double sigma = sigma0 + * ( CoupEW::ef2(idAbs) * gamProp * gamSum + + CoupEW::efvf(idAbs) * intProp * intSum + + CoupEW::vf2af2(idAbs) * resProp * resSum); + + // Correct for the running-width Z0 propagater weight in PhaseSpace. + sigma /= runBW3; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2gmZg::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, 23, 21); + + // Colour flow topologies. Swap when antiquarks. + setColAcol( 1, 0, 0, 2, 0, 0, 1, 2); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2qg2gmZq class. +// Cross section for q g -> gamma*/Z0 q. + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2qg2gmZq::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * (alpEM * alpS) + * (1./12.) * (sH2 + uH2 + 2. * tH * s3) / (-sH * uH); + + // Calculate flavour sums for final state. + flavSum(); + + // Calculate prefactors for gamma/interference/Z0 cross section terms. + propTerm(); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2qg2gmZq::sigmaHat() { + + // Combine gamma, interference and Z0 parts. + int idAbs = (id2 == 21) ? abs(id1) : abs(id2); + double sigma = sigma0 + * ( CoupEW::ef2(idAbs) * gamProp * gamSum + + CoupEW::efvf(idAbs) * intProp * intSum + + CoupEW::vf2af2(idAbs) * resProp * resSum); + + // Correct for the running-width Z0 propagater weight in PhaseSpace. + sigma /= runBW3; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qg2gmZq::setIdColAcol() { + + // Flavour set up for q g -> gamma*/Z0 q. + int idq = (id2 == 21) ? id1 : id2; + setId( id1, id2, 23, idq); + + // tH defined between f and f': must swap tHat <-> uHat if q g in. + swapTU = (id2 == 21); + + // Colour flow topologies. Swap when antiquarks. + if (id2 == 21) setColAcol( 1, 0, 2, 1, 0, 0, 2, 0); + else setColAcol( 2, 1, 1, 0, 0, 0, 2, 0); + if (idq < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2ffbar2gmZgm class. +// Cross section for f fbar -> gamma*/Z0 gamma. + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2ffbar2gmZgm::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * (alpEM*alpEM) + * 0.5 * (tH2 + uH2 + 2. * sH * s3) / (tH * uH); + + // Calculate flavour sums for final state. + flavSum(); + + // Calculate prefactors for gamma/interference/Z0 cross section terms. + propTerm(); + + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ffbar2gmZgm::sigmaHat() { + + // Combine gamma, interference and Z0 parts. + int idAbs = abs(id1); + double sigma = sigma0 * CoupEW::ef2(idAbs) + * ( CoupEW::ef2(idAbs) * gamProp * gamSum + + CoupEW::efvf(idAbs) * intProp * intSum + + CoupEW::vf2af2(idAbs) * resProp * resSum); + + // Correct for the running-width Z0 propagater weight in PhaseSpace. + sigma /= runBW3; + + // Colour factor. Answer. + if (idAbs < 9) sigma /= 3.; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2gmZgm::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, 23, 22); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2fgm2gmZf class. +// Cross section for f gamma -> gamma*/Z0 f'. + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2fgm2gmZf::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * (alpEM*alpEM) + * 0.5 * (sH2 + uH2 + 2. * tH * s3) / (- sH * uH); + + // Calculate flavour sums for final state. + flavSum(); + + // Calculate prefactors for gamma/interference/Z0 cross section terms. + propTerm(); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2fgm2gmZf::sigmaHat() { + + // Combine gamma, interference and Z0 parts. + int idAbs = (id2 == 22) ? abs(id1) : abs(id2); + double sigma = sigma0 * CoupEW::ef2(idAbs) + * ( CoupEW::ef2(idAbs) * gamProp * gamSum + + CoupEW::efvf(idAbs) * intProp * intSum + + CoupEW::vf2af2(idAbs) * resProp * resSum); + + // Correct for the running-width Z0 propagater weight in PhaseSpace. + sigma /= runBW3; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2fgm2gmZf::setIdColAcol() { + + // Flavour set up for q gamma -> gamma*/Z0 q. + int idq = (id2 == 22) ? id1 : id2; + setId( id1, id2, 23, idq); + + // tH defined between f and f': must swap tHat <-> uHat if q gamma in. + swapTU = (id2 == 22); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 0, 0, 0, 1, 0); + else if (abs(id2) < 9) setColAcol( 0, 0, 1, 0, 0, 0, 1, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (idq < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2ffbarWggm class. +// Collects common methods for f fbar -> W+- g/gamma and permutations. + +//********* + +// Evaluate weight for W+- decay angle. + +double Sigma2ffbarWggm::weightDecay( Event& process, int iResBeg, int iResEnd) { + + // W should sit in entry 5 and one more parton in entry 6. + if (iResBeg != 5 || iResEnd != 6) return 1.; + + // In an outgoing sense fermions are labelled f(1) fbar(2) f'(3) fbar'(4) + // where f' fbar' come from W+- decay. + int i1, i2; + int i3 = (process[7].id() > 0) ? 7 : 8; + int i4 = 15 - i3; + + // Order so that fbar(1) f(2) -> W+- g/gamma. + if (process[3].idAbs() < 20 && process[4].idAbs() < 20) { + i1 = (process[3].id() < 0) ? 3 : 4; + i2 = 7 - i1; + + // Order so that f(2)/fbar(1) g/gamma -> f(1)/fbar(2) f'(3) W+-. + } else if (process[3].idAbs() < 20) { + i1 = (process[3].id() < 0) ? 3 : 6; + i2 = 9 - i1; + } else { + i1 = (process[4].id() < 0) ? 4 : 6; + i2 = 10 - i1; + } + + // Evaluate four-vector products. + double p13 = process[i1].p() * process[i3].p(); + double p14 = process[i1].p() * process[i4].p(); + double p23 = process[i2].p() * process[i3].p(); + double p24 = process[i2].p() * process[i4].p(); + + // Calculate weight and its maximum. + double wt = pow2(p13) + pow2(p24); + double wtMax = pow2(p13 + p14) + pow2(p23 + p24); + + // Done. + return (wt / wtMax); + +} + +//************************************************************************** + +// Sigma2qqbar2Wg class. +// Cross section for q qbar' -> W+- g. + +//********* + +// Initialize process. + +void Sigma2qqbar2Wg::initProc() { + + // Secondary open width fractions, relevant for top (or heavier). + openFracPos = ParticleDataTable::resOpenFrac(24); + openFracNeg = ParticleDataTable::resOpenFrac(-24); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2qqbar2Wg::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * (alpEM * alpS / CoupEW::sin2thetaW()) + * (2./9.) * (tH2 + uH2 + 2. * sH * s3) / (tH * uH); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2qqbar2Wg::sigmaHat() { + + // CKM factor. Secondary width for W+ or W-. + double sigma = sigma0 * VCKM::V2id(abs(id1), abs(id2)); + int idUp = (abs(id1)%2 == 0) ? id1 : id2; + sigma *= (idUp > 0) ? openFracPos : openFracNeg; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2Wg::setIdColAcol() { + + // Sign of outgoing W. + int sign = 1 - 2 * (abs(id1)%2); + if (id1 < 0) sign = -sign; + setId( id1, id2, 24 * sign, 21); + + // Colour flow topologies. Swap when antiquarks. + setColAcol( 1, 0, 0, 2, 0, 0, 1, 2); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2qg2Wq class. +// Cross section for q g -> W+- q'. + +//********* + +// Initialize process. + +void Sigma2qg2Wq::initProc() { + + // Secondary open width fractions, relevant for top (or heavier). + openFracPos = ParticleDataTable::resOpenFrac(24); + openFracNeg = ParticleDataTable::resOpenFrac(-24); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2qg2Wq::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * (alpEM * alpS / CoupEW::sin2thetaW()) + * (1./12.) * (sH2 + uH2 + 2. * tH * s3) / (-sH * uH); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2qg2Wq::sigmaHat() { + + // CKM factor. Secondary width for W+ or W-. + int idAbs = (id2 == 21) ? abs(id1) : abs(id2); + double sigma = sigma0 * VCKM::V2sum(idAbs); + int idUp = (id2 == 21) ? id1 : id2; + if (idAbs%2 == 1) idUp = -idUp; + sigma *= (idUp > 0) ? openFracPos : openFracNeg; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qg2Wq::setIdColAcol() { + + // Sign of outgoing W. Flavour of outgoing quark. + int idq = (id2 == 21) ? id1 : id2; + int sign = 1 - 2 * (abs(idq)%2); + if (idq < 0) sign = -sign; + id4 = VCKM::V2pick(idq); + + // Flavour set up for q g -> W q. + setId( id1, id2, 24 * sign, id4); + + // tH defined between f and f': must swap tHat <-> uHat if q g in. + swapTU = (id2 == 21); + + // Colour flow topologies. Swap when antiquarks. + if (id2 == 21) setColAcol( 1, 0, 2, 1, 0, 0, 2, 0); + else setColAcol( 2, 1, 1, 0, 0, 0, 2, 0); + if (idq < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2ffbar2Wgm class. +// Cross section for f fbar' -> W+- gamma. + +//********* + +// Initialize process. + +void Sigma2ffbar2Wgm::initProc() { + + // Secondary open width fractions, relevant for top (or heavier). + openFracPos = ParticleDataTable::resOpenFrac(24); + openFracNeg = ParticleDataTable::resOpenFrac(-24); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2ffbar2Wgm::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * (alpEM*alpEM / CoupEW::sin2thetaW()) + * 0.5 * (tH2 + uH2 + 2. * sH * s3) / (tH * uH); +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ffbar2Wgm::sigmaHat() { + + // Extrafactor different for e nu and q qbar' instate. + int id1Abs = abs(id1); + int id2Abs = abs(id2); + double chgUp = (id1Abs > 10) ? 0. : 2./3.; + double sigma = sigma0 * pow2( chgUp - tH / (tH + uH) ); + + // CKM and colour factors. Secondary width for W+ or W-. + if (id1Abs < 9) sigma *= VCKM::V2id(id1Abs, id2Abs) / 3.; + int idUp = (abs(id1)%2 == 0) ? id1 : id2; + sigma *= (idUp > 0) ? openFracPos : openFracNeg; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2Wgm::setIdColAcol() { + + // Sign of outgoing W. + int sign = 1 - 2 * (abs(id1)%2); + if (id1 < 0) sign = -sign; + setId( id1, id2, 24 * sign, 22); + + // tH defined between (f,W-) or (fbar',W+). + swapTU = (sign * id1 > 0); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2fgm2Wf class. +// Cross section for f gamma -> W+- f'. + +//********* + +// Initialize process. + +void Sigma2fgm2Wf::initProc() { + + // Secondary open width fractions, relevant for top (or heavier). + openFracPos = ParticleDataTable::resOpenFrac(24); + openFracNeg = ParticleDataTable::resOpenFrac(-24); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2fgm2Wf::sigmaKin() { + + // Cross section part common for all incoming flavours. + sigma0 = (M_PI / sH2) * (alpEM*alpEM / CoupEW::sin2thetaW()) + * 0.5 * (sH2 + uH2 + 2. * tH * s3) / (pT2 * s3 - sH * uH); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2fgm2Wf::sigmaHat() { + + // Extrafactor dependent on charge of incoming fermion. + int idAbs = (id2 == 22) ? abs(id1) : abs(id2); + double charge = (idAbs > 10) ? 1. : ( (idAbs%2 == 1) ? 1./3. : 2./3. ); + double sigma = sigma0 * pow2( charge - sH / (sH + uH) ); + + // CKM factor. Secondary width for W+ or W-. + sigma *= VCKM::V2sum(idAbs); + int idUp = (id2 == 22) ? id1 : id2; + if (idAbs%2 == 1) idUp = -idUp; + sigma *= (idUp > 0) ? openFracPos : openFracNeg; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2fgm2Wf::setIdColAcol() { + + // Sign of outgoing W. Flavour of outgoing fermion. + int idq = (id2 == 22) ? id1 : id2; + int sign = 1 - 2 * (abs(idq)%2); + if (idq < 0) sign = -sign; + id4 = VCKM::V2pick(idq); + + // Flavour set up for q gamma -> W q. + setId( id1, id2, 24 * sign, id4); + + // tH defined between f and f': must swap tHat <-> uHat if q gamma in. + swapTU = (id2 == 22); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 0, 0, 0, 1, 0); + else if (abs(id2) < 9) setColAcol( 0, 0, 1, 0, 0, 0, 1, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (idq < 0) swapColAcol(); + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SigmaExtraDim.cxx b/PYTHIA8/pythia8130/src/SigmaExtraDim.cxx new file mode 100644 index 00000000000..abbcb45e498 --- /dev/null +++ b/PYTHIA8/pythia8130/src/SigmaExtraDim.cxx @@ -0,0 +1,443 @@ +// SigmaExtraDim.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// extra-dimensional simulation classes. + +#include "SigmaExtraDim.h" + +namespace Pythia8 { + +//************************************************************************** + +// Sigma1gg2GravitonStar class. +// Cross section for g g -> G* (excited graviton state). + +//********* + +// Initialize process. + +void Sigma1gg2GravitonStar::initProc() { + + // Store G* mass and width for propagator. + idGstar = 5000039; + mRes = ParticleDataTable::m0(idGstar); + GammaRes = ParticleDataTable::mWidth(idGstar); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Overall coupling strength kappa * m_G*. + kappaMG = Settings::parm("ExtraDimensionsG*:kappaMG"); + + // Set pointer to particle properties and decay table. + gStarPtr = ParticleDataTable::particleDataPtr(idGstar); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1gg2GravitonStar::sigmaKin() { + + // Incoming width for gluons. + double widthIn = pow2(kappaMG) * mH / (160. * M_PI); + + // Set up Breit-Wigner. Width out only includes open channels. + double sigBW = 5. * M_PI/ ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + double widthOut = gStarPtr->resWidthOpen(idGstar, mH); + + // Modify cross section in wings of peak. Done. + sigma = widthIn * sigBW * widthOut * pow2(sH / m2Res); + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1gg2GravitonStar::setIdColAcol() { + + // Flavours trivial. + setId( 21, 21, idGstar); + + // Colour flow topology. + setColAcol( 1, 2, 2, 1, 0, 0); + +} + +//********* + +// Evaluate weight for G* decay angle. + +double Sigma1gg2GravitonStar::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // G* should sit in entry 5. + if (iResBeg != 5 || iResEnd != 5) return 1.; + + // Phase space factors. Reconstruct decay angle. + double mr1 = pow2(process[6].m()) / sH; + double mr2 = pow2(process[7].m()) / sH; + double betaf = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2); + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * betaf); + + // Default is isotropic decay. + double wt = 1.; + + // Angular weight for g + g -> G* -> f + fbar. + if (process[6].idAbs() < 19) wt = 1. - pow4(cosThe); + + // Angular weight for g + g -> G* -> g + g or gamma + gamma. + else if (process[6].id() == 21 || process[6].id() == 22) + wt = (1. + 6. * pow2(cosThe) + pow4(cosThe)) / 8.; + + // Done. + return wt; + +} + +//************************************************************************** + +// Sigma1ffbar2GravitonStar class. +// Cross section for f fbar -> G* (excited graviton state). + +//********* + +// Initialize process. + +void Sigma1ffbar2GravitonStar::initProc() { + + // Store G* mass and width for propagator. + idGstar = 5000039; + mRes = ParticleDataTable::m0(idGstar); + GammaRes = ParticleDataTable::mWidth(idGstar); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Overall coupling strength kappa * m_G*. + kappaMG = Settings::parm("ExtraDimensionsG*:kappaMG"); + + // Set pointer to particle properties and decay table. + gStarPtr = ParticleDataTable::particleDataPtr(idGstar); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1ffbar2GravitonStar::sigmaKin() { + + // Incoming width for fermions, disregarding colour factor. + double widthIn = pow2(kappaMG) * mH / (80. * M_PI); + + // Set up Breit-Wigner. Width out only includes open channels. + double sigBW = 5. * M_PI/ ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + double widthOut = gStarPtr->resWidthOpen(idGstar, mH); + + // Modify cross section in wings of peak. Done. + sigma0 = widthIn * sigBW * widthOut * pow2(sH / m2Res); + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ffbar2GravitonStar::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, idGstar); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for G* decay angle. + +double Sigma1ffbar2GravitonStar::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // G* should sit in entry 5. + if (iResBeg != 5 || iResEnd != 5) return 1.; + + // Phase space factors. Reconstruct decay angle. + double mr1 = pow2(process[6].m()) / sH; + double mr2 = pow2(process[7].m()) / sH; + double betaf = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2); + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * betaf); + + // Default is isotropic decay. + double wt = 1.; + + // Angular weight for f + fbar -> G* -> f + fbar. + if (process[6].idAbs() < 19) + wt = (1. - 3. * pow2(cosThe) + 4. * pow4(cosThe)) / 2.; + + // Angular weight for f + fbar -> G* -> g + g or gamma + gamma. + else if (process[6].id() == 21 || process[6].id() == 22) + wt = 1. - pow4(cosThe); + + // Done. + return wt; + +} + +//************************************************************************** + +// Sigma2gg2GravitonStarg class. +// Cross section for g g -> G* g (excited graviton state). + +//********* + +// Initialize process. + +void Sigma2gg2GravitonStarg::initProc() { + + // Store G* mass and width for propagator. + idGstar = 5000039; + mRes = ParticleDataTable::m0(idGstar); + GammaRes = ParticleDataTable::mWidth(idGstar); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Overall coupling strength kappa * m_G*. + kappaMG = Settings::parm("ExtraDimensionsG*:kappaMG"); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(idGstar); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2gg2GravitonStarg::sigmaKin() { + + // Evaluate cross section. Secondary width for G*. + sigma = (3. * pow2(kappaMG) * alpS) / (32. * sH * s3) + * ( pow2(tH2 + tH * uH + uH2) / (sH2 * tH * uH) + + 2. * (tH2 / uH + uH2 / tH) / sH + 3. * (tH / uH + uH / tH) + + 2. * (sH / uH + sH/tH) + sH2 / (tH * uH) ); + sigma *= openFrac; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2gg2GravitonStarg::setIdColAcol() { + + // Flavours trivial. + setId( 21, 21, idGstar, 21); + + // Colour flow topologies: random choice between two mirrors. + if (Rndm::flat() < 0.5) setColAcol( 1, 2, 2, 3, 0, 0, 1, 3); + else setColAcol( 1, 2, 3, 1, 0, 0, 3, 2); + +} + +//********* + +// Evaluate weight for decay angles: currently G* assumed isotropic. + +double Sigma2gg2GravitonStarg::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // No equations for G* decay so assume isotropic. + return 1.; + +} + +//************************************************************************** + +// Sigma2qg2GravitonStarq class. +// Cross section for q g -> G* q (excited graviton state). + +//********* + +// Initialize process. + +void Sigma2qg2GravitonStarq::initProc() { + + // Store G* mass and width for propagator. + idGstar = 5000039; + mRes = ParticleDataTable::m0(idGstar); + GammaRes = ParticleDataTable::mWidth(idGstar); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Overall coupling strength kappa * m_G*. + kappaMG = Settings::parm("ExtraDimensionsG*:kappaMG"); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(idGstar); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2qg2GravitonStarq::sigmaKin() { + + // Evaluate cross section. Secondary width for G*. + sigma = -(pow2(kappaMG) * alpS) / (192. * sH * s3) + * ( 4. * (sH2 + uH2) / (tH * sH) + 9. * (sH + uH) / sH + sH / uH + + uH2 / sH2 + 3. * tH * (4. + sH / uH + uH / sH) / sH + + 4. * tH2 * (1. / uH + 1. / sH) / sH + 2. * tH2 * tH / (uH * sH2) ); + sigma *= openFrac; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qg2GravitonStarq::setIdColAcol() { + + // Flavour set up for q g -> H q. + int idq = (id2 == 21) ? id1 : id2; + setId( id1, id2, idGstar, idq); + + // tH defined between f and f': must swap tHat <-> uHat if q g in. + swapTU = (id2 == 21); + + // Colour flow topologies. Swap when antiquarks. + if (id2 == 21) setColAcol( 1, 0, 2, 1, 0, 0, 2, 0); + else setColAcol( 2, 1, 1, 0, 0, 0, 2, 0); + if (idq < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles: currently G* assumed isotropic. + +double Sigma2qg2GravitonStarq::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // No equations for G* decay so assume isotropic. + return 1.; + +} + +//************************************************************************** + +// Sigma2qqbar2GravitonStarg class. +// Cross section for q qbar -> G* g (excited graviton state). + +//********* + +// Initialize process. + +void Sigma2qqbar2GravitonStarg::initProc() { + + // Store G* mass and width for propagator. + idGstar = 5000039; + mRes = ParticleDataTable::m0(idGstar); + GammaRes = ParticleDataTable::mWidth(idGstar); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Overall coupling strength kappa * m_G*. + kappaMG = Settings::parm("ExtraDimensionsG*:kappaMG"); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(idGstar); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2qqbar2GravitonStarg::sigmaKin() { + + // Evaluate cross section. Secondary width for G*. + sigma = (pow2(kappaMG) * alpS) / (72. * sH * s3) + * ( 4. * (tH2 + uH2) / sH2 + 9. * (tH + uH) / sH + + (tH2 / uH + uH2 / tH) / sH + 3. * (4. + tH / uH + uH/ tH) + + 4. * (sH / uH + sH / tH) + 2. * sH2 / (tH * uH) ); + sigma *= openFrac; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2GravitonStarg::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, idGstar, 21); + + // Colour flow topologies. Swap when antiquarks. + setColAcol( 1, 0, 0, 2, 0, 0, 1, 2); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles: currently G* assumed isotropic. + +double Sigma2qqbar2GravitonStarg::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // No equations for G* decay so assume isotropic. + return 1.; + +} + + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SigmaHiggs.cxx b/PYTHIA8/pythia8130/src/SigmaHiggs.cxx new file mode 100644 index 00000000000..ccd2fd51951 --- /dev/null +++ b/PYTHIA8/pythia8130/src/SigmaHiggs.cxx @@ -0,0 +1,2530 @@ +// SigmaHiggs.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// Part of code written by Marc Montull, CERN summer student 2007. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. +// Function definitions (not found in the header) for the +// Higgs simulation classes. + +#include "SigmaHiggs.h" + +namespace Pythia8 { + +//************************************************************************** + +// Sigma1ffbar2H class. +// Cross section for f fbar -> H0 , H1, H2 or A3. +// (f is quark or lepton, H0 SM Higgs and H1, H2, A3 BSM Higgses ). + +//********* + +// Initialize process. + +void Sigma1ffbar2H::initProc() { + + // Properties specific to Higgs state. + if (higgsType == 0) { + nameSave = "f fbar -> H (SM)"; + codeSave = 901; + idRes = 25; + } + else if (higgsType == 1) { + nameSave = "f fbar -> h0(H1)"; + codeSave = 1001; + idRes = 25; + } + else if (higgsType == 2) { + nameSave = "f fbar -> H0(H2)"; + codeSave = 1021; + idRes = 35; + } + else if (higgsType == 3) { + nameSave = "f fbar -> A0(A3)"; + codeSave = 1041; + idRes = 36; + } + + // Find pointer to H0, H1, H2 or A3 depending on the value of idRes. + HResPtr = ParticleDataTable::particleDataPtr(idRes); + + // Store H0, H1, H2 or A3 mass and width for propagator. + mRes = HResPtr->m0(); + GammaRes = HResPtr->mWidth(); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + +} + + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma1ffbar2H::sigmaKin() { + + // Set up Breit-Wigner. + double width = HResPtr->resWidth(idRes, mH); + sigBW = 4. * M_PI/ ( pow2(sH - m2Res) + pow2(mH * width) ); + + // Width out only includes open channels. + widthOut = width * HResPtr->resOpenFrac(idRes); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma1ffbar2H::sigmaHat() { + + // Calculate mass-dependent incoming width, including colour factor. + int idAbs = abs(id1); + double widthIn = HResPtr->resWidthChan( mH, idAbs, -idAbs); + if (idAbs < 9) widthIn /= 9.; + + // Done. + return widthIn * sigBW * widthOut; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ffbar2H::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, idRes); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma1ffbar2H::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma1gg2H class. +// Cross section for g g -> H0, H1, H2 or A3 (H0 SM Higgs, H1, H2, A3 BSM). + +//********* + +// Initialize process. + +void Sigma1gg2H::initProc() { + + // Properties specific to Higgs state. + if (higgsType == 0) { + nameSave = "g g -> H (SM)"; + codeSave = 902; + idRes = 25; + } + else if (higgsType == 1) { + nameSave = "g g -> h0(H1)"; + codeSave = 1002; + idRes = 25; + } + else if (higgsType == 2) { + nameSave = "g g -> H0(H2)"; + codeSave = 1022; + idRes = 35; + } + else if (higgsType == 3) { + nameSave = "g g -> A0(A3)"; + codeSave = 1042; + idRes = 36; + } + + // Find pointer to H0, H1, H2 or A3 depending on idRes. + HResPtr = ParticleDataTable::particleDataPtr(idRes); + + // Store H0, H1, H2 or A3 mass and width for propagator. + mRes = HResPtr->m0(); + GammaRes = HResPtr->mWidth(); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1gg2H::sigmaKin() { + + // Incoming width for gluons, gives colour factor of 1/8 * 1/8. + double widthIn = HResPtr->resWidthChan( mH, 21, 21) / 64.; + + // Set up Breit-Wigner. + double width = HResPtr->resWidth(idRes, mH); + double sigBW = 8. * M_PI/ ( pow2(sH - m2Res) + pow2(mH * width) ); + + // Width out only includes open channels. + double widthOut = width * HResPtr->resOpenFrac(idRes); + + // Done. + sigma = widthIn * sigBW * widthOut; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1gg2H::setIdColAcol() { + + // Flavours trivial. + setId( 21, 21, idRes); + + // Colour flow topology. + setColAcol( 1, 2, 2, 1, 0, 0); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma1gg2H::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma1gmgm2H class. +// Cross section for gamma gamma -> H0, H1, H2 or H3. +// (H0 SM Higgs, H1, H2 and A3 BSM Higgses). + +//********* + +// Initialize process. + +void Sigma1gmgm2H::initProc() { + + // Properties specific to Higgs state. + if (higgsType == 0) { + nameSave = "gamma gamma -> H (SM)"; + codeSave = 903; + idRes = 25; + } + else if (higgsType == 1) { + nameSave = "gamma gamma -> h0(H1)"; + codeSave = 1003; + idRes = 25; + } + else if (higgsType == 2) { + nameSave = "gamma gamma -> H0(H2)"; + codeSave = 1023; + idRes = 35; + } + else if (higgsType == 3) { + nameSave = "gamma gamma -> A0(A3)"; + codeSave = 1043; + idRes = 36; + } + + // Find pointer to H0, H1, H2 or A3. + HResPtr = ParticleDataTable::particleDataPtr(idRes); + + // Store H0, H1, H2 or A3 mass and width for propagator. + mRes = HResPtr->m0(); + GammaRes = HResPtr->mWidth(); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1gmgm2H::sigmaKin() { + + // Incoming width for photons. + double widthIn = HResPtr->resWidthChan( mH, 22, 22); + + // Set up Breit-Wigner. + double width = HResPtr->resWidth(idRes, mH); + double sigBW = 8. * M_PI/ ( pow2(sH - m2Res) + pow2(mH * width) ); + + // Width out only includes open channels. + double widthOut = width * HResPtr->resOpenFrac(idRes); + + // Done. + sigma = widthIn * sigBW * widthOut; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1gmgm2H::setIdColAcol() { + + // Flavours trivial. + setId( 22, 22, idRes); + + // Colour flow trivial. + setColAcol( 0, 0, 0, 0, 0, 0); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma1gmgm2H::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma2ffbar2HZ class. +// Cross section for f fbar -> H0 Z0, H1 Z0, H2 Z0 or A3 Z0. +// (H0 SM Higgs, H1, H2 and A3 BSM Higgses). + +//********* + +// Initialize process. + +void Sigma2ffbar2HZ::initProc() { + + // Properties specific to Higgs state. + if (higgsType == 0) { + nameSave = "f fbar -> H0 Z0 (SM)"; + codeSave = 904; + idRes = 25; + coup2Z = 1.; + } + else if (higgsType == 1) { + nameSave = "f fbar -> h0(H1) Z0"; + codeSave = 1004; + idRes = 25; + coup2Z = Settings::parm("HiggsH1:coup2Z"); + } + else if (higgsType == 2) { + nameSave = "f fbar -> H0(H2) Z0"; + codeSave = 1024; + idRes = 35; + coup2Z = Settings::parm("HiggsH2:coup2Z"); + } + else if (higgsType == 3) { + nameSave = "f fbar -> A0(A3) ZO"; + codeSave = 1044; + idRes = 36; + coup2Z = Settings::parm("HiggsA3:coup2Z"); + } + + // Store Z0 mass and width for propagator. Common coupling factor. + mZ = ParticleDataTable::m0(23); + widZ = ParticleDataTable::mWidth(23); + mZS = mZ*mZ; + mwZS = pow2(mZ * widZ); + thetaWRat = 1. / (16. * CoupEW::sin2thetaW() * CoupEW::cos2thetaW()); + + // Secondary open width fraction. + openFracPair = ParticleDataTable::resOpenFrac(idRes, 23); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2ffbar2HZ::sigmaKin() { + + // Evaluate differential cross section. + sigma0 = (M_PI / sH2) * 8. * pow2(alpEM * thetaWRat * coup2Z) + * (tH * uH - s3 * s4 + 2. * sH * s4) / (pow2(sH - mZS) + mwZS); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ffbar2HZ::sigmaHat() { + + // Coupling a_f^2 + v_f^2 to s-channel Z0 and colour factor. + int idAbs = abs(id1); + double sigma = sigma0 * CoupEW::vf2af2(idAbs); + if (idAbs < 9) sigma /= 3.; + + // Secondary width for H0 and Z0 or H1 and Z0 or H2 and Z0 or A3 and Z0. + sigma *= openFracPair; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2HZ::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, idRes, 23); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma2ffbar2HZ::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // If not decay of Z0 created along with Higgs then done. + if (iResBeg != 5 || iResEnd != 6) return 1.; + + // Order so that fbar(1) f(2) -> H() f'(3) fbar'(4). + int i1 = (process[3].id() < 0) ? 3 : 4; + int i2 = 7 - i1; + int i3 = process[6].daughter1(); + int i4 = process[6].daughter2(); + if (process[i3].id() < 0) swap( i3, i4); + + // Find left- and righthanded couplings of fermion pairs. + int idAbs = process[i1].idAbs(); + double liS = pow2( CoupEW::lf(idAbs) ); + double riS = pow2( CoupEW::rf(idAbs) ); + idAbs = process[i3].idAbs(); + double lfS = pow2( CoupEW::lf(idAbs) ); + double rfS = pow2( CoupEW::rf(idAbs) ); + + // Evaluate relevant four-products. + double pp13 = process[i1].p() * process[i3].p(); + double pp14 = process[i1].p() * process[i4].p(); + double pp23 = process[i2].p() * process[i3].p(); + double pp24 = process[i2].p() * process[i4].p(); + + // Weight and maximum. + double wt = (liS * lfS + riS * rfS) * pp13 * pp24 + + (liS * rfS + riS * lfS) * pp14 * pp23; + double wtMax = (liS + riS) * (lfS + rfS) * (pp13 + pp14) * (pp23 + pp24); + + // Done. + return wt / wtMax; + +} + +//************************************************************************** + +// Sigma2ffbar2HW class. +// Cross section for f fbar -> H0 W+-, H1 W+-, H2 W+- or A3 W+-. +// (H0 SM Higgs, H1, H2 and A3 BSM Higgses). + +//********* + +// Initialize process. + +void Sigma2ffbar2HW::initProc() { + + // Properties specific to Higgs state. + if (higgsType == 0) { + nameSave = "f fbar -> H0 W+- (SM)"; + codeSave = 905; + idRes = 25; + coup2W = 1.; + } + else if (higgsType == 1) { + nameSave = "f fbar -> h0(H1) W+-"; + codeSave = 1005; + idRes = 25; + coup2W = Settings::parm("HiggsH1:coup2W"); + } + else if (higgsType == 2) { + nameSave = "f fbar -> H0(H2) W+-"; + codeSave = 1025; + idRes = 35; + coup2W = Settings::parm("HiggsH2:coup2W"); + } + else if (higgsType == 3) { + nameSave = "f fbar -> A0(A3) W+-"; + codeSave = 1045; + idRes = 36; + coup2W = Settings::parm("HiggsA3:coup2W"); + } + + // Store W+- mass and width for propagator. Common coupling factor. + mW = ParticleDataTable::m0(24); + widW = ParticleDataTable::mWidth(24); + mWS = mW*mW; + mwWS = pow2(mW * widW); + thetaWRat = 1. / (4. * CoupEW::sin2thetaW()); + + // Secondary open width fractions. + openFracPairPos = ParticleDataTable::resOpenFrac(idRes, 24); + openFracPairNeg = ParticleDataTable::resOpenFrac(idRes, -24); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2ffbar2HW::sigmaKin() { + + // Evaluate differential cross section. + sigma0 = (M_PI / sH2) * 2. * pow2(alpEM * thetaWRat * coup2W) + * (tH * uH - s3 * s4 + 2. * sH * s4) / (pow2(sH - mWS) + mwWS); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2ffbar2HW::sigmaHat() { + + // CKM and colour factors. + double sigma = sigma0; + if (abs(id1) < 9) sigma *= VCKM::V2id(abs(id1), abs(id2)) / 3.; + + // Secondary width for H0 and W+-. + int idUp = (abs(id1)%2 == 0) ? id1 : id2; + sigma *= (idUp > 0) ? openFracPairPos : openFracPairNeg; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2HW::setIdColAcol() { + + // Sign of outgoing W. + int sign = 1 - 2 * (abs(id1)%2); + if (id1 < 0) sign = -sign; + setId( id1, id2, idRes, 24 * sign); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma2ffbar2HW::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // If not decay of W+- created along with Higgs then done. + if (iResBeg != 5 || iResEnd != 6) return 1.; + + // Order so that fbar(1) f(2) -> H() f'(3) fbar'(4). + int i1 = (process[3].id() < 0) ? 3 : 4; + int i2 = 7 - i1; + int i3 = process[6].daughter1(); + int i4 = process[6].daughter2(); + if (process[i3].id() < 0) swap( i3, i4); + + // Evaluate relevant four-products. + double pp13 = process[i1].p() * process[i3].p(); + double pp14 = process[i1].p() * process[i4].p(); + double pp23 = process[i2].p() * process[i3].p(); + double pp24 = process[i2].p() * process[i4].p(); + + // Weight and maximum. + double wt = pp13 * pp24; + double wtMax = (pp13 + pp14) * (pp23 + pp24); + + // Done. + return wt / wtMax; + +} + +//************************************************************************** + +// Sigma3ff2HfftZZ class. +// Cross section for f f' -> H f f' (Z0 Z0 fusion of SM or BSM Higgs). +// (H can be H0 SM or H1, H2, A3 from BSM). + +//********* + +// Initialize process. + +void Sigma3ff2HfftZZ::initProc() { + + // Properties specific to Higgs state. + if (higgsType == 0) { + nameSave = "f f' -> H0 f f'(Z0 Z0 fusion) (SM)"; + codeSave = 906; + idRes = 25; + coup2Z = 1.; + } + else if (higgsType == 1) { + nameSave = "f f' -> h0(H1) f f' (Z0 Z0 fusion)"; + codeSave = 1006; + idRes = 25; + coup2Z = Settings::parm("HiggsH1:coup2Z"); + } + else if (higgsType == 2) { + nameSave = "f f' -> H0(H2) f f' (Z0 Z0 fusion)"; + codeSave = 1026; + idRes = 35; + coup2Z = Settings::parm("HiggsH2:coup2Z"); + } + else if (higgsType == 3) { + nameSave = "f f' -> A0(A3) f f' (Z0 Z0 fusion)"; + codeSave = 1046; + idRes = 36; + coup2Z = Settings::parm("HiggsA3:coup2Z"); + } + + // Common fixed mass and coupling factor. + mZS = pow2( ParticleDataTable::m0(23) ); + prefac = 0.25 * mZS + * pow3( 4. * M_PI / (CoupEW::sin2thetaW() * CoupEW::cos2thetaW()) ); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(idRes); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma3ff2HfftZZ::sigmaKin() { + + // Required four-vector products. + double pp12 = 0.5 * sH; + double pp14 = 0.5 * mH * p4cm.pMinus(); + double pp15 = 0.5 * mH * p5cm.pMinus(); + double pp24 = 0.5 * mH * p4cm.pPlus(); + double pp25 = 0.5 * mH * p5cm.pPlus(); + double pp45 = p4cm * p5cm; + + // Propagator factors and two possible numerators. + double prop = pow2( (2. * pp14 + mZS) * (2. * pp25 + mZS) ); + sigma1 = prefac * pp12 * pp45 / prop; + sigma2 = prefac * pp15 * pp24 / prop; + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma3ff2HfftZZ::sigmaHat() { + + // Flavour-dependent coupling factors for two incoming flavours. + int id1Abs = abs(id1); + int id2Abs = abs(id2); + double lf1S = pow2( CoupEW::lf(id1Abs) ); + double rf1S = pow2( CoupEW::rf(id1Abs) ); + double lf2S = pow2( CoupEW::lf(id2Abs) ); + double rf2S = pow2( CoupEW::rf(id2Abs) ); + double c1 = lf1S * lf2S + rf1S * rf2S; + double c2 = lf1S * rf2S + rf1S * lf2S; + + // Combine couplings and kinematics factors. + double sigma = pow3(alpEM) * (c1 * sigma1 + c2 * sigma2) * pow2(coup2Z); + + // Secondary width for H0, H1, H2 or A3. + sigma *= openFrac; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma3ff2HfftZZ::setIdColAcol() { + + // Trivial flavours: out = in. + setId( id1, id2, idRes, id1, id2); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9 && abs(id2) < 9 && id1*id2 > 0) + setColAcol( 1, 0, 2, 0, 0, 0, 1, 0, 2, 0); + else if (abs(id1) < 9 && abs(id2) < 9) + setColAcol( 1, 0, 0, 2, 0, 0, 1, 0, 0, 2); + else if (abs(id1) < 9) setColAcol( 1, 0, 0, 0, 0, 0, 1, 0, 0, 0); + else if (abs(id2) < 9) setColAcol( 0, 0, 1, 0, 0, 0, 0, 0, 1, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + if ( (abs(id1) < 9 && id1 < 0) || (abs(id1) > 10 && id2 < 0) ) + swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma3ff2HfftZZ::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma3ff2HfftWW class. +// Cross section for f_1 f_2 -> H0 f_3 f_4 (W+ W- fusion of SM or BSM Higgs). + +//********* + +// Initialize process. + +void Sigma3ff2HfftWW::initProc() { + + // Properties specific to Higgs state. + if (higgsType == 0) { + nameSave = "f_1 f_2 -> H0 f_3 f_4 (W+ W- fusion) (SM)"; + codeSave = 907; + idRes = 25; + coup2W = 1.; + } + else if (higgsType == 1) { + nameSave = "f_1 f_2 -> h0(H1) f_3 f_4 (W+ W- fusion)"; + codeSave = 1007; + idRes = 25; + coup2W = Settings::parm("HiggsH1:coup2W"); + } + else if (higgsType == 2) { + nameSave = "f_1 f_2 -> H0(H2) f_3 f_4 (W+ W- fusion)"; + codeSave = 1027; + idRes = 35; + coup2W = Settings::parm("HiggsH2:coup2W"); + } + else if (higgsType == 3) { + nameSave = "f_1 f_2 -> A0(A3) f_3 f_4 (W+ W- fusion)"; + codeSave = 1047; + idRes = 36; + coup2W = Settings::parm("HiggsA3:coup2W"); + } + + // Common fixed mass and coupling factor. + mWS = pow2( ParticleDataTable::m0(24) ); + prefac = mWS * pow3( 4. * M_PI / CoupEW::sin2thetaW() ); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(idRes); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma3ff2HfftWW::sigmaKin() { + + // Required four-vector products. + double pp12 = 0.5 * sH; + double pp14 = 0.5 * mH * p4cm.pMinus(); + double pp25 = 0.5 * mH * p5cm.pPlus(); + double pp45 = p4cm * p5cm; + + // Cross section: kinematics part. Combine with couplings. + double prop = pow2( (2. * pp14 + mWS) * (2. * pp25 + mWS) ); + sigma0 = prefac * pp12 * pp45 * pow2(coup2W) / prop; + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma3ff2HfftWW::sigmaHat() { + + // Some flavour combinations not possible. + int id1Abs = abs(id1); + int id2Abs = abs(id2); + if ( (id1Abs%2 == id2Abs%2 && id1 * id2 > 0) + || (id1Abs%2 != id2Abs%2 && id1 * id2 < 0) ) return 0.; + + // Basic cross section. CKM factors for final states. + double sigma = sigma0 * pow3(alpEM) * VCKM::V2sum(id1Abs) + * VCKM::V2sum(id2Abs); + + // Secondary width for H0, H1, H2 or A3. + sigma *= openFrac; + + // Spin-state extra factor 2 per incoming neutrino. + if (id1Abs == 12 || id1Abs == 14 || id1Abs == 16) sigma *= 2.; + if (id2Abs == 12 || id2Abs == 14 || id2Abs == 16) sigma *= 2.; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma3ff2HfftWW::setIdColAcol() { + + // Pick out-flavours by relative CKM weights. + id4 = VCKM::V2pick(id1); + id5 = VCKM::V2pick(id2); + setId( id1, id2, idRes, id4, id5); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9 && abs(id2) < 9 && id1*id2 > 0) + setColAcol( 1, 0, 2, 0, 0, 0, 1, 0, 2, 0); + else if (abs(id1) < 9 && abs(id2) < 9) + setColAcol( 1, 0, 0, 2, 0, 0, 1, 0, 0, 2); + else if (abs(id1) < 9) setColAcol( 1, 0, 0, 0, 0, 0, 1, 0, 0, 0); + else if (abs(id2) < 9) setColAcol( 0, 0, 1, 0, 0, 0, 0, 0, 1, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + if ( (abs(id1) < 9 && id1 < 0) || (abs(id1) > 10 && id2 < 0) ) + swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma3ff2HfftWW::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma3gg2HQQbar class. +// Cross section for g g -> H0 Q Qbar (Q Qbar fusion of SM or BSM Higgs). + +//********* + +// Initialize process. + +void Sigma3gg2HQQbar::initProc() { + + // Properties specific to Higgs state for the "g g -> H ttbar" process. + // (H can be H0 SM or H1, H2, A3 from BSM). + if (higgsType == 0 && idNew == 6) { + nameSave = "g g -> H t tbar (SM)"; + codeSave = 908; + idRes = 25; + coup2Q = 1.; + } + else if (higgsType == 1 && idNew == 6) { + nameSave = "g g -> h0(H1) t tbar"; + codeSave = 1008; + idRes = 25; + coup2Q = Settings::parm("HiggsH1:coup2u"); + } + else if (higgsType == 2 && idNew == 6) { + nameSave = "g g -> H0(H2) t tbar"; + codeSave = 1028; + idRes = 35; + coup2Q = Settings::parm("HiggsH2:coup2u"); + } + else if (higgsType == 3 && idNew == 6) { + nameSave = "g g -> A0(A3) t tbar"; + codeSave = 1048; + idRes = 36; + coup2Q = Settings::parm("HiggsA3:coup2u"); + } + + // Properties specific to Higgs state for the "g g -> H b bbar" process. + // (H can be H0 SM or H1, H2, A3 from BSM). + if (higgsType == 0 && idNew == 5) { + nameSave = "g g -> H b bbar (SM)"; + codeSave = 912; + idRes = 25; + coup2Q = 1.; + } + else if (higgsType == 1 && idNew == 5) { + nameSave = "g g -> h0(H1) b bbar"; + codeSave = 1012; + idRes = 25; + coup2Q = Settings::parm("HiggsH1:coup2d"); + } + else if (higgsType == 2 && idNew == 5) { + nameSave = "g g -> H0(H2) b bbar"; + codeSave = 1032; + idRes = 35; + coup2Q = Settings::parm("HiggsH2:coup2d"); + } + else if (higgsType == 3 && idNew == 5) { + nameSave = "g g -> A0(A3) b bbar"; + codeSave = 1052; + idRes = 36; + coup2Q = Settings::parm("HiggsA3:coup2d"); + } + + // Common mass and coupling factors. + double mWS = pow2(ParticleDataTable::m0(24)); + prefac = (4. * M_PI / CoupEW::sin2thetaW()) * pow2(4. * M_PI) + * 0.25 / mWS; + + // Secondary open width fraction. + openFracTriplet = ParticleDataTable::resOpenFrac(idRes, idNew, -idNew); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma3gg2HQQbar::sigmaKin() { + + // Running mass of heavy quark. + double mQ2run = pow2( ParticleDataTable::mRun(idNew, mH) ); + + // Linear combination of p_Q and p_Qbar to ensure common mass. + double mQ2 = m4 * m5; + double epsi = 0.; + if (m4 != m5) { + double s45 = (p4cm + p5cm).m2Calc(); + mQ2 = 0.5 * (s4 + s5) - 0.25 * pow2(s4 - s5) / s45; + epsi = 0.5 * (s5 - s4) / s45; + } + + // Set up kinematics: g(4) g(5) -> H(3) Q(1) Qbar(2) in outgoing sense. + Vec4 pTemp[6]; + pTemp[4] = Vec4( 0., 0., -0.5* mH, -0.5* mH); + pTemp[5] = Vec4( 0., 0., 0.5* mH, -0.5* mH); + pTemp[1] = p4cm + epsi * (p4cm + p5cm); + pTemp[2] = p5cm - epsi * (p4cm + p5cm); + pTemp[3] = p3cm; + + // Four-product combinations. + double z1 = pTemp[1] * pTemp[2]; + double z2 = pTemp[1] * pTemp[3]; + double z3 = pTemp[1] * pTemp[4]; + double z4 = pTemp[1] * pTemp[5]; + double z5 = pTemp[2] * pTemp[3]; + double z6 = pTemp[2] * pTemp[4]; + double z7 = pTemp[2] * pTemp[5]; + double z8 = pTemp[3] * pTemp[4]; + double z9 = pTemp[3] * pTemp[5]; + double z10 = pTemp[4] * pTemp[5]; + + // Powers required as shorthand in matriz elements. + double mQ4 = mQ2 * mQ2; + double mQ6 = mQ2 * mQ4; + double z1S = z1 * z1; + double z2S = z2 * z2; + double z3S = z3 * z3; + double z4S = z4 * z4; + double z5S = z5 * z5; + double z6S = z6 * z6; + double z7S = z7 * z7; + double z8S = z8 * z8; + double z9S = z9 * z9; + double z10S = z10 * z10; + + // Evaluate matriz elements for g + g -> Q + Qbar + H. + // (H can be H0 SM or H1, H2, A3 from BSM). + double fm[9][9]; + fm[1][1] = 64*mQ6+16*mQ4*s3+32*mQ4*(z1+2*z2+z4+z9+2* + z7+z5)+8*mQ2*s3*(-z1-z4+2*z7)+16*mQ2*(z2*z9+4*z2* + z7+z2*z5-2*z4*z7-2*z9*z7)+8*s3*z4*z7-16*z2*z9*z7; + fm[1][2] = 16*mQ6+8*mQ4*(-2*z1+z2-2*z3-2*z4-4*z10+z9-z8+2 + *z7-4*z6+z5)+8*mQ2*(-2*z1*z2-2*z2*z4-2*z2*z10+z2*z7-2* + z2*z6-2*z3*z7+2*z4*z7+4*z10*z7-z9*z7-z8*z7)+16*z2*z7*(z4+ + z10); + fm[1][3] = 16*mQ6-4*mQ4*s3+8*mQ4*(-2*z1+2*z2-2*z3-4* + z4-8*z10+z9+z8-2*z7-4*z6+2*z5)-(4*mQ2*s3)*(z1+z4+z10 + +z6)+8*mQ2*(-2*z1*z2-2*z1*z10+z1*z9+z1*z8-2*z1*z5+z2S + -4*z2*z4-5*z2*z10+z2*z8-z2*z7-3*z2*z6+z2*z5+z3*z9+2*z3*z7 + -z3*z5+z4*z8+2*z4*z6-3*z4*z5-5*z10*z5+z9*z8+z9*z6+z9*z5+ + z8*z7-4*z6*z5+z5S)-(16*z2*z5)*(z1+z4+z10+z6); + fm[1][4] = 16*mQ6+4*mQ4*s3+16*mQ4*(-z1+z2-z3-z4+z10- + z9-z8+2*z7+2*z6-z5)+4*mQ2*s3*(z1+z3+z4+z10+2*z7+2*z6 + )+8*mQ2*(4*z1*z10+4*z1*z7+4*z1*z6+2*z2*z10-z2*z9-z2*z8+ + 4*z2*z7+4*z2*z6-z2*z5+4*z10*z5+4*z7*z5+4*z6*z5)-(8*s3* + z1)*(z10+z7+z6)+16*z2*z5*(z10+z7+z6); + fm[1][5] = 8*mQ4*(-2*z1-2*z4+z10-z9)+4*mQ2*(4*z1S-2*z1* + z2+8*z1*z3+6*z1*z10-2*z1*z9+4*z1*z8+4*z1*z7+4*z1*z6+2*z1* + z5+z2*z10+4*z3*z4-z3*z9+2*z3*z7+3*z4*z8-2*z4*z6+2*z4*z5-4 + *z10*z7+3*z10*z5-3*z9*z6+3*z8*z7-4*z7S+4*z7*z5)+8*(z1S + *z9-z1S*z8-z1*z2*z7+z1*z2*z6+z1*z3*z9+z1*z3*z5-z1*z4* + z8-z1*z4*z5+z1*z10*z9+z1*z9*z7+z1*z9*z6-z1*z8*z7-z2*z3*z7 + +z2*z4*z6-z2*z10*z7-z2*z7S+z3*z7*z5-z4*z10*z5-z4*z7*z5- + z4*z6*z5); + fm[1][6] = 16*mQ4*(-4*z1-z4+z9-z7)+4*mQ2*s3*(-2*z1-z4- + z7)+16*mQ2*(-2*z1S-3*z1*z2-2*z1*z4-3*z1*z9-2*z1*z7-3* + z1*z5-2*z2*z4-2*z7*z5)-8*s3*z4*z7+8*(-z1*z2*z9-2*z1*z2 + *z5-z1*z9S-z1*z9*z5+z2S*z7-z2*z4*z5+z2*z9*z7-z2*z7*z5 + +z4*z9*z5+z4*z5S); + fm[1][7] = 8*mQ4*(2*z3+z4+3*z10+z9+2*z8+3*z7+6*z6)+2*mQ2* + s3*(-2*z3-z4+3*z10+3*z7+6*z6)+4*mQ2*(4*z1*z10+4*z1* + z7+8*z1*z6+6*z2*z10+z2*z9+2*z2*z8+6*z2*z7+12*z2*z6-8*z3* + z7+4*z4*z7+4*z4*z6+4*z10*z5+4*z9*z7+4*z9*z6-8*z8*z7+4*z7* + z5+8*z6*z5)+4*s3*(-z1*z10-z1*z7-2*z1*z6+2*z3*z7-z4*z7- + z4*z6)+8*z2*(z10*z5+z9*z7+z9*z6-2*z8*z7+z7*z5+2*z6*z5); + fm[1][8] = 8*mQ4*(2*z3+z4+3*z10+2*z9+z8+3*z7+6*z6)+2*mQ2* + s3*(-2*z3-z4+2*z10+z7+2*z6)+4*mQ2*(4*z1*z10-2*z1*z9+ + 2*z1*z8+4*z1*z7+8*z1*z6+5*z2*z10+2*z2*z9+z2*z8+4*z2*z7+8* + z2*z6-z3*z9-8*z3*z7+2*z3*z5+2*z4*z9-z4*z8+4*z4*z7+4*z4*z6 + +4*z4*z5+5*z10*z5+z9S-z9*z8+2*z9*z7+5*z9*z6+z9*z5-7*z8* + z7+2*z8*z5+2*z7*z5+10*z6*z5)+2*s3*(-z1*z10+z3*z7-2*z4* + z7+z4*z6)+4*(-z1*z9S+z1*z9*z8-2*z1*z9*z5-z1*z8*z5+2*z2* + z10*z5+z2*z9*z7+z2*z9*z6-2*z2*z8*z7+3*z2*z6*z5+z3*z9*z5+ + z3*z5S+z4*z9*z5-2*z4*z8*z5+2*z4*z5S); + fm[2][2] = 16*mQ6+16*mQ4*(-z1+z3-z4-z10+z7-z6)+16*mQ2*( + z3*z10+z3*z7+z3*z6+z4*z7+z10*z7)-16*z3*z10*z7; + fm[2][3] = 16*mQ6+8*mQ4*(-2*z1+z2+2*z3-4*z4-4*z10-z9+z8-2 + *z7-2*z6+z5)+8*mQ2*(-2*z1*z5+4*z3*z10-z3*z9-z3*z8-2*z3* + z7+2*z3*z6+z3*z5-2*z4*z5-2*z10*z5-2*z6*z5)+16*z3*z5*(z10+ + z6); + fm[2][4] = 8*mQ4*(-2*z1-2*z3+z10-z8)+4*mQ2*(4*z1S-2*z1* + z2+8*z1*z4+6*z1*z10+4*z1*z9-2*z1*z8+4*z1*z7+4*z1*z6+2*z1* + z5+z2*z10+4*z3*z4+3*z3*z9-2*z3*z7+2*z3*z5-z4*z8+2*z4*z6-4 + *z10*z6+3*z10*z5+3*z9*z6-3*z8*z7-4*z6S+4*z6*z5)+8*(-z1S + *z9+z1S*z8+z1*z2*z7-z1*z2*z6-z1*z3*z9-z1*z3*z5+z1*z4 + *z8+z1*z4*z5+z1*z10*z8-z1*z9*z6+z1*z8*z7+z1*z8*z6+z2*z3* + z7-z2*z4*z6-z2*z10*z6-z2*z6S-z3*z10*z5-z3*z7*z5-z3*z6* + z5+z4*z6*z5); + fm[2][5] = 16*mQ4*z10+8*mQ2*(2*z1S+2*z1*z3+2*z1*z4+2*z1 + *z10+2*z1*z7+2*z1*z6+z3*z7+z4*z6)+8*(-2*pow3(z1)-2*z1S*z3- + 2*z1S*z4-2*z1S*z10-2*z1S*z7-2*z1S*z6-2*z1*z3*z4- + z1*z3*z10-2*z1*z3*z6-z1*z4*z10-2*z1*z4*z7-z1*z10S-z1* + z10*z7-z1*z10*z6-2*z1*z7*z6+z3S*z7-z3*z4*z7-z3*z4*z6+z3 + *z10*z7+z3*z7S-z3*z7*z6+z4S*z6+z4*z10*z6-z4*z7*z6+z4* + z6S); + fm[2][6] = 8*mQ4*(-2*z1+z10-z9-2*z7)+4*mQ2*(4*z1S+2*z1* + z2+4*z1*z3+4*z1*z4+6*z1*z10-2*z1*z9+4*z1*z8+8*z1*z6-2*z1* + z5+4*z2*z4+3*z2*z10+2*z2*z7-3*z3*z9-2*z3*z7-4*z4S-4*z4* + z10+3*z4*z8+2*z4*z6+z10*z5-z9*z6+3*z8*z7+4*z7*z6)+8*(z1S + *z9-z1S*z8-z1*z2*z7+z1*z2*z6+z1*z3*z9+z1*z3*z5+z1*z4* + z9-z1*z4*z8-z1*z4*z5+z1*z10*z9+z1*z9*z6-z1*z8*z7-z2*z3*z7 + -z2*z4*z7+z2*z4*z6-z2*z10*z7+z3*z7*z5-z4S*z5-z4*z10*z5- + z4*z6*z5); + fm[2][7] = 8*mQ4*(z3+2*z4+3*z10+z7+2*z6)+4*mQ2*(-4*z1*z3- + 2*z1*z4-2*z1*z10+z1*z9-z1*z8-4*z1*z7-2*z1*z6+z2*z3+2*z2* + z4+3*z2*z10+z2*z7+2*z2*z6-6*z3*z4-6*z3*z10-2*z3*z9-2*z3* + z7-4*z3*z6-z3*z5-6*z4S-6*z4*z10-3*z4*z9-z4*z8-4*z4*z7-2 + *z4*z6-2*z4*z5-3*z10*z9-3*z10*z8-6*z10*z7-6*z10*z6+z10*z5 + +z9*z7-2*z8*z7-2*z8*z6-6*z7*z6+z7*z5-6*z6S+2*z6*z5)+4*( + -z1S*z9+z1S*z8-2*z1*z2*z10-3*z1*z2*z7-3*z1*z2*z6+z1* + z3*z9-z1*z3*z5+z1*z4*z9+z1*z4*z8+z1*z4*z5+z1*z10*z9+z1* + z10*z8-z1*z9*z6+z1*z8*z6+z2*z3*z7-3*z2*z4*z7-z2*z4*z6-3* + z2*z10*z7-3*z2*z10*z6-3*z2*z7*z6-3*z2*z6S-2*z3*z4*z5-z3 + *z10*z5-z3*z6*z5-z4S*z5-z4*z10*z5+z4*z6*z5); + fm[2][8] = 8*mQ4*(z3+2*z4+3*z10+z7+2*z6)+4*mQ2*(-4*z1*z3- + 2*z1*z4-2*z1*z10-z1*z9+z1*z8-4*z1*z7-2*z1*z6+z2*z3+2*z2* + z4+z2*z10-z2*z7-2*z2*z6-6*z3*z4-6*z3*z10-2*z3*z9+z3*z8-2* + z3*z7-4*z3*z6+z3*z5-6*z4S-6*z4*z10-2*z4*z9-4*z4*z7-2*z4 + *z6+2*z4*z5-3*z10*z9-3*z10*z8-6*z10*z7-6*z10*z6+3*z10*z5- + z9*z6-2*z8*z7-3*z8*z6-6*z7*z6+z7*z5-6*z6S+2*z6*z5)+4*( + z1S*z9-z1S*z8-z1*z2*z7+z1*z2*z6-3*z1*z3*z5+z1*z4*z9- + z1*z4*z8-3*z1*z4*z5+z1*z10*z9+z1*z10*z8-2*z1*z10*z5+z1*z9 + *z6+z1*z8*z7+z1*z8*z6-z2*z4*z7+z2*z4*z6-z2*z10*z7-z2*z10* + z6-2*z2*z7*z6-z2*z6S-3*z3*z4*z5-3*z3*z10*z5+z3*z7*z5-3* + z3*z6*z5-3*z4S*z5-3*z4*z10*z5-z4*z6*z5); + fm[3][3] = 64*mQ6+16*mQ4*s3+32*mQ4*(z1+z2+2*z3+z8+z6 + +2*z5)+8*mQ2*s3*(-z1+2*z3-z6)+16*mQ2*(z2*z5-2*z3* + z8-2*z3*z6+4*z3*z5+z8*z5)+8*s3*z3*z6-16*z3*z8*z5; + fm[3][4] = 16*mQ4*(-4*z1-z3+z8-z6)+4*mQ2*s3*(-2*z1-z3- + z6)+16*mQ2*(-2*z1S-3*z1*z2-2*z1*z3-3*z1*z8-2*z1*z6-3* + z1*z5-2*z2*z3-2*z6*z5)-8*s3*z3*z6+8*(-z1*z2*z8-2*z1*z2 + *z5-z1*z8S-z1*z8*z5+z2S*z6-z2*z3*z5+z2*z8*z6-z2*z6*z5 + +z3*z8*z5+z3*z5S); + fm[3][5] = 8*mQ4*(-2*z1+z10-z8-2*z6)+4*mQ2*(4*z1S+2*z1* + z2+4*z1*z3+4*z1*z4+6*z1*z10+4*z1*z9-2*z1*z8+8*z1*z7-2*z1* + z5+4*z2*z3+3*z2*z10+2*z2*z6-4*z3S-4*z3*z10+3*z3*z9+2*z3 + *z7-3*z4*z8-2*z4*z6+z10*z5+3*z9*z6-z8*z7+4*z7*z6)+8*(-z1S + *z9+z1S*z8+z1*z2*z7-z1*z2*z6-z1*z3*z9+z1*z3*z8-z1*z3 + *z5+z1*z4*z8+z1*z4*z5+z1*z10*z8-z1*z9*z6+z1*z8*z7+z2*z3* + z7-z2*z3*z6-z2*z4*z6-z2*z10*z6-z3S*z5-z3*z10*z5-z3*z7* + z5+z4*z6*z5); + fm[3][6] = 16*mQ6+4*mQ4*s3+16*mQ4*(-z1-z2+2*z3+2*z4+ + z10-z9-z8-z7-z6+z5)+4*mQ2*s3*(z1+2*z3+2*z4+z10+z7+z6 + )+8*mQ2*(4*z1*z3+4*z1*z4+4*z1*z10+4*z2*z3+4*z2*z4+4*z2* + z10-z2*z5+4*z3*z5+4*z4*z5+2*z10*z5-z9*z5-z8*z5)-(8*s3* + z1)*(z3+z4+z10)+16*z2*z5*(z3+z4+z10); + fm[3][7] = 8*mQ4*(3*z3+6*z4+3*z10+z9+2*z8+2*z7+z6)+2*mQ2* + s3*(z3+2*z4+2*z10-2*z7-z6)+4*mQ2*(4*z1*z3+8*z1*z4+4* + z1*z10+2*z1*z9-2*z1*z8+2*z2*z3+10*z2*z4+5*z2*z10+2*z2*z9+ + z2*z8+2*z2*z7+4*z2*z6-7*z3*z9+2*z3*z8-8*z3*z7+4*z3*z6+4* + z3*z5+5*z4*z8+4*z4*z6+8*z4*z5+5*z10*z5-z9*z8-z9*z6+z9*z5+ + z8S-z8*z7+2*z8*z6+2*z8*z5)+2*s3*(-z1*z10+z3*z7-2*z3* + z6+z4*z6)+4*(-z1*z2*z9-2*z1*z2*z8+z1*z9*z8-z1*z8S+z2S + *z7+2*z2S*z6+3*z2*z4*z5+2*z2*z10*z5-2*z2*z9*z6+z2*z8*z7 + +z2*z8*z6-2*z3*z9*z5+z3*z8*z5+z4*z8*z5); + fm[3][8] = 8*mQ4*(3*z3+6*z4+3*z10+2*z9+z8+2*z7+z6)+2*mQ2* + s3*(3*z3+6*z4+3*z10-2*z7-z6)+4*mQ2*(4*z1*z3+8*z1*z4+ + 4*z1*z10+4*z2*z3+8*z2*z4+4*z2*z10-8*z3*z9+4*z3*z8-8*z3*z7 + +4*z3*z6+6*z3*z5+4*z4*z8+4*z4*z6+12*z4*z5+6*z10*z5+2*z9* + z5+z8*z5)+4*s3*(-z1*z3-2*z1*z4-z1*z10+2*z3*z7-z3*z6-z4 + *z6)+8*z5*(z2*z3+2*z2*z4+z2*z10-2*z3*z9+z3*z8+z4*z8); + fm[4][4] = 64*mQ6+16*mQ4*s3+32*mQ4*(z1+2*z2+z3+z8+2* + z6+z5)+8*mQ2*s3*(-z1-z3+2*z6)+16*mQ2*(z2*z8+4*z2* + z6+z2*z5-2*z3*z6-2*z8*z6)+8*s3*z3*z6-16*z2*z8*z6; + fm[4][5] = 16*mQ6+8*mQ4*(-2*z1+z2-2*z3-2*z4-4*z10-z9+z8-4 + *z7+2*z6+z5)+8*mQ2*(-2*z1*z2-2*z2*z3-2*z2*z10-2*z2*z7+ + z2*z6+2*z3*z6-2*z4*z6+4*z10*z6-z9*z6-z8*z6)+16*z2*z6*(z3+ + z10); + fm[4][6] = 16*mQ6-4*mQ4*s3+8*mQ4*(-2*z1+2*z2-4*z3-2* + z4-8*z10+z9+z8-4*z7-2*z6+2*z5)-(4*mQ2*s3)*(z1+z3+z10 + +z7)+8*mQ2*(-2*z1*z2-2*z1*z10+z1*z9+z1*z8-2*z1*z5+z2S + -4*z2*z3-5*z2*z10+z2*z9-3*z2*z7-z2*z6+z2*z5+z3*z9+2*z3*z7 + -3*z3*z5+z4*z8+2*z4*z6-z4*z5-5*z10*z5+z9*z8+z9*z6+z8*z7+ + z8*z5-4*z7*z5+z5S)-(16*z2*z5)*(z1+z3+z10+z7); + fm[4][7] = 8*mQ4*(-z3-2*z4-3*z10-2*z9-z8-6*z7-3*z6)+2*mQ2 + *s3*(z3+2*z4-3*z10-6*z7-3*z6)+4*mQ2*(-4*z1*z10-8*z1* + z7-4*z1*z6-6*z2*z10-2*z2*z9-z2*z8-12*z2*z7-6*z2*z6-4*z3* + z7-4*z3*z6+8*z4*z6-4*z10*z5+8*z9*z6-4*z8*z7-4*z8*z6-8*z7* + z5-4*z6*z5)+4*s3*(z1*z10+2*z1*z7+z1*z6+z3*z7+z3*z6-2* + z4*z6)+8*z2*(-z10*z5+2*z9*z6-z8*z7-z8*z6-2*z7*z5-z6*z5); + fm[4][8] = 8*mQ4*(-z3-2*z4-3*z10-z9-2*z8-6*z7-3*z6)+2*mQ2 + *s3*(z3+2*z4-2*z10-2*z7-z6)+4*mQ2*(-4*z1*z10-2*z1*z9 + +2*z1*z8-8*z1*z7-4*z1*z6-5*z2*z10-z2*z9-2*z2*z8-8*z2*z7-4 + *z2*z6+z3*z9-2*z3*z8-4*z3*z7-4*z3*z6-4*z3*z5+z4*z8+8*z4* + z6-2*z4*z5-5*z10*z5+z9*z8+7*z9*z6-2*z9*z5-z8S-5*z8*z7-2 + *z8*z6-z8*z5-10*z7*z5-2*z6*z5)+2*s3*(z1*z10-z3*z7+2*z3 + *z6-z4*z6)+4*(-z1*z9*z8+z1*z9*z5+z1*z8S+2*z1*z8*z5-2*z2 + *z10*z5+2*z2*z9*z6-z2*z8*z7-z2*z8*z6-3*z2*z7*z5+2*z3*z9* + z5-z3*z8*z5-2*z3*z5S-z4*z8*z5-z4*z5S); + fm[5][5] = 16*mQ6+16*mQ4*(-z1-z3+z4-z10-z7+z6)+16*mQ2*( + z3*z6+z4*z10+z4*z7+z4*z6+z10*z6)-16*z4*z10*z6; + fm[5][6] = 16*mQ6+8*mQ4*(-2*z1+z2-4*z3+2*z4-4*z10+z9-z8-2 + *z7-2*z6+z5)+8*mQ2*(-2*z1*z5-2*z3*z5+4*z4*z10-z4*z9-z4* + z8+2*z4*z7-2*z4*z6+z4*z5-2*z10*z5-2*z7*z5)+16*z4*z5*(z10+ + z7); + fm[5][7] = 8*mQ4*(-2*z3-z4-3*z10-2*z7-z6)+4*mQ2*(2*z1*z3+ + 4*z1*z4+2*z1*z10+z1*z9-z1*z8+2*z1*z7+4*z1*z6-2*z2*z3-z2* + z4-3*z2*z10-2*z2*z7-z2*z6+6*z3S+6*z3*z4+6*z3*z10+z3*z9+ + 3*z3*z8+2*z3*z7+4*z3*z6+2*z3*z5+6*z4*z10+2*z4*z8+4*z4*z7+ + 2*z4*z6+z4*z5+3*z10*z9+3*z10*z8+6*z10*z7+6*z10*z6-z10*z5+ + 2*z9*z7+2*z9*z6-z8*z6+6*z7S+6*z7*z6-2*z7*z5-z6*z5)+4*(- + z1S*z9+z1S*z8+2*z1*z2*z10+3*z1*z2*z7+3*z1*z2*z6-z1*z3 + *z9-z1*z3*z8-z1*z3*z5-z1*z4*z8+z1*z4*z5-z1*z10*z9-z1*z10* + z8-z1*z9*z7+z1*z8*z7+z2*z3*z7+3*z2*z3*z6-z2*z4*z6+3*z2* + z10*z7+3*z2*z10*z6+3*z2*z7S+3*z2*z7*z6+z3S*z5+2*z3*z4 + *z5+z3*z10*z5-z3*z7*z5+z4*z10*z5+z4*z7*z5); + fm[5][8] = 8*mQ4*(-2*z3-z4-3*z10-2*z7-z6)+4*mQ2*(2*z1*z3+ + 4*z1*z4+2*z1*z10-z1*z9+z1*z8+2*z1*z7+4*z1*z6-2*z2*z3-z2* + z4-z2*z10+2*z2*z7+z2*z6+6*z3S+6*z3*z4+6*z3*z10+2*z3*z8+ + 2*z3*z7+4*z3*z6-2*z3*z5+6*z4*z10-z4*z9+2*z4*z8+4*z4*z7+2* + z4*z6-z4*z5+3*z10*z9+3*z10*z8+6*z10*z7+6*z10*z6-3*z10*z5+ + 3*z9*z7+2*z9*z6+z8*z7+6*z7S+6*z7*z6-2*z7*z5-z6*z5)+4*( + z1S*z9-z1S*z8-z1*z2*z7+z1*z2*z6+z1*z3*z9-z1*z3*z8+3* + z1*z3*z5+3*z1*z4*z5-z1*z10*z9-z1*z10*z8+2*z1*z10*z5-z1*z9 + *z7-z1*z9*z6-z1*z8*z7-z2*z3*z7+z2*z3*z6+z2*z10*z7+z2*z10* + z6+z2*z7S+2*z2*z7*z6+3*z3S*z5+3*z3*z4*z5+3*z3*z10*z5+ + z3*z7*z5+3*z4*z10*z5+3*z4*z7*z5-z4*z6*z5); + fm[6][6] = 64*mQ6+16*mQ4*s3+32*mQ4*(z1+z2+2*z4+z9+z7 + +2*z5)+8*mQ2*s3*(-z1+2*z4-z7)+16*mQ2*(z2*z5-2*z4* + z9-2*z4*z7+4*z4*z5+z9*z5)+8*s3*z4*z7-16*z4*z9*z5; + fm[6][7] = 8*mQ4*(-6*z3-3*z4-3*z10-2*z9-z8-z7-2*z6)+2*mQ2 + *s3*(-2*z3-z4-2*z10+z7+2*z6)+4*mQ2*(-8*z1*z3-4*z1*z4 + -4*z1*z10+2*z1*z9-2*z1*z8-10*z2*z3-2*z2*z4-5*z2*z10-z2*z9 + -2*z2*z8-4*z2*z7-2*z2*z6-5*z3*z9-4*z3*z7-8*z3*z5-2*z4*z9+ + 7*z4*z8-4*z4*z7+8*z4*z6-4*z4*z5-5*z10*z5-z9S+z9*z8-2*z9 + *z7+z9*z6-2*z9*z5+z8*z7-z8*z5)+2*s3*(z1*z10-z3*z7+2*z4 + *z7-z4*z6)+4*(2*z1*z2*z9+z1*z2*z8+z1*z9S-z1*z9*z8-2* + z2S*z7-z2S*z6-3*z2*z3*z5-2*z2*z10*z5-z2*z9*z7-z2*z9*z6+ + 2*z2*z8*z7-z3*z9*z5-z4*z9*z5+2*z4*z8*z5); + fm[6][8] = 8*mQ4*(-6*z3-3*z4-3*z10-z9-2*z8-z7-2*z6)+2*mQ2 + *s3*(-6*z3-3*z4-3*z10+z7+2*z6)+4*mQ2*(-8*z1*z3-4*z1* + z4-4*z1*z10-8*z2*z3-4*z2*z4-4*z2*z10-4*z3*z9-4*z3*z7-12* + z3*z5-4*z4*z9+8*z4*z8-4*z4*z7+8*z4*z6-6*z4*z5-6*z10*z5-z9 + *z5-2*z8*z5)+4*s3*(2*z1*z3+z1*z4+z1*z10+z3*z7+z4*z7-2* + z4*z6)+8*z5*(-2*z2*z3-z2*z4-z2*z10-z3*z9-z4*z9+2*z4*z8); + fm[7][7] = 72*mQ4*z10+18*mQ2*s3*z10+8*mQ2*(z1*z10+9* + z2*z10+7*z3*z7+2*z3*z6+2*z4*z7+7*z4*z6+z10*z5+2*z9*z7+7* + z9*z6+7*z8*z7+2*z8*z6)+2*s3*(-z1*z10-7*z3*z7-2*z3*z6-2 + *z4*z7-7*z4*z6)+4*z2*(z10*z5+2*z9*z7+7*z9*z6+7*z8*z7+2*z8 + *z6); + fm[7][8] = 72*mQ4*z10+2*mQ2*s3*z10+4*mQ2*(2*z1*z10+ + 10*z2*z10+7*z3*z9+2*z3*z8+14*z3*z7+4*z3*z6+2*z4*z9+7*z4* + z8+4*z4*z7+14*z4*z6+10*z10*z5+z9S+7*z9*z8+2*z9*z7+7*z9* + z6+z8S+7*z8*z7+2*z8*z6)+2*s3*(7*z1*z10-7*z3*z7-2*z3* + z6-2*z4*z7-7*z4*z6)+2*(-2*z1*z9S-14*z1*z9*z8-2*z1*z8S + +2*z2*z10*z5+2*z2*z9*z7+7*z2*z9*z6+7*z2*z8*z7+2*z2*z8*z6+ + 7*z3*z9*z5+2*z3*z8*z5+2*z4*z9*z5+7*z4*z8*z5); + fm[8][8] = 72*mQ4*z10+18*mQ2*s3*z10+8*mQ2*(z1*z10+z2 + *z10+7*z3*z9+2*z3*z8+7*z3*z7+2*z3*z6+2*z4*z9+7*z4*z8+2*z4 + *z7+7*z4*z6+9*z10*z5)+2*s3*(-z1*z10-7*z3*z7-2*z3*z6-2* + z4*z7-7*z4*z6)+4*z5*(z2*z10+7*z3*z9+2*z3*z8+2*z4*z9+7*z4* + z8); + double fm99 = -4*mQ4*z10-mQ2*s3*z10+4*mQ2*(-z1*z10-z2*z10+ + z3*z7+z4*z6-z10*z5+z9*z6+z8*z7)+s3*(z1*z10-z3*z7-z4*z6 + )+2*z2*(-z10*z5+z9*z6+z8*z7); + double fm910 = -4*mQ4*z10-mQ2*s3*z10+2*mQ2*(-2*z1*z10-2*z2* + z10+2*z3*z9+2*z3*z7+2*z4*z6-2*z10*z5+z9*z8+2*z8*z7)+s3 + *(z1*z10-z3*z7-z4*z6)+2*(-z1*z9*z8-z2*z10*z5+z2*z8*z7+z3* + z9*z5); + double fmxx = -4*mQ4*z10-mQ2*s3*z10+2*mQ2*(-2*z1*z10-2*z2* + z10+2*z4*z8+2*z4*z6+2*z3*z7-2*z10*z5+z9*z8+2*z9*z6)+s3 + *(z1*z10-z3*z7-z4*z6)+2*(-z1*z9*z8-z2*z10*z5+z2*z9*z6+z4* + z8*z5); + fm910 = 0.5*(fmxx+fm910); + double fm1010 = -4*mQ4*z10-mQ2*s3*z10+4*mQ2*(-z1*z10-z2*z10+ + z3*z7+z4*z6-z10*z5+z9*z3+z8*z4)+s3*(z1*z10-z3*z7-z4*z6 + )+2*z5*(-z10*z2+z9*z3+z8*z4); + fm[7][7] -= 2. * fm99; + fm[7][8] -= 2. * fm910; + fm[8][8] -= 2. * fm1010; + + // Propagators. + double ss1 = (pTemp[1] + pTemp[3]).m2Calc() - mQ2; + double ss2 = (pTemp[1] + pTemp[4]).m2Calc() - mQ2; + double ss3 = (pTemp[1] + pTemp[5]).m2Calc() - mQ2; + double ss4 = (pTemp[2] + pTemp[3]).m2Calc() - mQ2; + double ss5 = (pTemp[2] + pTemp[4]).m2Calc() - mQ2; + double ss6 = (pTemp[2] + pTemp[5]).m2Calc() - mQ2; + double ss7 = sH; + + // Propagator combinations. + double dz[9]; + dz[1] = ss1 * ss6; + dz[2] = ss2 * ss6; + dz[3] = ss2 * ss4; + dz[4] = ss1 * ss5; + dz[5] = ss3 * ss5; + dz[6] = ss3 * ss4; + dz[7] = ss7 * ss1; + dz[8] = ss7 * ss4; + + // Colour factors. + double clr[9][9]; + for (int i = 1; i < 4; ++i) + for (int j = 1; j < 4; ++j) { + clr[i][j] = 16. / 3.; + clr[i][j+3] = -2. / 3.; + clr[i+3][j] = -2. / 3.; + clr[i+3][j+3] = 16. / 3.; + } + for (int i = 1; i < 4; ++i) + for (int j = 1; j < 3; ++j) { + clr[i][j+6] = -6.; + clr[i+3][j+6] = 6.; + clr[j+6][i] = -6.; + clr[j+6][i+3] = 6.; + } + for (int i = 1; i < 3; ++i) + for (int j = 1; j < 3; ++j) + clr[i+6][j+6] = 12.; + + // Produce final result: matrix elements * colours * propagators. + double wtSum = 0.; + for (int i = 1; i < 9; ++i) + for (int j = i; j < 9; ++j) { + double fac = (j == i) ? 4. : 8.; + wtSum += fm[i][j] * fac * clr[i][j] / (dz[i] * dz[j]); + } + wtSum *= -1./256.; + + // Combine factors. + sigma = prefac * alpEM * pow2(alpS) * mQ2run * wtSum *pow2(coup2Q); + + // Secondary width for H, Q and Qbar (latter for top only). + // (H can be H0 SM or H1, H2, A3 from BSM). + sigma *= openFracTriplet; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma3gg2HQQbar::setIdColAcol() { + + // Pick out-flavours by relative CKM weights. + setId( id1, id2, idRes, idNew, -idNew); + + // Colour flow topologies. + if (Rndm::flat() < 0.5) setColAcol( 1, 2, 2, 3, 0, 0, 1, 0, 0, 3); + else setColAcol( 1, 2, 3, 1, 0, 0, 3, 0, 0, 2); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma3gg2HQQbar::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma3qqbar2HQQbar class. +// Cross section for q qbar -> H0 Q Qbar (Q Qbar fusion of SM Higgs). +// REDUCE output and part of the rest courtesy Z. Kunszt, +// see Z. Kunszt, Nucl. Phys. B247 (1984) 339. + +//********* + +// Initialize process. + +void Sigma3qqbar2HQQbar::initProc() { + + // Properties specific to Higgs state for the "q qbar -> H ttbar" process. + // (H can be H0 SM or H1, H2, A3 from BSM). + + if (higgsType == 0 && idNew == 6) { + nameSave = "q qbar -> H t tbar (SM)"; + codeSave = 909; + idRes = 25; + coup2Q = 1.; + } + else if (higgsType == 1 && idNew == 6) { + nameSave = "q qbar -> h0(H1) t tbar"; + codeSave = 1009; + idRes = 25; + coup2Q = Settings::parm("HiggsH1:coup2u"); + } + else if (higgsType == 2 && idNew == 6) { + nameSave = "q qbar -> H0(H2) t tbar"; + codeSave = 1029; + idRes = 35; + coup2Q = Settings::parm("HiggsH2:coup2u"); + } + else if (higgsType == 3 && idNew == 6) { + nameSave = "q qbar -> A0(A3) t tbar"; + codeSave = 1049; + idRes = 36; + coup2Q = Settings::parm("HiggsA3:coup2u"); + } + + // Properties specific to Higgs state for the "q qbar -> H b bbar" process. + // (H can be H0 SM or H1, H2, A3 from BSM). + if (higgsType == 0 && idNew == 5) { + nameSave = "q qbar -> H b bbar (SM)"; + codeSave = 913; + idRes = 25; + coup2Q = 1.; + } + else if (higgsType == 1 && idNew == 5) { + nameSave = "q qbar -> h0(H1) b bbar"; + codeSave = 1013; + idRes = 25; + coup2Q = Settings::parm("HiggsH1:coup2d"); + } + else if (higgsType == 2 && idNew == 5) { + nameSave = "q qbar -> H0(H2) b bbar"; + codeSave = 1033; + idRes = 35; + coup2Q = Settings::parm("HiggsH2:coup2d"); + } + else if (higgsType == 3 && idNew == 5) { + nameSave = "q qbar -> A0(A3) b bbar"; + codeSave = 1053; + idRes = 36; + coup2Q = Settings::parm("HiggsA3:coup2d"); + } + + // Common mass and coupling factors. + double mWS = pow2(ParticleDataTable::m0(24)); + prefac = (4. * M_PI / CoupEW::sin2thetaW()) * pow2(4. * M_PI) + * 0.25 / mWS; + + // Secondary open width fraction. + openFracTriplet = ParticleDataTable::resOpenFrac(idRes, idNew, -idNew); + +} + +//********* + +// Evaluate sigma(sHat), part independent of incoming flavour. + +void Sigma3qqbar2HQQbar::sigmaKin() { + + // Running mass of heavy quark. + double mQ2run = pow2( ParticleDataTable::mRun(idNew, mH) ); + + // Linear combination of p_Q and p_Qbar to ensure common mass. + double mQ2 = m4 * m5; + double epsi = 0.; + if (m4 != m5) { + double s45 = (p4cm + p5cm).m2Calc(); + mQ2 = 0.5 * (s4 + s5) - 0.25 * pow2(s4 - s5) / s45; + epsi = 0.5 * (s5 - s4) / s45; + } + + // Set up kinematics: q(4) qbar(5) -> H(3) Q(1) Qbar(2) in outgoing sense. + Vec4 pTemp[6]; + pTemp[4] = Vec4( 0., 0., -0.5* mH, -0.5* mH); + pTemp[5] = Vec4( 0., 0., 0.5* mH, -0.5* mH); + pTemp[1] = p4cm + epsi * (p4cm + p5cm); + pTemp[2] = p5cm - epsi * (p4cm + p5cm); + pTemp[3] = p3cm; + + // Four-product combinations. + double z1 = pTemp[1] * pTemp[2]; + double z2 = pTemp[1] * pTemp[3]; + double z3 = pTemp[1] * pTemp[4]; + double z4 = pTemp[1] * pTemp[5]; + double z5 = pTemp[2] * pTemp[3]; + double z6 = pTemp[2] * pTemp[4]; + double z7 = pTemp[2] * pTemp[5]; + double z8 = pTemp[3] * pTemp[4]; + double z9 = pTemp[3] * pTemp[5]; + double z10 = pTemp[4] * pTemp[5]; + + // Powers required as shorthand in matriz elements. + double mQ4 = mQ2 * mQ2; + + // Evaluate matrix elements for q + qbar -> Q + Qbar + H. + // (H can be H0 SM or H1, H2, A3 from BSM). + double a11 = -8.*mQ4*z10-2.*mQ2*s3*z10-(8.*mQ2)*(z2*z10+z3 + *z7+z4*z6+z9*z6+z8*z7)+2.*s3*(z3*z7+z4*z6)-(4.*z2)*(z9 + *z6+z8*z7); + double a12 = -8.*mQ4*z10+4.*mQ2*(-z2*z10-z3*z9-2.*z3*z7-z4*z8- + 2.*z4*z6-z10*z5-z9*z8-z9*z6-z8*z7)+2.*s3*(-z1*z10+z3*z7 + +z4*z6)+2.*(2.*z1*z9*z8-z2*z9*z6-z2*z8*z7-z3*z9*z5-z4*z8* + z5); + double a22 = -8.*mQ4*z10-2.*mQ2*s3*z10-(8.*mQ2)*(z3*z9+z3* + z7+z4*z8+z4*z6+z10*z5)+2.*s3*(z3*z7+z4*z6)-(4.*z5)*(z3 + *z9+z4*z8); + + // Propagators and propagator combinations. + double ss1 = (pTemp[1] + pTemp[3]).m2Calc() - mQ2; + double ss4 = (pTemp[2] + pTemp[3]).m2Calc() - mQ2; + double ss7 = sH; + double dz7 = ss7 * ss1; + double dz8 = ss7 * ss4; + + // Produce final result: matrix elements * propagators. + a11 /= (dz7 * dz7); + a12 /= (dz7 * dz8); + a22 /= (dz8 * dz8); + double wtSum = -(a11 + a22 + 2.*a12) * (8./9.); + + // Combine factors. + sigma = prefac * alpEM * pow2(alpS) * mQ2run * wtSum * pow2(coup2Q); + + // Secondary width for H, Q and Qbar (latter for top only). + // (H can be H0 SM or H1, H2, A3 from BSM). + sigma *= openFracTriplet; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma3qqbar2HQQbar::setIdColAcol() { + + // Pick out-flavours by relative CKM weights. + setId( id1, id2, idRes, idNew, -idNew); + + // Colour flow topologies. + if (id1 > 0) setColAcol( 1, 0, 0, 2, 0, 0, 1, 0, 0, 2); + else setColAcol( 0, 1, 2, 0, 0, 0, 2, 0, 0, 1); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma3qqbar2HQQbar::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma2qg2Hq class. +// Cross section for q g -> H q. +// (H can be H0 SM or H1, H2, A3 from BSM). + +//********* + +// Initialize process. + +void Sigma2qg2Hq::initProc() { + + // Properties specific to Higgs state for the "c g -> H c" process. + // (H can be H0 SM or H1, H2, A3 from BSM). + if (higgsType == 0 && idNew == 4) { + nameSave = "c g -> H c (SM)"; + codeSave = 911; + idRes = 25; + } + else if (higgsType == 1 && idNew == 4) { + nameSave = "c g -> h0(H1) c"; + codeSave = 1011; + idRes = 25; + } + else if (higgsType == 2 && idNew == 4) { + nameSave = "c g -> H0(H2) c"; + codeSave = 1031; + idRes = 35; + } + else if (higgsType == 3 && idNew == 4) { + nameSave = "c g -> A0(A3) c"; + codeSave = 1051; + idRes = 36; + } + + // Properties specific to Higgs state for the "b g -> H b" process. + // (H can be H0 SM or H1, H2, A3 from BSM). + if (higgsType == 0 && idNew == 5) { + nameSave = "b g -> H b (SM)"; + codeSave = 911; + idRes = 25; + } + else if (higgsType == 1 && idNew == 5) { + nameSave = "b g -> h0(H1) b"; + codeSave = 1011; + idRes = 25; + } + else if (higgsType == 2 && idNew == 5) { + nameSave = "b g -> H0(H2) b"; + codeSave = 1031; + idRes = 35; + } + else if (higgsType == 3 && idNew == 5) { + nameSave = "b g -> A0(A3) b"; + codeSave = 1051; + idRes = 36; + } + + // Standard parameters. + m2W = pow2( ParticleDataTable::m0(24) ); + thetaWRat = 1. / (24. * CoupEW::sin2thetaW()); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(idRes); + + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2qg2Hq::sigmaKin() { + + // Running mass provides coupling. + double m2Run = pow2( ParticleDataTable::mRun(idNew, mH) ); + + // Cross section, including couplings and kinematics. + sigma = (M_PI / sH2) * alpS * alpEM * thetaWRat * (m2Run/m2W) + * (sH / (s4 - uH) + 2. * s4 * (s3 - uH) / pow2(s4 - uH) + + (s4 - uH) / sH - 2. * s4 / (s4 - uH) + + 2. * (s3 - uH) * (s3 - s4 - sH) / ((s4 - uH) * sH) ); + + // Include secondary width for H0, H1, H2 or A3. Done. + sigma *= openFrac; + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma2qg2Hq::sigmaHat() { + + // Check that specified flavour present. + if (abs(id1) != idNew && abs(id2) != idNew) return 0.; + + // Answer. + return sigma; + +} + + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qg2Hq::setIdColAcol() { + + // Flavour set up for q g -> H0 q. + int idq = (id2 == 21) ? id1 : id2; + setId( id1, id2, idRes, idq); + + // tH defined between f and f': must swap tHat <-> uHat if q g in. + swapTU = (id2 == 21); + + // Colour flow topologies. Swap when antiquarks. + if (id2 == 21) setColAcol( 1, 0, 2, 1, 0, 0, 2, 0); + else setColAcol( 2, 1, 1, 0, 0, 0, 2, 0); + if (idq < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma2qg2Hq::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma2gg2Hglt class. +// Cross section for g g -> H g (H SM Higgs or BSM Higgs) via top loop. +// (H can be H0 SM or H1, H2, A3 from BSM). + +//********* + +// Initialize process. + +void Sigma2gg2Hglt::initProc() { + + // Properties specific to Higgs state. + if (higgsType == 0) { + nameSave = "g g -> H g (SM; top loop)"; + codeSave = 914; + idRes = 25; + } + else if (higgsType == 1) { + nameSave = "g g -> h0(H1) g (BSM; top loop)"; + codeSave = 1014; + idRes = 25; + } + else if (higgsType == 2) { + nameSave = "g g -> H0(H2) g (BSM; top loop)"; + codeSave = 1034; + idRes = 35; + } + else if (higgsType == 3) { + nameSave = "g g -> A0(A3) g (BSM; top loop)"; + codeSave = 1054; + idRes = 36; + } + + // Normalization factor by g g -> H partial width. + // (H can be H0 SM or H1, H2, A3 from BSM). + double mHiggs = ParticleDataTable::m0(idRes); + widHgg = ParticleDataTable::resWidthChan(idRes, mHiggs, 21, 21); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(idRes); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2gg2Hglt::sigmaKin() { + + // Evaluate cross section. Secondary width for H0, H1, H2 or A3. + sigma = (M_PI / sH2) * (3. / 16.) * alpS * (widHgg / m3) + * (sH2 * sH2 + tH2 * tH2 + uH2 * uH2 + pow4(s3)) + / (sH * tH * uH * s3); + sigma *= openFrac; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2gg2Hglt::setIdColAcol() { + + // Flavour set up for g g -> H g trivial. + // (H can be H0 SM or H1, H2, A3 from BSM). + setId( 21, 21, idRes, 21); + + // Colour flow topologies: random choice between two mirrors. + if (Rndm::flat() < 0.5) setColAcol( 1, 2, 2, 3, 0, 0, 1, 3); + else setColAcol( 1, 2, 3, 1, 0, 0, 3, 2); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma2gg2Hglt::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma2qg2Hqlt class. +// Cross section for q g -> H q (H SM or BSM Higgs) via top loop. +// (H can be H0 SM or H1, H2, A3 from BSM). + +//********* + +// Initialize process. + +void Sigma2qg2Hqlt::initProc() { + + // Properties specific to Higgs state. + if (higgsType == 0) { + nameSave = "q g -> H q (SM; top loop)"; + codeSave = 915; + idRes = 25; + } + else if (higgsType == 1) { + nameSave = "q g -> h0(H1) q (BSM; top loop)"; + codeSave = 1015; + idRes = 25; + } + else if (higgsType == 2) { + nameSave = "q g -> H0(H2) q (BSM; top loop)"; + codeSave = 1035; + idRes = 35; + } + else if (higgsType == 3) { + nameSave = "q g -> A0(A3) q (BSM; top loop)"; + codeSave = 1055; + idRes = 36; + } + + // Normalization factor by g g -> H partial width. + // (H can be H0 SM or H1, H2, A3 from BSM). + double mHiggs = ParticleDataTable::m0(idRes); + widHgg = ParticleDataTable::resWidthChan(idRes, mHiggs, 21, 21); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(idRes); + +} + +//********* + +// Evaluate sigmaHat(sHat, part independent of incoming flavour). + +void Sigma2qg2Hqlt::sigmaKin() { + + // Evaluate cross section. Secondary width for H0, H1, H2 or A3. + sigma = (M_PI / sH2) * (1. / 12.) * alpS * (widHgg / m3) + * (sH2 + uH2) / (-tH * s3); + sigma *= openFrac; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qg2Hqlt::setIdColAcol() { + + // Flavour set up for q g -> H q. + // (H can be H0 SM or H1, H2, A3 from BSM). + int idq = (id2 == 21) ? id1 : id2; + setId( id1, id2, idRes, idq); + + // tH defined between f and f': must swap tHat <-> uHat if q g in. + swapTU = (id2 == 21); + + // Colour flow topologies. Swap when antiquarks. + if (id2 == 21) setColAcol( 1, 0, 2, 1, 0, 0, 2, 0); + else setColAcol( 2, 1, 1, 0, 0, 0, 2, 0); + if (idq < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma2qg2Hqlt::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma2qqbar2Hglt class. +// Cross section for q qbar -> H g (H SM or BSM Higgs) via top loop. +// (H can be H0 SM or H1, H2, A3 from BSM). + +//********* + +// Initialize process. + +void Sigma2qqbar2Hglt::initProc() { + + // Properties specific to Higgs state. + if (higgsType == 0) { + nameSave = "q qbar -> H g (SM; top loop)"; + codeSave = 916; + idRes = 25; + } + else if (higgsType == 1) { + nameSave = "q qbar -> h0(H1) g (BSM; top loop)"; + codeSave = 1016; + idRes = 25; + } + else if (higgsType == 2) { + nameSave = "q qbar -> H0(H2) g (BSM; top loop)"; + codeSave = 1036; + idRes = 35; + } + else if (higgsType == 3) { + nameSave = "q qbar -> A0(A3) g (BSM; top loop)"; + codeSave = 1056; + idRes = 36; + } + + // Normalization factor by g g -> H partial width. + // (H can be H0 SM or H1, H2, A3 from BSM). + double mHiggs = ParticleDataTable::m0(idRes); + widHgg = ParticleDataTable::resWidthChan(idRes, mHiggs, 21, 21); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(idRes); + + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2qqbar2Hglt::sigmaKin() { + + // Evaluate cross section. Secondary width for H0, H1, H2 or A3. + sigma = (M_PI / sH2) * (2. / 9.) * alpS * (widHgg / m3) + * (tH2 + uH2) / (sH * s3); + sigma *= openFrac; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2Hglt::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, idRes, 21); + + // Colour flow topologies. Swap when antiquarks. + setColAcol( 1, 0, 0, 2, 0, 0, 1, 2); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma2qqbar2Hglt::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + + +//************************************************************************** + +// Sigma1ffbar2Hchg class. +// Cross section for f fbar -> H+- (f is quark or lepton). + +//********* + +// Initialize process. + +void Sigma1ffbar2Hchg::initProc() { + + // Find pointer to H+-. + HResPtr = ParticleDataTable::particleDataPtr(37); + + // Store H+- mass and width for propagator. + mRes = HResPtr->m0(); + GammaRes = HResPtr->mWidth(); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Couplings. + m2W = pow2(ParticleDataTable::m0(24)); + thetaWRat = 1. / (8. * CoupEW::sin2thetaW()); + tan2Beta = pow2(Settings::parm("HiggsHchg:tanBeta")); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma1ffbar2Hchg::sigmaKin() { + + // Set up Breit-Wigner. Width out only includes open channels. + sigBW = 4. * M_PI / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + widthOutPos = HResPtr->resWidthOpen( 37, mH); + widthOutNeg = HResPtr->resWidthOpen(-37, mH); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma1ffbar2Hchg::sigmaHat() { + + // Only allow generation-diagonal states. + int id1Abs = abs(id1); + int id2Abs = abs(id2); + int idUp = max(id1Abs, id2Abs); + int idDn = min(id1Abs, id2Abs); + if (idUp%2 != 0 || idUp - idDn != 1) return 0.; + + // Calculate mass-dependent incoming width. Total cross section. + double m2RunUp = pow2(ParticleDataTable::mRun(idUp, mH)); + double m2RunDn = pow2(ParticleDataTable::mRun(idDn, mH)); + double widthIn = alpEM * thetaWRat * (mH/m2W) + * (m2RunDn * tan2Beta + m2RunUp / tan2Beta); + int idUpChg = (id1Abs%2 == 0) ? id1 : id2; + double sigma = (idUpChg > 0) ? widthIn * sigBW * widthOutPos + : widthIn * sigBW * widthOutNeg; + + // Colour factor. Answer. + if (idUp < 9) sigma /= 3.; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ffbar2Hchg::setIdColAcol() { + + // Charge of Higgs. Fill flavours. + int idUpChg = (abs(id1)%2 == 0) ? id1 : id2; + int idHchg = (idUpChg > 0) ? 37 : -37; + setId( id1, id2, idHchg); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma1ffbar2Hchg::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma2qg2Hq class. +// Cross section for q g -> H+- q'. + +//********* + +// Initialize process. + +void Sigma2qg2Hchgq::initProc() { + + // Standard parameters. + m2W = pow2( ParticleDataTable::m0(24) ); + thetaWRat = 1. / (24. * CoupEW::sin2thetaW()); + tan2Beta = pow2(Settings::parm("HiggsHchg:tanBeta")); + + // Incoming flavour within same doublet. Uptype and downtype flavours. + idOld = (idNew%2 == 0) ? idNew - 1 : idNew + 1; + idUp = max(idOld, idNew); + idDn = min(idOld, idNew); + + // Secondary open width fraction. + openFracPos = (idOld%2 == 0) ? ParticleDataTable::resOpenFrac( 37, idNew) + : ParticleDataTable::resOpenFrac(-37, idNew); + openFracNeg = (idOld%2 == 0) ? ParticleDataTable::resOpenFrac(-37, -idNew) + : ParticleDataTable::resOpenFrac( 37, -idNew); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2qg2Hchgq::sigmaKin() { + + // Running masses provides coupling. + double m2RunUp = pow2(ParticleDataTable::mRun(idUp, mH)); + double m2RunDn = pow2(ParticleDataTable::mRun(idDn, mH)); + + // Cross section, including couplings and kinematics. + sigma = (M_PI / sH2) * alpS * alpEM * thetaWRat + * (m2RunDn * tan2Beta + m2RunUp / tan2Beta) / m2W + * (sH / (s4 - uH) + 2. * s4 * (s3 - uH) / pow2(s4 - uH) + + (s4 - uH) / sH - 2. * s4 / (s4 - uH) + + 2. * (s3 - uH) * (s3 - s4 - sH) / ((s4 - uH) * sH) ); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma2qg2Hchgq::sigmaHat() { + + // Check that specified flavour present. + if (abs(id1) != idOld && abs(id2) != idOld) return 0.; + + // Answer. + return (id1 == idOld || id2 == idOld) ? sigma * openFracPos + : sigma * openFracNeg; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qg2Hchgq::setIdColAcol() { + + // Flavour set up for q g -> H+- q'. + int idq = (id2 == 21) ? id1 : id2; + id3 = ( (idq > 0 && idOld%2 == 0) || (idq < 0 && idOld%2 != 0) ) + ? 37 : -37; + id4 = (idq > 0) ? idNew : -idNew; + setId( id1, id2, id3, id4); + + // tH defined between f and f': must swap tHat <-> uHat if q g in. + swapTU = (id2 == 21); + + // Colour flow topologies. Swap when antiquarks. + if (id2 == 21) setColAcol( 1, 0, 2, 1, 0, 0, 2, 0); + else setColAcol( 2, 1, 1, 0, 0, 0, 2, 0); + if (idq < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma2qg2Hchgq::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma2ffbar2A3H12 class. +// Cross section for f fbar -> A0(H_3) h0(H_1) or A0(H_3) H0(H_2). + +//********* + +// Initialize process. + +void Sigma2ffbar2A3H12::initProc() { + + // Set up whether h0(H_1) or H0(H_2). + higgs12 = (higgsType == 1) ? 25 : 35; + codeSave = (higgsType == 1) ? 1081 : 1082; + nameSave = (higgsType == 1) ? "f fbar -> A0(H3) h0(H1)" + : "f fbar -> A0(H3) H0(H2)"; + coupZA3H12 = (higgsType == 1) ? Settings::parm("HiggsA3:coup2H1Z") + : Settings::parm("HiggsA3:coup2H2Z"); + + // Standard parameters. + double mZ = ParticleDataTable::m0(23); + double GammaZ = ParticleDataTable::mWidth(23); + m2Z = mZ * mZ; + mGammaZ = mZ * GammaZ; + thetaWRat = 1. / (4. * CoupEW::sin2thetaW() * CoupEW::cos2thetaW()); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(36, higgs12); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2ffbar2A3H12::sigmaKin() { + + // Common kinematics factora. + sigma0 = (M_PI / sH2) * pow2(alpEM * thetaWRat * coupZA3H12) + * (uH * tH - s3 * s4) / ( pow2(sH - m2Z) + pow2(mGammaZ) ); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma2ffbar2A3H12::sigmaHat() { + + // Couplings for incoming flavour. + int idAbs = abs(id1); + double lIn = CoupEW::lf(idAbs); + double rIn = CoupEW::rf(idAbs); + + // Combine to total cross section. Colour factor. + double sigma = (pow2(lIn) + pow2(rIn)) * sigma0 * openFrac; + if (idAbs < 9) sigma /= 3.; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2A3H12::setIdColAcol() { + + // Flavours trivial + setId( id1, id2, 36, higgs12); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma2ffbar2A3H12::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma2ffbar2HchgH12 class. +// Cross section for f fbar -> H+- h0(H_1) or H+- H0(H_2). + +//********* + +// Initialize process. + +void Sigma2ffbar2HchgH12::initProc() { + + // Set up whether h0(H_1) or H0(H_2). + higgs12 = (higgsType == 1) ? 25 : 35; + codeSave = (higgsType == 1) ? 1083 : 1084; + nameSave = (higgsType == 1) ? "f fbar' -> H+- h0(H1)" + : "f fbar' -> H+- H0(H2)"; + coupWHchgH12 = (higgsType == 1) ? Settings::parm("HiggsHchg:coup2H1W") + : Settings::parm("HiggsHchg:coup2H2W"); + + // Standard parameters. + double mW = ParticleDataTable::m0(24); + double GammaW = ParticleDataTable::mWidth(24); + m2W = mW * mW; + mGammaW = mW * GammaW; + thetaWRat = 1. / (2. * CoupEW::sin2thetaW()); + + // Secondary open width fraction. + openFracPos = ParticleDataTable::resOpenFrac( 37, higgs12); + openFracNeg = ParticleDataTable::resOpenFrac(-37, higgs12); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2ffbar2HchgH12::sigmaKin() { + + // Common kinematics factora. + sigma0 = 0.5 * (M_PI / sH2) * pow2(alpEM * thetaWRat * coupWHchgH12) + * (uH * tH - s3 * s4) / ( pow2(sH - m2W) + pow2(mGammaW) ); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma2ffbar2HchgH12::sigmaHat() { + + // Combine to total cross section. CKM and colour factor. + int idUp = (abs(id1)%2 == 0) ? id1 : id2; + double sigma = (idUp > 0) ? sigma0 * openFracPos : sigma0 * openFracNeg; + if (abs(id1) < 9) sigma *= VCKM::V2id(abs(id1), abs(id2)) / 3.; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2HchgH12::setIdColAcol() { + + // Charge of Higgs. Fill flavours. + int idUpChg = (abs(id1)%2 == 0) ? id1 : id2; + int idHchg = (idUpChg > 0) ? 37 : -37; + setId( id1, id2, idHchg, higgs12); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma2ffbar2HchgH12::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma2ffbar2HposHneg class. +// Cross section for q g -> H+- q'. + +//********* + +// Initialize process. + +void Sigma2ffbar2HposHneg::initProc() { + + // Standard parameters. + double mZ = ParticleDataTable::m0(23); + double GammaZ = ParticleDataTable::mWidth(23); + m2Z = mZ * mZ; + mGammaZ = mZ * GammaZ; + thetaWRat = 1. / (4. * CoupEW::sin2thetaW() * CoupEW::cos2thetaW()); + + // Charged Higgs coupling to gamma and Z0. + eH = -1.; + lH = -1. + 2. * CoupEW::sin2thetaW(); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(37, -37); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2ffbar2HposHneg::sigmaKin() { + + // Common kinematics factora. + double preFac = M_PI * pow2(alpEM) * ((uH * tH - s3 * s4) / sH2); + double propZ = 1. / ( pow2(sH - m2Z) + pow2(mGammaZ) ); + + // Separate parts for gamma*, interference and Z0. + gamSig = preFac * 2. * pow2(eH) / sH2; + intSig = preFac * 2. * eH * lH * thetaWRat * propZ * (sH - m2Z) / sH; + resSig = preFac * pow2(lH * thetaWRat) * propZ; + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma2ffbar2HposHneg::sigmaHat() { + + // Couplings for incoming flavour. + int idAbs = int(id1); + double eIn = CoupEW::ef(idAbs); + double lIn = CoupEW::lf(idAbs); + double rIn = CoupEW::rf(idAbs); + + // Combine to total cross section. Colour factor. + double sigma = (pow2(eIn) * gamSig + eIn * (lIn + rIn) * intSig + + (pow2(lIn) + pow2(rIn)) * resSig) * openFrac; + if (idAbs < 9) sigma /= 3.; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2HposHneg::setIdColAcol() { + + // Flavours trivial + setId( id1, id2, 37, -37); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma2ffbar2HposHneg::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For Higgs decay hand over to standard routine. + if (idMother == 25 || idMother == 35 || idMother == 36) + return weightHiggsDecay( process, iResBeg, iResEnd); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SigmaLeftRightSym.cxx b/PYTHIA8/pythia8130/src/SigmaLeftRightSym.cxx new file mode 100644 index 00000000000..d2f7e89969a --- /dev/null +++ b/PYTHIA8/pythia8130/src/SigmaLeftRightSym.cxx @@ -0,0 +1,808 @@ +// SigmaLeftRightSym.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// left-right-symmetry simulation classes. + +#include "SigmaLeftRightSym.h" + +namespace Pythia8 { + +//************************************************************************** + +// Sigma1ffbar2ZRight class. +// Cross section for f fbar -> Z_R^0 (righthanded gauge boson). + +//********* + +// Initialize process. + +void Sigma1ffbar2ZRight::initProc() { + + // Store Z_R mass and width for propagator. + idZR = 9900023; + mRes = ParticleDataTable::m0(idZR); + GammaRes = ParticleDataTable::mWidth(idZR); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + sin2tW = CoupEW::sin2thetaW(); + + // Set pointer to particle properties and decay table. + ZRPtr = ParticleDataTable::particleDataPtr(idZR); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1ffbar2ZRight::sigmaKin() { + + // Set up Breit-Wigner. Width out only includes open channels. + double sigBW = 12. * M_PI/ ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + double widthOut = ZRPtr->resWidthOpen(idZR, mH); + + // Prefactor for incoming widths. Combine. Done. + double preFac = alpEM * mH / ( 48. * sin2tW * (1. - sin2tW) + * (1. - 2. * sin2tW) ); + sigma0 = preFac * sigBW * widthOut; + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma1ffbar2ZRight::sigmaHat() { + + // Vector and axial couplings of incoming fermion pair. + int idAbs = abs(id1); + double af = 0.; + double vf = 0.; + if (idAbs < 9 && idAbs%2 == 1) { + af = -1. + 2. * sin2tW; + vf = -1. + 4. * sin2tW / 3.; + } else if (idAbs < 9) { + af = 1. - 2. * sin2tW; + vf = 1. - 8. * sin2tW / 3.; + } else if (idAbs < 19 && idAbs%2 == 1) { + af = -1. + 2. * sin2tW; + vf = -1. + 4. * sin2tW; + } + + // Colour factor. Answer. + double sigma = (vf*vf + af*af) * sigma0; + if (idAbs < 9) sigma /= 3.; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ffbar2ZRight::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, idZR); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for Z_R decay angle. + +double Sigma1ffbar2ZRight::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Z_R should sit in entry 5. + if (iResBeg != 5 || iResEnd != 5) return 1.; + + // Couplings for in- and out-flavours. + double ai, vi, af, vf; + int idInAbs = process[3].idAbs(); + if (idInAbs < 9 && idInAbs%2 == 1) { + ai = -1. + 2. * sin2tW; + vi = -1. + 4. * sin2tW / 3.; + } else if (idInAbs < 9) { + ai = 1. - 2. * sin2tW; + vi = 1. - 8. * sin2tW / 3.; + } else { + ai = -1. + 2. * sin2tW; + vi = -1. + 4. * sin2tW; + } + int idOutAbs = process[6].idAbs(); + if (idOutAbs < 9 && idOutAbs%2 == 1) { + af = -1. + 2. * sin2tW; + vf = -1. + 4. * sin2tW / 3.; + } else if (idOutAbs < 9) { + af = 1. - 2. * sin2tW; + vf = 1. - 8. * sin2tW / 3.; + } else { + af = -1. + 2. * sin2tW; + vf = -1. + 4. * sin2tW; + } + + // Phase space factors. Reconstruct decay angle. + double mr1 = pow2(process[6].m()) / sH; + double mr2 = pow2(process[7].m()) / sH; + double betaf = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2); + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * betaf); + + // Angular weight and its maximum. + double wt1 = (vi*vi + ai*ai) * (vf*vf + af*af * betaf*betaf); + double wt2 = (1. - betaf*betaf) * (vi*vi + ai*ai) * vf*vf; + double wt3 = betaf * 4. * vi * ai * vf * af; + if (process[3].id() * process[6].id() < 0) wt3 = -wt3; + double wt = wt1 * (1. + cosThe*cosThe) + wt2 * (1. - cosThe*cosThe) + + 2. * wt3 * cosThe; + double wtMax = 2. * (wt1 + abs(wt3)); + + // Done. + return wt / wtMax; + +} + +//************************************************************************** + +// Sigma1ffbar2WRight class. +// Cross section for f fbar' -> W_R^+- (righthanded gauge boson). + +//********* + +// Initialize process. + +void Sigma1ffbar2WRight::initProc() { + + // Store W_R^+- mass and width for propagator. + idWR = 9900024; + mRes = ParticleDataTable::m0(idWR); + GammaRes = ParticleDataTable::mWidth(idWR); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + thetaWRat = 1. / (12. * CoupEW::sin2thetaW()); + + // Set pointer to particle properties and decay table. + particlePtr = ParticleDataTable::particleDataPtr(idWR); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1ffbar2WRight::sigmaKin() { + + // Common coupling factors. + double colQ = 3. * (1. + alpS / M_PI); + + // Reset quantities to sum. Declare variables inside loop. + double widOutPos = 0.; + double widOutNeg = 0.; + int id1Now, id2Now, id1Abs, id2Abs, id1Neg, id2Neg, onMode; + double widNow, widSecPos, widSecNeg, mf1, mf2, mr1, mr2, kinFac; + + // Loop over all W_R^+- decay channels. + for (int i = 0; i < particlePtr->decay.size(); ++i) { + widNow = 0.; + id1Now = particlePtr->decay[i].product(0); + id2Now = particlePtr->decay[i].product(1); + id1Abs = abs(id1Now); + id2Abs = abs(id2Now); + + // Check that above threshold. Phase space. + mf1 = ParticleDataTable::m0(id1Abs); + mf2 = ParticleDataTable::m0(id2Abs); + if (mH > mf1 + mf2 + MASSMARGIN) { + mr1 = pow2(mf1 / mH); + mr2 = pow2(mf2 / mH); + kinFac = (1. - 0.5 * (mr1 + mr2) - 0.5 * pow2(mr1 - mr2)) + * sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2 ); + + // Combine kinematics with colour factor and CKM couplings. + widNow = kinFac; + if (id1Abs < 9) widNow *= colQ * VCKM::V2id(id1Abs, id2Abs); + + // Secondary width from top and righthanded neutrino decay. + id1Neg = (id1Abs < 19) ? -id1Now : id1Abs; + id2Neg = (id2Abs < 19) ? -id2Now : id2Abs; + widSecPos = ParticleDataTable::resOpenFrac(id1Now, id2Now); + widSecNeg = ParticleDataTable::resOpenFrac(id1Neg, id2Neg); + + // Add weight for channels on for all, W_R^+ and W_R^-, respectively. + onMode = particlePtr->decay[i].onMode(); + if (onMode == 1 || onMode == 2) widOutPos += widNow * widSecPos; + if (onMode == 1 || onMode == 3) widOutNeg += widNow * widSecNeg; + + // End loop over fermions. + } + } + + // Set up Breit-Wigner. Cross section for W_R^+ and W_R^- separately. + double sigBW = 12. * M_PI * pow2(alpEM * thetaWRat) * sH + / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + sigma0Pos = sigBW * widOutPos; + sigma0Neg = sigBW * widOutNeg; + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma1ffbar2WRight::sigmaHat() { + + // Secondary width for W_R^+ or W_R^-. CKM and colour factors. + int idUp = (abs(id1)%2 == 0) ? id1 : id2; + double sigma = (idUp > 0) ? sigma0Pos : sigma0Neg; + if (abs(id1) < 9) sigma *= VCKM::V2id(abs(id1), abs(id2)) / 3.; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ffbar2WRight::setIdColAcol() { + + // Sign of outgoing W_R. + int sign = (abs(id1)%2 == 0) ? 1 : -1; + if (id1 < 0) sign = -sign; + setId( id1, id2, idWR * sign); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for W_R decay angle. + +double Sigma1ffbar2WRight::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // W_R should sit in entry 5. + if (iResBeg != 5 || iResEnd != 5) return 1.; + + // Phase space factors. + double mr1 = pow2(process[6].m()) / sH; + double mr2 = pow2(process[7].m()) / sH; + double betaf = sqrtpos( pow2(1. - mr1 - mr2) - 4. * mr1 * mr2); + + // Sign of asymmetry. + double eps = (process[3].id() * process[6].id() > 0) ? 1. : -1.; + + // Reconstruct decay angle and weight for it. + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * betaf); + double wtMax = 4.; + double wt = pow2(1. + betaf * eps * cosThe) - pow2(mr1 - mr2); + + // Done. + return (wt / wtMax); + +} + +//************************************************************************** + +// Sigma1ll2Hchgchg class. +// Cross section for l l -> H_L^++-- or H_R^++-- (doubly charged Higgs). + +//********* + +// Initialize process. + +void Sigma1ll2Hchgchg::initProc() { + + // Set process properties: H_L^++-- or H_R^++--. + if (leftRight == 1) { + idHLR = 9900041; + codeSave = 3121; + nameSave = "l l -> H_L^++--"; + } else { + idHLR = 9900042; + codeSave = 3141; + nameSave = "l l -> H_R^++--"; + } + + // Read in Yukawa matrix for couplings to a lepton pair. + yukawa[1][1] = Settings::parm("LeftRightSymmmetry:coupHee"); + yukawa[2][1] = Settings::parm("LeftRightSymmmetry:coupHmue"); + yukawa[2][2] = Settings::parm("LeftRightSymmmetry:coupHmumu"); + yukawa[3][1] = Settings::parm("LeftRightSymmmetry:coupHtaue"); + yukawa[3][2] = Settings::parm("LeftRightSymmmetry:coupHtaumu"); + yukawa[3][3] = Settings::parm("LeftRightSymmmetry:coupHtautau"); + + // Store H_L/R mass and width for propagator. + mRes = ParticleDataTable::m0(idHLR); + GammaRes = ParticleDataTable::mWidth(idHLR); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Set pointer to particle properties and decay table. + particlePtr = ParticleDataTable::particleDataPtr(idHLR); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma1ll2Hchgchg::sigmaHat() { + + // Initial state must consist of two identical-sign leptons. + if (id1 * id2 < 0) return 0.; + int id1Abs = abs(id1); + int id2Abs = abs(id2); + if (id1Abs != 11 && id1Abs != 13 && id1Abs != 15) return 0.; + if (id2Abs != 11 && id2Abs != 13 && id2Abs != 15) return 0.; + + // Set up Breit-Wigner, inwidth and outwidth. + double sigBW = 8. * M_PI / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + double widIn = pow2(yukawa[(id1Abs-9)/2][(id2Abs-9)/2]) + * mH / (8. * M_PI); + int idSgn = (id1 < 0) ? idHLR : -idHLR; + double widOut = particlePtr->resWidthOpen( idSgn, mH); + + // Answer. + return widIn * sigBW * widOut; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ll2Hchgchg::setIdColAcol() { + + // Sign of outgoing H_L/R. + int idSgn = (id1 < 0) ? idHLR : -idHLR; + setId( id1, id2, idSgn); + + // No colours whatsoever. + setColAcol( 0, 0, 0, 0, 0, 0); + +} + +//********* + +// Evaluate weight for H_L/R sequential decay angles. + +double Sigma1ll2Hchgchg::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else isotropic decay. + return 1.; + +} + +//************************************************************************** + +// Sigma2lgm2Hchgchgl class. +// Cross section for l l -> H_L^++-- or H_R^++-- (doubly charged Higgs). + +//********* + +// Initialize process. + +void Sigma2lgm2Hchgchgl::initProc() { + + // Set process properties: H_L^++-- or H_R^++-- and e/mu/tau. + idHLR = (leftRight == 1) ? 9900041 : 9900042; + codeSave = (leftRight == 1) ? 3122 : 3142; + if (idLep == 13) codeSave += 2; + if (idLep == 15) codeSave += 4; + if (codeSave == 3122) nameSave = "l^+- gamma -> H_L^++-- e^-+"; + else if (codeSave == 3123) nameSave = "l^+- gamma -> H_L^++-- mu^-+"; + else if (codeSave == 3124) nameSave = "l^+- gamma -> H_L^++-- tau^-+"; + else if (codeSave == 3142) nameSave = "l^+- gamma -> H_R^++-- e^-+"; + else if (codeSave == 3143) nameSave = "l^+- gamma -> H_R^++-- mu^-+"; + else nameSave = "l^+- gamma -> H_R^++-- tau^-+"; + + // Read in relevantYukawa matrix for couplings to a lepton pair. + if (idLep == 11) { + yukawa[1] = Settings::parm("LeftRightSymmmetry:coupHee"); + yukawa[2] = Settings::parm("LeftRightSymmmetry:coupHmue"); + yukawa[3] = Settings::parm("LeftRightSymmmetry:coupHtaue"); + } else if (idLep == 13) { + yukawa[1] = Settings::parm("LeftRightSymmmetry:coupHmue"); + yukawa[2] = Settings::parm("LeftRightSymmmetry:coupHmumu"); + yukawa[3] = Settings::parm("LeftRightSymmmetry:coupHtaumu"); + } else { + yukawa[1] = Settings::parm("LeftRightSymmmetry:coupHtaue"); + yukawa[2] = Settings::parm("LeftRightSymmmetry:coupHtaumu"); + yukawa[3] = Settings::parm("LeftRightSymmmetry:coupHtautau"); + } + + // Secondary open width fractions. + openFracPos = ParticleDataTable::resOpenFrac( idHLR); + openFracNeg = ParticleDataTable::resOpenFrac(-idHLR); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma2lgm2Hchgchgl::sigmaHat() { + + // Initial state must consist of a lepton and a photon. + int idIn = (id2 == 22) ? id1 : id2; + int idInAbs = abs(idIn); + if (idInAbs != 11 && idInAbs != 13 && idInAbs != 15) return 0.; + + // Incoming squared lepton mass. + double s1 = pow2( ParticleDataTable::m0(idInAbs) ); + + // Kinematical expressions. + double smm1 = 8. * (sH + tH - s3) * (sH + tH - 2. * s3 - s1 - s4) + / pow2(uH - s3); + double smm2 = 2. * ( (2. * s3 - 3. * s1) * s4 + (s1 - 2. * s4) * tH + - (tH - s4) * sH ) / pow2(tH - s4); + double smm3 = 2. * ( (2. * s3 - 3. * s4 + tH) * s1 + - (2. * s1 - s4 + tH) * sH ) / pow2(sH - s1); + double smm12 = 4. * ( (2. * s1 - s4 - 2. * s3 + tH) * sH + + (tH - 3. * s3 - 3. * s4) * tH + (2. * s3 - 2. * s1 + + 3. * s4) * s3 ) / ( (uH - s3) * (tH - s4) ); + double smm13 = -4. * ( (tH + s1 - 2. * s4) * tH - (s3 + 3. * s1 - 2. * s4) + * s3 + (s3 + 3. * s1 + tH) * sH - pow2(tH - s3 + sH) ) + / ( (uH - s3) * (sH - s1) ); + double smm23 = -4. * ( (s1 - s4 + s3) * tH - s3*s3 + s3 * (s1 + s4) + - 3. * s1 * s4 - (s1 - s4 - s3 + tH) * sH) + / ( (sH - s1) * (tH - s4) ); + double sigma = alpEM * pow2(sH / (sH - s1) ) * (smm1 + smm2 + smm3 + + smm12 + smm13 + smm23) / (4. * sH2); + + // Lepton Yukawa and secondary widths. + sigma *= pow2(yukawa[(idInAbs-9)/2]); + sigma *= (idIn < 0) ? openFracPos : openFracNeg; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2lgm2Hchgchgl::setIdColAcol() { + + // Sign of outgoing H_L/R. + int idIn = (id2 == 22) ? id1 : id2; + int idSgn = (idIn < 0) ? idHLR : -idHLR; + int idOut = (idIn < 0) ? idLep : -idLep; + setId( id1, id2, idSgn, idOut); + + // tHat is defined between incoming lepton and outgoing Higgs. + if (id1 == 22) swapTU = true; + + // No colours whatsoever. + setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + +} + +//********* + +// Evaluate weight for H_L/R sequential decay angles. + +double Sigma2lgm2Hchgchgl::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else isotropic decay. + return 1.; + +} + +//************************************************************************** + +// Sigma3ff2HchgchgfftWW class. +// Cross section for f_1 f_2 -> H0 f_3 f_4 (W+ W- fusion of SM Higgs). + +//********* + +// Initialize process. + +void Sigma3ff2HchgchgfftWW::initProc() { + + // Set process properties: H_L^++-- or H_R^++--. + if (leftRight == 1) { + idHLR = 9900041; + codeSave = 3125; + nameSave = "f_1 f_2 -> H_L^++-- f_3 f_4 (W+- W+- fusion)"; + } else { + idHLR = 9900042; + codeSave = 3145; + nameSave = "f_1 f_2 -> H_R^++-- f_3 f_4 (W+- W+- fusion)"; + } + + // Common fixed mass and coupling factor. + double mW = ParticleDataTable::m0(24); + double mWR = ParticleDataTable::m0(9900024); + mWS = (leftRight == 1) ? pow2(mW) : pow2(mWR); + double gL = Settings::parm("LeftRightSymmmetry:gL"); + double gR = Settings::parm("LeftRightSymmmetry:gR"); + double vL = Settings::parm("LeftRightSymmmetry:vL"); + prefac = (leftRight == 1) ? pow2(pow4(gL) * vL) + : 2. * pow2(pow3(gR) * mWR); + // Secondary open width fractions. + openFracPos = ParticleDataTable::resOpenFrac( idHLR); + openFracNeg = ParticleDataTable::resOpenFrac(-idHLR); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma3ff2HchgchgfftWW::sigmaKin() { + + // Required four-vector products. + double pp12 = 0.5 * sH; + double pp14 = 0.5 * mH * p4cm.pMinus(); + double pp15 = 0.5 * mH * p5cm.pMinus(); + double pp24 = 0.5 * mH * p5cm.pPlus(); + double pp25 = 0.5 * mH * p5cm.pPlus(); + double pp45 = p4cm * p5cm; + + // Cross section: kinematics part. Combine with couplings. + double propT = 1. / ( (2. * pp14 + mWS) * (2. * pp25 + mWS) ); + double propU = 1. / ( (2. * pp24 + mWS) * (2. * pp15 + mWS) ); + sigma0TU = prefac * pp12 * pp45 * pow2(propT + propU); + sigma0T = prefac * pp12 * pp45 * 2. * pow2(propT); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma3ff2HchgchgfftWW::sigmaHat() { + + // Do not allow creation of righthanded neutrinos for H_R. + int id1Abs = abs(id1); + int id2Abs = abs(id2); + if ( leftRight == 2 && (id1Abs > 10 || id2Abs > 10) ) return 0.; + + // Many flavour combinations not possible because of charge. + int chg1 = (( id1Abs%2 == 0 && id1 > 0) + || (id1Abs%2 == 1 && id1 < 0) ) ? 1 : -1; + int chg2 = (( id2Abs%2 == 0 && id2 > 0) + || (id2Abs%2 == 1 && id2 < 0) ) ? 1 : -1; + if (abs(chg1 + chg2) != 2) return 0.; + + // Basic cross section. CKM factors for final states. + double sigma = (id2 == id1 && id1Abs > 10) ? sigma0TU : sigma0T; + sigma *= VCKM::V2sum(id1Abs) * VCKM::V2sum(id2Abs); + + // Secondary width for H0. + sigma *= (chg1 + chg2 == 2) ? openFracPos : openFracNeg; + + // Spin-state extra factor 2 per incoming neutrino. + if (id1Abs == 12 || id1Abs == 14 || id1Abs == 16) sigma *= 2.; + if (id2Abs == 12 || id2Abs == 14 || id2Abs == 16) sigma *= 2.; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma3ff2HchgchgfftWW::setIdColAcol() { + + // Pick out-flavours by relative CKM weights. + int id1Abs = abs(id1); + int id2Abs = abs(id2); + id4 = VCKM::V2pick(id1); + id5 = VCKM::V2pick(id2); + + // Find charge of Higgs . + id3 = (( id1Abs%2 == 0 && id1 > 0) || (id1Abs%2 == 1 && id1 < 0) ) + ? idHLR : -idHLR; + setId( id1, id2, id3, id4, id5); + + // Colour flow topologies. Swap when antiquarks. + if (id1Abs < 9 && id2Abs < 9 && id1*id2 > 0) + setColAcol( 1, 0, 2, 0, 0, 0, 1, 0, 2, 0); + else if (id1Abs < 9 && id2Abs < 9) + setColAcol( 1, 0, 0, 2, 0, 0, 1, 0, 0, 2); + else if (id1Abs < 9) setColAcol( 1, 0, 0, 0, 0, 0, 1, 0, 0, 0); + else if (id2Abs < 9) setColAcol( 0, 0, 1, 0, 0, 0, 0, 0, 1, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + if ( (id1Abs < 9 && id1 < 0) || (id1Abs > 10 && id2 < 0) ) + swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles. + +double Sigma3ff2HchgchgfftWW::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else done. + return 1.; + +} + +//************************************************************************** + +// Sigma2ffbar2HchgchgHchgchg class. +// Cross section for f fbar -> H_(L/R)^++ H_(L/R)^-- (doubly charged Higgs). + +//********* + +// Initialize process. + +void Sigma2ffbar2HchgchgHchgchg::initProc() { + + // Set process properties: H_L^++ H_L^-- or H_R^++ H_R^--. + if (leftRight == 1) { + idHLR = 9900041; + codeSave = 3126; + nameSave = "f fbar -> H_L^++ H_L^--"; + } else { + idHLR = 9900042; + codeSave = 3146; + nameSave = "f fbar -> H_R^++ H_R^--"; + } + + // Read in Yukawa matrix for couplings to a lepton pair. + yukawa[1][1] = Settings::parm("LeftRightSymmmetry:coupHee"); + yukawa[2][1] = Settings::parm("LeftRightSymmmetry:coupHmue"); + yukawa[2][2] = Settings::parm("LeftRightSymmmetry:coupHmumu"); + yukawa[3][1] = Settings::parm("LeftRightSymmmetry:coupHtaue"); + yukawa[3][2] = Settings::parm("LeftRightSymmmetry:coupHtaumu"); + yukawa[3][3] = Settings::parm("LeftRightSymmmetry:coupHtautau"); + + // Electroweak parameters. + mRes = ParticleDataTable::m0(23); + GammaRes = ParticleDataTable::mWidth(23); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + sin2tW = CoupEW::sin2thetaW(); + preFac = (1. - 2. * sin2tW) / ( 8. * sin2tW * (1. - sin2tW) ); + + // Open fraction from secondary widths. + openFrac = ParticleDataTable::resOpenFrac( idHLR, -idHLR); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma2ffbar2HchgchgHchgchg::sigmaHat() { + + // Electroweak couplings to gamma^*/Z^0. + int idAbs = abs(id1); + double ei = CoupEW::ef(idAbs); + double vi = CoupEW::vf(idAbs); + double ai = CoupEW::af(idAbs); + + // Part via gamma^*/Z^0 propagator.No Z^0 coupling to H_R. + double resProp = 1. / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + double sigma = 8. * pow2(alpEM) * ei*ei / sH2; + if (leftRight == 1) sigma += 8. * pow2(alpEM) + * (2. * ei * vi * preFac * (sH - m2Res) * resProp / sH + + (vi * vi + ai * ai) * pow2(preFac) * resProp); + + // Part via t-channel lepton + interference; sum over possibilities. + if (idAbs == 11 || idAbs == 13 || idAbs == 15) { + double yuk2Sum; + if (idAbs == 11) yuk2Sum + = pow2(yukawa[1][1]) + pow2(yukawa[2][1]) + pow2(yukawa[3][1]); + else if (idAbs == 13) yuk2Sum + = pow2(yukawa[2][1]) + pow2(yukawa[2][2]) + pow2(yukawa[3][2]); + else yuk2Sum + = pow2(yukawa[3][1]) + pow2(yukawa[3][2]) + pow2(yukawa[3][3]); + yuk2Sum /= 4. * M_PI; + sigma += 8. * alpEM * ei * yuk2Sum / (sH * tH) + + 4. * pow2(yuk2Sum) / tH2; + if (leftRight == 1) sigma += 8. * alpEM * (vi + ai) * yuk2Sum + * preFac * (sH - m2Res) * resProp / tH; + } + + // Common kinematical factor. Colour factor. + sigma *= M_PI * (tH * uH - s3 * s4) / sH2; + if (idAbs < 9) sigma /= 3.; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2ffbar2HchgchgHchgchg::setIdColAcol() { + + // Outgoing flavours trivial. + setId( id1, id2, idHLR, -idHLR); + + // tHat is defined between incoming fermion and outgoing H--. + if (id1 > 0) swapTU = true; + + // No colours at all or one flow topology. Swap if first is antiquark. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for H_L/R sequential decay angles. + +double Sigma2ffbar2HchgchgHchgchg::weightDecay( Event& process, + int iResBeg, int iResEnd) { + + // Identity of mother of decaying reseonance(s). + int idMother = process[process[iResBeg].mother1()].idAbs(); + + // For top decay hand over to standard routine. + if (idMother == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Else isotropic decay. + return 1.; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SigmaLeptoquark.cxx b/PYTHIA8/pythia8130/src/SigmaLeptoquark.cxx new file mode 100644 index 00000000000..c42802f6896 --- /dev/null +++ b/PYTHIA8/pythia8130/src/SigmaLeptoquark.cxx @@ -0,0 +1,310 @@ +// SigmaLeptoquark.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// leptoquark simulation classes. + +#include "SigmaLeptoquark.h" + +namespace Pythia8 { + +//************************************************************************** + +// Sigma1ql2LeptoQuark class. +// Cross section for q l -> LQ (leptoquark state). + +//********* + +// Initialize process. + +void Sigma1ql2LeptoQuark::initProc() { + + // Store LQ mass and width for propagator. + mRes = ParticleDataTable::m0(42); + GammaRes = ParticleDataTable::mWidth(42); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Yukawa coupling strength. + kCoup = Settings::parm("LeptoQuark:kCoup"); + + // Set pointer to particle properties and decay table. + LQPtr = ParticleDataTable::particleDataPtr(42); + + // Read out quark and lepton the LQ couples to. + idQuark = LQPtr->decay[0].product(0); + idLepton = LQPtr->decay[0].product(1); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1ql2LeptoQuark::sigmaKin() { + + // Incoming width for correct quark-lepton pair.. + widthIn = 0.25 * alpEM * kCoup * mH; + + // Set up Breit-Wigner. + sigBW = 4. * M_PI/ ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + +} + +//********* + +// Evaluate sigmaHat(sHat) for specific incoming flavours. + +double Sigma1ql2LeptoQuark::sigmaHat() { + + // Identify whether correct incoming flavours. + int idLQ = 0; + if (id1 == idQuark && id2 == idLepton) idLQ = 42; + else if (id2 == idQuark && id1 == idLepton) idLQ = 42; + else if (id1 == -idQuark && id2 == -idLepton) idLQ = -42; + else if (id2 == -idQuark && id1 == -idLepton) idLQ = -42; + if (idLQ == 0) return 0.; + + // Outgoing width and total sigma. Done. + return widthIn * sigBW * LQPtr->resWidthOpen(idLQ, mH); + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ql2LeptoQuark::setIdColAcol() { + + // Flavours. + int idq = (abs(id1) < 9) ? id1 : id2; + int idLQ = (idq > 0) ? 42 : -42; + setId( id1, id2, idLQ); + + // Colour flow topology. + if (id1 == idq) setColAcol( 1, 0, 0, 0, 1, 0); + else setColAcol( 0, 0, 1, 0, 1, 0); + if (idq < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2qg2LeptoQuarkl class. +// Cross section for q g -> LQ l (leptoquark state). + +//********* + +// Initialize process. + +void Sigma2qg2LeptoQuarkl::initProc() { + + // Store LQ mass and width for propagator. + mRes = ParticleDataTable::m0(42); + GammaRes = ParticleDataTable::mWidth(42); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Yukawa coupling strength. + kCoup = Settings::parm("LeptoQuark:kCoup"); + + // Read out quark and lepton the LQ couples to. + ParticleDataEntry* LQPtr = ParticleDataTable::particleDataPtr(42); + idQuark = LQPtr->decay[0].product(0); + idLepton = LQPtr->decay[0].product(1); + + // Secondary open width fraction. + openFracPos = LQPtr->resOpenFrac( 42); + openFracNeg = LQPtr->resOpenFrac(-42); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2qg2LeptoQuarkl::sigmaKin() { + + // Evaluate cross section. + sigma0 = (M_PI / sH2) * kCoup * (alpS * alpEM / 6.) * (-tH / sH) + * (uH2 + s3 * s3) / pow2(uH - s3); + +} + +//********* + +// Evaluate sigmaHat(sHat) for specific incoming flavours. + +double Sigma2qg2LeptoQuarkl::sigmaHat() { + + // Check that correct incoming flavour. + if (abs(id1) != idQuark && abs(id2) != idQuark) return 0.; + + // Answer, with secondary width correction. + double sigma = sigma0; + sigma *= (id1 == idQuark || id2 == idQuark) ? openFracPos : openFracNeg; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qg2LeptoQuarkl::setIdColAcol() { + + // Flavour set up for q g -> H q. + int idq = (id2 == 21) ? id1 : id2; + int idLQ = (idq > 0) ? 42 : -42; + int idlp = (idq > 0) ? idLepton : -idLepton; + setId( id1, id2, idLQ, idlp); + + // tH defined between f and f': must swap tHat <-> uHat if q g in. + swapTU = (id2 == 21); + + // Colour flow topologies. Swap when antiquarks. + if (id2 == 21) setColAcol( 1, 0, 2, 1, 2, 0, 0, 0); + else setColAcol( 2, 1, 1, 0, 2, 0, 0, 0); + if (idq < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2gg2LQLQbar class. +// Cross section for g g -> LQ LQbar (leptoquark state). + +//********* + +// Initialize process. + +void Sigma2gg2LQLQbar::initProc() { + + // Store LQ mass and width for propagator. + mRes = ParticleDataTable::m0(42); + GammaRes = ParticleDataTable::mWidth(42); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(42, -42); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2gg2LQLQbar::sigmaKin() { + + // Average outgoing masses and adjust kinematics accordingly. + double delta = 0.25 * pow2(s3 - s4) / sH; + double m2avg = 0.5 * (s3 + s4) - delta; + double tHavg = tH - delta; + double uHavg = uH - delta; + + // Evaluate cross section. Secondary width for G*. + sigma = (M_PI / sH2) * 0.5 * pow2(alpS) + * ( 7. / 48. + 3. * pow2(uHavg - tHavg) / (16. * sH2) ) + * ( 1. + 2. * m2avg * tHavg / pow2(tHavg - m2avg) + + 2. * m2avg * uHavg / pow2(uHavg - m2avg) + + 4. * m2avg * m2avg / ((tHavg - m2avg) * (uHavg - m2avg)) ); + sigma *= openFrac; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2gg2LQLQbar::setIdColAcol() { + + // Flavours trivial. + setId( 21, 21, 42, -42); + + // Colour flow topologies: random choice between two mirrors. + if (Rndm::flat() < 0.5) setColAcol( 1, 2, 2, 3, 1, 0, 0, 3); + else setColAcol( 1, 2, 3, 1, 3, 0, 0, 2); + +} + +//************************************************************************** + +// Sigma2qqbar2LQLQbar class. +// Cross section for q qbar -> LQ LQbar (leptoquark state). + +//********* + +// Initialize process. + +void Sigma2qqbar2LQLQbar::initProc() { + + // Store LQ mass and width for propagator. + mRes = ParticleDataTable::m0(42); + GammaRes = ParticleDataTable::mWidth(42); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + + // Yukawa coupling strength. + kCoup = Settings::parm("LeptoQuark:kCoup"); + + // Read out quark and lepton the LQ couples to. + ParticleDataEntry* LQPtr = ParticleDataTable::particleDataPtr(42); + idQuark = LQPtr->decay[0].product(0); + + // Secondary open width fraction. + openFrac = ParticleDataTable::resOpenFrac(42, -42); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma2qqbar2LQLQbar::sigmaKin() { + + // Average outgoing masses and adjust kinematics accordingly. + double delta = 0.25 * pow2(s3 - s4) / sH; + double m2avg = 0.5 * (s3 + s4) - delta; + double tHavg = tH - delta; + double uHavg = uH - delta; + + // Evaluate cross section for quark of different flavour than LQ. + sigmaDiff = (M_PI / sH2) * (pow2(alpS) / 9.) + * ( sH * (sH - 4. * m2avg) - pow2(uHavg - tHavg) ) / sH2; + + // Evaluate cross section for quark of same flavour as LQ. + sigmaSame = sigmaDiff + (M_PI / sH2) * (pow2(kCoup * alpEM) / 8.) + * (-sH * tHavg - pow2(m2avg-tHavg)) / pow2(tHavg) + + (M_PI / sH2) * (kCoup * alpEM * alpS / 18.) * ( (m2avg - tHavg) + * (uHavg - tHavg) + sH * (m2avg + tHavg) ) / (sH * tHavg); + + // Open fraction. + sigmaDiff *= openFrac; + sigmaSame *= openFrac; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2LQLQbar::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, 42, -42); + + // tH defined between f and LQ: must swap tHat <-> uHat if qbar q in. + swapTU = (id1 < 0); + + // Colour flow topologies. + if (id1 > 0) setColAcol( 1, 0, 0, 2, 1, 0, 0, 2); + else setColAcol( 0, 2, 1, 0, 1, 0, 0, 2); + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SigmaNewGaugeBosons.cxx b/PYTHIA8/pythia8130/src/SigmaNewGaugeBosons.cxx new file mode 100644 index 00000000000..e4c04f2c50f --- /dev/null +++ b/PYTHIA8/pythia8130/src/SigmaNewGaugeBosons.cxx @@ -0,0 +1,757 @@ +// SigmaNewGaugeBosons.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// leptoquark simulation classes. + +#include "SigmaNewGaugeBosons.h" + +namespace Pythia8 { + + +//************************************************************************** + +// Sigma1ffbarZprimeWprime class. +// Collects common methods for f fbar -> Z'/W' -> WW/WZ -> 4 fermions. +// Copied from SigmaEW for gauge-boson-pair production. + +//********* + +// Calculate and store internal products. + +void Sigma1ffbarZprimeWprime::setupProd( Event& process, int i1, int i2, + int i3, int i4, int i5, int i6) { + + // Store incoming and outgoing momenta, + pRot[1] = process[i1].p(); + pRot[2] = process[i2].p(); + pRot[3] = process[i3].p(); + pRot[4] = process[i4].p(); + pRot[5] = process[i5].p(); + pRot[6] = process[i6].p(); + + // Do random rotation to avoid accidental zeroes in HA expressions. + bool smallPT = false; + do { + smallPT = false; + double thetaNow = acos(2. * Rndm::flat() - 1.); + double phiNow = 2. * M_PI * Rndm::flat(); + for (int i = 1; i <= 6; ++i) { + pRot[i].rot( thetaNow, phiNow); + if (pRot[i].pT2() < 1e-4 * pRot[i].pAbs2()) smallPT = true; + } + } while (smallPT); + + // Calculate internal products. + for (int i = 1; i < 6; ++i) { + for (int j = i + 1; j <= 6; ++j) { + hA[i][j] = + sqrt( (pRot[i].e() - pRot[i].pz()) * (pRot[j].e() + pRot[j].pz()) + / pRot[i].pT2() ) * complex( pRot[i].px(), pRot[i].py() ) + - sqrt( (pRot[i].e() + pRot[i].pz()) * (pRot[j].e() - pRot[j].pz()) + / pRot[j].pT2() ) * complex( pRot[j].px(), pRot[j].py() ); + hC[i][j] = conj( hA[i][j] ); + if (i <= 2) { + hA[i][j] *= complex( 0., 1.); + hC[i][j] *= complex( 0., 1.); + } + hA[j][i] = - hA[i][j]; + hC[j][i] = - hC[i][j]; + } + } + +} + +//********* + +// Evaluate the F function of Gunion and Kunszt. + +complex Sigma1ffbarZprimeWprime::fGK(int j1, int j2, int j3, int j4, + int j5, int j6) { + + return 4. * hA[j1][j3] * hC[j2][j6] + * ( hA[j1][j5] * hC[j1][j4] + hA[j3][j5] * hC[j3][j4] ); + +} + +//********* + +// Evaluate the Xi function of Gunion and Kunszt. + +double Sigma1ffbarZprimeWprime::xiGK( double tHnow, double uHnow, + double s3now, double s4now) { + + return - 4. * s3now * s4now + tHnow * (3. * tHnow + 4. * uHnow) + + tHnow * tHnow * ( tHnow * uHnow / (s3now * s4now) + - 2. * (1. / s3now + 1./s4now) * (tHnow + uHnow) + + 2. * (s3now / s4now + s4now / s3now) ); + +} + +//********* + +// Evaluate the Xj function of Gunion and Kunszt. + +double Sigma1ffbarZprimeWprime::xjGK( double tHnow, double uHnow, + double s3now, double s4now) { + + return 8. * pow2(s3now + s4now) - 8. * (s3now + s4now) * (tHnow + uHnow) + - 6. * tHnow * uHnow - 2. * tHnow * uHnow * ( tHnow * uHnow + / (s3now * s4now) - 2. * (1. / s3now + 1. / s4now) * (tHnow + uHnow) + + 2. * (s3now / s4now + s4now / s3now) ); + +} + +//************************************************************************* + +// Sigma1ffbar2gmZZprime class. +// Cross section for f fbar -> gamma*/Z0/Z'0 (f is quark or lepton). + +//********* + +// Initialize process. + +void Sigma1ffbar2gmZZprime::initProc() { + + // Allow to pick only parts of full gamma*/Z0/Z'0 expression. + gmZmode = Settings::mode("Zprime:gmZmode"); + + // Store Z'0 mass and width for propagator. + mRes = ParticleDataTable::m0(32); + GammaRes = ParticleDataTable::mWidth(32); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + sin2tW = CoupEW::sin2thetaW(); + cos2tW = 1. - sin2tW; + thetaWRat = 1. / (16. * sin2tW * cos2tW); + + // Properties of Z0 resonance also needed. + mZ = ParticleDataTable::m0(23); + GammaZ = ParticleDataTable::mWidth(23); + m2Z = mZ*mZ; + GamMRatZ = GammaZ / mZ; + + // Ensure that arrays initially are empty. + for (int i = 0; i < 20; ++i) afZp[i] = 0.; + for (int i = 0; i < 20; ++i) vfZp[i] = 0.; + + // Store first-generation axial and vector couplings. + afZp[1] = Settings::parm("Zprime:ad"); + afZp[2] = Settings::parm("Zprime:au"); + afZp[11] = Settings::parm("Zprime:ae"); + afZp[12] = Settings::parm("Zprime:anue"); + vfZp[1] = Settings::parm("Zprime:vd"); + vfZp[2] = Settings::parm("Zprime:vu"); + vfZp[11] = Settings::parm("Zprime:ve"); + vfZp[12] = Settings::parm("Zprime:vnue"); + + // Second and third generation could be carbon copy of this... + if (Settings::flag("Zprime:universality")) { + for (int i = 3; i <= 6; ++i) { + afZp[i] = afZp[i-2]; + vfZp[i] = vfZp[i-2]; + afZp[i+10] = afZp[i+8]; + vfZp[i+10] = vfZp[i+8]; + } + + // ... or could have different couplings. + } else { + afZp[3] = Settings::parm("Zprime:as"); + afZp[4] = Settings::parm("Zprime:ac"); + afZp[5] = Settings::parm("Zprime:ab"); + afZp[6] = Settings::parm("Zprime:at"); + afZp[13] = Settings::parm("Zprime:amu"); + afZp[14] = Settings::parm("Zprime:anumu"); + afZp[15] = Settings::parm("Zprime:atau"); + afZp[16] = Settings::parm("Zprime:anutau"); + vfZp[3] = Settings::parm("Zprime:vs"); + vfZp[4] = Settings::parm("Zprime:vc"); + vfZp[5] = Settings::parm("Zprime:vb"); + vfZp[6] = Settings::parm("Zprime:vt"); + vfZp[13] = Settings::parm("Zprime:vmu"); + vfZp[14] = Settings::parm("Zprime:vnumu"); + vfZp[15] = Settings::parm("Zprime:vtau"); + vfZp[16] = Settings::parm("Zprime:vnutau"); + } + + // Coupling for Z' -> W+ W- and decay angular admixture. + coupZpWW = Settings::parm("Zprime:coup2WW"); + anglesZpWW = Settings::parm("Zprime:anglesWW"); + + // Set pointer to particle properties and decay table. + particlePtr = ParticleDataTable::particleDataPtr(32); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1ffbar2gmZZprime::sigmaKin() { + + // Common coupling factors. + double colQ = 3. * (1. + alpS / M_PI); + + // Reset quantities to sum. Declare variables in loop. + gamSum = 0.; + gamZSum = 0.; + ZSum = 0.; + gamZpSum = 0.; + ZZpSum = 0.; + ZpSum = 0.; + int idAbs, onMode; + double mf, mr, ps, kinFacA, kinFacV, ef, af, vf, apf, vpf, + ef2, efvf, vaf2, efvpf, vafvapf, vapf2, colf; + + // Loop over all open Z'0 decay channels. + for (int i = 0; i < particlePtr->decay.size(); ++i) { + onMode = particlePtr->decay[i].onMode(); + if (onMode != 1 && onMode != 2) continue; + idAbs = abs( particlePtr->decay[i].product(0) ); + + // Contributions from three fermion generations. + if ( (idAbs > 0 && idAbs < 7) || ( idAbs > 10 && idAbs < 17) ) { + mf = ParticleDataTable::m0(idAbs); + + // Check that above threshold. + if (mH > 2. * mf + MASSMARGIN) { + mr = pow2(mf / mH); + ps = sqrtpos(1. - 4. * mr); + + // Couplings of gamma^*/Z^0/Z'^0 to final flavour + ef = CoupEW::ef(idAbs); + af = CoupEW::af(idAbs); + vf = CoupEW::vf(idAbs); + apf = afZp[idAbs]; + vpf = vfZp[idAbs]; + + // Combine couplings with kinematical factors. + kinFacA = pow3(ps); + kinFacV = ps * (1. + 2. * mr); + ef2 = ef * ef * kinFacV; + efvf = ef * vf * kinFacV; + vaf2 = vf * vf * kinFacV + af * af * kinFacA; + efvpf = ef * vpf * kinFacV; + vafvapf = vf * vpf * kinFacV + af * apf * kinFacA; + vapf2 = vpf * vpf * kinFacV + apf * apf * kinFacA; + + // Colour factor. Additionally secondary width for top. + colf = (idAbs < 9) ? colQ : 1.; + if (idAbs == 6) colf *= ParticleDataTable::resOpenFrac(6, -6); + + // Store sum of combinations. + gamSum += colf * ef2; + gamZSum += colf * efvf; + ZSum += colf * vaf2; + gamZpSum += colf * efvpf; + ZZpSum += colf * vafvapf; + ZpSum += colf * vapf2; + } + + // Optional contribution from W+ W-. + } else if (idAbs == 24) { + mf = ParticleDataTable::m0(idAbs); + if (mH > 2. * mf + MASSMARGIN) { + mr = pow2(mf / mH); + ps = sqrtpos(1. - 4. * mr); + ZpSum += pow2(coupZpWW * cos2tW) * pow3(ps) + * (1. + 20. * mr + 12. * mr*mr) + * ParticleDataTable::resOpenFrac(24, -24); + } + } + } + + // Calculate prefactors for gamma/Z0/Z'0 cross section terms. + double propZ = sH / ( pow2(sH - m2Z) + pow2(sH * GamMRatZ) ); + double propZp = sH / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + gamNorm = 4. * M_PI * pow2(alpEM) / (3. * sH); + gamZNorm = gamNorm * 2. * thetaWRat * (sH - m2Z) * propZ; + ZNorm = gamNorm * pow2(thetaWRat) * sH * propZ; + gamZpNorm = gamNorm * 2. * thetaWRat * (sH - m2Res) * propZp; + ZZpNorm = gamNorm * 2. * pow2(thetaWRat) * ((sH - m2Z) * (sH - m2Res) + + sH * GamMRatZ * sH * GamMRat) * propZ * propZp; + ZpNorm = gamNorm * pow2(thetaWRat) * sH * propZp; + + // Optionally only keep some of gamma*, Z0 and Z' terms. + if (gmZmode == 1) {gamZNorm = 0; ZNorm = 0.; gamZpNorm = 0.; + ZZpNorm = 0.; ZpNorm = 0.;} + if (gmZmode == 2) {gamNorm = 0.; gamZNorm = 0.; gamZpNorm = 0.; + ZZpNorm = 0.; ZpNorm = 0.;} + if (gmZmode == 3) {gamNorm = 0.; gamZNorm = 0.; ZNorm = 0.; + gamZpNorm = 0.; ZZpNorm = 0.;} + if (gmZmode == 4) {gamZpNorm = 0.; ZZpNorm = 0.; ZpNorm = 0.;} + if (gmZmode == 5) {gamZNorm = 0.; ZNorm = 0.; ZZpNorm = 0.;} + if (gmZmode == 6) {gamNorm = 0.; gamZNorm = 0.; gamZpNorm = 0.;} + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma1ffbar2gmZZprime::sigmaHat() { + + // Couplings to an incoming flavour. + int idAbs = abs(id1); + double ei = CoupEW::ef(idAbs); + double ai = CoupEW::af(idAbs); + double vi = CoupEW::vf(idAbs); + double api = afZp[idAbs]; + double vpi = vfZp[idAbs]; + double ei2 = ei * ei; + double eivi = ei * vi; + double vai2 = vi * vi + ai * ai; + double eivpi = ei * vpi; + double vaivapi = vi * vpi + ai * api;; + double vapi2 = vpi * vpi + api * api; + + // Combine gamma, interference and Z0 parts. + double sigma = ei2 * gamNorm * gamSum + eivi * gamZNorm * gamZSum + + vai2 * ZNorm * ZSum + eivpi * gamZpNorm * gamZpSum + + vaivapi * ZZpNorm * ZZpSum + vapi2 * ZpNorm * ZpSum; + + // Colour factor. Answer. + if (idAbs < 9) sigma /= 3.; + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ffbar2gmZZprime::setIdColAcol() { + + // Flavours trivial. + setId( id1, id2, 32); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for gamma*/Z0/Z'0 decay angle. + +double Sigma1ffbar2gmZZprime::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Default values, in- and out-flavours in process. + double wt = 1.; + double wtMax = 1.; + int idInAbs = process[3].idAbs(); + int idOutAbs = process[6].idAbs(); + + // Angular weight for outgoing fermion pair. + if (iResBeg == 5 && iResEnd == 5 && + (idOutAbs < 7 || ( idOutAbs > 10 && idOutAbs < 17)) ) { + + // Couplings for in- and out-flavours. + double ei = CoupEW::ef(idInAbs); + double vi = CoupEW::vf(idInAbs); + double ai = CoupEW::af(idInAbs); + double vpi = vfZp[idInAbs]; + double api = afZp[idInAbs]; + double ef = CoupEW::ef(idOutAbs); + double vf = CoupEW::vf(idOutAbs); + double af = CoupEW::af(idOutAbs); + double vpf = vfZp[idOutAbs]; + double apf = afZp[idOutAbs]; + + // Phase space factors. (One power of beta left out in formulae.) + double mr1 = pow2(process[6].m()) / sH; + double mr2 = pow2(process[7].m()) / sH; + double ps = sqrtpos(pow2(1. - mr1 - mr2) - 4. * mr1 * mr2); + double mrAvg = 0.5 * (mr1 + mr2) - 0.25 * pow2(mr1 - mr2); + + // Coefficients of angular expression. + double coefTran = ei*ei * gamNorm * ef*ef + ei * vi * gamZNorm * ef * vf + + (vi*vi + ai*ai) * ZNorm * (vf*vf + ps*ps * af*af) + + ei * vpi * gamZpNorm * ef * vpf + + (vi * vpi + ai * api) * ZZpNorm * (vf * vpf + ps*ps * af * apf) + + (vpi*vpi + api*api) * ZpNorm * (vpf*vpf + ps*ps * apf*apf); + double coefLong = 4. * mrAvg * ( ei*ei * gamNorm * ef*ef + + ei * vi * gamZNorm * ef * vf + (vi*vi + ai*ai) * ZNorm * vf*vf + + ei * vpi * gamZpNorm * ef * vpf + + (vi * vpi + ai * api) * ZZpNorm * vf * vpf + + (vpi*vpi + api*api) * ZpNorm * vpf*vpf ); + double coefAsym = ps * ( ei * ai * gamZNorm * ef * af + + 4. * vi * ai * ZNorm * vf * af + ei * api * gamZpNorm * ef * apf + + (vi * api + vpi * ai) * ZZpNorm * (vf * apf + vpf * af) + + 4. * vpi * api * ZpNorm * vpf * apf ); + + // Flip asymmetry for in-fermion + out-antifermion. + if (process[3].id() * process[6].id() < 0) coefAsym = -coefAsym; + + // Reconstruct decay angle and weight for it. + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * ps); + wt = coefTran * (1. + pow2(cosThe)) + + coefLong * (1. - pow2(cosThe)) + 2. * coefAsym * cosThe; + wtMax = 2. * (coefTran + abs(coefAsym)); + } + + // Angular weight for Z' -> W+ W-. + else if (iResBeg == 5 && iResEnd == 5 && idOutAbs == 24) { + double mr1 = pow2(process[6].m()) / sH; + double mr2 = pow2(process[7].m()) / sH; + double ps = sqrtpos(pow2(1. - mr1 -mr2) - 4. * mr1 * mr2); + double cCos2 = - (1./16.) * ps*ps * (1. - 2. * mr1 - 2. * mr2 + + mr1*mr1 + mr2*mr2 + 10. * mr1 * mr2); + double cFlat = -cCos2 + 0.5 * (mr1 + mr2) + * (1. - 2. * mr1 - 2. * mr2 + pow2(mr1 - mr2)); + + // Reconstruct decay angle and weight for it. + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * ps); + wt = cFlat + cCos2 * cosThe*cosThe; + wtMax = cFlat + max(0., cCos2); + } + + // Angular weight for f + fbar -> Z' -> W+ + W- -> 4 fermions.. + else if (iResBeg == 6 && iResEnd == 7 && idOutAbs == 24) { + + // Order so that fbar(1) f(2) -> f'(3) fbar'(4) f"(5) fbar"(6). + // with f' fbar' from W- and f" fbar" from W+. + int i1 = (process[3].id() < 0) ? 3 : 4; + int i2 = 7 - i1; + int i3 = (process[8].id() > 0) ? 8 : 9; + int i4 = 17 - i3; + int i5 = (process[10].id() > 0) ? 10 : 11; + int i6 = 21 - i5; + if (process[6].id() > 0) {swap(i3, i5); swap(i4, i6);} + + // Decay distribution like in f fbar -> Z^* -> W+ W-. + if (Rndm::flat() > anglesZpWW) { + + // Set up four-products and internal products. + setupProd( process, i1, i2, i3, i4, i5, i6); + + // tHat and uHat of fbar f -> W- W+, and their squared masses. + int iNeg = (process[6].id() < 0) ? 6 : 7; + int iPos = 13 - iNeg; + double tHres = (process[i1].p() - process[iNeg].p()).m2Calc(); + double uHres = (process[i1].p() - process[iPos].p()).m2Calc(); + double s3now = process[iNeg].m2(); + double s4now = process[iPos].m2(); + + // Kinematics combinations (norm(x) = |x|^2). + double fGK135 = norm(fGK( 1, 2, 3, 4, 5, 6) - fGK( 1, 2, 5, 6, 3, 4) ); + double fGK253 = norm(fGK( 2, 1, 5, 6, 3, 4) - fGK( 2, 1, 3, 4, 5, 6) ); + double xiT = xiGK( tHres, uHres, s3now, s4now); + double xiU = xiGK( uHres, tHres, s3now, s4now); + double xjTU = xjGK( tHres, uHres, s3now, s4now); + + // Couplings of incoming (anti)fermion. Combine with kinematics. + int idAbs = process[i1].idAbs(); + double li = 0.5 * (vfZp[idAbs] + afZp[idAbs]); + double ri = 0.5 * (vfZp[idAbs] - afZp[idAbs]); + wt = li*li * fGK135 + ri*ri * fGK253; + wtMax = 4. * s3now * s4now * (li*li + ri*ri) + * (xiT + xiU - xjTU); + + // Decay distribution like in f fbar -> h^0 -> W+ W-. + } else { + double p35 = 2. * process[i3].p() * process[i5].p(); + double p46 = 2. * process[i4].p() * process[i6].p(); + wt = 16. * p35 * p46; + wtMax = sH2; + } + } + + // Angular weight in top decay by standard routine. + else if (process[process[iResBeg].mother1()].idAbs() == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + + // Done. + return (wt / wtMax); + +} + +//************************************************************************** + +// Sigma1ffbar2Wprime class. +// Cross section for f fbar' -> W'+- (f is quark or lepton). + +//********* + +// Initialize process. + +void Sigma1ffbar2Wprime::initProc() { + + // Store W+- mass and width for propagator. + mRes = ParticleDataTable::m0(34); + GammaRes = ParticleDataTable::mWidth(34); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + thetaWRat = 1. / (12. * CoupEW::sin2thetaW()); + + // Axial and vector couplings of fermions. + aqWp = Settings::parm("Wprime:aq"); + vqWp = Settings::parm("Wprime:vq"); + alWp = Settings::parm("Wprime:al"); + vlWp = Settings::parm("Wprime:vl"); + + // Coupling for W' -> W Z and decay angular admixture. + coupWpWZ = Settings::parm("Wprime:coup2WZ"); + anglesWpWZ = Settings::parm("Wprime:anglesWZ"); + + // Set pointer to particle properties and decay table. + particlePtr = ParticleDataTable::particleDataPtr(34); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1ffbar2Wprime::sigmaKin() { + + // Set up Breit-Wigner. Cross section for W+ and W- separately. + double sigBW = 12. * M_PI / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + double preFac = alpEM * thetaWRat * mH; + sigma0Pos = preFac * sigBW * particlePtr->resWidthOpen(34, mH); + sigma0Neg = preFac * sigBW * particlePtr->resWidthOpen(-34, mH); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma1ffbar2Wprime::sigmaHat() { + + // Secondary width for W+ or W-. CKM and colour factors. + int idUp = (abs(id1)%2 == 0) ? id1 : id2; + double sigma = (idUp > 0) ? sigma0Pos : sigma0Neg; + if (abs(id1) < 7) sigma *= VCKM::V2id(abs(id1), abs(id2)) / 3.; + + // Couplings. + if (abs(id1) < 7) sigma *= 0.5 * (aqWp * aqWp + vqWp * vqWp); + else sigma *= 0.5 * (alWp * alWp + vlWp * vlWp); + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ffbar2Wprime::setIdColAcol() { + + // Sign of outgoing W. + int sign = 1 - 2 * (abs(id1)%2); + if (id1 < 0) sign = -sign; + setId( id1, id2, 34 * sign); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for W decay angle. + +double Sigma1ffbar2Wprime::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // Default values, in- and out-flavours in process. + double wt = 1.; + double wtMax = 1.; + int idInAbs = process[3].idAbs(); + int idOutAbs = process[6].idAbs(); + + // Angular weight for outgoing fermion pair. + if (iResBeg == 5 && iResEnd == 5 && + (idOutAbs < 7 || ( idOutAbs > 10 && idOutAbs < 17)) ) { + + // Couplings for in- and out-flavours. + double ai = (idInAbs < 9) ? aqWp : alWp; + double vi = (idInAbs < 9) ? vqWp : vlWp; + double af = (idOutAbs < 9) ? aqWp : alWp; + double vf = (idOutAbs < 9) ? vqWp : vlWp; + + // Asymmetry expression. + double coefAsym = 8. * vi * ai * vf * af + / ((vi*vi + ai*ai) * (vf*vf + af*af)); + + // Flip asymmetry for in-fermion + out-antifermion. + if (process[3].id() * process[6].id() < 0) coefAsym = -coefAsym; + + // Phase space factors. + double mr1 = pow2(process[6].m()) / sH; + double mr2 = pow2(process[7].m()) / sH; + double ps = sqrtpos(pow2(1. - mr1 - mr2) - 4. * mr1 * mr2); + + // Reconstruct decay angle and weight for it. + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * ps); + wt = 1. + coefAsym * cosThe + cosThe * cosThe; + wtMax = 2. + abs(coefAsym); + } + + // Angular weight for W' -> W Z. + else if (iResBeg == 5 && iResEnd == 5 && idOutAbs == 24) { + double mr1 = pow2(process[6].m()) / sH; + double mr2 = pow2(process[7].m()) / sH; + double ps = sqrtpos(pow2(1. - mr1 - mr2) - 4. * mr1 * mr2); + double cCos2 = - (1./16.) * ps*ps * (1. - 2. * mr1 - 2. * mr2 + + mr1*mr1 + mr2*mr2 + 10. * mr1 * mr2); + double cFlat = -cCos2 + 0.5 * (mr1 + mr2) + * (1. - 2. * mr1 - 2. * mr2 + pow2(mr1 - mr2)); + + // Reconstruct decay angle and weight for it. + double cosThe = (process[3].p() - process[4].p()) + * (process[7].p() - process[6].p()) / (sH * ps); + wt = cFlat + cCos2 * cosThe*cosThe; + wtMax = cFlat + max(0., cCos2); + } + + // Angular weight for f + fbar -> W' -> W + Z -> 4 fermions. + else if (iResBeg == 6 && iResEnd == 7 + && (idOutAbs == 24 || idOutAbs == 23)) { + + // Order so that fbar(1) f(2) -> f'(3) fbar'(4) f"(5) fbar"(6). + // with f' fbar' from W and f" fbar" from Z. + int i1 = (process[3].id() < 0) ? 3 : 4; + int i2 = 7 - i1; + int i3 = (process[8].id() > 0) ? 8 : 9; + int i4 = 17 - i3; + int i5 = (process[10].id() > 0) ? 10 : 11; + int i6 = 21 - i5; + if (process[6].id() == 23) {swap(i3, i5); swap(i4, i6);} + + // Decay distribution like in f fbar -> Z^* -> W+ W-. + if (Rndm::flat() > anglesWpWZ) { + + // Set up four-products and internal products. + setupProd( process, i1, i2, i3, i4, i5, i6); + + // tHat and uHat of fbar f -> W Z, and their squared masses. + int iW = (process[6].id() == 23) ? 7 : 6; + int iZ = 13 - iW; + double tHres = (process[i1].p() - process[iW].p()).m2Calc(); + double uHres = (process[i1].p() - process[iZ].p()).m2Calc(); + double s3now = process[iW].m2(); + double s4now = process[iZ].m2(); + + // Kinematics combinations (norm(x) = |x|^2). + double fGK135 = norm(fGK( 1, 2, 3, 4, 5, 6) - fGK( 1, 2, 5, 6, 3, 4) ); + double fGK136 = norm(fGK( 1, 2, 3, 4, 6, 5) - fGK( 1, 2, 6, 5, 3, 4) ); + double xiT = xiGK( tHres, uHres, s3now, s4now); + double xiU = xiGK( uHres, tHres, s3now, s4now); + double xjTU = xjGK( tHres, uHres, s3now, s4now); + + // Couplings of outgoing fermion from Z. Combine with kinematics. + int idAbs = process[i5].idAbs(); + double lfZ = CoupEW::lf(idAbs); + double rfZ = CoupEW::rf(idAbs); + wt = lfZ*lfZ * fGK135 + rfZ*rfZ * fGK136; + wtMax = 4. * s3now * s4now * (lfZ*lfZ + rfZ*rfZ) + * (xiT + xiU - xjTU); + + // Decay distribution like in f fbar -> H^+- -> W+- Z0. + } else { + double p35 = 2. * process[i3].p() * process[i5].p(); + double p46 = 2. * process[i4].p() * process[i6].p(); + wt = 16. * p35 * p46; + wtMax = sH2; + } + } + + // Angular weight in top decay by standard routine. + else if (process[process[iResBeg].mother1()].idAbs() == 6) + return weightTopDecay( process, iResBeg, iResEnd); + + // Done. + return (wt / wtMax); + +} + + +//************************************************************************** + +// Sigma1ffbar2Rhorizontal class. +// Cross section for f fbar' -> R^0 (f is a quark or lepton). + +//********* + +// Initialize process. + +void Sigma1ffbar2Rhorizontal::initProc() { + + // Store R^0 mass and width for propagator. + mRes = ParticleDataTable::m0(41); + GammaRes = ParticleDataTable::mWidth(41); + m2Res = mRes*mRes; + GamMRat = GammaRes / mRes; + thetaWRat = 1. / (12. * CoupEW::sin2thetaW()); + + // Set pointer to particle properties and decay table. + particlePtr = ParticleDataTable::particleDataPtr(41); + +} + +//********* + +// Evaluate sigmaHat(sHat), part independent of incoming flavour. + +void Sigma1ffbar2Rhorizontal::sigmaKin() { + + // Set up Breit-Wigner. Cross section for W+ and W- separately. + double sigBW = 12. * M_PI / ( pow2(sH - m2Res) + pow2(sH * GamMRat) ); + double preFac = alpEM * thetaWRat * mH; + sigma0Pos = preFac * sigBW * particlePtr->resWidthOpen(41, mH); + sigma0Neg = preFac * sigBW * particlePtr->resWidthOpen(-41, mH); + +} + +//********* + +// Evaluate sigmaHat(sHat), including incoming flavour dependence. + +double Sigma1ffbar2Rhorizontal::sigmaHat() { + + // Check for allowed flavour combinations, one generation apart. + if (id1 * id2 > 0 || abs(id1 + id2) != 2) return 0.; + + // Find whether R0 or R0bar. Colour factors. + double sigma = (id1 + id2 > 0) ? sigma0Pos : sigma0Neg; + if (abs(id1) < 7) sigma /= 3.; + + // Answer. + return sigma; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma1ffbar2Rhorizontal::setIdColAcol() { + + // Outgoing R0 or R0bar. + id3 = (id1 +id2 > 0) ? 41 : -41; + setId( id1, id2, id3); + + // Colour flow topologies. Swap when antiquarks. + if (abs(id1) < 9) setColAcol( 1, 0, 0, 1, 0, 0); + else setColAcol( 0, 0, 0, 0, 0, 0); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SigmaOnia.cxx b/PYTHIA8/pythia8130/src/SigmaOnia.cxx new file mode 100644 index 00000000000..649b5b0e8c3 --- /dev/null +++ b/PYTHIA8/pythia8130/src/SigmaOnia.cxx @@ -0,0 +1,626 @@ +// SigmaOnia.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// charmonia/bottomonia simulation classes. + +#include "SigmaOnia.h" + +namespace Pythia8 { + +//************************************************************************** + +// Sigma2gg2QQbar3S11g class. +// Cross section g g -> QQbar[3S1(1)] g (Q = c or b). + +//********* + +// Initialize process. + +void Sigma2gg2QQbar3S11g::initProc() { + + // Produced state. Process name. Onium matrix element. + idHad = (idNew == 4) ? 443 : 553; + nameSave = (idNew == 4) ? "g g -> ccbar[3S1(1)] g" + : "g g -> bbbar[3S1(1)] g"; + oniumME = (idNew == 4) ? Settings::parm("Charmonium:OJpsi3S11") + : Settings::parm("Bottomonium:OUpsilon3S11"); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat); no explicit flavour dependence. + +void Sigma2gg2QQbar3S11g::sigmaKin() { + + // Calculate kinematics dependence. + double stH = sH + tH; + double tuH = tH + uH; + double usH = uH + sH; + double sig = (10. * M_PI / 81.) * m3 * ( pow2(sH * tuH) + + pow2(tH * usH) + pow2(uH * stH) ) / pow2( stH * tuH * usH ); + + // Answer. + sigma = (M_PI/sH2) * pow3(alpS) * oniumME * sig; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2gg2QQbar3S11g::setIdColAcol() { + + // Flavours are trivial. + setId( id1, id2, idHad, 21); + + // Two orientations of colour flow.. + setColAcol( 1, 2, 2, 3, 0, 0, 1, 3); + if (Rndm::flat() > 0.5) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2gg2QQbar3PJ1g class. +// Cross section g g -> QQbar[3PJ(1)] g (Q = c or b, J = 0, 1 or 2). + +//********* + +// Initialize process. + +void Sigma2gg2QQbar3PJ1g::initProc() { + + // Produced state. Process name. Onium matrix element. + idHad = 0; + nameSave = "illegal process"; + if (jSave == 0) { + idHad = (idNew == 4) ? 10441 : 10551; + nameSave = (idNew == 4) ? "g g -> ccbar[3P0(1)] g" + : "g g -> bbbar[3P0(1)] g"; + } else if (jSave == 1) { + idHad = (idNew == 4) ? 20443 : 20553; + nameSave = (idNew == 4) ? "g g -> ccbar[3P1(1)] g" + : "g g -> bbbar[3P1(1)] g"; + } else if (jSave == 2) { + idHad = (idNew == 4) ? 445 : 555; + nameSave = (idNew == 4) ? "g g -> ccbar[3P2(1)] g" + : "g g -> bbbar[3P2(1)] g"; + } + oniumME = (idNew == 4) ? Settings::parm("Charmonium:Ochic03P01") + : Settings::parm("Bottomonium:Ochib03P01"); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat); no explicit flavour dependence. + +void Sigma2gg2QQbar3PJ1g::sigmaKin() { + + // Useful derived kinematics quantities. + double pRat = (sH * uH + uH * tH + tH * sH)/ sH2; + double qRat = tH * uH / sH2; + double rRat = s3 / sH; + double pRat2 = pRat * pRat; + double pRat3 = pRat2 * pRat; + double pRat4 = pRat3 * pRat; + double qRat2 = qRat * qRat; + double qRat3 = qRat2 * qRat; + double qRat4 = qRat3 * qRat; + double rRat2 = rRat * rRat; + double rRat3 = rRat2 * rRat; + double rRat4 = rRat3 * rRat; + + // Calculate kinematics dependence. + double sig = 0.; + if (jSave == 0) { + sig = (8. * M_PI / (9. * m3 * sH)) + * ( 9. * rRat2 * pRat4 * (rRat4 - 2. * rRat2 * pRat + pRat2) + - 6. * rRat * pRat3 * qRat * (2. * rRat4 - 5. * rRat2 * pRat + + pRat2) - pRat2 * qRat2 * (rRat4 + 2. * rRat2 * pRat - pRat2) + + 2. * rRat * pRat * qRat3 * (rRat2 - pRat) + 6. * rRat2 * qRat4) + / (qRat * pow4(qRat - rRat * pRat)); + } else if (jSave == 1) { + sig = (8. * M_PI / (3.* m3 * sH)) * pRat2 + * (rRat * pRat2 * (rRat2 - 4. * pRat) + + 2. * qRat * (-rRat4 + 5. * rRat2 * pRat + pRat2) + - 15. * rRat * qRat2) / pow4(qRat - rRat * pRat); + } else if (jSave == 2) { + sig = (8. * M_PI / (9. * m3 * sH)) + * (12. * rRat2 * pRat4 * (rRat4 - 2. * rRat2 * pRat + pRat2) + - 3. * rRat * pRat3 * qRat * (8. * rRat4 - rRat2 * pRat + 4. * pRat2) + + 2. * pRat2 * qRat2 * (-7. * rRat4 + 43. * rRat2 * pRat + pRat2) + + rRat * pRat * qRat3 * (16. * rRat2 - 61. * pRat) + + 12. * rRat2 * qRat4) / (qRat * pow4(qRat-rRat * pRat)); + } + + // Answer. + sigma = (M_PI/sH2) * pow3(alpS) * oniumME * sig; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2gg2QQbar3PJ1g::setIdColAcol() { + + // Flavours are trivial. + setId( id1, id2, idHad, 21); + + // Two orientations of colour flow. + setColAcol( 1, 2, 2, 3, 0, 0, 1, 3); + if (Rndm::flat() > 0.5) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2qg2QQbar3PJ1q class. +// Cross section q g -> QQbar[3PJ(1)] q (Q = c or b, J = 0, 1 or 2). + +//********* + +// Initialize process. + +void Sigma2qg2QQbar3PJ1q::initProc() { + + // Produced state. Process name. Onium matrix element. + idHad = 0; + nameSave = "illegal process"; + if (jSave == 0) { + idHad = (idNew == 4) ? 10441 : 10551; + nameSave = (idNew == 4) ? "q g -> ccbar[3P0(1)] q" + : "q g -> bbbar[3P0(1)] q"; + } else if (jSave == 1) { + idHad = (idNew == 4) ? 20443 : 20553; + nameSave = (idNew == 4) ? "q g -> ccbar[3P1(1)] q" + : "q g -> bbbar[3P1(1)] q"; + } else if (jSave == 2) { + idHad = (idNew == 4) ? 445 : 555; + nameSave = (idNew == 4) ? "q g -> ccbar[3P2(1)] q" + : "q g -> bbbar[3P2(1)] q"; + } + oniumME = (idNew == 4) ? Settings::parm("Charmonium:Ochic03P01") + : Settings::parm("Bottomonium:Ochib03P01"); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat); no explicit flavour dependence. + +void Sigma2qg2QQbar3PJ1q::sigmaKin() { + + // Calculate kinematics dependence. + double usH = uH + sH; + double sig = 0.; + if (jSave == 0) { + sig = - (16. * M_PI / 81.) * pow2(tH - 3. * s3) * (sH2 + uH2) + / (m3 * tH * pow4(usH)); + } else if (jSave == 1) { + sig = - (32. * M_PI / 27.) * (4. * s3 * sH * uH + tH * (sH2 + uH2)) + / (m3 * pow4(usH)); + } else if (jSave == 2) { + sig = - (32. *M_PI / 81.) * ( (6. * s3*s3 + tH2) * pow2(usH) + - 2. * sH * uH * (tH2 + 6. * s3 * usH)) / (m3 * tH * pow4(usH)); + } + + // Answer. + sigma = (M_PI/sH2) * pow3(alpS) * oniumME * sig; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qg2QQbar3PJ1q::setIdColAcol() { + + // Flavours are trivial. + int idq = (id2 == 21) ? id1 : id2; + setId( id1, id2, idHad, idq); + + // tH defined between q_in and q_out: must swap tHat <-> uHat if q g in. + swapTU = (id2 == 21); + + // Colour flow topologies. Swap when antiquarks. + if (id2 == 21) setColAcol( 1, 0, 2, 1, 0, 0, 2, 0); + else setColAcol( 2, 1, 1, 0, 0, 0, 2, 0); + if (idq < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2qqbar2QQbar3PJ1g class. +// Cross section q qbar -> QQbar[3PJ(1)] g (Q = c or b, J = 0, 1 or 2). + +//********* + +// Initialize process. + +void Sigma2qqbar2QQbar3PJ1g::initProc() { + + // Produced state. Process name. Onium matrix element. + idHad = 0; + nameSave = "illegal process"; + if (jSave == 0) { + idHad = (idNew == 4) ? 10441 : 10551; + nameSave = (idNew == 4) ? "q qbar -> ccbar[3P0(1)] g" + : "q qbar -> bbbar[3P0(1)] g"; + } else if (jSave == 1) { + idHad = (idNew == 4) ? 20443 : 20553; + nameSave = (idNew == 4) ? "q qbar -> ccbar[3P1(1)] g" + : "q qbar -> bbbar[3P1(1)] g"; + } else if (jSave == 2) { + idHad = (idNew == 4) ? 445 : 555; + nameSave = (idNew == 4) ? "q qbar -> ccbar[3P2(1)] g" + : "q qbar -> bbbar[3P2(1)] g"; + } + oniumME = (idNew == 4) ? Settings::parm("Charmonium:Ochic03P01") + : Settings::parm("Bottomonium:Ochib03P01"); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat); no explicit flavour dependence. + +void Sigma2qqbar2QQbar3PJ1g::sigmaKin() { + + // Calculate kinematics dependence. + double tuH = tH + uH; + double sig = 0.; + if (jSave == 0) { + sig =(128. * M_PI / 243.) * pow2(sH - 3. * s3) * (tH2 + uH2) + / (m3 * sH * pow4(tuH)); + } else if (jSave == 1) { + sig = (256. * M_PI / 81.) * (4. * s3 * tH * uH + sH * (tH2 + uH2)) + / (m3 * pow4(tuH)); + } else if (jSave == 2) { + sig = (256. * M_PI / 243.) * ( (6. * s3*s3 + sH2) * pow2(tuH) + - 2. * tH * uH * (sH2 + 6. * s3 * tuH) )/ (m3 * sH * pow4(tuH)); + } + + // Answer. + sigma = (M_PI/sH2) * pow3(alpS) * oniumME * sig; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2QQbar3PJ1g::setIdColAcol() { + + // Flavours are trivial. + setId( id1, id2, idHad, 21); + + // Colour flow topologies. Swap when antiquarks. + setColAcol( 1, 0, 0, 2, 0, 0, 1, 2); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2gg2QQbarX8g class. +// Cross section g g -> QQbar[X(8)] g (Q = c or b, X = 3S1, 1S0 or 3PJ). + +//********* + +// Initialize process. + +void Sigma2gg2QQbarX8g::initProc() { + + // Produced state. Process name. Onium matrix element. + idHad = 0; + nameSave = "illegal process"; + if (stateSave == 0) { + idHad = (idNew == 4) ? 9900443 : 9900553; + nameSave = (idNew == 4) ? "g g -> ccbar[3S1(8)] g" + : "g g -> bbbar[3S1(8)] g"; + oniumME = (idNew == 4) ? Settings::parm("Charmonium:OJpsi3S18") + : Settings::parm("Bottomonium:OUpsilon3S18"); + } else if (stateSave == 1) { + idHad = (idNew == 4) ? 9900441 : 9900551; + nameSave = (idNew == 4) ? "g g -> ccbar[1S0(8)] g" + : "g g -> bbbar[1S0(8)] g"; + oniumME = (idNew == 4) ? Settings::parm("Charmonium:OJpsi1S08") + : Settings::parm("Bottomonium:OUpsilon1S08"); + } else if (stateSave == 2) { + idHad = (idNew == 4) ? 9910441 : 9910551; + nameSave = (idNew == 4) ? "g g -> ccbar[3PJ(8)] g" + : "g g -> bbbar[3PJ(8)] g"; + oniumME = (idNew == 4) ? Settings::parm("Charmonium:OJpsi3P08") + : Settings::parm("Bottomonium:OUpsilon3P08"); + } + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat); no explicit flavour dependence. + +void Sigma2gg2QQbarX8g::sigmaKin() { + + // Calculate kinematics dependence. + double stH = sH + tH; + double tuH = tH + uH; + double usH = uH + sH; + double sig = 0.; + if (stateSave == 0) { + sig = (M_PI / 72.) * m3 * ( 27. * (pow2(stH) + pow2(tuH) + + pow2(usH)) / (s3*s3) - 16. ) * ( pow2(sH * tuH) + + pow2(tH * usH) + pow2(uH * stH) ) / pow2( stH * tuH * usH ); + } else if (stateSave == 1) { + sig = (5. * M_PI / 16.) * m3 * ( pow2(uH / (tuH * usH)) + + pow2(sH / (stH * usH)) + pow2(tH / (stH * tuH)) ) * ( 12. + + (pow4(stH) + pow4(tuH) + pow4(usH)) / (s3 * sH * tH * uH) ); + } else if (stateSave == 2) { + double sH3 = sH2 * sH; + double sH4 = sH3 * sH; + double sH5 = sH4 * sH; + double sH6 = sH5 * sH; + double sH7 = sH6 * sH; + double sH8 = sH7 * sH; + double tH3 = tH2 * tH; + double tH4 = tH3 * tH; + double tH5 = tH4 * tH; + double tH6 = tH5 * tH; + double tH7 = tH6 * tH; + double tH8 = tH7 * tH; + double ssttH = sH * sH + sH * tH + tH * tH; + sig = 5. * M_PI * (3. * sH * tH * stH * pow4(ssttH) + - s3 * pow2(ssttH) * (7. * sH6 + 36. * sH5 * tH + 45. * sH4 * tH2 + + 28. * sH3 * tH3 + 45. * sH2 * tH4 + 36. * sH * tH5 + 7. * tH6) + + pow2(s3) * stH * (35. *sH8 + 169. * sH7 * tH + 299. * sH6 * tH2 + + 401. * sH5 * tH3 + 418. * sH4 * tH4 + 401. * sH3 * tH5 + + 299. * sH2 * tH6 + 169. * sH * tH7 + 35. * tH8) + - pow3(s3) * (84. *sH8+432. *sH7*tH+905. *sH6*tH2 + + 1287. * sH5 * tH3 + 1436. * sH4 * tH4 +1287. * sH3 * tH5 + + 905. * sH2 * tH6 + 432. * sH * tH7 + 84. * tH8) + + pow4(s3) * stH * (126. * sH6 + 451. * sH5 * tH +677. * sH4 * tH2 + + 836. * sH3 * tH3 + 677. * sH2 * tH4 + 451. * sH * tH5 + + 126. * tH6) + - pow5(s3) * 3. * (42. * sH6 + 171. * sH5 * tH + 304. * sH4 * tH2 + + 362. * sH3 * tH3 + 304. * sH2 * tH4 + 171. * sH * tH5 + + 42. * tH6) + + pow3(s3 * s3) * 2. * stH * (42. * sH4 + 106. * sH3 * tH + + 119. * sH2 * tH2 + 106. * sH * tH3 + 42. * tH4) + - pow4(s3) * pow3(s3) * (35. * sH4 + 99. * sH3 * tH + + 120. * sH2 * tH2 + 99. * sH * tH3 + 35. * tH4) + + pow4(s3 * s3) * 7. * stH * ssttH) + / (sH * tH * uH * s3 * m3 * pow3(stH * tuH * usH)); + } + + // Answer. + sigma = (M_PI/sH2) * pow3(alpS) * oniumME * sig; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2gg2QQbarX8g::setIdColAcol() { + + // Flavours are trivial. + setId( id1, id2, idHad, 21); + + // Split total contribution into different colour flows just like in + // g g -> g g (with kinematics recalculated for massless partons). + double sHr = - (tH + uH); + double sH2r = sHr * sHr; + double sigTS = tH2/sH2r + 2.*tH/sHr + 3. + 2.*sHr/tH + sH2r/tH2; + double sigUS = uH2/sH2r + 2.*uH/sHr + 3. + 2.*sHr/uH + sH2r/uH2; + double sigTU = tH2/uH2 + 2.*tH/uH + 3. + 2.*uH/tH + uH2/tH2; + double sigSum = sigTS + sigUS + sigTU; + + // Three colour flow topologies, each with two orientations. + double sigRand = sigSum * Rndm::flat(); + if (sigRand < sigTS) setColAcol( 1, 2, 2, 3, 1, 4, 4, 3); + else if (sigRand < sigTS + sigUS) + setColAcol( 1, 2, 3, 1, 3, 4, 4, 2); + else setColAcol( 1, 2, 3, 4, 1, 4, 3, 2); + if (Rndm::flat() > 0.5) swapColAcol(); + + +} + +//************************************************************************** + +// Sigma2qg2QQbarX8q class. +// Cross section q g -> QQbar[X(8)] q (Q = c or b, X = 3S1, 1S0 or 3PJ). + +//********* + +// Initialize process. + +void Sigma2qg2QQbarX8q::initProc() { + + // Produced state. Process name. Onium matrix element. + idHad = 0; + nameSave = "illegal process"; + if (stateSave == 0) { + idHad = (idNew == 4) ? 9900443 : 9900553; + nameSave = (idNew == 4) ? "q g -> ccbar[3S1(8)] q" + : "q g -> bbbar[3S1(8)] q"; + oniumME = (idNew == 4) ? Settings::parm("Charmonium:OJpsi3S18") + : Settings::parm("Bottomonium:OUpsilon3S18"); + } else if (stateSave == 1) { + idHad = (idNew == 4) ? 9900441 : 9900551; + nameSave = (idNew == 4) ? "q g -> ccbar[1S0(8)] q" + : "q g -> bbbar[1S0(8)] q"; + oniumME = (idNew == 4) ? Settings::parm("Charmonium:OJpsi1S08") + : Settings::parm("Bottomonium:OUpsilon1S08"); + } else if (stateSave == 2) { + idHad = (idNew == 4) ? 9910441 : 9910551; + nameSave = (idNew == 4) ? "q g -> ccbar[3PJ(8)] q" + : "q g -> bbbar[3PJ(8)] q"; + oniumME = (idNew == 4) ? Settings::parm("Charmonium:OJpsi3P08") + : Settings::parm("Bottomonium:OUpsilon3P08"); + } + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat); no explicit flavour dependence. + +void Sigma2qg2QQbarX8q::sigmaKin() { + + // Calculate kinematics dependence. + double stH = sH + tH; + double tuH = tH + uH; + double usH = uH + sH; + double stH2 = stH * stH; + double tuH2 = tuH * tuH; + double usH2 = usH * usH; + double sig = 0.; + if (stateSave == 0) { + sig = - (M_PI / 27.)* (4. * (sH2 + uH2) - sH * uH) * (stH2 +tuH2) + / (s3 * m3 * sH * uH * usH2); + } else if (stateSave == 1) { + sig = - (5. * M_PI / 18.) * (sH2 + uH2) / (m3 * tH * usH2); + } else if (stateSave == 2) { + sig = - (10. * M_PI / 9.) * ( (7. * usH + 8. * tH) * (sH2 + uH2) + + 4. * tH * (2. * pow2(s3) - stH2 - tuH2) ) + / (s3 * m3 * tH * usH2 * usH); + } + + // Answer. + sigma = (M_PI/sH2) * pow3(alpS) * oniumME * sig; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qg2QQbarX8q::setIdColAcol() { + + // Flavours are trivial. + int idq = (id2 == 21) ? id1 : id2; + setId( id1, id2, idHad, idq); + + // tH defined between q_in and q_out: must swap tHat <-> uHat if q g in. + swapTU = (id2 == 21); + + // Split total contribution into different colour flows just like in + // q g -> q g (with kinematics recalculated for massless partons). + double sHr = - (tH + uH); + double sH2r = sHr * sHr; + double sigTS = uH2/tH2 - (4./9.) * uH/sHr; + double sigTU = sH2r/tH2 - (4./9.) * sHr/uH; + double sigSum = sigTS + sigTU; + + // Two colour flow topologies. Swap if first is gluon, or when antiquark. + double sigRand = sigSum * Rndm::flat(); + if (sigRand < sigTS) setColAcol( 1, 0, 2, 1, 2, 3, 3, 0); + else setColAcol( 1, 0, 2, 3, 1, 3, 2, 0); + if (id1 == 21) swapCol12(); + if (idq < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2qqbar2QQbarX8g class. +// Cross section q qbar -> QQbar[X(8)] g (Q = c or b, X = 3S1, 1S0 or 3PJ). + +//********* + +// Initialize process. + +void Sigma2qqbar2QQbarX8g::initProc() { + + // Produced state. Process name. Onium matrix element. + idHad = 0; + nameSave = "illegal process"; + if (stateSave == 0) { + idHad = (idNew == 4) ? 9900443 : 9900553; + nameSave = (idNew == 4) ? "q qbar -> ccbar[3S1(8)] g" + : "q qbar -> bbbar[3S1(8)] g"; + oniumME = (idNew == 4) ? Settings::parm("Charmonium:OJpsi3S18") + : Settings::parm("Bottomonium:OUpsilon3S18"); + } else if (stateSave == 1) { + idHad = (idNew == 4) ? 9900441 : 9900551; + nameSave = (idNew == 4) ? "q qbar -> ccbar[1S0(8)] g" + : "q qbar -> bbbar[1S0(8)] g"; + oniumME = (idNew == 4) ? Settings::parm("Charmonium:OJpsi1S08") + : Settings::parm("Bottomonium:OUpsilon1S08"); + } else if (stateSave == 2) { + idHad = (idNew == 4) ? 9910441 : 9910551; + nameSave = (idNew == 4) ? "q qbar -> ccbar[3PJ(8)] g" + : "q qbar -> bbbar[3PJ(8)] g"; + oniumME = (idNew == 4) ? Settings::parm("Charmonium:OJpsi3P08") + : Settings::parm("Bottomonium:OUpsilon3P08"); + } + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat); no explicit flavour dependence. + +void Sigma2qqbar2QQbarX8g::sigmaKin() { + + // Calculate kinematics dependence. + double stH = sH + tH; + double tuH = tH + uH; + double usH = uH + sH; + double stH2 = stH * stH; + double tuH2 = tuH * tuH; + double usH2 = usH * usH; + double sig = 0.; + if (stateSave == 0) { + sig = (8. * M_PI / 81.) * (4. * (tH2 + uH2) - tH * uH) + * (stH2 + usH2) / (s3 * m3 * tH * uH * tuH2); + } else if (stateSave == 1) { + sig = (20. * M_PI / 27.) * (tH2 + uH2) / (m3 * sH * tuH2); + } else if (stateSave == 2) { + sig = (80. * M_PI / 27.) * ( (7. * tuH + 8. * sH) * (tH2 + uH2) + + 4. * sH * (2. * pow2(s3) - stH2 -usH2) ) + / (s3 * m3 * sH * tuH2 * tuH); + } + + // Answer. + sigma = (M_PI/sH2) * pow3(alpS) * oniumME * sig; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2QQbarX8g::setIdColAcol() { + + // Flavours are trivial. + setId( id1, id2, idHad, 21); + + // Split total contribution into different colour flows just like in + // q qbar -> g g (with kinematics recalculated for massless partons). + double sHr = - (tH + uH); + double sH2r = sHr * sHr; + double sigTS = (4. / 9.) * uH / tH - uH2 / sH2r; + double sigUS = (4. / 9.) * tH / uH - tH2 / sH2r; + double sigSum = sigTS + sigUS; + + // Two colour flow topologies. Swap if first is antiquark. + double sigRand = sigSum * Rndm::flat(); + if (sigRand < sigTS) setColAcol( 1, 0, 0, 2, 1, 3, 3, 2); + else setColAcol( 1, 0, 0, 2, 3, 2, 1, 3); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +} // end namespace Pythia8 + diff --git a/PYTHIA8/pythia8130/src/SigmaProcess.cxx b/PYTHIA8/pythia8130/src/SigmaProcess.cxx new file mode 100644 index 00000000000..c75cb350d74 --- /dev/null +++ b/PYTHIA8/pythia8130/src/SigmaProcess.cxx @@ -0,0 +1,947 @@ +// SigmaProcess.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// SigmaProcess class, and classes derived from it. + +#include "SigmaProcess.h" + +namespace Pythia8 { + +//************************************************************************** + +// The SigmaProcess class. +// Base class for cross sections. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Conversion of GeV^{-2} to mb for cross section. +const double SigmaProcess::CONVERT2MB = 0.389380; + +// The sum of outgoing masses must not be too close to the cm energy. +const double SigmaProcess::MASSMARGIN = 0.1; + +//********* + +// Perform simple initialization and store pointers. + +void SigmaProcess::init(Info* infoPtrIn, BeamParticle* beamAPtrIn, + BeamParticle* beamBPtrIn, AlphaStrong* alphaSPtrIn, + AlphaEM* alphaEMPtrIn,SigmaTotal* sigmaTotPtrIn, + SusyLesHouches* slhaPtrIn) { + + // Store pointers. + infoPtr = infoPtrIn; + beamAPtr = beamAPtrIn; + beamBPtr = beamBPtrIn; + alphaSPtr = alphaSPtrIn; + alphaEMPtr = alphaEMPtrIn; + sigmaTotPtr = sigmaTotPtrIn; + slhaPtr = slhaPtrIn; + + // Read out some properties of beams to allow shorthand. + idA = beamAPtr->id(); + idB = beamBPtr->id(); + mA = beamAPtr->m(); + mB = beamBPtr->m(); + isLeptonA = beamAPtr->isLepton(); + isLeptonB = beamBPtr->isLepton(); + hasLeptonBeams = isLeptonA || isLeptonB; + + // K factor, multiplying resolved processes. (But not here for MI.) + Kfactor = Settings::parm("SigmaProcess:Kfactor"); + + // Maximum incoming quark flavour. + nQuarkIn = Settings::mode("PDFinProcess:nQuarkIn"); + + // Renormalization scale choice. + renormScale1 = Settings::mode("SigmaProcess:renormScale1"); + renormScale2 = Settings::mode("SigmaProcess:renormScale2"); + renormScale3 = Settings::mode("SigmaProcess:renormScale3"); + renormScale3VV = Settings::mode("SigmaProcess:renormScale3VV"); + renormMultFac = Settings::parm("SigmaProcess:renormMultFac"); + renormFixScale = Settings::parm("SigmaProcess:renormFixScale"); + + // Factorization scale choice. + factorScale1 = Settings::mode("SigmaProcess:factorScale1"); + factorScale2 = Settings::mode("SigmaProcess:factorScale2"); + factorScale3 = Settings::mode("SigmaProcess:factorScale3"); + factorScale3VV = Settings::mode("SigmaProcess:factorScale3VV"); + factorMultFac = Settings::parm("SigmaProcess:factorMultFac"); + factorFixScale = Settings::parm("SigmaProcess:factorFixScale"); + + // CP violation parameters for the BSM Higgs sector. + higgsH1parity = Settings::mode("HiggsH1:parity"); + higgsH1eta = Settings::parm("HiggsH1:etaParity"); + higgsH2parity = Settings::mode("HiggsH2:parity"); + higgsH2eta = Settings::parm("HiggsH2:etaParity"); + higgsA3parity = Settings::mode("HiggsA3:parity"); + higgsA3eta = Settings::parm("HiggsA3:etaParity"); + + // If BSM not switched on then H1 should have SM properties. + if (!Settings::flag("Higgs:useBSM")){ + higgsH1parity = 1; + higgsH1eta = 0.; + } + +} + +//********* + +// Set up allowed flux of incoming partons. +// addBeam: set up PDF's that need to be evaluated for the two beams. +// addPair: set up pairs of incoming partons from the two beams. + +bool SigmaProcess::initFlux() { + + // Read in process-specific channel information. + string fluxType = inFlux(); + + // Case with g g incoming state. + if (fluxType == "gg") { + addBeamA(21); + addBeamB(21); + addPair(21, 21); + } + + // Case with q g incoming state. + else if (fluxType == "qg") { + for (int i = -nQuarkIn; i <= nQuarkIn; ++i) { + int idNow = (i == 0) ? 21 : i; + addBeamA(idNow); + addBeamB(idNow); + } + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) { + addPair(idNow, 21); + addPair(21, idNow); + } + } + + // Case with q q', q qbar' or qbar qbar' incoming state. + else if (fluxType == "qq") { + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) { + addBeamA(idNow); + addBeamB(idNow); + } + for (int id1Now = -nQuarkIn; id1Now <= nQuarkIn; ++id1Now) + if (id1Now != 0) + for (int id2Now = -nQuarkIn; id2Now <= nQuarkIn; ++id2Now) + if (id2Now != 0) + addPair(id1Now, id2Now); + } + + // Case with q qbar incoming state. + else if (fluxType == "qqbarSame") { + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) { + addBeamA(idNow); + addBeamB(idNow); + } + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) + addPair(idNow, -idNow); + } + + // Case with f f', f fbar', fbar fbar' incoming state. + else if (fluxType == "ff") { + // If beams are leptons then they are also the colliding partons. + if ( isLeptonA && isLeptonB ) { + addBeamA(idA); + addBeamB(idB); + addPair(idA, idB); + // First beam is lepton and second is hadron. + } else if ( isLeptonA ) { + addBeamA(idA); + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) { + addBeamB(idNow); + addPair(idA, idNow); + } + // First beam is hadron and second is lepton. + } else if ( isLeptonB ) { + addBeamB(idB); + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) { + addBeamA(idNow); + addPair(idNow, idB); + } + // Hadron beams gives quarks. + } else { + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) { + addBeamA(idNow); + addBeamB(idNow); + } + for (int id1Now = -nQuarkIn; id1Now <= nQuarkIn; ++id1Now) + if (id1Now != 0) + for (int id2Now = -nQuarkIn; id2Now <= nQuarkIn; ++id2Now) + if (id2Now != 0) + addPair(id1Now, id2Now); + } + } + + // Case with f fbar incoming state. + else if (fluxType == "ffbarSame") { + // If beams are antiparticle pair and leptons then also colliding partons. + if ( idA + idB == 0 && isLeptonA ) { + addBeamA(idA); + addBeamB(idB); + addPair(idA, idB); + // Else assume both to be hadrons, for better or worse. + } else { + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) { + addBeamA(idNow); + addBeamB(idNow); + } + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) + addPair(idNow, -idNow); + } + } + + // Case with f fbar' charged(+-1) incoming state. + else if (fluxType == "ffbarChg") { + // If beams are leptons then also colliding partons. + if ( isLeptonA && isLeptonB && abs( ParticleDataTable::chargeType(idA) + + ParticleDataTable::chargeType(idB) ) == 3 ) { + addBeamA(idA); + addBeamB(idB); + addPair(idA, idB); + // Hadron beams gives quarks. + } else { + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) { + addBeamA(idNow); + addBeamB(idNow); + } + for (int id1Now = -nQuarkIn; id1Now <= nQuarkIn; ++id1Now) + if (id1Now != 0) + for (int id2Now = -nQuarkIn; id2Now <= nQuarkIn; ++id2Now) + if (id2Now != 0 && id1Now * id2Now < 0 + && (abs(id1Now) + abs(id2Now))%2 == 1) addPair(id1Now, id2Now); + } + } + + // Case with f fbar' generic incoming state. + else if (fluxType == "ffbar") { + // If beams are leptons then also colliding partons. + if (isLeptonA && isLeptonB && idA * idB < 0) { + addBeamA(idA); + addBeamB(idB); + addPair(idA, idB); + // Hadron beams gives quarks. + } else { + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) { + addBeamA(idNow); + addBeamB(idNow); + } + for (int id1Now = -nQuarkIn; id1Now <= nQuarkIn; ++id1Now) + if (id1Now != 0) + for (int id2Now = -nQuarkIn; id2Now <= nQuarkIn; ++id2Now) + if (id2Now != 0 && id1Now * id2Now < 0) + addPair(id1Now, id2Now); + } + } + + // Case with f gamma incoming state. + else if (fluxType == "fgm") { + // Fermion from incoming side A. + if ( isLeptonA ) { + addBeamA(idA); + addPair(idA, 22); + } else { + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) { + addBeamA(idNow); + addPair(idNow, 22); + } + } + // Fermion from incoming side B. + if ( isLeptonB ) { + addBeamB( idB); + addPair(22, idB); + } else { + for (int idNow = -nQuarkIn; idNow <= nQuarkIn; ++idNow) + if (idNow != 0) { + addBeamB(idNow); + addPair(22, idNow); + } + } + // Photons in the beams. + addBeamA(22); + addBeamB(22); + } + + // Case with gamma gamma incoming state. + else if (fluxType == "ggm") { + addBeamA(21); + addBeamA(22); + addBeamB(21); + addBeamB(22); + addPair(21, 22); + addPair(22, 21); + } + + // Case with gamma gamma incoming state. + else if (fluxType == "gmgm") { + addBeamA(22); + addBeamB(22); + addPair(22, 22); + } + + // Unrecognized fluxType is bad sign. Else done. + else { + infoPtr->errorMsg("Error in SigmaProcess::initFlux: " + "unrecognized inFlux type", fluxType); + return false; + } + return true; + +} + +//********* + +// Convolute matrix-element expression(s) with parton flux and K factor. + +double SigmaProcess::sigmaPDF() { + + // Evaluate and store the required parton densities. + for (int j = 0; j < sizeBeamA(); ++j) + inBeamA[j].pdf = beamAPtr->xfHard( inBeamA[j].id, x1Save, Q2FacSave); + for (int j = 0; j < sizeBeamB(); ++j) + inBeamB[j].pdf = beamBPtr->xfHard( inBeamB[j].id, x2Save, Q2FacSave); + + // Loop over allowed incoming channels. + sigmaSumSave = 0.; + for (int i = 0; i < sizePair(); ++i) { + + // Evaluate hard-scattering cross section. Include K factor. + inPair[i].pdfSigma = Kfactor + * sigmaHatWrap(inPair[i].idA, inPair[i].idB); + + // Multiply by respective parton densities. + for (int j = 0; j < sizeBeamA(); ++j) + if (inPair[i].idA == inBeamA[j].id) { + inPair[i].pdfA = inBeamA[j].pdf; + inPair[i].pdfSigma *= inBeamA[j].pdf; + break; + } + for (int j = 0; j < sizeBeamB(); ++j) + if (inPair[i].idB == inBeamB[j].id) { + inPair[i].pdfB = inBeamB[j].pdf; + inPair[i].pdfSigma *= inBeamB[j].pdf; + break; + } + + // Sum for all channels. + sigmaSumSave += inPair[i].pdfSigma; + } + + // Done. + return sigmaSumSave; + +} + +//********* + +// Select incoming parton channel and extract parton densities (resolved). + +void SigmaProcess::pickInState(int id1in, int id2in) { + + // Multiple interactions: partons already selected. + if (id1in != 0 && id2in != 0) { + id1 = id1in; + id2 = id2in; + } + + // Pick channel. Extract channel flavours and pdf's. + double sigmaRand = sigmaSumSave * Rndm::flat(); + for (int i = 0; i < sizePair(); ++i) { + sigmaRand -= inPair[i].pdfSigma; + if (sigmaRand <= 0.) { + id1 = inPair[i].idA; + id2 = inPair[i].idB; + pdf1Save = inPair[i].pdfA; + pdf2Save = inPair[i].pdfB; + break; + } + } + +} + +//********* + +// Evaluate weight for W decay distribution in t -> W b -> f fbar b. + +double SigmaProcess::weightTopDecay( Event& process, int iResBeg, + int iResEnd) { + + // If not pair W d/s/b and mother t then return unit weight. + if (iResEnd - iResBeg != 1) return 1.; + int iW1 = iResBeg; + int iB2 = iResBeg + 1; + int idW1 = process[iW1].idAbs(); + int idB2 = process[iB2].idAbs(); + if (idW1 != 24) { + swap(iW1, iB2); + swap(idW1, idB2); + } + if (idW1 != 24 || (idB2 != 1 && idB2 != 3 && idB2 != 5)) return 1.; + int iT = process[iW1].mother1(); + if (iT <= 0 || process[iT].idAbs() != 6) return 1.; + + // Find sign-matched order of W decay products. + int iF = process[iW1].daughter1(); + int iFbar = process[iW1].daughter2(); + if (iFbar - iF != 1) return 1.; + if (process[iT].id() * process[iF].id() < 0) swap(iF, iFbar); + + // Weight and maximum weight. + double wt = (process[iT].p() * process[iFbar].p()) + * (process[iF].p() * process[iB2].p()); + double wtMax = ( pow4(process[iT].m()) - pow4(process[iW1].m()) ) / 8.; + + // Done. + return wt / wtMax; + +} + + +//********* + +// Evaluate weight for Z0/W+- decay distributions in H -> Z0/W+ Z0/W- -> 4f. + +double SigmaProcess::weightHiggsDecay( Event& process, int iResBeg, + int iResEnd) { + + // If not pair Z0 Z0 or W+ W- then return unit weight. + if (iResEnd - iResBeg != 1) return 1.; + int iZW1 = iResBeg; + int iZW2 = iResBeg + 1; + int idZW1 = process[iZW1].id(); + int idZW2 = process[iZW2].id(); + if (idZW1 < 0) { + swap(iZW1, iZW2); + swap(idZW1, idZW2); + } + if ( (idZW1 != 23 || idZW2 != 23) && (idZW1 != 24 || idZW2 != -24) ) + return 1.; + + // If mother is not Higgs then return unit weight. + int iH = process[iZW1].mother1(); + if (iH <= 0) return 1.; + int idH = process[iH].id(); + if (idH != 25 && idH != 35 && idH !=36) return 1.; + + // Parameters depend on Higgs type: H0(H_1), H^0(H_2) or A^0(H_3). + int higgsParity = higgsH1parity; + double higgsEta = higgsH1eta; + if (idH == 35) { + higgsParity = higgsH2parity; + higgsEta = higgsH2eta; + } else if (idH == 36) { + higgsParity = higgsA3parity; + higgsEta = higgsA3eta; + } + + // Option with isotropic decays. + if (higgsParity == 0) return 1.; + + // Maximum and initial weight. + double wtMax = pow4(process[iH].m()); + double wt = wtMax; + + // Find sign-matched order of Z0/W+- decay products. + int i3 = process[iZW1].daughter1(); + int i4 = process[iZW1].daughter2(); + if (process[i3].id() < 0) swap( i3, i4); + int i5 = process[iZW2].daughter1(); + int i6 = process[iZW2].daughter2(); + if (process[i5].id() < 0) swap( i5, i6); + + // Evaluate four-vector products and find masses.. + double p35 = 2. * process[i3].p() * process[i5].p(); + double p36 = 2. * process[i3].p() * process[i6].p(); + double p45 = 2. * process[i4].p() * process[i5].p(); + double p46 = 2. * process[i4].p() * process[i6].p(); + double p34 = 2. * process[i3].p() * process[i4].p(); + double p56 = 2. * process[i5].p() * process[i6].p(); + double mZW1 = process[iZW1].m(); + double mZW2 = process[iZW2].m(); + + // For mixed CP states need epsilon product and gauge boson masses. + double epsilonProd = 0.; + if (higgsParity == 3) { + double p[4][4]; + for (int i = 0; i < 4; ++i) { + int ii = i3; + if (i == 1) ii = i4; + if (i == 2) ii = i5; + if (i == 3) ii = i6; + p[i][0] = process[ii].e(); + p[i][1] = process[ii].px(); + p[i][2] = process[ii].py(); + p[i][3] = process[ii].pz(); + } + epsilonProd + = p[0][0]*p[1][1]*p[2][2]*p[3][3] - p[0][0]*p[1][1]*p[2][3]*p[3][2] + - p[0][0]*p[1][2]*p[2][1]*p[3][3] + p[0][0]*p[1][2]*p[2][3]*p[3][1] + + p[0][0]*p[1][3]*p[2][1]*p[3][2] - p[0][0]*p[1][3]*p[2][2]*p[3][1] + - p[0][1]*p[1][0]*p[2][2]*p[3][3] + p[0][1]*p[1][0]*p[2][3]*p[3][2] + + p[0][1]*p[1][2]*p[2][0]*p[3][3] - p[0][1]*p[1][2]*p[2][3]*p[3][0] + - p[0][1]*p[1][3]*p[2][0]*p[3][2] + p[0][1]*p[1][3]*p[2][2]*p[3][0] + + p[0][2]*p[1][0]*p[2][1]*p[3][3] - p[0][2]*p[1][0]*p[2][3]*p[3][1] + - p[0][2]*p[1][1]*p[2][0]*p[3][3] + p[0][2]*p[1][1]*p[2][3]*p[3][0] + + p[0][2]*p[1][3]*p[2][0]*p[3][1] - p[0][2]*p[1][3]*p[2][1]*p[3][0] + - p[0][3]*p[1][0]*p[2][1]*p[3][2] + p[0][3]*p[1][0]*p[2][2]*p[3][1] + + p[0][3]*p[1][1]*p[2][0]*p[3][2] - p[0][3]*p[1][1]*p[2][2]*p[3][0] + - p[0][3]*p[1][2]*p[2][0]*p[3][1] + p[0][3]*p[1][2]*p[2][1]*p[3][0]; + } + + // Z0 Z0 decay: vector and axial couplings of two fermion pairs. + if (idZW1 == 23) { + double vf1 = CoupEW::vf(process[i3].idAbs()); + double af1 = CoupEW::af(process[i3].idAbs()); + double vf2 = CoupEW::vf(process[i5].idAbs()); + double af2 = CoupEW::af(process[i5].idAbs()); + double va12asym = 4. * vf1 * af1 * vf2 * af2 + / ( (vf1*vf1 + af1*af1) * (vf2*vf2 + af2*af2) ); + double etaMod = higgsEta / pow2( ParticleDataTable::m0(23) ); + + // Normal CP-even decay. + if (higgsParity == 1) wt = 8. * (1. + va12asym) * p35 * p46 + + 8. * (1. - va12asym) * p36 * p45; + + // CP-odd decay (normal for A0(H_3)). + else if (higgsParity == 2) wt = ( pow2(p35 + p46) + + pow2(p36 + p45) - 2. * p34 * p56 + - 2. * pow2(p35 * p46 - p36 * p45) / (p34 * p56) + + va12asym * (p35 + p36 - p45 - p46) * (p35 + p45 - p36 - p46) ) + / (1. + va12asym); + + // Mixed CP states. + else wt = 32. * ( 0.25 * ( (1. + va12asym) * p35 * p46 + + (1. - va12asym) * p36 * p45 ) - 0.5 * etaMod * epsilonProd + * ( (1. + va12asym) * (p35 + p46) - (1. - va12asym) * (p36 + p45) ) + + 0.0625 * etaMod * etaMod * (-2. * pow2(p34 * p56) + - 2. * pow2(p35 * p46 - p36 * p45) + + p34 * p56 * (pow2(p35 + p46) + pow2(p36 + p45)) + + va12asym * p34 * p56 * (p35 + p36 - p45 - p46) + * (p35 + p45 - p36 - p46) ) ) / ( 1. + 2. * etaMod * mZW1 * mZW2 + + 2. * pow2(etaMod * mZW1 * mZW2) * (1. + va12asym) ); + + // W+ W- decay. + } else if (idZW1 == 24) { + double etaMod = higgsEta / pow2( ParticleDataTable::m0(24) ); + + // Normal CP-even decay. + if (higgsParity == 1) wt = 16. * p35 * p46; + + // CP-odd decay (normal for A0(H_3)). + else if (higgsParity == 2) wt = 0.5 * ( pow2(p35 + p46) + + pow2(p36 + p45) - 2. * p34 * p56 + - 2. * pow2(p35 * p46 - p36 * p45) / (p34 * p56) + + (p35 + p36 - p45 - p46) * (p35 + p45 - p36 - p46) ); + + // Mixed CP states. + else wt = 32. * ( 0.25 * 2. * p35 * p46 + - 0.5 * etaMod * epsilonProd * 2. * (p35 + p46) + + 0.0625 * etaMod * etaMod * (-2. * pow2(p34 * p56) + - 2. * pow2(p35 * p46 - p36 * p45) + + p34 * p56 * (pow2(p35 + p46) + pow2(p36 + p45)) + + p34 * p56 * (p35 + p36 - p45 - p46) * (p35 + p45 - p36 - p46) ) ) + / ( 1. * 2. * etaMod * mZW1 * mZW2 + 2. * pow2(etaMod * mZW1 * mZW2) ); + } + + // Done. + return wt / wtMax; + +} + +//************************************************************************** + +// The Sigma1Process class. +// Base class for resolved 2 -> 1 cross sections; derived from SigmaProcess. + +//********* + +// Input and complement kinematics for resolved 2 -> 1 process. + +void Sigma1Process::store1Kin( double x1in, double x2in, double sHin) { + + // Default value only sensible for these processes. + swapTU = false; + + // Incoming parton momentum fractions and sHat. + x1Save = x1in; + x2Save = x2in; + sH = sHin; + mH = sqrt(sH); + sH2 = sH * sH; + + // Different options for renormalization scale, but normally sHat. + Q2RenSave = renormMultFac * sH; + if (renormScale1 == 2) Q2RenSave = renormFixScale; + + // Different options for factorization scale, but normally sHat. + Q2FacSave = factorMultFac * sH; + if (factorScale1 == 2) Q2RenSave = factorFixScale; + + // Evaluate alpha_strong and alpha_EM. + alpS = alphaSPtr->alphaS(Q2RenSave); + alpEM = alphaEMPtr->alphaEM(Q2RenSave); + +} + +//************************************************************************** + +// The Sigma2Process class. +// Base class for resolved 2 -> 2 cross sections; derived from SigmaProcess. + +//********* + +// Input and complement kinematics for resolved 2 -> 2 process. + +void Sigma2Process::store2Kin( double x1in, double x2in, double sHin, + double tHin, double m3in, double m4in, double runBW3in, double runBW4in) { + + // Default ordering of particles 3 and 4. + swapTU = false; + + // Incoming parton momentum fractions. + x1Save = x1in; + x2Save = x2in; + + // Incoming masses and their squares. + bool masslessKin = (id3Mass() == 0) && (id4Mass() == 0); + if (masslessKin) { + m3 = 0.; + m4 = 0.; + } else { + m3 = m3in; + m4 = m4in; + } + mSave[3] = m3; + mSave[4] = m4; + s3 = m3 * m3; + s4 = m4 * m4; + + // Standard Mandelstam variables and their squares. + sH = sHin; + tH = tHin; + uH = (masslessKin) ? -(sH + tH) : s3 + s4 - (sH + tH); + mH = sqrt(sH); + sH2 = sH * sH; + tH2 = tH * tH; + uH2 = uH * uH; + + // The nominal Breit-Wigner factors with running width. + runBW3 = runBW3in; + runBW4 = runBW4in; + + // Calculate squared transverse momentum. + pT2 = (masslessKin) ? tH * uH / sH : (tH * uH - s3 * s4) / sH; + + // Special case: pick scale as if 2 -> 1 process in disguise. + if (isSChannel()) { + + // Different options for renormalization scale, but normally sHat. + Q2RenSave = renormMultFac * sH; + if (renormScale1 == 2) Q2RenSave = renormFixScale; + + // Different options for factorization scale, but normally sHat. + Q2FacSave = factorMultFac * sH; + if (factorScale1 == 2) Q2RenSave = factorFixScale; + + // Normal case with "true" 2 -> 2. + } else { + + // Different options for renormalization scale. + if (masslessKin) Q2RenSave = (renormScale2 < 4) ? pT2 : sH; + else if (renormScale2 == 1) Q2RenSave = pT2 + min(s3, s4); + else if (renormScale2 == 2) Q2RenSave = sqrt((pT2 + s3) * (pT2 + s4)); + else if (renormScale2 == 3) Q2RenSave = pT2 + 0.5 * (s3 + s4); + else Q2RenSave = sH; + Q2RenSave *= renormMultFac; + if (renormScale2 == 5) Q2RenSave = renormFixScale; + + // Different options for factorization scale. + if (masslessKin) Q2FacSave = (factorScale2 < 4) ? pT2 : sH; + else if (factorScale2 == 1) Q2FacSave = pT2 + min(s3, s4); + else if (factorScale2 == 2) Q2FacSave = sqrt((pT2 + s3) * (pT2 + s4)); + else if (factorScale2 == 3) Q2FacSave = pT2 + 0.5 * (s3 + s4); + else Q2FacSave = sH; + Q2FacSave *= factorMultFac; + if (factorScale2 == 5) Q2FacSave = factorFixScale; + } + + // Evaluate alpha_strong and alpha_EM. + alpS = alphaSPtr->alphaS(Q2RenSave); + alpEM = alphaEMPtr->alphaEM(Q2RenSave); + +} + +//********* + +// As above, special kinematics for multiple interactions. + +void Sigma2Process::store2KinMI( double x1in, double x2in, + double sHin, double tHin, double uHin, double alpSin, double alpEMin, + bool needMasses, double m3in, double m4in) { + + // Default ordering of particles 3 and 4. + swapTU = false; + + // Incoming x values. + x1Save = x1in; + x2Save = x2in; + + // Standard Mandelstam variables and their squares. + sH = sHin; + tH = tHin; + uH = uHin; + mH = sqrt(sH); + sH2 = sH * sH; + tH2 = tH * tH; + uH2 = uH * uH; + + // Strong and electroweak couplings. + alpS = alpSin; + alpEM = alpEMin; + + // Assume vanishing masses. (Will be modified in final kinematics.) + m3 = 0.; + s3 = 0.; + m4 = 0.; + s4 = 0.; + sHBeta = sH; + + // Scattering angle. + cosTheta = (tH - uH) / sH; + sinTheta = 2. * sqrtpos( tH * uH ) / sH; + + // In some cases must use masses and redefine meaning of tHat and uHat. + if (needMasses) { + m3 = m3in; + s3 = m3 * m3; + m4 = m4in; + s4 = m4 * m4; + sHMass = sH - s3 - s4; + sHBeta = sqrtpos(sHMass*sHMass - 4. * s3 * s4); + tH = -0.5 * (sHMass - sHBeta * cosTheta); + uH = -0.5 * (sHMass + sHBeta * cosTheta); + tH2 = tH * tH; + uH2 = uH * uH; + } + + // pT2 with masses (at this stage) included. + pT2Mass = 0.25 * sHBeta * pow2(sinTheta); + +} + +//********* + +// Perform kinematics for a Multiple Interaction. + +bool Sigma2Process::final2KinMI() { + + // Have to set flavours and colours. + setIdColAcol(); + + // Check that masses of outgoing particles not too big. + m3 = ParticleDataTable::m0(idSave[3]); + m4 = ParticleDataTable::m0(idSave[4]); + mH = sqrt(sH); + if (m3 + m4 + MASSMARGIN > mH) return false; + s3 = m3 * m3; + s4 = m4 * m4; + + // Do kinematics of the decay. + double eIn = 0.5 * mH; + double e3 = 0.5 * (sH + s3 - s4) / mH; + double e4 = 0.5 * (sH + s4 - s3) / mH; + double pAbs = sqrtpos( e3*e3 - s3 ); + phi = 2. * M_PI * Rndm::flat(); + double pZ = pAbs * cosTheta; + double pX = pAbs * sinTheta * sin(phi); + double pY = pAbs * sinTheta * cos(phi); + double scale = eIn * sinTheta; + + // Fill particle info. + parton[1] = Particle( idSave[1], -31, 0, 0, 3, 4, colSave[1], acolSave[1], + 0., 0., eIn, eIn, 0., scale); + parton[2] = Particle( idSave[2], -31, 0, 0, 3, 4, colSave[2], acolSave[2], + 0., 0., -eIn, eIn, 0., scale); + parton[3] = Particle( idSave[3], 33, 1, 2, 0, 0, colSave[3], acolSave[3], + pX, pY, pZ, e3, m3, scale); + parton[4] = Particle( idSave[4], 33, 1, 2, 0, 0, colSave[4], acolSave[4], + -pX, -pY, -pZ, e4, m4, scale); + + // Boost particles from subprocess rest frame to event rest frame. + double betaZ = (x1Save - x2Save) / (x1Save + x2Save); + for (int i = 1; i <= 4; ++i) parton[i].bst(0., 0., betaZ); + + // Done. + return true; + +} + +//************************************************************************** + +// The Sigma3Process class. +// Base class for resolved 2 -> 3 cross sections; derived from SigmaProcess. + +//********* + +// Input and complement kinematics for resolved 2 -> 3 process. + +void Sigma3Process::store3Kin( double x1in, double x2in, double sHin, + Vec4 p3cmIn, Vec4 p4cmIn, Vec4 p5cmIn, double m3in, double m4in, + double m5in, double runBW3in, double runBW4in, double runBW5in) { + + // Default ordering of particles 3 and 4 - not relevant here. + swapTU = false; + + // Incoming parton momentum fractions. + x1Save = x1in; + x2Save = x2in; + + // Incoming masses and their squares. + if (id3Mass() == 0 && id4Mass() == 0 && id5Mass() == 0) { + m3 = 0.; + m4 = 0.; + m5 = 0.; + } else { + m3 = m3in; + m4 = m4in; + m5 = m5in; + } + mSave[3] = m3; + mSave[4] = m4; + mSave[5] = m5; + s3 = m3 * m3; + s4 = m4 * m4; + s5 = m5 * m5; + + // Standard Mandelstam variables and four-momenta in rest frame. + sH = sHin; + mH = sqrt(sH); + p3cm = p3cmIn; + p4cm = p4cmIn; + p5cm = p5cmIn; + + // The nominal Breit-Wigner factors with running width. + runBW3 = runBW3in; + runBW4 = runBW4in; + runBW5 = runBW5in; + + // Special case: pick scale as if 2 -> 1 process in disguise. + if (isSChannel()) { + + // Different options for renormalization scale, but normally sHat. + Q2RenSave = renormMultFac * sH; + if (renormScale1 == 2) Q2RenSave = renormFixScale; + + // Different options for factorization scale, but normally sHat. + Q2FacSave = factorMultFac * sH; + if (factorScale1 == 2) Q2RenSave = factorFixScale; + + // "Normal" 2 -> 3 processes, i.e. not vector boson fusion. + } else if ( idTchan1() != 23 && idTchan1() != 24 && idTchan2() != 23 + && idTchan1() != 24 ) { + double mT3S = s3 + p3cm.pT2(); + double mT4S = s4 + p4cm.pT2(); + double mT5S = s5 + p5cm.pT2(); + + // Different options for renormalization scale. + if (renormScale3 == 1) Q2RenSave = min( mT3S, min(mT4S, mT5S) ); + else if (renormScale3 == 2) Q2RenSave = sqrt( mT3S * mT4S * mT5S + / max( mT3S, max(mT4S, mT5S) ) ); + else if (renormScale3 == 3) Q2RenSave = pow( mT3S * mT4S * mT5S, + 1./3. ); + else if (renormScale3 == 4) Q2RenSave = (mT3S * mT4S * mT5S) / 3.; + else Q2RenSave = sH; + Q2RenSave *= renormMultFac; + if (renormScale3 == 6) Q2RenSave = renormFixScale; + + // Different options for factorization scale. + if (factorScale3 == 1) Q2FacSave = min( mT3S, min(mT4S, mT5S) ); + else if (factorScale3 == 2) Q2FacSave = sqrt( mT3S * mT4S * mT5S + / max( mT3S, max(mT4S, mT5S) ) ); + else if (factorScale3 == 3) Q2FacSave = pow( mT3S * mT4S * mT5S, + 1./3. ); + else if (factorScale3 == 4) Q2FacSave = (mT3S * mT4S * mT5S) / 3.; + else Q2FacSave = sH; + Q2RenSave *= factorMultFac; + if (factorScale3 == 6) Q2FacSave = factorFixScale; + + // Vector boson fusion 2 -> 3 processes; recoils in positions 4 and 5. + } else { + double sV4 = pow2( ParticleDataTable::m0(idTchan1()) ); + double sV5 = pow2( ParticleDataTable::m0(idTchan2()) ); + double mT3S = s3 + p3cm.pT2(); + double mTV4S = sV4 + p4cm.pT2(); + double mTV5S = sV5 + p5cm.pT2(); + + // Different options for renormalization scale. + if (renormScale3VV == 1) Q2RenSave = max( sV4, sV5); + else if (renormScale3VV == 2) Q2RenSave = sqrt( mTV4S * mTV5S ); + else if (renormScale3VV == 3) Q2RenSave = pow( mT3S * mTV4S * mTV5S, + 1./3. ); + else if (renormScale3VV == 4) Q2RenSave = (mT3S * mTV4S * mTV5S) / 3.; + else Q2RenSave = sH; + Q2RenSave *= renormMultFac; + if (renormScale3VV == 6) Q2RenSave = renormFixScale; + + // Different options for factorization scale. + if (factorScale3VV == 1) Q2FacSave = max( sV4, sV5); + else if (factorScale3VV == 2) Q2FacSave = sqrt( mTV4S * mTV5S ); + else if (factorScale3VV == 3) Q2FacSave = pow( mT3S * mTV4S * mTV5S, + 1./3. ); + else if (factorScale3VV == 4) Q2FacSave = (mT3S * mTV4S * mTV5S) / 3.; + else Q2FacSave = sH; + Q2RenSave *= factorMultFac; + if (factorScale3VV == 6) Q2FacSave = factorFixScale; + } + + // Evaluate alpha_strong and alpha_EM. + alpS = alphaSPtr->alphaS(Q2RenSave); + alpEM = alphaEMPtr->alphaEM(Q2RenSave); + +} + +//************************************************************************** + +// The SigmaLHAProcess class. +// Wrapper for Les Houches Accord external input; derived from SigmaProcess. +// Note: arbitrary subdivision into PhaseSpaceLHA and SigmaLHAProcess tasks. + +//********* + +// Obtain number of final-state partons from LHA object. + +int SigmaLHAProcess::nFinal() const { + + // At initialization size unknown, so return 0. + if (lhaUpPtr->sizePart() <= 0) return 0; + + // Sum up all particles that has first mother = 1. + int nFin = 0; + for (int i = 3; i < lhaUpPtr->sizePart(); ++i) + if (lhaUpPtr->mother1(i) == 1) ++nFin; + return nFin; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SigmaQCD.cxx b/PYTHIA8/pythia8130/src/SigmaQCD.cxx new file mode 100644 index 00000000000..f4f3404dc4b --- /dev/null +++ b/PYTHIA8/pythia8130/src/SigmaQCD.cxx @@ -0,0 +1,542 @@ +// SigmaQCD.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// QCD simulation classes. + +#include "SigmaQCD.h" + +namespace Pythia8 { + +//************************************************************************** + +// Sigma0AB2AB class. +// Cross section for elastic scattering A B -> A B. + +//********* + +// Select identity, colour and anticolour. + +void Sigma0AB2AB::setIdColAcol() { + + // Flavours and colours are trivial. + setId( idA, idB, idA, idB); + setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); +} + +//************************************************************************** + +// Sigma0AB2XB class. +// Cross section for single diffractive scattering A B -> X B. + +//********* + +// Select identity, colour and anticolour. + +void Sigma0AB2XB::setIdColAcol() { + + // Flavours and colours are trivial. + int idX = 10* (abs(idA) / 10) + 9900000; + if (idA < 0) idX = -idX; + setId( idA, idB, idX, idB); + setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + +} + +//************************************************************************** + +// Sigma0AB2AX class. +// Cross section for single diffractive scattering A B -> A X. + +//********* + +// Select identity, colour and anticolour. + +void Sigma0AB2AX::setIdColAcol() { + + // Flavours and colours are trivial. + int idX = 10* (abs(idB) / 10) + 9900000; + if (idB < 0) idX = -idX; + setId( idA, idB, idA, idX); + setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + +} + +//************************************************************************** + +// Sigma0AB2XX class. +// Cross section for double diffractive scattering A B -> X X. + +//********* + +// Select identity, colour and anticolour. + +void Sigma0AB2XX::setIdColAcol() { + + // Flavours and colours are trivial. + int idX1 = 10* (abs(idA) / 10) + 9900000; + if (idA < 0) idX1 = -idX1; + int idX2 = 10* (abs(idB) / 10) + 9900000; + if (idB < 0) idX2 = -idX2; + setId( idA, idB, idX1, idX2); + setColAcol( 0, 0, 0, 0, 0, 0, 0, 0); + +} + +//************************************************************************** + +// Sigma2gg2gg class. +// Cross section for g g -> g g. + +//********* + +// Evaluate d(sigmaHat)/d(tHat) - no incoming flavour dependence. + +void Sigma2gg2gg::sigmaKin() { + + // Calculate kinematics dependence. + sigTS = (9./4.) * (tH2 / sH2 + 2. * tH / sH + 3. + 2. * sH / tH + + sH2 / tH2); + sigUS = (9./4.) * (uH2 / sH2 + 2. * uH / sH + 3. + 2. * sH / uH + + sH2 / uH2); + sigTU = (9./4.) * (tH2 / uH2 + 2. * tH / uH + 3. + 2. * uH / tH + + uH2 / tH2); + sigSum = sigTS + sigUS + sigTU; + + // Answer contains factor 1/2 from identical gluons. + sigma = (M_PI / sH2) * pow2(alpS) * 0.5 * sigSum; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2gg2gg::setIdColAcol() { + + // Flavours are trivial. + setId( id1, id2, 21, 21); + + // Three colour flow topologies, each with two orientations. + double sigRand = sigSum * Rndm::flat(); + if (sigRand < sigTS) setColAcol( 1, 2, 2, 3, 1, 4, 4, 3); + else if (sigRand < sigTS + sigUS) + setColAcol( 1, 2, 3, 1, 3, 4, 4, 2); + else setColAcol( 1, 2, 3, 4, 1, 4, 3, 2); + if (Rndm::flat() > 0.5) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2gg2qqbar class. +// Cross section for g g -> q qbar (q = u, d, s, i.e. almost massless). + +//********* + +// Initialize process. + +void Sigma2gg2qqbar::initProc() { + + // Read number of quarks to be considered in massless approximation. + nQuarkNew = Settings::mode("HardQCD:nQuarkNew"); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat) - no incoming flavour dependence. + +void Sigma2gg2qqbar::sigmaKin() { + + // Pick new flavour. + idNew = 1 + int( nQuarkNew * Rndm::flat() ); + mNew = ParticleDataTable::m0(idNew); + m2New = mNew*mNew; + + // Calculate kinematics dependence. + sigTS = 0.; + sigUS = 0.; + if (sH > 4. * m2New) { + sigTS = (1./6.) * uH / tH - (3./8.) * uH2 / sH2; + sigUS = (1./6.) * tH / uH - (3./8.) * tH2 / sH2; + } + sigSum = sigTS + sigUS; + + // Answer is proportional to number of outgoing flavours. + sigma = (M_PI / sH2) * pow2(alpS) * nQuarkNew * sigSum; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2gg2qqbar::setIdColAcol() { + + // Flavours are trivial. + setId( id1, id2, idNew, -idNew); + + // Two colour flow topologies. + double sigRand = sigSum * Rndm::flat(); + if (sigRand < sigTS) setColAcol( 1, 2, 2, 3, 1, 0, 0, 3); + else setColAcol( 1, 2, 3, 1, 3, 0, 0, 2); + +} + +//************************************************************************** + +// Sigma2qg2qg class. +// Cross section for q g -> q g. + +//********* + +// Evaluate d(sigmaHat)/d(tHat) - no incoming flavour dependence. + +void Sigma2qg2qg::sigmaKin() { + + // Calculate kinematics dependence. + sigTS = uH2 / tH2 - (4./9.) * uH / sH; + sigTU = sH2 / tH2 - (4./9.) * sH / uH; + sigSum = sigTS + sigTU; + + // Answer. + sigma = (M_PI / sH2) * pow2(alpS) * sigSum; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qg2qg::setIdColAcol() { + + // Outgoing = incoming flavours. + setId( id1, id2, id1, id2); + + // Two colour flow topologies. Swap if first is gluon, or when antiquark. + double sigRand = sigSum * Rndm::flat(); + if (sigRand < sigTS) setColAcol( 1, 0, 2, 1, 3, 0, 2, 3); + else setColAcol( 1, 0, 2, 3, 2, 0, 1, 3); + if (id1 == 21) swapCol1234(); + if (id1 < 0 || id2 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2qq2qq class. +// Cross section for q qbar' -> q qbar' or q q' -> q q' +// (qbar qbar' -> qbar qbar'), q' may be same as q. + +//********* + +// Evaluate d(sigmaHat)/d(tHat), part independent of incoming flavour. + +void Sigma2qq2qq::sigmaKin() { + + // Calculate kinematics dependence for different terms. + sigT = (4./9.) * (sH2 + uH2) / tH2; + sigU = (4./9.) * (sH2 + tH2) / uH2; + sigTU = - (8./27.) * sH2 / (tH * uH); + sigST = - (8./27.) * uH2 / (sH * tH); + +} + +//********* + + +// Evaluate d(sigmaHat)/d(tHat), including incoming flavour dependence. + +double Sigma2qq2qq::sigmaHat() { + + // Combine cross section terms; factor 1/2 when identical quarks. + if (id2 == id1) sigSum = 0.5 * (sigT + sigU + sigTU); + else if (id2 == -id1) sigSum = sigT + sigST; + else sigSum = sigT; + + // Answer. + return (M_PI/sH2) * pow2(alpS) * sigSum; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qq2qq::setIdColAcol() { + + // Outgoing = incoming flavours. + setId( id1, id2, id1, id2); + + // Colour flow topologies. Swap when antiquarks. + if (id1 * id2 > 0) setColAcol( 1, 0, 2, 0, 2, 0, 1, 0); + else setColAcol( 1, 0, 0, 1, 2, 0, 0, 2); + if (id2 == id1 && (sigT + sigU) * Rndm::flat() > sigT) + setColAcol( 1, 0, 2, 0, 1, 0, 2, 0); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2qqbar2gg class. +// Cross section for q qbar -> g g. + +//********* + +// Evaluate d(sigmaHat)/d(tHat) - no incoming flavour dependence. + +void Sigma2qqbar2gg::sigmaKin() { + + // Calculate kinematics dependence. + sigTS = (32./27.) * uH / tH - (8./3.) * uH2 / sH2; + sigUS = (32./27.) * tH / uH - (8./3.) * tH2 / sH2; + sigSum = sigTS + sigUS; + + // Answer contains factor 1/2 from identical gluons. + sigma = (M_PI / sH2) * pow2(alpS) * 0.5 * sigSum; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2gg::setIdColAcol() { + + // Outgoing flavours trivial. + setId( id1, id2, 21, 21); + + // Two colour flow topologies. Swap if first is antiquark. + double sigRand = sigSum * Rndm::flat(); + if (sigRand < sigTS) setColAcol( 1, 0, 0, 2, 1, 3, 3, 2); + else setColAcol( 1, 0, 0, 2, 3, 2, 1, 3); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2qqbar2qqbarNew class. +// Cross section q qbar -> q' qbar'. + +//********* + +// Initialize process. + +void Sigma2qqbar2qqbarNew::initProc() { + + // Read number of quarks to be considered in massless approximation. + nQuarkNew = Settings::mode("HardQCD:nQuarkNew"); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat) - no incoming flavour dependence. + +void Sigma2qqbar2qqbarNew::sigmaKin() { + + // Pick new flavour. + idNew = 1 + int( nQuarkNew * Rndm::flat() ); + mNew = ParticleDataTable::m0(idNew); + m2New = mNew*mNew; + + // Calculate kinematics dependence. + sigS = 0.; + if (sH > 4. * m2New) sigS = (4./9.) * (tH2 + uH2) / sH2; + + // Answer is proportional to number of outgoing flavours. + sigma = (M_PI / sH2) * pow2(alpS) * nQuarkNew * sigS; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2qqbarNew::setIdColAcol() { + + // Set outgoing flavours ones. + id3 = (id1 > 0) ? idNew : -idNew; + setId( id1, id2, id3, -id3); + + // Colour flow topologies. Swap when antiquarks. + setColAcol( 1, 0, 0, 2, 1, 0, 0, 2); + if (id1 < 0) swapColAcol(); + +} + +//************************************************************************** + +// Sigma2gg2QQbar class. +// Cross section g g -> Q Qbar (Q = c, b or t). +// Only provided for fixed m3 = m4 so do some gymnastics: +// i) s34Avg picked so that beta34 same when s3, s4 -> s34Avg. +// ii) tHQ = tH - mQ^2 = -0.5 sH (1 - beta34 cos(thetaH)) for m3 = m4 = mQ, +// but tH - uH = sH beta34 cos(thetaH) also for m3 != m4, so use +// tH, uH selected for m3 != m4 to derive tHQ, uHQ valid for m3 = m4. + +//********* + +// Initialize process. + +void Sigma2gg2QQbar::initProc() { + + // Process name. + nameSave = "g g -> Q Qbar"; + if (idNew == 4) nameSave = "g g -> c cbar"; + if (idNew == 5) nameSave = "g g -> b bbar"; + if (idNew == 6) nameSave = "g g -> t tbar"; + if (idNew == 7) nameSave = "g g -> b' b'bar"; + if (idNew == 8) nameSave = "g g -> t' t'bar"; + + // Secondary open width fraction. + openFracPair = ParticleDataTable::resOpenFrac(idNew, -idNew); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat) - no incoming flavour dependence. + +void Sigma2gg2QQbar::sigmaKin() { + + // Modified Mandelstam variables for massive kinematics with m3 = m4. + double s34Avg = 0.5 * (s3 + s4) - 0.25 * pow2(s3 - s4) / sH; + double tHQ = -0.5 * (sH - tH + uH); + double uHQ = -0.5 * (sH + tH - uH); + double tHQ2 = tHQ * tHQ; + double uHQ2 = uHQ * uHQ; + + // Calculate kinematics dependence. + double tumHQ = tHQ * uHQ - s34Avg * sH; + sigTS = ( uHQ / tHQ - 2.25 * uHQ2 / sH2 + 4.5 * s34Avg * tumHQ + / ( sH * tHQ2) + 0.5 * s34Avg * (tHQ + s34Avg) / tHQ2 + - s34Avg*s34Avg / (sH * tHQ) ) / 6.; + sigUS = ( tHQ / uHQ - 2.25 * tHQ2 / sH2 + 4.5 * s34Avg * tumHQ + / ( sH * uHQ2) + 0.5 * s34Avg * (uHQ + s34Avg) / uHQ2 + - s34Avg*s34Avg / (sH * uHQ) ) / 6.; + sigSum = sigTS + sigUS; + + // Answer. + sigma = (M_PI / sH2) * pow2(alpS) * sigSum * openFracPair; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2gg2QQbar::setIdColAcol() { + + // Flavours are trivial. + setId( id1, id2, idNew, -idNew); + + // Two colour flow topologies. + double sigRand = sigSum * Rndm::flat(); + if (sigRand < sigTS) setColAcol( 1, 2, 2, 3, 1, 0, 0, 3); + else setColAcol( 1, 2, 3, 1, 3, 0, 0, 2); + +} + +//********* + +// Evaluate weight for decay angles of W in top decay. + +double Sigma2gg2QQbar::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // For top decay hand over to standard routine, else done. + if (idNew == 6 && process[process[iResBeg].mother1()].idAbs() == 6) + return weightTopDecay( process, iResBeg, iResEnd); + else return 1.; + +} + +//************************************************************************** + +// Sigma2qqbar2QQbar class. +// Cross section q qbar -> Q Qbar (Q = c, b or t). +// Only provided for fixed m3 = m4 so do some gymnastics: +// i) s34Avg picked so that beta34 same when s3, s4 -> s34Avg. +// ii) tHQ = tH - mQ^2 = -0.5 sH (1 - beta34 cos(thetaH)) for m3 = m4 = mQ, +// but tH - uH = sH beta34 cos(thetaH) also for m3 != m4, so use +// tH, uH selected for m3 != m4 to derive tHQ, uHQ valid for m3 = m4. + +//********* + +// Initialize process, especially parton-flux object. + +void Sigma2qqbar2QQbar::initProc() { + + // Process name. + nameSave = "q qbar -> Q Qbar"; + if (idNew == 4) nameSave = "q qbar -> c cbar"; + if (idNew == 5) nameSave = "q qbar -> b bbar"; + if (idNew == 6) nameSave = "q qbar -> t tbar"; + if (idNew == 7) nameSave = "q qbar -> b' b'bar"; + if (idNew == 8) nameSave = "q qbar -> t' t'bar"; + + // Secondary open width fraction. + openFracPair = ParticleDataTable::resOpenFrac(idNew, -idNew); + +} + +//********* + +// Evaluate d(sigmaHat)/d(tHat) - no incoming flavour dependence. + +void Sigma2qqbar2QQbar::sigmaKin() { + + // Modified Mandelstam variables for massive kinematics with m3 = m4. + double s34Avg = 0.5 * (s3 + s4) - 0.25 * pow2(s3 - s4) / sH; + double tHQ = -0.5 * (sH - tH + uH); + double uHQ = -0.5 * (sH + tH - uH); + double tHQ2 = tHQ * tHQ; + double uHQ2 = uHQ * uHQ; + + // Calculate kinematics dependence. + double sigS = (4./9.) * ((tHQ2 + uHQ2) / sH2 + 2. * s34Avg / sH); + + // Answer. + sigma = (M_PI / sH2) * pow2(alpS) * sigS * openFracPair; + +} + +//********* + +// Select identity, colour and anticolour. + +void Sigma2qqbar2QQbar::setIdColAcol() { + + // Set outgoing flavours. + id3 = (id1 > 0) ? idNew : -idNew; + setId( id1, id2, id3, -id3); + + // Colour flow topologies. Swap when antiquarks. + setColAcol( 1, 0, 0, 2, 1, 0, 0, 2); + if (id1 < 0) swapColAcol(); + +} + +//********* + +// Evaluate weight for decay angles of W in top decay. + +double Sigma2qqbar2QQbar::weightDecay( Event& process, int iResBeg, + int iResEnd) { + + // For top decay hand over to standard routine, else done. + if (idNew == 6 && process[process[iResBeg].mother1()].idAbs() == 6) + return weightTopDecay( process, iResBeg, iResEnd); + else return 1.; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SigmaSUSY.cxx b/PYTHIA8/pythia8130/src/SigmaSUSY.cxx new file mode 100644 index 00000000000..d872f624332 --- /dev/null +++ b/PYTHIA8/pythia8130/src/SigmaSUSY.cxx @@ -0,0 +1,656 @@ +// SigmaSUSY.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// supersymmetry simulation classes. + +#include "SigmaSUSY.h" + +namespace Pythia8 { + +//************************************************************************** + +// Sigma2qqbar2gauginogaugino "mother" class. +// Cross section for gaugino pair production: neutralino pair, +// neutralino-chargino, and chargino pair production all inherit from this. + +//********* + +// Initialize process. + +void Sigma2qqbar2gauginogaugino::initProc() { + + // Construct name of process. + nameSave = "q qbar -> " + ParticleDataTable::name(id3) + " " + + ParticleDataTable::name(id4); + + // Count number of final-state charged particles (default = 0) + // (useful since charginos inherit from this class.) + nCharged=0; + if (abs(id3) == 1000024 || abs(id3) == 1000037) nCharged++; + if (abs(id4) == 1000024 || abs(id4) == 1000037) nCharged++; + + // Set up couplings + mZpole = ParticleDataTable::m0(23); + wZpole = ParticleDataTable::mWidth(23); + double mWpole = ParticleDataTable::m0(24); + + // Running masses and weak mixing angle + // (default to pole values if no running available) + double mW = mWpole; + double mZ = mZpole; + sin2W = 1.0 - pow(mW/mZ,2); + if (slhaPtr->gauge.exists(1) && slhaPtr->gauge.exists(2) + && slhaPtr->hmix.exists(3)) { + double gp=slhaPtr->gauge(1); + double g =slhaPtr->gauge(2); + double v =slhaPtr->hmix(3); + mW = g * v / 2.0; + mZ = sqrt(pow(gp,2)+pow(g,2)) * v / 2.0; + sin2W = pow2(gp)/(pow2(g)+pow2(gp)); + } + + // Shorthand for SUSY couplings + // By default, use the running one in HMIX + // If not found, use the MZ one in MINPAR + double tanb = slhaPtr->hmix.exists(2) ? + slhaPtr->hmix(2) : slhaPtr->minpar(3); + double sinW=sqrt(sin2W); + double cosW=sqrt(1.0-sin2W); + double cosb = sqrt( 1.0 / (1.0 + tanb*tanb) ); + double sinb = sqrt(max(0.0,1.0-cosb*cosb)); + SusyLesHouches::matrixblock<6> Ru(slhaPtr->usqmix); + SusyLesHouches::matrixblock<6> Rd(slhaPtr->dsqmix); + SusyLesHouches::matrixblock<6> imRu(slhaPtr->imusqmix); + SusyLesHouches::matrixblock<6> imRd(slhaPtr->imusqmix); + + // Local complex copies of neutralino mixing matrix entries. + // (incl NMSSM for future use) + complex ni1,nj1,ni2,nj2,ni3,nj3,ni4,nj4,ni5,nj5; + if (slhaPtr->modsel(3) != 1) { + ni1=complex( slhaPtr->nmix(id3chi,1), slhaPtr->imnmix(id3chi,1) ); + nj1=complex( slhaPtr->nmix(id4chi,1), slhaPtr->imnmix(id4chi,1) ); + ni2=complex( slhaPtr->nmix(id3chi,2), slhaPtr->imnmix(id3chi,2) ); + nj2=complex( slhaPtr->nmix(id4chi,2), slhaPtr->imnmix(id4chi,2) ); + ni3=complex( slhaPtr->nmix(id3chi,3), slhaPtr->imnmix(id3chi,3) ); + nj3=complex( slhaPtr->nmix(id4chi,3), slhaPtr->imnmix(id4chi,3) ); + ni4=complex( slhaPtr->nmix(id3chi,4), slhaPtr->imnmix(id3chi,4) ); + nj4=complex( slhaPtr->nmix(id4chi,4), slhaPtr->imnmix(id4chi,4) ); + ni5=complex( 0.,0.); + nj5=complex( 0.,0.); + } else { + ni1=complex( slhaPtr->nmnmix(id3chi,1), slhaPtr->imnmnmix(id3chi,1) ); + nj1=complex( slhaPtr->nmnmix(id4chi,1), slhaPtr->imnmnmix(id4chi,1) ); + ni2=complex( slhaPtr->nmnmix(id3chi,2), slhaPtr->imnmnmix(id3chi,2) ); + nj2=complex( slhaPtr->nmnmix(id4chi,2), slhaPtr->imnmnmix(id4chi,2) ); + ni3=complex( slhaPtr->nmnmix(id3chi,3), slhaPtr->imnmnmix(id3chi,3) ); + nj3=complex( slhaPtr->nmnmix(id4chi,3), slhaPtr->imnmnmix(id4chi,3) ); + ni4=complex( slhaPtr->nmnmix(id3chi,4), slhaPtr->imnmnmix(id3chi,4) ); + nj4=complex( slhaPtr->nmnmix(id4chi,4), slhaPtr->imnmnmix(id4chi,4) ); + ni5=complex( slhaPtr->nmnmix(id3chi,5), slhaPtr->imnmnmix(id3chi,5) ); + nj5=complex( slhaPtr->nmnmix(id4chi,5), slhaPtr->imnmnmix(id4chi,5) ); + } + + // Change to positive mass convention. + complex iRot( 0., 1.); + if (slhaPtr->mass(abs(id3)) < 0.) { + ni1 *= iRot; + ni2 *= iRot; + ni3 *= iRot; + ni4 *= iRot; + ni5 *= iRot; + }; + if (slhaPtr->mass(abs(id4)) < 0.) { + nj1 *= iRot; + nj2 *= iRot; + nj3 *= iRot; + nj4 *= iRot; + nj5 *= iRot; + }; + + // Local copies of Chargino mixing + complex ui1,ui2,vi1,vi2,uj1,uj2,vj1,vj2; + if (id3chi <= 2) { + ui1=complex( slhaPtr->umix(id3chi,1), slhaPtr->imumix(id3chi,1) ); + ui2=complex( slhaPtr->umix(id3chi,2), slhaPtr->imumix(id3chi,2) ); + vi1=complex( slhaPtr->vmix(id3chi,1), slhaPtr->imvmix(id3chi,1) ); + vi2=complex( slhaPtr->vmix(id3chi,2), slhaPtr->imvmix(id3chi,2) ); + } + if (id4chi <= 2) { + uj1=complex( slhaPtr->umix(id4chi,1), slhaPtr->imumix(id4chi,1) ); + uj2=complex( slhaPtr->umix(id4chi,2), slhaPtr->imumix(id4chi,2) ); + vj1=complex( slhaPtr->vmix(id4chi,1), slhaPtr->imvmix(id4chi,1) ); + vj2=complex( slhaPtr->vmix(id4chi,2), slhaPtr->imvmix(id4chi,2) ); + } + + // Z chi_i chi_j + OLpp = -0.5 * ni3 * conj(nj3) + 0.5 * ni4 * conj(nj4); + ORpp = 0.5 * conj(ni3) * nj3 - 0.5 * conj(ni4) * nj4; + + // Z cha_i cha_j + OLp = -vi1*conj(vj1) - 0.5*vi2*conj(vj2) + + ( (id3chi == id4chi) ? sin2W : 0.0); + ORp = -conj(ui1)*uj1 - 0.5*conj(ui2)*uj2 + + ( (id3chi == id4chi) ? sin2W : 0.0); + + // W chi_i cha_j + OL = -1.0/sqrt(2.0)*ni4*conj(vj2)+ni2*conj(vj1); + OR = 1.0/sqrt(2.0)*conj(ni3)*uj2+conj(ni2)*uj1; + + // Z q_{idq} q_{idq} (def with extra factor 2 compared to [Okun]) + for (int idq = 1; idq <= 5; ++idq) { + // No FCNC in Zqq, so here sum over diagonal only + // No t in beam, so only sum up to 5 + LqqZ[idq] = CoupEW::lf(idq); + RqqZ[idq] = CoupEW::rf(idq); + } + + // ~chi^0_i ~q_jsq idq + for (int jsq = 1; jsq<=6; jsq++) { + // Sum jsq over all squarks + for (int idq = 1; idq<=5; idq++) { + // No t in beam, so only sum iq over 5 lightest quarks. + + // quark index + int k=(idq+1)/2; + + // Set quark mass for use in couplings + // Initial guess 0,0,0,mc,mb, with the latter from the PDT + double mq = ParticleDataTable::m0(idq); + if (idq <= 3) mq=0.0; + + // Treat u and d quarks separately + if (idq % 2 == 1) { + + // idq = d quark + double eq = -1.0/3.0; + double T3q = -0.5; + + // Compute running mass from Yukawas and vevs if possible. + if (slhaPtr->yd.exists() && slhaPtr->hmix.exists(3)) { + double ykk=slhaPtr->yd(k,k); + double v1=slhaPtr->hmix(3)/sqrt(1+pow(tanb,2)); + if (ykk != 0.0) mq = ykk * v1 / sqrt(2.0) ; + // cout < GeV^2) * (G_3P)^n, +// with n = 0 elastic, n = 1 single and n = 2 double diffractive. +const double SigmaTotal::CONVERTEL = 0.0510925; +const double SigmaTotal::CONVERTSD = 0.0336; +const double SigmaTotal::CONVERTDD = 0.0084; + +// Diffractive mass spectrum starts at m + MMIN0 and has a low-mass +// enhancement, factor cRes, up to around m + mRes0. +const double SigmaTotal::MMIN0 = 0.28; +const double SigmaTotal::CRES = 2.0; +const double SigmaTotal::MRES0 = 1.062; + +// Parameters and coefficients for single diffractive scattering. +const int SigmaTotal::ISDTABLE[] = { 0, 0, 1, 1, 1, 2, 3, 4, 5, + 6, 7, 8, 9}; +const double SigmaTotal::CSD[10][8] = { + { 0.213, 0.0, -0.47, 150., 0.213, 0.0, -0.47, 150., } , + { 0.213, 0.0, -0.47, 150., 0.267, 0.0, -0.47, 100., } , + { 0.213, 0.0, -0.47, 150., 0.232, 0.0, -0.47, 110., } , + { 0.213, 7.0, -0.55, 800., 0.115, 0.0, -0.47, 110., } , + { 0.267, 0.0, -0.46, 75., 0.267, 0.0, -0.46, 75., } , + { 0.232, 0.0, -0.46, 85., 0.267, 0.0, -0.48, 100., } , + { 0.115, 0.0, -0.50, 90., 0.267, 6.0, -0.56, 420., } , + { 0.232, 0.0, -0.48, 110., 0.232, 0.0, -0.48, 110., } , + { 0.115, 0.0, -0.52, 120., 0.232, 6.0, -0.56, 470., } , + { 0.115, 5.5, -0.58, 570., 0.115, 5.5, -0.58, 570. } }; + +// Parameters and coefficients for double diffractive scattering. +const int SigmaTotal::IDDTABLE[] = { 0, 0, 1, 1, 1, 2, 3, 4, 5, + 6, 7, 8, 9}; +const double SigmaTotal::CDD[10][9] = { + { 3.11, -7.34, 9.71, 0.068, -0.42, 1.31, -1.37, 35.0, 118., } , + { 3.11, -7.10, 10.6, 0.073, -0.41, 1.17, -1.41, 31.6, 95., } , + { 3.12, -7.43, 9.21, 0.067, -0.44, 1.41, -1.35, 36.5, 132., } , + { 3.13, -8.18, -4.20, 0.056, -0.71, 3.12, -1.12, 55.2, 1298., } , + { 3.11, -6.90, 11.4, 0.078, -0.40, 1.05, -1.40, 28.4, 78., } , + { 3.11, -7.13, 10.0, 0.071, -0.41, 1.23, -1.34, 33.1, 105., } , + { 3.12, -7.90, -1.49, 0.054, -0.64, 2.72, -1.13, 53.1, 995., } , + { 3.11, -7.39, 8.22, 0.065, -0.44, 1.45, -1.36, 38.1, 148., } , + { 3.18, -8.95, -3.37, 0.057, -0.76, 3.32, -1.12, 55.6, 1472., } , + { 4.18, -29.2, 56.2, 0.074, -1.36, 6.67, -1.14, 116.2, 6532. } }; +const double SigmaTotal::SPROTON = 0.880; + +//********* + +// Store pointer to Info and initialize data members. + +void SigmaTotal::init(Info* infoPtrIn) { + + // Store pointer. + infoPtr = infoPtrIn; + + // User-set values for cross sections. + setTotal = Settings::flag("SigmaTotal:setOwn"); + sigTotOwn = Settings::parm("SigmaTotal:sigmaTot"); + sigElOwn = Settings::parm("SigmaTotal:sigmaEl"); + sigXBOwn = Settings::parm("SigmaTotal:sigmaXB"); + sigAXOwn = Settings::parm("SigmaTotal:sigmaAX"); + sigXXOwn = Settings::parm("SigmaTotal:sigmaXX"); + + // User-set values for handling of elastic sacattering. + setElastic = Settings::flag("SigmaElastic:setOwn"); + bSlope = Settings::parm("SigmaElastic:bSlope"); + rho = Settings::parm("SigmaElastic:rho"); + lambda = Settings::parm("SigmaElastic:lambda"); + tAbsMin = Settings::parm("SigmaElastic:tAbsMin"); + alphaEM0 = Settings::parm("StandardModel:alphaEM0"); +} + +//********* + +// Function that calculates the relevant properties. + +bool SigmaTotal::calc( int idA, int idB, double eCM) { + + // Derived quantities. + alP2 = 2. * ALPHAPRIME; + s0 = 1. / ALPHAPRIME; + + // Reset everything to zero to begin with. + isCalc = false; + sigTot = sigEl = sigXB = sigAX = sigXX = sigND = bEl = s = bA = bB = 0.; + + // Order flavour of incoming hadrons: idAbsA < idAbsB (restore later). + int idAbsA = abs(idA); + int idAbsB = abs(idB); + bool swapped = false; + if (idAbsA > idAbsB) { + swap( idAbsA, idAbsB); + swapped = true; + } + double sameSign = (idA * idB > 0); + + // Find process number. + int iProc = -1; + if (idAbsA > 1000) { + iProc = (sameSign) ? 0 : 1; + } else if (idAbsA > 100 && idAbsB > 1000) { + iProc = (sameSign) ? 2 : 3; + if (idAbsA/10 == 11 || idAbsA/10 == 22) iProc = 4; + if (idAbsA > 300) iProc = 5; + if (idAbsA > 400) iProc = 6; + } else if (idAbsA > 100) { + iProc = 7; + if (idAbsB > 300) iProc = 8; + if (idAbsB > 400) iProc = 9; + if (idAbsA > 300) iProc = 10; + if (idAbsA > 300 && idAbsB > 400) iProc = 11; + if (idAbsA > 400) iProc = 12; + } + if (iProc == -1) return false; + + // Find hadron masses and check that energy is enough. + // For mesons use the corresponding vector meson masses. + int idModA = (idAbsA > 1000) ? idAbsA : 10 * (idAbsA/10) + 3; + int idModB = (idAbsB > 1000) ? idAbsB : 10 * (idAbsB/10) + 3; + double mA = ParticleDataTable::m0(idModA); + double mB = ParticleDataTable::m0(idModB); + if (eCM < mA + mB + MMIN) return false; + + // Evaluate the total cross section. + s = eCM*eCM; + double sEps = pow( s, EPSILON); + double sEta = pow( s, ETA); + sigTot = X[iProc] * sEps + Y[iProc] * sEta; + + // Slope of hadron form factors. + int iHadA = IHADATABLE[iProc]; + int iHadB = IHADBTABLE[iProc]; + bA = BHAD[iHadA]; + bB = BHAD[iHadB]; + + // Elastic slope parameter and cross section. + bEl = 2.*bA + 2.*bB + 4.*sEps - 4.2; + sigEl = CONVERTEL * pow2(sigTot) / bEl; + + // Lookup coefficients for single and double diffraction. + int iSD = ISDTABLE[iProc]; + int iDD = IDDTABLE[iProc]; + double sum1, sum2, sum3, sum4; + + // Single diffractive scattering A + B -> X + B cross section. + mMinXBsave = mA + MMIN0; + double sMinXB = pow2(mMinXBsave); + mResXBsave = mA + MRES0; + double sResXB = pow2(mResXBsave); + double sRMavgXB = mResXBsave * mMinXBsave; + double sRMlogXB = log(1. + sResXB/sMinXB); + double sMaxXB = CSD[iSD][0] * s + CSD[iSD][1]; + double BcorrXB = CSD[iSD][2] + CSD[iSD][3] / s; + sum1 = log( (2.*bB + alP2 * log(s/sMinXB)) + / (2.*bB + alP2 * log(s/sMaxXB)) ) / alP2; + sum2 = CRES * sRMlogXB / (2.*bB + alP2 * log(s/sRMavgXB) + BcorrXB) ; + sigXB = CONVERTSD * X[iProc] * BETA0[iHadB] * max( 0., sum1 + sum2); + + // Single diffractive scattering A + B -> A + X cross section. + mMinAXsave = mB + MMIN0; + double sMinAX = pow2(mMinAXsave); + mResAXsave = mB + MRES0; + double sResAX = pow2(mResAXsave); + double sRMavgAX = mResAXsave * mMinAXsave; + double sRMlogAX = log(1. + sResAX/sMinAX); + double sMaxAX = CSD[iSD][4] * s + CSD[iSD][5]; + double BcorrAX = CSD[iSD][6] + CSD[iSD][7] / s; + sum1 = log( (2.*bA + alP2 * log(s/sMinAX)) + / (2.*bA + alP2 * log(s/sMaxAX)) ) / alP2; + sum2 = CRES * sRMlogAX / (2.*bA + alP2 * log(s/sRMavgAX) + BcorrAX) ; + sigAX = CONVERTSD * X[iProc] * BETA0[iHadA] * max( 0., sum1 + sum2); + + // Order single diffractive correctly. + if (swapped) { + swap( bB, bA); + swap( sigXB, sigAX); + swap( mMinXBsave, mMinAXsave); + swap( mResXBsave, mResAXsave); + } + + // Double diffractive scattering A + B -> X1 + X2 cross section. + double y0min = log( s * SPROTON / (sMinXB * sMinAX) ) ; + double sLog = log(s); + double Delta0 = CDD[iDD][0] + CDD[iDD][1] / sLog + + CDD[iDD][2] / pow2(sLog); + sum1 = (y0min * (log( max( 1e-10, y0min/Delta0) ) - 1.) + Delta0)/ alP2; + if (y0min < 0.) sum1 = 0.; + double sMaxXX = s * ( CDD[iDD][3] + CDD[iDD][4] / sLog + + CDD[iDD][5] / pow2(sLog) ); + double sLogUp = log( max( 1.1, s * s0 / (sMinXB * sRMavgAX) )); + double sLogDn = log( max( 1.1, s * s0 / (sMaxXX * sRMavgAX) )); + sum2 = CRES * log( sLogUp / sLogDn ) * sRMlogAX / alP2; + sLogUp = log( max( 1.1, s * s0 / (sMinAX * sRMavgXB) )); + sLogDn = log( max( 1.1, s * s0 / (sMaxXX * sRMavgXB) )); + sum3 = CRES * log(sLogUp / sLogDn) * sRMlogXB / alP2; + double BcorrXX = CDD[iDD][6] + CDD[iDD][7] / eCM + CDD[iDD][8] / s; + sum4 = pow2(CRES) * sRMlogAX * sRMlogXB + / max( 0.1, alP2 * log( s * s0 / (sRMavgAX * sRMavgXB) ) + BcorrXX); + sigXX = CONVERTDD * X[iProc] * max( 0., sum1 + sum2 + sum3 + sum4); + + // Option with user-set values for total and partial cross sections. + // (Is not done earlier since want diffractive slopes anyway.) + double sigNDOwn = sigTotOwn - sigElOwn - sigXBOwn - sigAXOwn - sigXXOwn; + double sigElMax = sigEl; + if (setTotal && sigNDOwn > 0.) { + sigTot = sigTotOwn; + sigEl = sigElOwn; + sigXB = sigXBOwn; + sigAX = sigAXOwn; + sigXX = sigXXOwn; + sigElMax = sigEl; + + // Sub-option to set elastic parameters, including Coulomb contribution. + if (setElastic) { + bEl = bSlope; + sigEl = CONVERTEL * pow2(sigTot) * (1. + rho*rho) / bSlope; + sigElMax = 2. * (sigEl * exp(-bSlope * tAbsMin) + + alphaEM0 * alphaEM0 / (4. * CONVERTEL * tAbsMin) ); + } + } + + // Inelastic nondiffractive by unitarity. + sigND = sigTot - sigEl - sigXB - sigAX - sigXX; + if (sigND < 0.) infoPtr->errorMsg("Error in SigmaTotal::init: " + "sigND < 0"); + else if (sigND < 0.4 * sigTot) infoPtr->errorMsg("Warning in " + "SigmaTotal::init: sigND suspiciously low"); + + // Upper estimate of elastic, including Coulomb term, where appropriate. + sigEl = sigElMax; + + // Done. + isCalc = true; + return true; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SpaceShower.cxx b/PYTHIA8/pythia8130/src/SpaceShower.cxx new file mode 100644 index 00000000000..161f73de373 --- /dev/null +++ b/PYTHIA8/pythia8130/src/SpaceShower.cxx @@ -0,0 +1,1209 @@ +// SpaceShower.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the +// SpaceShower class. + +#include "SpaceShower.h" + +namespace Pythia8 { + +//************************************************************************** + +// The SpaceShower class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Leftover companion can give PDF > 0 at small Q2 where other PDF's = 0, +// and then one can end in infinite loop of impossible kinematics. +const int SpaceShower::MAXLOOPTINYPDF = 10; + +// Switch to alternative (but equivalent) backwards evolution for +// g -> Q Qbar (Q = c or b) when below QTHRESHOLD * mQ2. +const double SpaceShower::CTHRESHOLD = 2.0; +const double SpaceShower::BTHRESHOLD = 2.0; + +// Renew evaluation of PDF's when the pT2 step is bigger than this +// (in addition to initial scale and c and b thresholds.) +const double SpaceShower::EVALPDFSTEP = 0.1; + +// Lower limit on PDF value in order to avoid division by zero. +const double SpaceShower::TINYPDF = 1e-10; + +// Lower limit on estimated evolution rate, below which stop. +const double SpaceShower::TINYKERNELPDF = 1e-6; + +// Lower limit on pT2, below which branching is rejected. +const double SpaceShower::TINYPT2 = 0.25e-6; + +// No attempt to do backwards evolution of a heavy (c or b) quark +// if evolution starts at a scale pT2 < HEAVYPT2EVOL * mQ2. +const double SpaceShower::HEAVYPT2EVOL = 1.1; + +// No attempt to do backwards evolution of a heavy (c or b) quark +// if evolution starts at a x > HEAVYXEVOL * x_max, where +// x_max is the largest possible x value for a g -> Q Qbar branching. +const double SpaceShower::HEAVYXEVOL = 0.9; + +// When backwards evolution Q -> g + Q creates a heavy quark Q, +// an earlier branching g -> Q + Qbar will restrict kinematics +// to M_{Q Qbar}^2 > EXTRASPACEQ * 4 m_Q^2. (Smarter to be found??) +const double SpaceShower::EXTRASPACEQ = 2.0; + +// Never pick pT so low that alphaS is evaluated too close to Lambda_3. +const double SpaceShower::LAMBDA3MARGIN = 1.1; + +// Cutoff for f_e^e at x < 1 - 10^{-10} to be used in z selection. +// Note: the x_min quantity come from 1 - x_max. +const double SpaceShower::LEPTONXMIN = 1e-10; +const double SpaceShower::LEPTONXMAX = 1. - 1e-10; + +// Stop l -> l gamma evolution slightly above m2l. +const double SpaceShower::LEPTONPT2MIN = 1.2; + +// Enhancement of l -> l gamma trial rate to compensate imperfect modelling. +const double SpaceShower::LEPTONFUDGE = 10.; + +//********* + +// Initialize alphaStrong, alphaEM and related pTmin parameters. + +void SpaceShower::init( BeamParticle* beamAPtrIn, + BeamParticle* beamBPtrIn) { + + // Store input pointers for future use. + beamAPtr = beamAPtrIn; + beamBPtr = beamBPtrIn; + + // Main flags to switch on and off branchings. + doQCDshower = Settings::flag("SpaceShower:QCDshower"); + doQEDshowerByQ = Settings::flag("SpaceShower:QEDshowerByQ"); + doQEDshowerByL = Settings::flag("SpaceShower:QEDshowerByL"); + + // Matching in pT of hard interaction to shower evolution. + pTmaxMatch = Settings::mode("SpaceShower:pTmaxMatch"); + pTdampMatch = Settings::mode("SpaceShower:pTdampMatch"); + pTmaxFudge = Settings::parm("SpaceShower:pTmaxFudge"); + pTdampFudge = Settings::parm("SpaceShower:pTdampFudge"); + + // Optionally force emissions to be ordered in rapidity/angle. + doRapidityOrder = Settings::flag("SpaceShower:rapidityOrder"); + + // Charm, bottom and lepton mass thresholds. + mc = ParticleDataTable::m0(4); + mb = ParticleDataTable::m0(5); + m2c = pow2(mc); + m2b = pow2(mb); + + // Parameters of alphaStrong generation. + alphaSvalue = Settings::parm("SpaceShower:alphaSvalue"); + alphaSorder = Settings::mode("SpaceShower:alphaSorder"); + alphaS2pi = 0.5 * alphaSvalue / M_PI; + + // Initialize alpha_strong generation. + alphaS.init( alphaSvalue, alphaSorder); + + // Lambda for 5, 4 and 3 flavours. + Lambda5flav = alphaS.Lambda5(); + Lambda4flav = alphaS.Lambda4(); + Lambda3flav = alphaS.Lambda3(); + Lambda5flav2 = pow2(Lambda5flav); + Lambda4flav2 = pow2(Lambda4flav); + Lambda3flav2 = pow2(Lambda3flav); + + // Regularization of QCD evolution for pT -> 0. Can be taken + // same as for multiple interactions, or be set separately. + useSamePTasMI = Settings::flag("SpaceShower:samePTasMI"); + if (useSamePTasMI) { + pT0Ref = Settings::parm("MultipleInteractions:pT0Ref"); + ecmRef = Settings::parm("MultipleInteractions:ecmRef"); + ecmPow = Settings::parm("MultipleInteractions:ecmPow"); + pTmin = Settings::parm("MultipleInteractions:pTmin"); + } else { + pT0Ref = Settings::parm("SpaceShower:pT0Ref"); + ecmRef = Settings::parm("SpaceShower:ecmRef"); + ecmPow = Settings::parm("SpaceShower:ecmPow"); + pTmin = Settings::parm("SpaceShower:pTmin"); + } + + // Calculate nominal invariant mass of events. Set current pT0 scale. + sCM = m2( beamAPtr->p(), beamBPtr->p()); + eCM = sqrt(sCM); + pT0 = pT0Ref * pow(eCM / ecmRef, ecmPow); + + // Restrict pTmin to ensure that alpha_s(pTmin^2 + pT_0^2) does not blow up. + pTmin = max( pTmin, sqrtpos(pow2(LAMBDA3MARGIN) * Lambda3flav2 - pT0*pT0) ); + + // Parameters of alphaEM generation. + alphaEMorder = Settings::mode("SpaceShower:alphaEMorder"); + + // Initialize alphaEM generation. + alphaEM.init( alphaEMorder); + + // Parameters of QED evolution. + pTminChgQ = Settings::parm("SpaceShower:pTminchgQ"); + pTminChgL = Settings::parm("SpaceShower:pTminchgL"); + + // Derived parameters of QCD evolution. + pT20 = pow2(pT0); + pT2min = pow2(pTmin); + pT2minChgQ = pow2(pTminChgQ); + pT2minChgL = pow2(pTminChgL); + + // Various other parameters. + doMEcorrections = Settings::flag("SpaceShower:MEcorrections"); + doPhiPolAsym = Settings::flag("SpaceShower:phiPolAsym"); + nQuarkIn = Settings::mode("SpaceShower:nQuarkIn"); + +} + +//********* + +// Find whether to limit maximum scale of emissions. + +bool SpaceShower::limitPTmax( Event& event, double Q2Fac, double Q2Ren) { + + // Find whether to limit pT. Begin by user-set cases. + bool dopTlimit = false; + if (pTmaxMatch == 1) dopTlimit = true; + else if (pTmaxMatch == 2) dopTlimit = false; + + // Look if any quark (u, d, s, c, b), gluon or photon in final state. + else { + for (int i = 5; i < event.size(); ++i) + if (event[i].status() != -21) { + int idAbs = event[i].idAbs(); + if (idAbs <= 5 || idAbs == 21 || idAbs == 22) dopTlimit = true; + } + } + + // Dampening at factorization or renormalization scale. + dopTdamp = false; + pT2damp = 0.; + if ( !dopTlimit && (pTdampMatch == 1 || pTdampMatch == 2) ) { + dopTdamp = true; + pT2damp = pow2(pTdampFudge) * ((pTdampMatch == 1) ? Q2Fac : Q2Ren); + } + + // Done. + return dopTlimit; + +} + +//********* + +// Prepare system for evolution; identify ME. +// Routine may be called after multiple interactions, for a new subystem. + +void SpaceShower::prepare( int iSys, Event& event, bool limitPTmaxIn) { + + // Find positions of incoming colliding partons. + int in1 = event.getInSystem( iSys, 0); + int in2 = event.getInSystem( iSys, 1); + + // Reset dipole-ends list for first interaction. + if (iSys == 0) dipEnd.resize(0); + + // Find matrix element corrections for system. + int MEtype = findMEtype( iSys, event); + + // Maximum pT scale for dipole ends. + double pTmax1 = (limitPTmaxIn) ? event[in1].scale() : eCM; + double pTmax2 = (limitPTmaxIn) ? event[in2].scale() : eCM; + if (iSys == 0 && limitPTmaxIn) { + pTmax1 *= pTmaxFudge; + pTmax2 *= pTmaxFudge; + } + + // Find dipole ends for QCD radiation. + if (doQCDshower) { + int colType1 = event[in1].colType(); + dipEnd.push_back( SpaceDipoleEnd( iSys, 1, in1, in2, pTmax1, + colType1, 0, MEtype) ); + int colType2 = event[in2].colType(); + dipEnd.push_back( SpaceDipoleEnd( iSys, 2, in2, in1, pTmax2, + colType2, 0, MEtype) ); + } + + // Find dipole ends for QED radiation. + if (doQEDshowerByQ || doQEDshowerByL) { + int chgType1 = ( (event[in1].isQuark() && doQEDshowerByQ) + || (event[in1].isLepton() && doQEDshowerByL) ) + ? event[in1].chargeType() : 0; + dipEnd.push_back( SpaceDipoleEnd( iSys, -1, in1, in2, pTmax1, + 0, chgType1, MEtype) ); + int chgType2 = ( (event[in2].isQuark() && doQEDshowerByQ) + || (event[in2].isLepton() && doQEDshowerByL) ) + ? event[in2].chargeType() : 0; + dipEnd.push_back( SpaceDipoleEnd( iSys, -2, in2, in1, pTmax2, + 0, chgType2, MEtype) ); + } + +} + +//********* + +// Select next pT in downwards evolution of the existing dipoles. + +double SpaceShower::pTnext( Event& , double pTbegAll, double pTendAll, + int nRadIn) { + + // Current cm energy, in case it varies between events. + sCM = m2( beamAPtr->p(), beamBPtr->p()); + + // Starting values: no radiating dipole found. + nRad = nRadIn; + double pT2sel = pow2(pTendAll); + iDipSel = 0; + iSysSel = 0; + dipEndSel = 0; + + // Loop over all possible dipole ends. + for (int iDipEnd = 0; iDipEnd < int(dipEnd.size()); ++iDipEnd) { + iDipNow = iDipEnd; + dipEndNow = &dipEnd[iDipEnd]; + iSysNow = dipEndNow->system; + dipEndNow->pT2 = 0.; + + // Check whether dipole end should be allowed to shower. + double pT2begDip = pow2( min( pTbegAll, dipEndNow->pTmax )); + if (pT2begDip > pT2sel + && ( dipEndNow->colType != 0 || dipEndNow->chgType != 0 ) ) { + double pT2endDip = 0.; + + // Determine lower cut for evolution, for QCD or QED (q or l). + if (dipEndNow->colType != 0) pT2endDip = max( pT2sel, pT2min ); + else if (abs(dipEndNow->chgType) != 3) pT2endDip + = max( pT2sel, pT2minChgQ ); + else pT2endDip = max( pT2sel, pT2minChgL ); + + // Find properties of dipole and radiating dipole end. + bool ordered = ( abs(dipEndNow->side) == 1 ); + BeamParticle& beamNow = (ordered) ? *beamAPtr : *beamBPtr; + BeamParticle& beamRec = (ordered) ? *beamBPtr : *beamAPtr; + iNow = beamNow[iSysNow].iPos(); + iRec = beamRec[iSysNow].iPos(); + idDaughter = beamNow[iSysNow].id(); + xDaughter = beamNow[iSysNow].x(); + x1Now = (ordered) ? xDaughter : beamRec[iSysNow].x(); + x2Now = (ordered) ? beamRec[iSysNow].x() : xDaughter; + m2Dip = x1Now * x2Now * sCM; + + // Now do evolution in pT2, for QCD or QED + if (pT2begDip > pT2endDip) { + if (dipEndNow->colType != 0) pT2nextQCD( pT2begDip, pT2endDip); + else pT2nextQED( pT2begDip, pT2endDip); + } + + // Update if found larger pT than current maximum. + if (dipEndNow->pT2 > pT2sel) { + pT2sel = dipEndNow->pT2; + iDipSel = iDipNow; + iSysSel = iSysNow; + dipEndSel = dipEndNow; + } + + // End loop over dipole ends. + } + } + + // Return nonvanishing value if found pT is bigger than already found. + return (dipEndSel == 0) ? 0. : sqrt(pT2sel); +} + +//********* + +// Evolve a QCD dipole end. + +void SpaceShower::pT2nextQCD( double pT2begDip, double pT2endDip) { + + // Some properties and kinematical starting values. + BeamParticle& beam = ( abs(dipEndNow->side) == 1 ) + ? *beamAPtr : *beamBPtr; + bool isGluon = (idDaughter == 21); + bool isValence = beam[iSysNow].isValence(); + int MEtype = dipEndNow->MEtype; + double pT2 = pT2begDip; + double xMaxAbs = beam.xMax(iSysNow); + double zMinAbs = xDaughter / xMaxAbs; + + // Starting values for handling of massive quarks (c/b), if any. + double idMassive = 0; + if ( abs(idDaughter) == 4 ) idMassive = 4; + if ( abs(idDaughter) == 5 ) idMassive = 5; + bool isMassive = (idMassive > 0); + double m2Massive = 0.; + double mRatio = 0.; + double zMaxMassive = 1.; + double m2Threshold = pT2; + + // Evolution below scale of massive quark or at large x is impossible. + if (isMassive) { + m2Massive = (idMassive == 4) ? m2c : m2b; + if (pT2 < HEAVYPT2EVOL * m2Massive) return; + mRatio = sqrt( m2Massive / m2Dip ); + zMaxMassive = (1. - mRatio) / ( 1. + mRatio * (1. - mRatio) ); + if (xDaughter > HEAVYXEVOL * zMaxMassive * xMaxAbs) return; + + // Find threshold scale below which only g -> Q + Qbar will be allowed. + m2Threshold = (idMassive == 4) ? min( pT2, CTHRESHOLD * m2c) + : min( pT2, BTHRESHOLD * m2b); + } + + // Variables used inside evolution loop. (Mainly dummy starting values.) + int nFlavour = 3; + double b0 = 4.5; + double Lambda2 = Lambda3flav2; + double pT2minNow = pT2endDip; + int idMother = 0; + int idSister = 0; + double z = 0.; + double zMaxAbs = 0.; + double zRootMax = 0.; + double zRootMin = 0.; + double g2gInt = 0.; + double q2gInt = 0.; + double q2qInt = 0.; + double g2qInt = 0.; + double g2Qenhance = 0.; + double xPDFdaughter = 0.; + double xPDFmother[21] = {0.}; + double xPDFgMother = 0.; + double xPDFmotherSum = 0.; + double kernelPDF = 0.; + double xMother = 0.; + double wt = 0.; + double Q2 = 0.; + double mSister = 0.; + double m2Sister = 0.; + double pT2corr = 0.; + double phi = 0.; + double pT2PDF = pT2; + bool needNewPDF = true; + + // Begin evolution loop towards smaller pT values. + int loopTinyPDFdau = 0; + bool hasTinyPDFdau = false; + do { + wt = 0.; + + // Bad sign if repeated looping with small daughter PDF, so fail. + // (Example: if all PDF's = 0 below Q_0, except for c/b companion.) + if (hasTinyPDFdau) ++loopTinyPDFdau; + if (loopTinyPDFdau > MAXLOOPTINYPDF) { + infoPtr->errorMsg("Warning in SpaceShower::pT2nextQCD: " + "small daughter PDF"); + return; + } + + // Initialize integrals of splitting kernels and evaluate parton + // densities at the beginning. Reinitialize after long evolution + // in pT2 or when crossing c and b flavour thresholds. + if (needNewPDF || pT2 < EVALPDFSTEP * pT2PDF) { + pT2PDF = pT2; + hasTinyPDFdau = false; + + // Determine overestimated z range; switch at c and b masses. + if (pT2 > m2b) { + nFlavour = 5; + pT2minNow = m2b; + b0 = 23./6.; + Lambda2 = Lambda5flav2; + } else if (pT2 > m2c) { + nFlavour = 4; + pT2minNow = m2c; + b0 = 25./6.; + Lambda2 = Lambda4flav2; + } else { + nFlavour = 3; + pT2minNow = pT2endDip; + b0 = 27./6.; + Lambda2 = Lambda3flav2; + } + zMaxAbs = 1. - 0.5 * (pT2minNow / m2Dip) * + ( sqrt( 1. + 4. * m2Dip / pT2minNow ) - 1. ); + if (isMassive) zMaxAbs = min( zMaxAbs, zMaxMassive); + + // Go to another z range with lower mass scale if current is closed. + if (zMinAbs > zMaxAbs) { + if (nFlavour == 3 || (idMassive == 4 && nFlavour == 4) + || idMassive == 5) return; + pT2 = (nFlavour == 4) ? m2c : m2b; + continue; + } + + // Parton density of daughter at current scale. + xPDFdaughter = beam.xfISR(iSysNow, idDaughter, xDaughter, pT2); + if (xPDFdaughter < TINYPDF) { + xPDFdaughter = TINYPDF; + hasTinyPDFdau = true; + } + + // Integrals of splitting kernels for gluons: g -> g, q -> g. + if (isGluon) { + g2gInt = 6. * log(zMaxAbs * (1.-zMinAbs) + / (zMinAbs * (1.-zMaxAbs))); + if (doMEcorrections) g2gInt *= calcMEmax(MEtype, 21, 21); + q2gInt = (16./3.) * (1./sqrt(zMinAbs) - 1./sqrt(zMaxAbs)); + if (doMEcorrections) q2gInt *= calcMEmax(MEtype, 1, 21); + + // Parton density of potential quark mothers to a g. + xPDFmotherSum = 0.; + for (int i = -nQuarkIn; i <= nQuarkIn; ++i) { + if (i == 0) { + xPDFmother[10] = 0.; + } else { + xPDFmother[i+10] = beam.xfISR(iSysNow, i, xDaughter, pT2); + xPDFmotherSum += xPDFmother[i+10]; + } + } + + // Total QCD evolution coefficient for a gluon. + kernelPDF = g2gInt + q2gInt * xPDFmotherSum / xPDFdaughter; + + // For valence quark only need consider q -> q g branchings. + // Introduce an extra factor sqrt(z) to smooth bumps. + } else if (isValence) { + zRootMin = (1. + sqrt(zMinAbs)) / (1. - sqrt(zMinAbs)); + zRootMax = (1. + sqrt(zMaxAbs)) / (1. - sqrt(zMaxAbs)); + q2qInt = (8./3.) * log( zRootMax / zRootMin ); + if (doMEcorrections) q2qInt *= calcMEmax(MEtype, 1, 1); + g2qInt = 0.; + kernelPDF = q2qInt; + + // Integrals of splitting kernels for quarks: q -> q, g -> q. + } else { + q2qInt = (8./3.) * log( (1. - zMinAbs) / (1. - zMaxAbs) ); + if (doMEcorrections) q2qInt *= calcMEmax(MEtype, 1, 1); + g2qInt = 0.5 * (zMaxAbs - zMinAbs); + if (doMEcorrections) g2qInt *= calcMEmax(MEtype, 21, 1); + + // Increase estimated upper weight for g -> Q + Qbar. + if (isMassive) { + double m2log = log( m2Massive / Lambda2); + g2Qenhance = log( log(pT2/Lambda2) / m2log ) + / log( log(m2Threshold/Lambda2) / m2log ); + g2qInt *= g2Qenhance; + } + + // Parton density of a potential gluon mother to a q. + xPDFgMother = beam.xfISR(iSysNow, 21, xDaughter, pT2); + + // Total QCD evolution coefficient for a quark. + kernelPDF = q2qInt + g2qInt * xPDFgMother / xPDFdaughter; + } + + // End evaluation of splitting kernels and parton densities. + needNewPDF = false; + } + if (kernelPDF < TINYKERNELPDF) return; + + // Pick pT2 (in overestimated z range), for one of three different cases. + // Assume form alphas(pT0^2 + pT^2) * dpT^2/(pT0^2 + pT^2). + double Q2alphaS; + + // Fixed alpha_strong. + if (alphaSorder == 0) { + pT2 = (pT2 + pT20) * pow( Rndm::flat(), + 1. / (alphaS2pi * kernelPDF)) - pT20; + + // First-order alpha_strong. + } else if (alphaSorder == 1) { + pT2 = Lambda2 * pow( (pT2 + pT20) / Lambda2, + pow(Rndm::flat(), b0 / kernelPDF) ) - pT20; + + // For second order reject by second term in alpha_strong expression. + } else { + do { + pT2 = Lambda2 * pow( (pT2 + pT20) / Lambda2, + pow(Rndm::flat(), b0 / kernelPDF) ) - pT20; + Q2alphaS = max(pT2 + pT20, pow2(LAMBDA3MARGIN) * Lambda3flav2); + } while (alphaS.alphaS2OrdCorr(Q2alphaS) < Rndm::flat() + && pT2 > pT2minNow); + } + + // Check for pT2 values that prompt special action. + + // If fallen into b threshold region, force g -> b + bbar. + if (idMassive == 5 && pT2 < m2Threshold) { + pT2nearQCDthreshold( beam, m2Massive, m2Threshold, zMinAbs, + zMaxMassive ); + return; + + // If crossed b threshold, continue evolution from this threshold. + } else if (nFlavour == 5 && pT2 < m2b) { + needNewPDF = true; + pT2 = m2b; + continue; + + // If fallen into c threshold region, force g -> c + cbar. + } else if (idMassive == 4 && pT2 < m2Threshold) { + pT2nearQCDthreshold( beam, m2Massive, m2Threshold, zMinAbs, + zMaxMassive ); + return; + + // If crossed c threshold, continue evolution from this threshold. + } else if (nFlavour == 4 && pT2 < m2c) { + needNewPDF = true; + pT2 = m2c; + continue; + + // Abort evolution if below cutoff scale, or below another branching. + } else if (pT2 < pT2endDip) return; + + // Select z value of branching to g, and corrective weight. + if (isGluon) { + // g -> g (+ g). + if (Rndm::flat() * kernelPDF < g2gInt) { + idMother = 21; + idSister = 21; + z = 1. / ( 1. + ((1. - zMinAbs) / zMinAbs) * pow( (zMinAbs * + (1. - zMaxAbs)) / (zMaxAbs * (1. - zMinAbs)), Rndm::flat() ) ); + wt = pow2( 1. - z * (1. - z)); + } else { + // q -> g (+ q): also select flavour. + double temp = xPDFmotherSum * Rndm::flat(); + idMother = -nQuarkIn - 1; + do { temp -= xPDFmother[(++idMother) + 10]; } + while (temp > 0. && idMother < nQuarkIn); + idSister = idMother; + z = (zMinAbs * zMaxAbs) / pow2( sqrt(zMinAbs) + Rndm::flat() + * ( sqrt(zMaxAbs)- sqrt(zMinAbs) )); + wt = 0.5 * (1. + pow2(1. - z)) * sqrt(z) + * xPDFdaughter / xPDFmother[idMother + 10]; + } + + // Select z value of branching to q, and corrective weight. + // Include massive kernel corrections for c and b quarks. + } else { + // q -> q (+ g). + if (isValence || Rndm::flat() * kernelPDF < q2qInt) { + idMother = idDaughter; + idSister = 21; + // Valence more peaked at large z. + if (isValence) { + double zTmp = zRootMin * pow(zRootMax / zRootMin, Rndm::flat() ); + z = pow2( (1. - zTmp) / (1. + zTmp) ); + } else { + z = 1. - (1. - zMinAbs) * pow( (1. - zMaxAbs) / (1. - zMinAbs), + Rndm::flat() ); + } + if (!isMassive) { + wt = 0.5 * (1. + pow2(z)); + } else { + wt = 0.5 * (1. + pow2(z) - z * pow2(1.-z) * m2Massive / pT2); + } + if (isValence) wt *= sqrt(z); + // g -> q (+ qbar). + } else { + idMother = 21; + idSister = - idDaughter; + z = zMinAbs + Rndm::flat() * (zMaxAbs - zMinAbs); + if (!isMassive) { + wt = (pow2(z) + pow2(1.-z)) * xPDFdaughter / xPDFgMother ; + } else { + wt = (pow2(z) + pow2(1.-z) + 2. * z * (1.-z) * m2Massive / pT2) + * xPDFdaughter / (xPDFgMother * g2Qenhance) ; + } + } + } + + // Derive Q2 and x of mother from pT2 and z. + Q2 = pT2 / (1.- z); + xMother = xDaughter / z; + + // Forbidden emission if outside allowed z range for given pT2. + mSister = ParticleDataTable::m0(idSister); + m2Sister = pow2(mSister); + pT2corr = Q2 - z * (m2Dip + Q2) * (Q2 + m2Sister) / m2Dip; + if(pT2corr < TINYPT2) { wt = 0.; continue; } + + // Optionally veto emissions not ordered in rapidity (= angle). + if ( doRapidityOrder && dipEndNow->nBranch > 0 + && pT2 > pow2( (1. - z) / (z * (1. - dipEndNow->zOld)) ) + * dipEndNow->pT2Old ) { wt = 0.; continue; } + + // If creating heavy quark by Q -> g + Q then next need g -> Q + Qbar. + // So minimum total mass2 is 4 * m2Sister, but use more to be safe. + if ( isGluon && ( abs(idMother) == 4 || abs(idMother) == 5 )) { + double m2QQsister = EXTRASPACEQ * 4. * m2Sister; + double pT2QQcorr = Q2 - z * (m2Dip + Q2) * (Q2 + m2QQsister) / m2Dip; + if(pT2QQcorr < TINYPT2) { wt = 0.; continue; } + } + + // Select phi angle of branching at random. + phi = 2. * M_PI * Rndm::flat(); + + // Evaluation of ME correction. + if (doMEcorrections) wt *= calcMEcorr(MEtype, idMother, idDaughter, + m2Dip, z, Q2) / calcMEmax(MEtype, idMother, idDaughter); + + // Optional dampening of large pT values in first radiation. + if (dopTdamp && iSysNow == 0 && MEtype == 0 && nRad == 0) + wt *= pT2damp / (pT2 + pT2damp); + + // Evaluation of new daughter and mother PDF's. + double xPDFdaughterNew = max ( TINYPDF, + beam.xfISR(iSysNow, idDaughter, xDaughter, pT2) ); + double xPDFmotherNew = beam.xfISR(iSysNow, idMother, xMother, pT2); + wt *= xPDFmotherNew / xPDFdaughterNew; + + // Check that valence step does not cause problem. + if (wt > 1.) infoPtr->errorMsg("Warning in SpaceShower::" + "pT2nextQCD: weight above unity"); + + // Iterate until acceptable pT (or have fallen below pTmin). + } while (wt < Rndm::flat()) ; + + // Save values for (so far) acceptable branching. + dipEndNow->store( idDaughter,idMother, idSister, x1Now, x2Now, m2Dip, + pT2, z, Q2, mSister, m2Sister, pT2corr, phi); + +} + +//********* + +// Evolve a QCD dipole end near threshold, with g -> Q + Qbar enforced. +// Note: No explicit Sudakov factor formalism here. Instead use that +// df_Q(x, pT2) = (alpha_s/2pi) * (dT2/pT2) * ((gluon) * (splitting)). +// This implies that effects of Q -> Q + g are neglected in this range. + +void SpaceShower::pT2nearQCDthreshold( BeamParticle& beam, + double m2Massive, double m2Threshold, double zMinAbs, + double zMaxMassive) { + + // Initial values, to be used in kinematics and weighting. + double Lambda2 = (abs(idDaughter) == 4) ? Lambda4flav2 : Lambda5flav2; + double logM2Lambda2 = log( m2Massive / Lambda2 ); + double xPDFmotherOld = beam.xfISR(iSysNow, 21, xDaughter, m2Threshold); + + // Variables used inside evolution loop. (Mainly dummy start values.) + int loop = 0; + double wt = 0.; + double pT2 = 0.; + double z = 0.; + double Q2 = 0.; + double pT2corr = 0.; + + // Begin loop over tries to find acceptable g -> Q + Qbar branching. + do { + wt = 0.; + + // Check that not caught in infinite loop with impossible kinematics. + if (++loop > 100) { + infoPtr->errorMsg("Error in SpaceShower::pT2nearQCDthreshold: " + "stuck in loop"); + return; + } + + // Pick dpT2/pT2 in range [m2Massive,thresholdRatio * m2Massive]. + pT2 = m2Massive * pow( m2Threshold / m2Massive, Rndm::flat() ); + + // Pick z flat in allowed range. + z = zMinAbs + Rndm::flat() * (zMaxMassive - zMinAbs); + + // Check that kinematically possible choice. + Q2 = pT2 / (1.-z) - m2Massive; + pT2corr = Q2 - z * (m2Dip + Q2) * (Q2 + m2Massive) / m2Dip; + if(pT2corr < TINYPT2) continue; + + // Correction factor for running alpha_s. ?? + wt = logM2Lambda2 / log( pT2 / Lambda2 ); + + // Correction factor for splitting kernel. + wt *= pow2(z) + pow2(1.-z) + 2. * z * (1.-z) * m2Massive / pT2; + + // Correction factor for gluon density. + double xPDFmotherNew = beam.xfISR(iSysNow, 21, xDaughter/z, pT2); + wt *= xPDFmotherNew / xPDFmotherOld; + + // Iterate until acceptable pT and z. + } while (wt < Rndm::flat()) ; + + // Select phi angle of branching at random. + double phi = 2. * M_PI * Rndm::flat(); + + // Save values for (so far) acceptable branching. + double mSister = (abs(idDaughter) == 4) ? mc : mb; + dipEndNow->store( idDaughter, 21, -idDaughter, x1Now, x2Now, m2Dip, + pT2, z, Q2, mSister, pow2(mSister), pT2corr, phi); + +} + +//********* + +// Evolve a QED dipole end. + +void SpaceShower::pT2nextQED( double pT2begDip, double pT2endDip) { + + // Type of dipole and starting values. + BeamParticle& beam = ( abs(dipEndNow->side) == 1 ) + ? *beamAPtr : *beamBPtr; + bool isLeptonBeam = beam.isLepton(); + int MEtype = dipEndNow->MEtype; + bool isPhoton = (idDaughter == 22); + double pT2 = pT2begDip; + double m2Lepton = (isLeptonBeam) ? pow2(beam.m()) : 0.; + if (isLeptonBeam && pT2begDip < m2Lepton) return; + + // Currently no f -> gamma branching implemented. ?? + if (isPhoton) return; + + // alpha_em at maximum scale provides upper estimate. + double alphaEMmax = alphaEM.alphaEM(pT2begDip); + double alphaEM2pi = alphaEMmax / (2. * M_PI); + + // Maximum x of mother implies minimum z = xDaughter / xMother. + double xMaxAbs = (isLeptonBeam) ? LEPTONXMAX : beam.xMax(iSysNow); + double zMinAbs = xDaughter / xMaxAbs; + + // Maximum z from minimum pT and, for lepton, from minimum x_gamma. + double zMaxAbs = 1. - 0.5 * (pT2endDip / m2Dip) * + ( sqrt( 1. + 4. * m2Dip / pT2endDip ) - 1. ); + if (isLeptonBeam) { + double zMaxLepton = xDaughter / (xDaughter + LEPTONXMIN); + if (zMaxLepton < zMaxAbs) zMaxAbs = zMaxLepton; + } + if (zMaxAbs < zMinAbs) return; + + // Integrals of splitting kernels for fermions: f -> f. Use 1 + z^2 < 2. + // Ansatz f(z) = 2 / (1 - z), with + 2 / (z - xDaughter) for lepton. + double f2fInt = 0.; + double f2fIntA = 2. * log( (1. - zMinAbs) / (1. - zMaxAbs) ); + double f2fIntB = 0.; + if (isLeptonBeam) { + f2fIntB = 2. * log( (zMaxAbs - xDaughter) / (zMinAbs - xDaughter) ); + f2fInt = f2fIntA + f2fIntB; + } else f2fInt = pow2(dipEndNow->chgType / 3.) * f2fIntA; + + // Upper estimate for evolution equation, including fudge factor. + if (doMEcorrections) f2fInt *= calcMEmax(MEtype, 1, 1); + double kernelPDF = alphaEM2pi * f2fInt; + double fudge = (isLeptonBeam) ? LEPTONFUDGE * log(m2Dip/m2Lepton) : 1.; + kernelPDF *= fudge; + if (kernelPDF < TINYKERNELPDF) return; + + // Variables used inside evolution loop. (Mainly dummy start values.) + int idMother = 0; + double z = 0.; + double xMother = 0.; + double wt = 0.; + double Q2 = 0.; + double mSister = 0.; + double m2Sister = 0.; + double pT2corr = 0.; + double phi = 0.; + + // Begin evolution loop towards smaller pT values. + do { + wt = 0.; + + // Pick pT2 (in overestimated z range). + // For l -> l gamma include extrafactor 1 / ln(pT2 / m2l) in evolution. + double shift = pow(Rndm::flat(), 1. / kernelPDF); + if (isLeptonBeam) pT2 = m2Lepton * pow( pT2 / m2Lepton, shift); + else pT2 = pT2 * shift; + + // Abort evolution if below cutoff scale, or below another branching. + if (pT2 < pT2endDip) return; + if (isLeptonBeam && pT2 < LEPTONPT2MIN * m2Lepton) return; + + // Select z value of branching f -> f + gamma, and corrective weight. + idMother = idDaughter; + wt = 0.5 * (1. + pow2(z)); + if (isLeptonBeam) { + if (f2fIntA > Rndm::flat() * (f2fIntA + f2fIntB)) + z = 1. - (1. - zMinAbs) + * pow( (1. - zMaxAbs) / (1. - zMinAbs), Rndm::flat() ); + else z = xDaughter + (zMinAbs - xDaughter) + * pow( (zMaxAbs - xDaughter) / (zMinAbs - xDaughter), Rndm::flat() ); + wt *= (z - xDaughter) / (1. - xDaughter); + } else { + z = 1. - (1. - zMinAbs) + * pow( (1. - zMaxAbs) / (1. - zMinAbs), Rndm::flat() ); + } + + // Derive Q2 and x of mother from pT2 and z. + Q2 = pT2 / (1. - z); + xMother = xDaughter / z; + + // Forbidden emission if outside allowed z range for given pT2. + mSister = 0.; + m2Sister = 0.; + pT2corr = Q2 - z * (m2Dip + Q2) * (Q2 + m2Sister) / m2Dip; + if(pT2corr < TINYPT2) { wt = 0.; continue; } + + // Select phi angle of branching at random. + phi = 2. * M_PI * Rndm::flat(); + + // Correct by ln(pT2 / m2l) and fudge factor. + if (isLeptonBeam) wt *= log(pT2 / m2Lepton) / fudge; + + // Evaluation of ME correction. + if (doMEcorrections) wt *= calcMEcorr(MEtype, idMother, idDaughter, + m2Dip, z, Q2) / calcMEmax(MEtype, idMother, idDaughter); + + // Optional dampening of large pT values in first radiation. + if (dopTdamp && iSysNow == 0 && MEtype == 0 && nRad == 0) + wt *= pT2damp / (pT2 + pT2damp); + + // Correct to current value of alpha_EM. + double alphaEMnow = alphaEM.alphaEM(pT2); + wt *= (alphaEMnow / alphaEMmax); + + // Evaluation of new daughter and mother PDF's. + double xPDFdaughterNew = max ( TINYPDF, + beam.xfISR(iSysNow, idDaughter, xDaughter, pT2) ); + double xPDFmotherNew = beam.xfISR(iSysNow, idMother, xMother, pT2); + wt *= xPDFmotherNew / xPDFdaughterNew; + + // Iterate until acceptable pT (or have fallen below pTmin). + } while (wt < Rndm::flat()) ; + + // Save values for (so far) acceptable branching. + dipEndNow->store( idDaughter,idMother, 22, x1Now, x2Now, m2Dip, + pT2, z, Q2, mSister, m2Sister, pT2corr, phi); + +} + +//********* + +// Kinematics of branching. +// Construct mother -> daughter + sister, with recoiler on other side. + +bool SpaceShower::branch( Event& event) { + + // Side on which branching occured. + int side = abs(dipEndSel->side); + double sideSign = (side == 1) ? 1. : -1.; + + // Read in flavour and colour variables. + int iDaughter = event.getInSystem( iSysSel, side - 1); + int iRecoiler = event.getInSystem( iSysSel, 2 - side); + int idDaughterNow = dipEndSel->idDaughter; + int idMother = dipEndSel->idMother; + int idSister = dipEndSel->idSister; + int colDaughter = event[iDaughter].col(); + int acolDaughter = event[iDaughter].acol(); + + // Read in kinematical variables. + double x1 = dipEndSel->x1; + double x2 = dipEndSel->x2; + double m2 = dipEndSel->m2Dip; + double m = sqrt(m2); + double pT2 = dipEndSel->pT2; + double z = dipEndSel->z; + double Q2 = dipEndSel->Q2; + double mSister = dipEndSel->mSister; + double m2Sister = dipEndSel->m2Sister; + double pT2corr = dipEndSel->pT2corr; + double phi = dipEndSel->phi; + + // Take copy of existing system, to be given modified kinematics. + int eventSizeOld = event.size(); + int systemSizeOld = event.sizeSystem(iSysSel); + for ( int iCopy = 0; iCopy < systemSizeOld; ++iCopy) { + int iOldCopy = event.getInSystem( iSysSel, iCopy); + int statusNew = (iOldCopy == iDaughter + || iOldCopy == iRecoiler) ? event[iOldCopy].status() : 44; + event.copy(iOldCopy, statusNew); + } + + // Define colour flow in branching. + // Default corresponds to f -> f + gamma. + int colMother = colDaughter; + int acolMother = acolDaughter; + int colSister = 0; + int acolSister = 0; + if (idSister == 22) ; + // q -> q + g and 50% of g -> g + g; need new colour. + else if (idSister == 21 && ( (idMother > 0 && idMother < 9) + || (idMother == 21 && Rndm::flat() < 0.5) ) ) { + colMother = event.nextColTag(); + colSister = colMother; + acolSister = colDaughter; + // qbar -> qbar + g and other 50% of g -> g + g; need new colour. + } else if (idSister == 21) { + acolMother = event.nextColTag(); + acolSister = acolMother; + colSister = acolDaughter; + // q -> g + q. + } else if (idDaughterNow == 21 && idMother > 0) { + colMother = colDaughter; + acolMother = 0; + colSister = acolDaughter; + // qbar -> g + qbar + } else if (idDaughterNow == 21) { + acolMother = acolDaughter; + colMother = 0; + acolSister = colDaughter; + // g -> q + qbar. + } else if (idDaughterNow > 0 && idDaughterNow < 9) { + acolMother = event.nextColTag(); + acolSister = acolMother; + // g -> qbar + q. + } else if (idDaughterNow < 0 && idDaughterNow > -9) { + colMother = event.nextColTag(); + colSister = colMother; + // q -> gamma + q. + } else if (idDaughterNow == 22 && idMother > 0) { + colMother = event.nextColTag(); + colSister = colMother; + // qbar -> gamma + qbar. + } else if (idDaughterNow == 22) { + acolMother = event.nextColTag(); + acolSister = acolMother; + } + + // Construct kinematics of mother, sister and recoiler in old rest frame. + double pTbranch = sqrt(pT2corr) * m2 / ( z * (m2 + Q2) ); + double pzMother = sideSign * 0.5 * m * ( (m2 - Q2) / ( z * (m2 + Q2) ) + + (Q2 + m2Sister) / m2 ); + double eMother = sqrt( pow2(pTbranch) + pow2(pzMother) ); + double pzSister = pzMother - sideSign * 0.5 * (m2 + Q2) / m; + double eSister = sqrt( pow2(pTbranch) + pow2(pzSister) + m2Sister ); + double eNewRecoiler = 0.5 * (m2 + Q2) / m; + Vec4 pMother( pTbranch, 0., pzMother, eMother ); + Vec4 pSister( pTbranch, 0., pzSister, eSister ); + Vec4 pNewRecoiler( 0., 0., -sideSign * eNewRecoiler, eNewRecoiler); + + // Indices of partons involved. Add new sister. + int iMother = eventSizeOld + side - 1; + int iNewRecoiler = eventSizeOld + 2 - side; + int iSister = event.append( idSister, 43, iMother, 0, 0, 0, + colSister, acolSister, pSister, mSister, sqrt(pT2) ); + + // References to the partons involved. + Particle& daughter = event[iDaughter]; + Particle& mother = event[iMother]; + Particle& newRecoiler = event[iNewRecoiler]; + Particle& sister = event.back(); + + // Replace old by new mother; update new recoiler. + mother.id( idMother ); + mother.status( -41); + mother.cols( colMother, acolMother); + mother.p( pMother); + newRecoiler.status( -42); + newRecoiler.p( pNewRecoiler); + + // Update mother and daughter pointers; also for beams. + daughter.mothers( iMother, 0); + mother.daughters( iSister, iDaughter); + if (iSysSel == 0) { + event[1].daughter1( (side == 1) ? iMother : iNewRecoiler ); + event[2].daughter1( (side == 2) ? iMother : iNewRecoiler ); + } + + // Find boost to old rest frame, and rotation -phi. + RotBstMatrix Mtot; + Mtot.bst(0., 0., (x2 - x1) / (x1 + x2) ); + Mtot.rot(0., -phi); + + // Find boost from old rest frame to event cm frame. + RotBstMatrix MfromRest; + // The boost to the new rest frame. + Vec4 sumNew = pMother + pNewRecoiler; + double betaX = sumNew.px() / sumNew.e(); + double betaZ = sumNew.pz() / sumNew.e(); + MfromRest.bst( -betaX, 0., -betaZ); + // Alignment of radiator + recoiler to +- z axis, and rotation +phi. + pMother.rotbst(MfromRest); + double theta = pMother.theta(); + if (side == 2) theta += M_PI; + MfromRest.rot(-theta, phi); + // Longitudinal boost to radiator + recoiler in event cm frame. + double x1New = (side == 1) ? x1 / z : x1; + double x2New = (side == 2) ? x2 / z : x2; + MfromRest.bst(0., 0., (x1New - x2New) / (x1New + x2New) ); + Mtot.rotbst(MfromRest); + + // Perform cumulative rotation/boost operation. + // Mother, recoiler and sister from old rest frame to event cm frame. + mother.rotbst(MfromRest); + newRecoiler.rotbst(MfromRest); + sister.rotbst(MfromRest); + // The rest from (and to) event cm frame. + for ( int i = eventSizeOld + 2; i < eventSizeOld + systemSizeOld; ++i) + event[i].rotbst(Mtot); + + // Update list of partons in system; adding newly produced one. + for ( int iCopy = 0; iCopy < systemSizeOld; ++iCopy) + event.setInSystem( iSysSel, iCopy, eventSizeOld + iCopy); + event.addToSystem( iSysSel, eventSizeOld + systemSizeOld); + + // Update info on dipole ends (QCD or QED). + for (int iDip = 0; iDip < int(dipEnd.size()); ++iDip) + if ( dipEnd[iDip].system == iSysSel && abs(dipEnd[iDip].side) == side ) { + dipEnd[iDip].iRadiator = iMother; + dipEnd[iDip].iRecoiler = iNewRecoiler; + if (dipEnd[iDip].side > 0) + dipEnd[iDip].colType = mother.colType(); + else { + dipEnd[iDip].chgType = 0; + if ( (mother.isQuark() && doQEDshowerByQ) + || (mother.isLepton() && doQEDshowerByL) ) + dipEnd[iDip].chgType = mother.chargeType(); + } + // Kill ME corrections after first emission. + dipEnd[iDip].MEtype = 0; + } + + // Update info on beam remnants. + BeamParticle& beamNow = (side == 1) ? *beamAPtr : *beamBPtr; + double xNew = (side == 1) ? x1New : x2New; + beamNow[iSysSel].update( iMother, idMother, xNew); + // Redo choice of companion kind whenever new flavour. + if (idMother != idDaughterNow) { + beamNow.xfISR( iSysSel, idMother, xNew, pT2); + beamNow.pickValSeaComp(); + } + BeamParticle& beamRec = (side == 1) ? *beamBPtr : *beamAPtr; + beamRec[iSysSel].iPos( iNewRecoiler); + + // Store branching values of current dipole. (For rapidity ordering.) + ++dipEndSel->nBranch; + dipEndSel->pT2Old = pT2; + dipEndSel->zOld = z; + + + // Done without any errors. + return true; + +} + +//********* + +// Find class of ME correction. + +int SpaceShower::findMEtype( int iSys, Event& event) { + + // Default values and no action. + int MEtype = 0; + if (!doMEcorrections) ; + + // Identify systems producing a single resonance. + else if (event.sizeSystem( iSys) == 3) { + int idIn1 = event[event.getInSystem( iSys, 0)].id(); + int idIn2 = event[event.getInSystem( iSys, 1)].id(); + int idRes = event[event.getInSystem( iSys, 2)].id(); + + // f + fbar -> vector boson. + if ( (idRes == 23 || abs(idRes) == 24 || idRes == 32 + || idRes == 33 || abs(idRes) == 34 || abs(idRes) == 41) + && abs(idIn1) < 20 && abs(idIn2) < 20 ) MEtype = 1; + + // g + g, gamma + gamma -> Higgs boson. + if ( (idRes == 25 || idRes == 35 || idRes == 36) + && ( ( idIn1 == 21 && idIn2 == 21 ) + || ( idIn1 == 22 && idIn2 == 22 ) ) ) MEtype = 2; + + // f + fbar -> Higgs boson. + if ( (idRes == 25 || idRes == 35 || idRes == 36) + && abs(idIn1) < 20 && abs(idIn2) < 20 ) MEtype = 3; + } + + // Done. + return MEtype; + +} + +//********* + +// Provide maximum of expected ME weight; for preweighting of evolution. + +double SpaceShower::calcMEmax( int MEtype, int idMother, int idDaughterIn) { + + // Currently only one non-unity case: g(gamma) f -> V f'. + if (MEtype == 1 && idMother > 20 && idDaughterIn < 20) return 3.; + return 1.; + +} + +//********* + +// Provide actual ME weight for current branching. +// Note: currently ME corrections are only allowed for first branching +// on each side, so idDaughter is essentially known and checks overkill. + +double SpaceShower::calcMEcorr(int MEtype, int idMother, int idDaughterIn, + double M2, double z, double Q2) { + + // Convert to Mandelstam variables. Sometimes may need to swap later. + double sH = M2 / z; + double tH = -Q2; + double uH = Q2 - M2 * (1. - z) / z; + int idMabs = abs(idMother); + int idDabs = abs(idDaughterIn); + + // Corrections for f + fbar -> s-channel vector boson. + if (MEtype == 1) { + if (idMabs < 20 && idDabs < 20) { + return (tH*tH + uH*uH + 2. * M2 * sH) / (sH*sH + M2*M2); + } else if (idDabs < 20) { + // g(gamma) f -> V f': -Q2 = (p_g - p_f')^2 in PS while + // tHat = (p_f - p_f')^2 in ME so need to swap tHat <-> uHat. + swap( tH, uH); + return (sH*sH + uH*uH + 2. * M2 * tH) / (pow2(sH - M2) + M2*M2); + } + + // Corrections for g + g -> Higgs boson. + } else if (MEtype == 2) { + if (idMabs < 20 && idDabs > 20) { + return (sH*sH + uH*uH) / (sH*sH + pow2(sH - M2)); + } else if (idDabs > 20) { + return 0.5 * (pow4(sH) + pow4(tH) + pow4(uH) + pow4(M2)) + / pow2(sH*sH - M2 * (sH - M2)); + } + + // Corrections for f + fbar -> Higgs boson (f = b mainly). + } else if (MEtype == 3) { + if (idMabs < 20 && idDabs < 20) { + // The PS and ME answers agree for f fbar -> H g/gamma. + return 1.; + } else if (idDabs < 20) { + // Need to swap tHat <-> uHat, cf. vector-boson production above. + swap( tH, uH); + return (sH*sH + uH*uH + 2. * (M2 - uH) * (M2 - sH)) + / (pow2(sH - M2) + M2*M2); + } + } + + return 1.; + +} + +//********* + +// Print the list of dipoles. + +void SpaceShower::list(ostream& os) { + + // Header. + os << "\n -------- PYTHIA SpaceShower Dipole Listing ---------- \n" + << "\n i syst side rad rec pTmax col chg type \n" + << fixed << setprecision(3); + + // Loop over dipole list and print it. + for (int i = 0; i < int(dipEnd.size()); ++i) + os << setw(5) << i << setw(6) << dipEnd[i].system + << setw(6) << dipEnd[i].side << setw(6) << dipEnd[i].iRadiator + << setw(6) << dipEnd[i].iRecoiler << setw(12) << dipEnd[i].pTmax + << setw(5) << dipEnd[i].colType << setw(5) << dipEnd[i].chgType + << setw(5) << dipEnd[i].MEtype << "\n"; + + // Done. + os << "\n -------- End PYTHIA SpaceShower Dipole Listing ------" + << endl; + + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/StandardModel.cxx b/PYTHIA8/pythia8130/src/StandardModel.cxx new file mode 100644 index 00000000000..594cdad9a71 --- /dev/null +++ b/PYTHIA8/pythia8130/src/StandardModel.cxx @@ -0,0 +1,509 @@ +// StandardModel.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the AlphaStrong class. + +#include "StandardModel.h" + +namespace Pythia8 { + +//************************************************************************** + +// The AlphaStrong class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Number of iterations to determine Lambda from given alpha_s. +const int AlphaStrong::NITER = 10; + +// Always evaluate running alpha_s above Lambda3 to avoid disaster. +// Safety margin picked to freeze roughly for alpha_s = 10. +const double AlphaStrong::SAFETYMARGIN1 = 1.07; +const double AlphaStrong::SAFETYMARGIN2 = 1.33; + +//********* + +// Initialize alpha_strong calculation by finding Lambda values etc. + +void AlphaStrong::init( double valueIn, int orderIn) { + + // Order of alpha_s evaluation. Charm, bottom and Z0 masses. + // Pick defaults if ParticleDataTable not properly initialized. + valueRef = valueIn; + order = max( 0, min( 2, orderIn ) ); + mc = ParticleDataTable::m0(4); + if (mc < 1. || mc > 2.) mc = 1.5; + mb = ParticleDataTable::m0(5); + if (mb < 3. || mb > 6.) mb = 4.8; + mZ = ParticleDataTable::m0(23); + if (mZ < 90. || mZ > 92.) mZ = 91.188; + + // Fix alpha_s. + if (order == 0) { + Lambda3Save = Lambda4Save = Lambda5Save = scale2Min = 0.; + + // First order alpha_s: match at flavour thresholds. + } else if (order == 1) { + Lambda5Save = mZ * exp( -6. * M_PI / (23. * valueRef) ); + Lambda4Save = Lambda5Save * pow(mb/Lambda5Save, 2./25.); + Lambda3Save = Lambda4Save * pow(mc/Lambda4Save, 2./27.); + scale2Min = pow2(SAFETYMARGIN1 * Lambda3Save); + + // Second order alpha_s: iterative match at flavour thresholds. + } else { + double b15 = 348. / 529.; + double b14 = 462. / 625.; + double b13 = 64. / 81.; + double b25 = 224687. / 242208.; + double b24 = 548575. / 426888.; + double b23 = 938709. / 663552.; + double logScale, loglogScale, correction, valueIter; + + // Find Lambda_5 at m_Z. + Lambda5Save = mZ * exp( -6. * M_PI / (23. * valueRef) ); + for (int iter = 0; iter < NITER; ++iter) { + logScale = 2. * log(mZ/Lambda5Save); + loglogScale = log(logScale); + correction = 1. - b15 * loglogScale / logScale + + pow2(b15 / logScale) * (pow2(loglogScale - 0.5) + b25 - 1.25); + valueIter = valueRef / correction; + Lambda5Save = mZ * exp( -6. * M_PI / (23. * valueIter) ); + } + + // Find Lambda_4 at m_b. + double logScaleB = 2. * log(mb/Lambda5Save); + double loglogScaleB = log(logScaleB); + double valueB = 12. * M_PI / (23. * logScaleB) + * (1. - b15 * loglogScaleB / logScaleB + + pow2(b15 / logScaleB) * (pow2(loglogScaleB - 0.5) + b25- 1.25) ); + Lambda4Save = Lambda5Save; + for (int iter = 0; iter < NITER; ++iter) { + logScale = 2. * log(mb/Lambda4Save); + loglogScale = log(logScale); + correction = 1. - b14 * loglogScale / logScale + + pow2(b14 / logScale) * (pow2(loglogScale - 0.5) + b24 - 1.25); + valueIter = valueB / correction; + Lambda4Save = mb * exp( -6. * M_PI / (25. * valueIter) ); + } + + // Find Lambda_3 at m_c. + double logScaleC = 2. * log(mc/Lambda4Save); + double loglogScaleC = log(logScaleC); + double valueC = 12. * M_PI / (25. * logScaleC) + * (1. - b14 * loglogScaleC / logScaleC + + pow2(b14 / logScaleC) * (pow2(loglogScaleC - 0.5) + b24 - 1.25) ); + Lambda3Save = Lambda4Save; + for (int iter = 0; iter < NITER; ++iter) { + logScale = 2. * log(mc/Lambda3Save); + loglogScale = log(logScale); + correction = 1. - b13 * loglogScale / logScale + + pow2(b13 / logScale) * (pow2(loglogScale - 0.5) + b23 - 1.25); + valueIter = valueC / correction; + Lambda3Save = mc * exp( -6. * M_PI / (27. * valueIter) ); + } + scale2Min = pow2(SAFETYMARGIN2 * Lambda3Save); + } + + // Save squares of mass and Lambda values as well. + mc2 = pow2(mc); + mb2 = pow2(mb); + Lambda3Save2 = pow2(Lambda3Save); + Lambda4Save2 = pow2(Lambda4Save); + Lambda5Save2 = pow2(Lambda5Save); + valueNow = valueIn; + scale2Now = mZ * mZ; + isInit = true; + +} + +//********* + +// Calculate alpha_s value + +double AlphaStrong::alphaS( double scale2) { + + // Check for initialization and ensure minimal scale2 value. + if (!isInit) return 0.; + if (scale2 < scale2Min) scale2 = scale2Min; + + // If equal to old scale then same answer. + if (scale2 == scale2Now && (order < 2 || lastCallToFull)) return valueNow; + scale2Now = scale2; + lastCallToFull = true; + + // Fix alpha_s. + if (order == 0) { + valueNow = valueRef; + + // First order alpha_s: differs by mass region. + } else if (order == 1) { + if (scale2 > mb2) + valueNow = 12. * M_PI / (23. * log(scale2/Lambda5Save2)); + else if (scale2 > mc2) + valueNow = 12. * M_PI / (25. * log(scale2/Lambda4Save2)); + else valueNow = 12. * M_PI / (27. * log(scale2/Lambda3Save2)); + + // Second order alpha_s: differs by mass region. + } else { + double Lambda2, b0, b1, b2; + if (scale2 > mb2) { + Lambda2 = Lambda5Save2; + b0 = 23.; + b1 = 348. / 529.; + b2 = 224687. / 242208.; + } else if (scale2 > mc2) { + Lambda2 = Lambda4Save2; + b0 = 25.; + b1 = 462. / 625.; + b2 = 548575. / 426888.; + } else { + Lambda2 = Lambda3Save2; + b0 = 27.; + b1 = 64. / 81.; + b2 = 938709. / 663552.; + } + double logScale = log(scale2/Lambda2); + double loglogScale = log(logScale); + valueNow = 12. * M_PI / (b0 * logScale) + * ( 1. - b1 * loglogScale / logScale + + pow2(b1 / logScale) * (pow2(loglogScale - 0.5) + b2 - 1.25) ); + } + + // Done. + return valueNow; + +} + +//********* + +// Calculate alpha_s value, but only use up to first-order piece. +// (To be combined with alphaS2OrdCorr.) + +double AlphaStrong::alphaS1Ord( double scale2) { + + // Check for initialization and ensure minimal scale2 value. + if (!isInit) return 0.; + if (scale2 < scale2Min) scale2 = scale2Min; + + // If equal to old scale then same answer. + if (scale2 == scale2Now && (order < 2 || !lastCallToFull)) return valueNow; + scale2Now = scale2; + lastCallToFull = false; + + // Fix alpha_S. + if (order == 0) { + valueNow = valueRef; + + // First/second order alpha_s: differs by mass region. + } else { + if (scale2 > mb2) + valueNow = 12. * M_PI / (23. * log(scale2/Lambda5Save2)); + else if (scale2 > mc2) + valueNow = 12. * M_PI / (25. * log(scale2/Lambda4Save2)); + else valueNow = 12. * M_PI / (27. * log(scale2/Lambda3Save2)); + } + + // Done. + return valueNow; +} + +//********* + +// Calculates the second-order extra factor in alpha_s. +// (To be combined with alphaS1Ord.) + +double AlphaStrong::alphaS2OrdCorr( double scale2) { + + // Check for initialization and ensure minimal scale2 value. + if (!isInit) return 1.; + if (scale2 < scale2Min) scale2 = scale2Min; + + // Only meaningful for second order calculations. + if (order < 2) return 1.; + + // Second order correction term: differs by mass region. + double Lambda2, b0, b1, b2; + if (scale2 > mb2) { + Lambda2 = Lambda5Save2; + b0 = 23.; + b1 = 348. / 529.; + b2 = 224687. / 242208.; + } else if (scale2 > mc2) { + Lambda2 = Lambda4Save2; + b0 = 25.; + b1 = 462. / 625.; + b2 = 548575. / 426888.; + } else { + Lambda2 = Lambda3Save2; + b0 = 27.; + b1 = 64. / 81.; + b2 = 938709. / 663552.; + } + double logScale = log(scale2/Lambda2); + double loglogScale = log(logScale); + return ( 1. - b1 * loglogScale / logScale + + pow2(b1 / logScale) * (pow2(loglogScale - 0.5) + b2 - 1.25) ); + +} + +//************************************************************************** + +// The AlphaEM class. + +//********* + +// Definitions of static variables. +double AlphaEM::alpEM0 = 0.00729735; +double AlphaEM::alpEMmZ = 0.00781751; +double AlphaEM::mZ2 = 8315.; +// Effective thresholds for electron, muon, light quarks, tau+c, b. +double AlphaEM::Q2step[5] = {0.26e-6, 0.011, 0.25, 3.5, 90.}; +// Running coefficients are sum charge2 / 3 pi in pure QED, here slightly +// enhanced for quarks to approximately account for QCD corrections. +double AlphaEM::bRun[5] = {0.1061, 0.2122, 0.460, 0.700, 0.725}; +double AlphaEM::alpEMstep[5] = {}; + +//********* + +// Initialize alpha_EM calculation. + +void AlphaEM::initStatic() { + + // Read in alpha_EM value at 0 and m_Z, and mass of Z. + alpEM0 = Settings::parm("StandardModel:alphaEM0"); + alpEMmZ = Settings::parm("StandardModel:alphaEMmZ"); + double mZ = ParticleDataTable::m0(23); + mZ2 = mZ * mZ; + + // AlphaEM values at matching scales and matching b value. + + // Step down from mZ to tau/charm threshold. + alpEMstep[4] = alpEMmZ / ( 1. + alpEMmZ * bRun[4] + * log(mZ2 / Q2step[4]) ); + alpEMstep[3] = alpEMstep[4] / ( 1. - alpEMstep[4] * bRun[3] + * log(Q2step[3] / Q2step[4]) ); + + // Step up from me to light-quark threshold. + alpEMstep[0] = alpEM0; + alpEMstep[1] = alpEMstep[0] / ( 1. - alpEMstep[0] * bRun[0] + * log(Q2step[1] / Q2step[0]) ); + alpEMstep[2] = alpEMstep[1] / ( 1. - alpEMstep[1] * bRun[1] + * log(Q2step[2] / Q2step[1]) ); + + // Fit b in range between light-quark and tau/charm to join smoothly. + bRun[2] = (1./alpEMstep[3] - 1./alpEMstep[2]) + / log(Q2step[2] / Q2step[3]); + +} + +//********* + +// Calculate alpha_EM value + +double AlphaEM::alphaEM( double scale2) { + + // Fix alphaEM; for order = -1 fixed at m_Z. + if (order == 0) return alpEM0; + if (order < 0) return alpEMmZ; + + // Running alphaEM. + for (int i = 4; i >= 0; --i) if (scale2 > Q2step[i]) + return alpEMstep[i] / (1. - bRun[i] * alpEMstep[i] + * log(scale2 / Q2step[i]) ); + return alpEM0; + +} + +//************************************************************************** + +// The CoupEW class. + +//********* + +// Definitions of static variables. + +double CoupEW::s2tW = 0.232; +double CoupEW::c2tW = 0.768; +double CoupEW::s2tWbar = 0.232; +double CoupEW::efSave[20] = { 0., -1./3., 2./3., -1./3., 2./3., -1./3., + 2./3., -1./3., 2./3., 0., 0., -1., 0., -1., 0., -1., 0., -1., 0., 0.}; +double CoupEW::vfSave[20] = { }; +double CoupEW::afSave[20] = { 0., -1., 1., -1., 1., -1., 1., -1., 1., + 0., 0., -1., 1., -1., 1., -1., 1., -1., 1., 0.}; +double CoupEW::lfSave[20] = { }; +double CoupEW::rfSave[20] = { }; +double CoupEW::ef2Save[20] = { }; +double CoupEW::vf2Save[20] = { }; +double CoupEW::af2Save[20] = { }; +double CoupEW::efvfSave[20] = { }; +double CoupEW::vf2af2Save[20] = { }; + +//********* + +// Initialize electroweak mixing angle and couplings. + +void CoupEW::initStatic() { + + // Read in electroweak mixing angle. + s2tW = Settings::parm("StandardModel:sin2thetaW"); + c2tW = 1. - s2tW; + s2tWbar = Settings::parm("StandardModel:sin2thetaWbar"); + + // Initialize electroweak couplings. + for (int i = 0; i < 20; ++i) { + vfSave[i] = afSave[i] - 4. * s2tWbar * efSave[i]; + lfSave[i] = afSave[i] - 2. * s2tWbar * efSave[i]; + rfSave[i] = - 2. * s2tWbar * efSave[i]; + ef2Save[i] = pow2(efSave[i]); + vf2Save[i] = pow2(vfSave[i]); + af2Save[i] = pow2(afSave[i]); + efvfSave[i] = efSave[i] * vfSave[i]; + vf2af2Save[i] = vf2Save[i] + af2Save[i]; + } + +} + +//************************************************************************** + +// The VCKM class. + +//********* + +// Definitions of static variables. Initialize to all elements zero. + +double VCKM::Vsave[5][5] = { }; +double VCKM::V2save[5][5] = { }; +double VCKM::V2out[20] = { }; + +//********* + +// Prepare to handle CKM matrix elements. + +void VCKM::initStatic() { + + // Read in matrix element values and store them. + Vsave[1][1] = Settings::parm("StandardModel:Vud"); + Vsave[1][2] = Settings::parm("StandardModel:Vus"); + Vsave[1][3] = Settings::parm("StandardModel:Vub"); + Vsave[2][1] = Settings::parm("StandardModel:Vcd"); + Vsave[2][2] = Settings::parm("StandardModel:Vcs"); + Vsave[2][3] = Settings::parm("StandardModel:Vcb"); + Vsave[3][1] = Settings::parm("StandardModel:Vtd"); + Vsave[3][2] = Settings::parm("StandardModel:Vts"); + Vsave[3][3] = Settings::parm("StandardModel:Vtb"); + + // Also allow for the potential existence of a fourth generation. + Vsave[1][4] = Settings::parm("FourthGeneration:VubPrime"); + Vsave[2][4] = Settings::parm("FourthGeneration:VcbPrime"); + Vsave[3][4] = Settings::parm("FourthGeneration:VtbPrime"); + Vsave[4][1] = Settings::parm("FourthGeneration:VtPrimed"); + Vsave[4][2] = Settings::parm("FourthGeneration:VtPrimes"); + Vsave[4][3] = Settings::parm("FourthGeneration:VtPrimeb"); + Vsave[4][4] = Settings::parm("FourthGeneration:VtPrimebPrime"); + + // Calculate squares of matrix elements. + for(int i = 1; i < 5; ++i) for(int j = 1; j < 5; ++j) + V2save[i][j] = pow2(Vsave[i][j]); + + // Sum VCKM^2_out sum for given incoming flavour, excluding top as partner. + V2out[1] = V2save[1][1] + V2save[2][1]; + V2out[2] = V2save[1][1] + V2save[1][2] + V2save[1][3]; + V2out[3] = V2save[1][2] + V2save[2][2]; + V2out[4] = V2save[2][1] + V2save[2][2] + V2save[2][3]; + V2out[5] = V2save[1][3] + V2save[2][3]; + V2out[6] = V2save[3][1] + V2save[3][2] + V2save[3][3]; + V2out[7] = V2save[1][4] + V2save[2][4]; + V2out[8] = V2save[4][1] + V2save[4][2] + V2save[4][3]; + for (int i = 11; i <= 18; ++i) V2out[i] = 1.; + +} + +//********* + +// Return CKM value for incoming flavours (sign irrelevant). + +double VCKM::Vid(int id1, int id2) { + + // Use absolute sign (want to cover both f -> f' W and f fbar' -> W). + int id1Abs = abs(id1); + int id2Abs = abs(id2); + if (id1Abs == 0 || id2Abs == 0 || (id1Abs + id2Abs)%2 != 1) return 0.; + + // Ensure proper order before reading out from Vsave or lepton match. + if (id1Abs%2 == 1) swap(id1Abs, id2Abs); + if (id1Abs <= 8 && id2Abs <= 8) return Vsave[id1Abs/2][(id2Abs + 1)/2]; + if ( (id1Abs == 12 || id1Abs == 14 || id1Abs == 16 || id1Abs == 18) + && id2Abs == id1Abs - 1 ) return 1.; + + // No more valid cases. + return 0.; + +} + +//********* + +// Return squared CKM value for incoming flavours (sign irrelevant). + +double VCKM::V2id(int id1, int id2) { + + // Use absolute sign (want to cover both f -> f' W and f fbar' -> W). + int id1Abs = abs(id1); + int id2Abs = abs(id2); + if (id1Abs == 0 || id2Abs == 0 || (id1Abs + id2Abs)%2 != 1) return 0.; + + // Ensure proper order before reading out from V2save or lepton match. + if (id1Abs%2 == 1) swap(id1Abs, id2Abs); + if (id1Abs <= 8 && id2Abs <= 8) return V2save[id1Abs/2][(id2Abs + 1)/2]; + if ( (id1Abs == 12 || id1Abs == 14 || id1Abs == 16 || id1Abs == 18) + && id2Abs == id1Abs - 1 ) return 1.; + + // No more valid cases. + return 0.; + +} + +//********* + +// Pick an outgoing flavour for given incoming one, given CKM mixing. + +int VCKM::V2pick(int id) { + + // Initial values. + int idIn = abs(id); + int idOut = 0; + + // Quarks: need to make random choice. + if (idIn >= 1 && idIn <= 8) { + double V2rndm = Rndm::flat() * V2out[idIn]; + if (idIn == 1) idOut = (V2rndm < V2save[1][1]) ? 2 : 4; + else if (idIn == 2) idOut = (V2rndm < V2save[1][1]) ? 1 + : ( (V2rndm < V2save[1][1] + V2save[1][2]) ? 3 : 5 ); + else if (idIn == 3) idOut = (V2rndm < V2save[1][2]) ? 2 : 4; + else if (idIn == 4) idOut = (V2rndm < V2save[2][1]) ? 1 + : ( (V2rndm < V2save[2][1] + V2save[2][2]) ? 3 : 5 ); + else if (idIn == 5) idOut = (V2rndm < V2save[1][3]) ? 2 : 4; + else if (idIn == 6) idOut = (V2rndm < V2save[3][1]) ? 1 + : ( (V2rndm < V2save[3][1] + V2save[3][2]) ? 3 : 5 ); + else if (idIn == 7) idOut = (V2rndm < V2save[1][4]) ? 2 : 4; + else if (idIn == 8) idOut = (V2rndm < V2save[4][1]) ? 1 + : ( (V2rndm < V2save[4][1] + V2save[4][2]) ? 3 : 5 ); + + // Leptons: unambiguous. + } else if (idIn >= 11 && idIn <= 18) { + if (idIn%2 == 1) idOut = idIn + 1; + else idOut = idIn - 1; + } + + // Done. Return with sign. + return ( (id > 0) ? idOut : -idOut ); + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/StringFragmentation.cxx b/PYTHIA8/pythia8130/src/StringFragmentation.cxx new file mode 100644 index 00000000000..2e55c7d1c8f --- /dev/null +++ b/PYTHIA8/pythia8130/src/StringFragmentation.cxx @@ -0,0 +1,1209 @@ +// StringFragmentation.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the StringEnd and +// StringFragmentation classes. + +#include "StringFragmentation.h" + +namespace Pythia8 { + +//************************************************************************** + +// The StringEnd class. + +//********* + +// Constants: could be changed here if desired, but normally should not. + +// Avoid unphysical solutions to equation system. +const double StringEnd::TINY = 1e-6; + +// Assume two (eX, eY) regions are related if pT2 differs by less. +const double StringEnd::PT2SAME = 0.01; + +//********* + +// Set up initial endpoint values from input. + +void StringEnd::setUp(bool fromPosIn, int iEndIn, int idOldIn, int iMaxIn, + double pxIn, double pyIn, double GammaIn, double xPosIn, double xNegIn) { + + // Simple transcription from input. + fromPos = fromPosIn; + iEnd = iEndIn; + iMax = iMaxIn; + flavOld = FlavContainer(idOldIn); + pxOld = pxIn; + pyOld = pyIn; + GammaOld = GammaIn; + iPosOld = (fromPos) ? 0 : iMax; + iNegOld = (fromPos) ? iMax : 0; + xPosOld = xPosIn; + xNegOld = xNegIn; + +} + +//********* + +// Fragment off one hadron from the string system, in flavour and pT. + +void StringEnd::newHadron() { + + // Pick new flavour and form a new hadron. + do { + flavNew = flavSelPtr->pick( flavOld); + idHad = flavSelPtr->combine( flavOld, flavNew); + } while (idHad == 0); + + // Pick its transverse momentum. + pxNew = pTSelPtr->px(); + pyNew = pTSelPtr->py(); + pxHad = pxOld + pxNew; + pyHad = pyOld + pyNew; + + // Pick its mass and thereby define its transverse mass. + mHad = ParticleDataTable::mass(idHad); + mT2Had = pow2(mHad) + pow2(pxHad) + pow2(pyHad); + +} + +//********* + +// Fragment off one hadron from the string system, in momentum space, +// by taking steps from positive end. + +Vec4 StringEnd::kinematicsHadron( StringSystem& system) { + + // Pick fragmentation step z and calculate new Gamma. + zHad = zSelPtr->zFrag( flavOld.id, flavNew.id, mT2Had); + GammaNew = (1. - zHad) * (GammaOld + mT2Had / zHad); + + // Set up references that are direction-neutral; + // ...Dir for direction of iteration and ...Inv for its inverse. + int& iDirOld = (fromPos) ? iPosOld : iNegOld; + int& iInvOld = (fromPos) ? iNegOld : iPosOld; + int& iDirNew = (fromPos) ? iPosNew : iNegNew; + int& iInvNew = (fromPos) ? iNegNew : iPosNew; + double& xDirOld = (fromPos) ? xPosOld : xNegOld; + double& xInvOld = (fromPos) ? xNegOld : xPosOld; + double& xDirNew = (fromPos) ? xPosNew : xNegNew; + double& xInvNew = (fromPos) ? xNegNew : xPosNew; + double& xDirHad = (fromPos) ? xPosHad : xNegHad; + double& xInvHad = (fromPos) ? xNegHad : xPosHad; + + // Start search for new breakup in the old region. + iDirNew = iDirOld; + iInvNew = iInvOld; + Vec4 pTNew; + + // Each step corresponds to trying a new string region. + for (int iStep = 0; ; ++iStep) { + + // Referance to current string region. + StringRegion& region = system.region( iPosNew, iNegNew); + + // Now begin special section for rapid processing of low region. + if (iStep == 0 && iPosOld + iNegOld == iMax) { + + // A first step within a low region is easy. + if (mT2Had < zHad * xDirOld * (1. - xInvOld) * region.w2) { + + // Translate into x coordinates. + xDirHad = zHad * xDirOld; + xInvHad = mT2Had / (xDirHad * region.w2); + xDirNew = xDirOld - xDirHad; + xInvNew = xInvOld + xInvHad; + + // Find and return four-momentum of the produced particle. + return region.pHad( xPosHad, xNegHad, pxHad, pyHad); + + // A first step out of a low region also OK, if there are more regions. + // Negative energy signals failure, i.e. in last region. + } else { + --iInvNew; + if (iInvNew < 0) return Vec4(0., 0., 0., -1.); + + // Momentum taken by stepping out of region. Continue to next region. + xInvHad = 1. - xInvOld; + xDirHad = 0.; + pSoFar = region.pHad( xPosHad, xNegHad, pxOld, pyOld); + continue; + } + + // Else, for first step, take into account starting pT. + } else if (iStep == 0) { + pSoFar = region.pHad( 0., 0., pxOld, pyOld); + pTNew = region.pHad( 0., 0., pxNew, pyNew); + } + + // Now begin normal treatment of nontrivial regions. + // Set up four-vectors in a region not visited before. + if (!region.isSetUp) region.setUp( + system.regionLowPos(iPosNew).pPos, + system.regionLowNeg(iNegNew).pNeg, true); + + // If new region is vanishingly small, continue immediately to next. + // Negative energy signals failure to do this, i.e. moved too low. + if (region.isEmpty) { + xDirHad = (iDirNew == iDirOld) ? xDirOld : 1.; + xInvHad = 0.; + pSoFar += region.pHad( xPosHad, xNegHad, 0., 0.); + ++iDirNew; + if (iDirNew + iInvNew > iMax) return Vec4(0., 0., 0., -1.); + continue; + } + + // Reexpress pTNew w.r.t. base vectors in new region, if possible. + // Recall minus sign from normalization e_x^2 = e_y^2 = -1. + double pxNewTemp = -pTNew * region.eX; + double pyNewTemp = -pTNew * region.eY; + if (abs( pxNewTemp * pxNewTemp + pyNewTemp * pyNewTemp + - pxNew * pxNew - pyNew * pyNew) < PT2SAME) { + pxNew = pxNewTemp; + pyNew = pyNewTemp; + } + + // Four-momentum taken so far, including new pT. + Vec4 pTemp = pSoFar + region.pHad( 0., 0., pxNew, pyNew); + + // Derive coefficients for m2 expression. + // cM2 * x+ + cM3 * x- + cM4 * x+ * x- = m^2 - cM1; + double cM1 = pTemp.m2Calc(); + double cM2 = 2. * (pTemp * region.pPos); + double cM3 = 2. * (pTemp * region.pNeg); + double cM4 = region.w2; + if (!fromPos) swap( cM2, cM3); + + // Derive coefficients for Gamma expression. + // cGam2 * x+ + cGam3 * x- + cGam4 * x+ * x- = Gamma_new - cGam1; + double cGam1 = 0.; + double cGam2 = 0.; + double cGam3 = 0.; + double cGam4 = 0.; + for (int iInv = iInvNew; iInv <= iMax - iDirNew; ++iInv) { + double xInv = 1.; + if (iInv == iInvNew) xInv = (iInvNew == iInvOld) ? xInvOld : 0.; + for (int iDir = iDirNew; iDir <= iMax - iInv; ++iDir) { + double xDir = (iDir == iDirOld) ? xDirOld : 1.; + int iPos = (fromPos) ? iDir : iInv; + int iNeg = (fromPos) ? iInv : iDir; + StringRegion& regionGam = system.region( iPos, iNeg); + if (!regionGam.isSetUp) regionGam.setUp( + system.regionLowPos(iPos).pPos, + system.regionLowNeg(iNeg).pNeg, true); + double w2 = regionGam.w2; + cGam1 += xDir * xInv * w2; + if (iDir == iDirNew) cGam2 -= xInv * w2; + if (iInv == iInvNew) cGam3 += xDir * w2; + if (iDir == iDirNew && iInv == iInvNew) cGam4 -= w2; + } + } + + // Solve (m2, Gamma) equation system => r2 * x-^2 + r1 * x- + r0 = 0. + double cM0 = pow2(mHad) - cM1; + double cGam0 = GammaNew - cGam1; + double r2 = cM3 * cGam4 - cM4 * cGam3; + double r1 = cM4 * cGam0 - cM0 * cGam4 + cM3 * cGam2 - cM2 * cGam3; + double r0 = cM2 * cGam0 - cM0 * cGam2; + double root = sqrtpos( r1*r1 - 4. * r2 * r0 ); + if (abs(r2) < TINY || root < TINY) return Vec4(0., 0., 0., -1.); + xInvHad = 0.5 * (root / abs(r2) - r1 / r2); + xDirHad = (cM0 - cM3 * xInvHad) / (cM2 + cM4 * xInvHad); + + // Define position of new trial vertex. + xDirNew = (iDirNew == iDirOld) ? xDirOld - xDirHad : 1. - xDirHad; + xInvNew = (iInvNew == iInvOld) ? xInvOld + xInvHad : xInvHad; + + // Step up to new region if new x- > 1. + if (xInvNew > 1.) { + xInvHad = (iInvNew == iInvOld) ? 1. - xInvOld : 1.; + xDirHad = 0.; + pSoFar += region.pHad( xPosHad, xNegHad, 0., 0.); + --iInvNew; + if (iInvNew < 0) return Vec4(0., 0., 0., -1.); + continue; + + // Step down to new region if new x+ < 0. + } else if (xDirNew < 0.) { + xDirHad = (iDirNew == iDirOld) ? xDirOld : 1.; + xInvHad = 0.; + pSoFar += region.pHad( xPosHad, xNegHad, 0., 0.); + ++iDirNew; + if (iDirNew + iInvNew > iMax) return Vec4(0., 0., 0., -1.); + continue; + } + + // Else we have found the correct region, and can return four-momentum. + return pSoFar + region.pHad( xPosHad, xNegHad, pxNew, pyNew); + + // End of "infinite" loop of stepping to new region. + } + +} + +//********* + +// Update string end information after a hadron has been removed. + +void StringEnd::update() { + + flavOld.anti(flavNew); + iPosOld = iPosNew; + iNegOld = iNegNew; + pxOld = -pxNew; + pyOld = -pyNew; + GammaOld = GammaNew; + xPosOld = xPosNew; + xNegOld = xNegNew; + +} + +//************************************************************************** + +// The StringFragmentation class. + +//********* + +// Constants: could be changed here if desired, but normally should not. +// These are of technical nature, as described for each. + +// Maximum number of tries to (flavour-, energy) join the two string ends. +const int StringFragmentation::NTRYFLAV = 10; +const int StringFragmentation::NTRYJOIN = 25; + +// The last few times gradually increase the stop mass to make it easier. +const int StringFragmentation::NSTOPMASS = 10; +const double StringFragmentation::FACSTOPMASS = 1.05; + +// For closed string, pick a Gamma by taking a step with fictitious mass. +const double StringFragmentation::CLOSEDM2MAX = 25.; +const double StringFragmentation::CLOSEDM2FRAC = 0.1; + +// Do not allow too large argument to exp function. +const double StringFragmentation::EXPMAX = 50.; + +// Matching criterion that p+ and p- not the same (can happen in gg loop). +const double StringFragmentation::MATCHPOSNEG = 1e-6; + +// For pull on junction, do not trace too far down each leg. +const double StringFragmentation::EJNWEIGHTMAX = 10.; + +// Iterate junction rest frame boost until convergence or too many tries. +const double StringFragmentation::CONVJNREST = 1e-5; +const int StringFragmentation::NTRYJNREST = 20; + +// Fail and try again when two legs combined to diquark (3 loops). +const int StringFragmentation::NTRYJNMATCH = 20; + +// Consider junction-leg parton as massless if m2 tiny. +const double StringFragmentation::M2MAXJRF = 1e-4; + +// Iterate junction rest frame equation until convergence or too many tries. +const double StringFragmentation::CONVJRFEQ = 1e-12; +const int StringFragmentation::NTRYJRFEQ = 40; + +//********* + +// Initialize and save pointers. + +void StringFragmentation::init(Info* infoPtrIn, StringFlav* flavSelPtrIn, + StringPT* pTSelPtrIn, StringZ* zSelPtrIn) { + + // Save pointers. + infoPtr = infoPtrIn; + flavSelPtr = flavSelPtrIn; + pTSelPtr = pTSelPtrIn; + zSelPtr = zSelPtrIn; + + // Initialize the StringFragmentation class. + stopMass = Settings::parm("StringFragmentation:stopMass"); + stopNewFlav = Settings::parm("StringFragmentation:stopNewFlav"); + stopSmear = Settings::parm("StringFragmentation:stopSmear"); + eNormJunction = Settings::parm("StringFragmentation:eNormJunction"); + eBothLeftJunction + = Settings::parm("StringFragmentation:eBothLeftJunction"); + eMaxLeftJunction + = Settings::parm("StringFragmentation:eMaxLeftJunction"); + eMinLeftJunction + = Settings::parm("StringFragmentation:eMinLeftJunction"); + + // Initialize the b parameter of the z spectrum, used when joining jets. + bLund = Settings::parm("StringZ:bLund"); + + // Send on pointers to the two StringEnd instances. + posEnd.init( flavSelPtr, pTSelPtr, zSelPtr); + negEnd.init( flavSelPtr, pTSelPtr, zSelPtr); + +} + +//********* + +// Perform the fragmentation. + +bool StringFragmentation::fragment( int iSub, ColConfig& colConfig, + Event& event) { + + // Find partons and their total four-momentum. + iParton = colConfig[iSub].iParton; + iPos = iParton[0]; + if (iPos < 0) iPos = iParton[1]; + int idPos = event[iPos].id(); + iNeg = iParton.back(); + int idNeg = event[iNeg].id(); + pSum = colConfig[iSub].pSum; + + // Reset the local event record. + hadrons.clear(); + + // For closed gluon string: pick first breakup region. + isClosed = colConfig[iSub].isClosed; + if (isClosed) iParton = findFirstRegion(iParton, event); + + // For junction topology: fragment off two of the string legs. + // Then iParton overwritten to remaining leg + leftover diquark. + pJunctionHadrons = 0.; + hasJunction = colConfig[iSub].hasJunction; + if (hasJunction && !fragmentToJunction(event)) return false; + int junctionHadrons = hadrons.size(); + if (hasJunction) { + idPos = event[ iParton[0] ].id(); + idNeg = event.back().id(); + pSum -= pJunctionHadrons; + } + + // Set up kinematics of string evolution ( = motion). + system.setUp(iParton, event); + stopMassNow = stopMass; + + // Fallback loop, when joining in the middle fails. Bailout if stuck. + for ( int iTry = 0; ; ++iTry) { + if (iTry > NTRYJOIN) { + infoPtr->errorMsg("Error in StringFragmentation::fragment: " + "stuck in joining"); + if (hasJunction) event.popBack(1); + return false; + } + + // After several failed tries gradually allow larger stop mass. + if (iTry > NTRYJOIN - NSTOPMASS) stopMassNow *= FACSTOPMASS; + + // Set up flavours of two string ends, and reset other info. + setStartEnds(idPos, idNeg, system); + pRem = pSum; + + // Begin fragmentation loop, interleaved from the two ends. + bool fromPos; + for ( ; ; ) { + + // Take a step either from the positive or the negative end. + fromPos = (Rndm::flat() < 0.5); + StringEnd& nowEnd = (fromPos) ? posEnd : negEnd; + + // Construct trial hadron and check that energy remains. + nowEnd.newHadron(); + if ( energyUsedUp(fromPos) ) break; + + // Construct kinematics of the new hadron and store it. + Vec4 pHad = nowEnd.kinematicsHadron(system); + int statusHad = (fromPos) ? 83 : 84; + hadrons.append( nowEnd.idHad, statusHad, iPos, iNeg, + 0, 0, 0, 0, pHad, nowEnd.mHad); + if (pHad.e() < 0.) break; + + // Update string end and remaining momentum. + nowEnd.update(); + pRem -= pHad; + + // End of fragmentation loop. + } + + // When done, join in the middle. If this works, then really done. + if ( finalTwo(fromPos) ) break; + + // Else remove produced particles (except from first two junction legs) + // and start all over. + int newHadrons = hadrons.size() - junctionHadrons; + hadrons.popBack(newHadrons); + } + + // Junctions: remove fictitious end, restore original parton list + if (hasJunction) { + event.popBack(1); + iParton = colConfig[iSub].iParton; + } + + // Store the hadrons in the normal event record, ordered from one end. + store(event); + + // Done. + return true; + +} + +//********* + +// Find region where to put first string break for closed gluon loop. + +vector StringFragmentation::findFirstRegion(vector& iPartonIn, + Event& event) { + + // Evaluate mass-squared for all adjacent gluon pairs. + vector m2Pair; + double m2Sum = 0.; + int size = iPartonIn.size(); + for (int i = 0; i < size; ++i) { + double m2Now = 0.5 * event[ iPartonIn[i] ].p() + * event[ iPartonIn[(i + 1)%size] ].p(); + m2Pair.push_back(m2Now); + m2Sum += m2Now; + } + + // Pick breakup region with probability proportional to mass-squared. + double m2Reg = m2Sum * Rndm::flat(); + int iReg = -1; + do m2Reg -= m2Pair[++iReg]; + while (m2Reg > 0 && iReg < size - 1); + + // Create reordered parton list, with breakup string region duplicated. + vector iPartonOut; + for (int i = 0; i < size + 2; ++i) + iPartonOut.push_back( iPartonIn[(i + iReg)%size] ); + + // Done. + return iPartonOut; + +} + +//********* + +// Set flavours and momentum position for initial string endpoints. + +void StringFragmentation::setStartEnds( int idPos, int idNeg, + StringSystem systemNow) { + + // Variables characterizing string endpoints: defaults for open string. + double px = 0.; + double py = 0.; + double Gamma = 0.; + double xPosFromPos = 1.; + double xNegFromPos = 0.; + double xPosFromNeg = 0.; + double xNegFromNeg = 1.; + + // For closed gluon loop need to pick an initial flavour. + if (isClosed) { + do { + int idTry = flavSelPtr->pickLightQ(); + FlavContainer flavTry(idTry, 1); + flavTry = flavSelPtr->pick( flavTry); + flavTry = flavSelPtr->pick( flavTry); + idPos = flavTry.id; + idNeg = -idPos; + } while (idPos == 0); + + // Also need pT and breakup vertex position in region. + px = pTSelPtr->px(); + py = pTSelPtr->py(); + double m2Region = systemNow.regionLowPos(0).w2; + double m2Temp = min( CLOSEDM2MAX, CLOSEDM2FRAC * m2Region); + do { + double zTemp = zSelPtr->zFrag( idPos, idNeg, m2Temp); + xPosFromPos = 1. - zTemp; + xNegFromPos = m2Temp / (zTemp * m2Region); + } while (xNegFromPos > 1.); + Gamma = xPosFromPos * xNegFromPos * m2Region; + xPosFromNeg = xPosFromPos; + xNegFromNeg = xNegFromPos; + } + + // Initialize two string endpoints. + posEnd.setUp( true, iPos, idPos, systemNow.iMax, px, py, + Gamma, xPosFromPos, xNegFromPos); + negEnd.setUp( false, iNeg, idNeg, systemNow.iMax, -px, -py, + Gamma, xPosFromNeg, xNegFromNeg); + + // For closed gluon loop can allow popcorn on one side but not both. + if (isClosed) { + flavSelPtr->assignPopQ(posEnd.flavOld); + flavSelPtr->assignPopQ(negEnd.flavOld); + if (Rndm::flat() < 0.5) posEnd.flavOld.nPop = 0; + else negEnd.flavOld.nPop = 0; + posEnd.flavOld.rank = 1; + negEnd.flavOld.rank = 1; + } + + // Done. + +} + +//********* + +// Check remaining energy-momentum whether it is OK to continue. + +bool StringFragmentation::energyUsedUp(bool fromPos) { + + // If remaining negative energy then abort right away. + if (pRem.e() < 0.) return true; + + // Calculate W2_minimum and done if remaining W2 is below it. + double wMin = stopMassNow + + ParticleDataTable::constituentMass(posEnd.flavOld.id) + + ParticleDataTable::constituentMass(negEnd.flavOld.id); + if (fromPos) wMin += stopNewFlav + * ParticleDataTable::constituentMass(posEnd.flavNew.id); + else wMin += stopNewFlav + * ParticleDataTable::constituentMass(negEnd.flavNew.id); + wMin *= 1. + (2. * Rndm::flat() - 1.) * stopSmear; + w2Rem = pRem.m2Calc(); + if (w2Rem < pow2(wMin)) return true; + + // Else still enough energy left to continue iteration. + return false; + +} + +//********* + +// Produce the final two partons to complete the system. + +bool StringFragmentation::finalTwo(bool fromPos) { + + // Check whether we went too far in p+-. + if (pRem.e() < 0. || w2Rem < 0. || (hadrons.size() > 0 + && hadrons.back().e() < 0.) ) return false; + if ( posEnd.iPosOld > negEnd.iPosOld || negEnd.iNegOld > posEnd.iNegOld) + return false; + if ( posEnd.iPosOld == negEnd.iPosOld && posEnd.xPosOld < negEnd.xPosOld) + return false; + if ( posEnd.iNegOld == negEnd.iNegOld && posEnd.xNegOld > negEnd.xNegOld) + return false; + + // Construct the final hadron from the leftover flavours. + // Impossible to join two diquarks. Also break if stuck for other reason. + FlavContainer flav1 = (fromPos) ? posEnd.flavNew.anti() : posEnd.flavOld; + FlavContainer flav2 = (fromPos) ? negEnd.flavOld : negEnd.flavNew.anti(); + if (abs(flav1.id) > 8 && abs(flav2.id) > 8) return false; + int idHad; + for (int iTry = 0; iTry < NTRYFLAV; ++iTry) { + idHad = flavSelPtr->combine( flav1, flav2); + if (idHad != 0) break; + } + if (idHad == 0) return false; + + // Store the final particle and its new pT, and construct its mass. + if (fromPos) { + negEnd.idHad = idHad; + negEnd.pxNew = -posEnd.pxNew; + negEnd.pyNew = -posEnd.pyNew; + negEnd.mHad = ParticleDataTable::mass(idHad); + } else { + posEnd.idHad = idHad; + posEnd.pxNew = -negEnd.pxNew; + posEnd.pyNew = -negEnd.pyNew; + posEnd.mHad = ParticleDataTable::mass(idHad); + } + + // String region in which to do the joining. + StringRegion region = finalRegion(); + if (region.isEmpty) return false; + + // Project remaining momentum along longitudinal and transverse directions. + region.project( pRem); + double pxRem = region.px() - posEnd.pxOld - negEnd.pxOld; + double pyRem = region.py() - posEnd.pyOld - negEnd.pyOld; + double xPosRem = region.xPos(); + double xNegRem = region.xNeg(); + + // Share extra pT kick evenly between final two hadrons. + posEnd.pxOld += 0.5 * pxRem; + posEnd.pyOld += 0.5 * pyRem; + negEnd.pxOld += 0.5 * pxRem; + negEnd.pyOld += 0.5 * pyRem; + + // Construct new pT and mT of the final two particles. + posEnd.pxHad = posEnd.pxOld + posEnd.pxNew; + posEnd.pyHad = posEnd.pyOld + posEnd.pyNew; + posEnd.mT2Had = pow2(posEnd.mHad) + pow2(posEnd.pxHad) + + pow2(posEnd.pyHad); + negEnd.pxHad = negEnd.pxOld + negEnd.pxNew; + negEnd.pyHad = negEnd.pyOld + negEnd.pyNew; + negEnd.mT2Had = pow2(negEnd.mHad) + pow2(negEnd.pxHad) + + pow2(negEnd.pyHad); + + // Construct remaining system transverse mass. + double wT2Rem = w2Rem + pow2( posEnd.pxHad + negEnd.pxHad) + + pow2( posEnd.pyHad + negEnd.pyHad); + + // Check that kinematics possible. + if ( sqrt(wT2Rem) < sqrt(posEnd.mT2Had) + sqrt(negEnd.mT2Had) ) + return false; + double lambda2 = pow2( wT2Rem - posEnd.mT2Had - negEnd.mT2Had) + - 4. * posEnd.mT2Had * negEnd.mT2Had; + if (lambda2 <= 0.) return false; + + // Construct kinematics, as viewed in the transverse rest frame. + double lambda = sqrt(lambda2); + double probReverse = 1. / (1. + exp( min( EXPMAX, bLund * lambda) ) ); + double xpzPos = 0.5 * lambda/ wT2Rem; + if (probReverse > Rndm::flat()) xpzPos = -xpzPos; + double xmDiff = (posEnd.mT2Had - negEnd.mT2Had) / wT2Rem; + double xePos = 0.5 * (1. + xmDiff); + double xeNeg = 0.5 * (1. - xmDiff ); + + // Translate this into kinematics in the string frame. + Vec4 pHadPos = region.pHad( (xePos + xpzPos) * xPosRem, + (xePos - xpzPos) * xNegRem, posEnd.pxHad, posEnd.pyHad); + Vec4 pHadNeg = region.pHad( (xeNeg - xpzPos) * xPosRem, + (xeNeg + xpzPos) * xNegRem, negEnd.pxHad, negEnd.pyHad); + + // Add produced particles to the event record. + hadrons.append( posEnd.idHad, 83, posEnd.iEnd, negEnd.iEnd, + 0, 0, 0, 0, pHadPos, posEnd.mHad); + hadrons.append( negEnd.idHad, 84, posEnd.iEnd, negEnd.iEnd, + 0, 0, 0, 0, pHadNeg, negEnd.mHad); + + // It worked. + return true; + +} + +//********* + +// Construct a special joining region for the final two hadrons. + +StringRegion StringFragmentation::finalRegion() { + + // Simple case when both string ends are in the same region. + if (posEnd.iPosOld == negEnd.iPosOld && posEnd.iNegOld == negEnd.iNegOld) + return system.region( posEnd.iPosOld, posEnd.iNegOld); + + // Start out with empty region. (Empty used for error returns.) + StringRegion region; + + // Add up all remaining p+. + Vec4 pPosJoin; + if ( posEnd.iPosOld == negEnd.iPosOld) { + double xPosJoin = posEnd.xPosOld - negEnd.xPosOld; + if (xPosJoin < 0.) return region; + pPosJoin = system.regionLowPos(posEnd.iPosOld).pHad( xPosJoin, 0., 0., 0.); + } else { + for (int iPosNow = posEnd.iPosOld; iPosNow <= negEnd.iPosOld; ++iPosNow) { + if (iPosNow == posEnd.iPosOld) pPosJoin + += system.regionLowPos(iPosNow).pHad( posEnd.xPosOld, 0., 0., 0.); + else if (iPosNow == negEnd.iPosOld) pPosJoin + += system.regionLowPos(iPosNow).pHad( 1. - negEnd.xPosOld, 0., 0., 0.); + else pPosJoin += system.regionLowPos(iPosNow).pHad( 1., 0., 0., 0.); + } + } + + // Add up all remaining p-. + Vec4 pNegJoin; + if ( negEnd.iNegOld == posEnd.iNegOld) { + double xNegJoin = negEnd.xNegOld - posEnd.xNegOld; + if (xNegJoin < 0.) return region; + pNegJoin = system.regionLowNeg(negEnd.iNegOld).pHad( 0., xNegJoin, 0., 0.); + } else { + for (int iNegNow = negEnd.iNegOld; iNegNow <= posEnd.iNegOld; ++iNegNow) { + if (iNegNow == negEnd.iNegOld) pNegJoin + += system.regionLowNeg(iNegNow).pHad( 0., negEnd.xNegOld, 0., 0.); + else if (iNegNow == posEnd.iNegOld) pNegJoin + += system.regionLowNeg(iNegNow).pHad( 0., 1. - posEnd.xNegOld, 0., 0.); + else pNegJoin += system.regionLowNeg(iNegNow).pHad( 0., 1., 0., 0.); + } + } + + // For a closed gluon loop pPosJoin == pNegJoin and the above does not work. + // So reshuffle; "perfect" for g g systems, OK in general. + Vec4 pTest = pPosJoin - pNegJoin; + if ( abs(pTest.px()) + abs(pTest.py()) + abs(pTest.pz()) + abs(pTest.e()) + < MATCHPOSNEG * (pPosJoin.e() + pNegJoin.e()) ) { + Vec4 delta + = system.regionLowPos(posEnd.iPosOld + 1).pHad( 1., 0., 0., 0.) + - system.regionLowNeg(negEnd.iNegOld + 1).pHad( 0., 1., 0., 0.); + pPosJoin -= delta; + pNegJoin += delta; + } + + // Construct a new region from remaining p+ and p-. + region.setUp( pPosJoin, pNegJoin); + if (region.isEmpty) return region; + + // Project the existing pTold vectors onto the new directions. + Vec4 pTposOld = system.region( posEnd.iPosOld, posEnd.iNegOld).pHad( + 0., 0., posEnd.pxOld, posEnd.pyOld); + region.project( pTposOld); + posEnd.pxOld = region.px(); + posEnd.pyOld = region.py(); + Vec4 pTnegOld = system.region( negEnd.iPosOld, negEnd.iNegOld).pHad( + 0., 0., negEnd.pxOld, negEnd.pyOld); + region.project( pTnegOld); + negEnd.pxOld = region.px(); + negEnd.pyOld = region.py(); + + // Done. + return region; + +} + +//********* + +// Store the hadrons in the normal event record, ordered from one end. + +void StringFragmentation::store(Event& event) { + + // Starting position. + int iFirst = event.size(); + + // Copy straight over from first two junction legs. + if (hasJunction) { + for (int i = 0; i < hadrons.size(); ++i) + if (hadrons[i].status() == 85 || hadrons[i].status() == 86) + event.append( hadrons[i] ); + } + + // Loop downwards, copying all from the positive end. + for (int i = 0; i < hadrons.size(); ++i) + if (hadrons[i].status() == 83) event.append( hadrons[i] ); + + // Loop upwards, copying all from the negative end. + for (int i = hadrons.size() - 1; i >= 0 ; --i) + if (hadrons[i].status() == 84) event.append( hadrons[i] ); + int iLast = event.size() - 1; + + // Set decay vertex when this is displaced. + if (event[posEnd.iEnd].hasVertex()) { + Vec4 vDec = event[posEnd.iEnd].vDec(); + for (int i = iFirst; i <= iLast; ++i) event[i].vProd( vDec ); + } + + // Set lifetime of hadrons. + for (int i = iFirst; i <= iLast; ++i) + event[i].tau( event[i].tau0() * Rndm::exp() ); + + // Mark original partons as hadronized and set their daughter range. + for (int i = 0; i < int(iParton.size()); ++i) + if (iParton[i] >= 0) { + event[ iParton[i] ].statusNeg(); + event[ iParton[i] ].daughters(iFirst, iLast); + } + +} + +//********* + +// Fragment off two of the string legs in to a junction. + +bool StringFragmentation::fragmentToJunction(Event& event) { + + // Identify range of partons on the three legs. + // (Each leg begins with an iParton[i] = -(10 + 10*junctionNuber + leg), + // and partons then appear ordered from the junction outwards.) + int legBeg[3], legEnd[3]; + int leg = -1; + for (int i = 0; i < int(iParton.size()); ++i) { + if (iParton[i] < 0) legBeg[++leg] = i + 1; + else legEnd[leg] = i; + } + + // Iterate from system rest frame towards the junction rest frame (JRF). + RotBstMatrix MtoJRF, Mstep; + MtoJRF.bstback(pSum); + Vec4 pWTinJRF[3]; + int iter = 0; + double errInCM = 0.; + do { + ++iter; + + // Find weighted sum of momenta on the three sides of the junction. + for (leg = 0; leg < 3; ++ leg) { + pWTinJRF[leg] = 0.; + double eWeight = 0.; + for (int i = legBeg[leg]; i <= legEnd[leg]; ++i) { + Vec4 pTemp = event[ iParton[i] ].p(); + pTemp.rotbst(MtoJRF); + pWTinJRF[leg] += pTemp * exp(-eWeight); + eWeight += pTemp.e() / eNormJunction; + if (eWeight > EJNWEIGHTMAX) break; + } + } + + // Store original deviation from 120 degree topology. + if (iter == 1) errInCM = pow2(costheta(pWTinJRF[0], pWTinJRF[1]) + 0.5) + + pow2(costheta(pWTinJRF[0], pWTinJRF[2]) + 0.5) + + pow2(costheta(pWTinJRF[1], pWTinJRF[2]) + 0.5); + + // Find new JRF from the set of weighted momenta. + Mstep = junctionRestFrame( pWTinJRF[0], pWTinJRF[1], pWTinJRF[2]); + // Fortran code will not take full step after the first few + // iterations. How implement this in terms of an M matrix?? + MtoJRF.rotbst( Mstep ); + } while (iter < 3 || (Mstep.deviation() > CONVJNREST && iter < NTRYJNREST) ); + + // If final deviation from 120 degrees is bigger than in CM then revert. + double errInJRF = pow2(costheta(pWTinJRF[0], pWTinJRF[1]) + 0.5) + + pow2(costheta(pWTinJRF[0], pWTinJRF[2]) + 0.5) + + pow2(costheta(pWTinJRF[1], pWTinJRF[2]) + 0.5); + if (errInJRF > errInCM) { + infoPtr->errorMsg("Warning in StringFragmentation::fragmentTo" + "Junction: bad convergence junction rest frame"); + MtoJRF.reset(); + MtoJRF.bstback(pSum); + } + + // Opposite operation: boost from JRF to original system. + RotBstMatrix MfromJRF = MtoJRF; + MfromJRF.invert(); + + // Sum leg four-momenta in original frame and in JRF. + Vec4 pInLeg[3], pInJRF[3]; + for (leg = 0; leg < 3; ++leg) { + pInLeg[leg] = 0.; + for (int i = legBeg[leg]; i <= legEnd[leg]; ++i) + pInLeg[leg] += event[ iParton[i] ].p(); + pInJRF[leg] = pInLeg[leg]; + pInJRF[leg].rotbst(MtoJRF); + } + + // Pick the two legs with lowest energy in JRF. + int legMin = (pInJRF[0].e() < pInJRF[1].e()) ? 0 : 1; + int legMax = 1 - legMin; + if (pInJRF[2].e() < min(pInJRF[0].e(), pInJRF[1].e()) ) legMin = 2; + else if (pInJRF[2].e() > max(pInJRF[0].e(), pInJRF[1].e()) ) legMax = 2; + int legMid = 3 - legMin - legMax; + + // Save info on which status codes belong with the three legs. + int iJunction = (-iParton[0]) / 10 - 1; + event.statusJunction( iJunction, legMin, 85); + event.statusJunction( iJunction, legMid, 86); + event.statusJunction( iJunction, legMax, 83); + + // Temporarily copy the partons on the low-energy legs, into the JRF, + // in reverse order, so (anti)quark leg end first. + vector iPartonMin; + for (int i = legEnd[legMin]; i >= legBeg[legMin]; --i) { + int iNew = event.append( event[ iParton[i] ] ); + event[iNew].rotbst(MtoJRF); + iPartonMin.push_back( iNew ); + } + vector iPartonMid; + for (int i = legEnd[legMid]; i >= legBeg[legMid]; --i) { + int iNew = event.append( event[ iParton[i] ] ); + event[iNew].rotbst(MtoJRF); + iPartonMid.push_back( iNew ); + } + + // Find final weighted sum of momenta on each of the two legs. + double eWeight = 0.; + pWTinJRF[legMin] = 0.; + for (int i = iPartonMin.size() - 1; i >= 0; --i) { + pWTinJRF[legMin] += event[ iPartonMin[i] ].p() * exp(-eWeight); + eWeight += event[ iPartonMin[i] ].e() / eNormJunction; + if (eWeight > EJNWEIGHTMAX) break; + } + eWeight = 0.; + pWTinJRF[legMid] = 0.; + for (int i = iPartonMid.size() - 1; i >= 0; --i) { + pWTinJRF[legMid] += event[ iPartonMid[i] ].p() * exp(-eWeight); + eWeight += event[ iPartonMid[i] ].e() / eNormJunction; + if (eWeight > EJNWEIGHTMAX) break; + } + + // Define fictitious opposing partons in JRF and store as string ends. + Vec4 pOppose = pWTinJRF[legMin]; + pOppose.flip3(); + int idOppose = (Rndm::flat() > 0.5) ? 2 : 1; + if (event[ iPartonMin[0] ].col() > 0) idOppose = -idOppose; + int iOppose = event.append( idOppose, 77, 0, 0, 0, 0, 0, 0, + pOppose, 0.); + iPartonMin.push_back( iOppose); + pOppose = pWTinJRF[legMid]; + pOppose.flip3(); + idOppose = (Rndm::flat() > 0.5) ? 2 : 1; + if (event[ iPartonMid[0] ].col() > 0) idOppose = -idOppose; + iOppose = event.append( idOppose, 77, 0, 0, 0, 0, 0, 0, + pOppose, 0.); + iPartonMid.push_back( iOppose); + + // Set up kinematics of string evolution in low-energy temporary systems. + systemMin.setUp(iPartonMin, event); + systemMid.setUp(iPartonMid, event); + + // Outer fallback loop, when too little energy left for third leg. + int idMin = 0; + int idMid = 0; + Vec4 pDiquark; + for ( int iTryOuter = 0; ; ++iTryOuter) { + + // Middle fallback loop, when much unused energy in leg remnants. + double eLeftMin = 0.; + double eLeftMid = 0.; + for ( int iTryMiddle = 0; ; ++iTryMiddle) { + + // Loop over the two lowest-energy legs. + for (int legLoop = 0; legLoop < 2; ++ legLoop) { + int legNow = (legLoop == 0) ? legMin : legMid; + + // Read in properties specific to this leg. + StringSystem& systemNow = (legLoop == 0) ? systemMin : systemMid; + int idPos = (legLoop == 0) ? event[ iPartonMin[0] ].id() + : event[ iPartonMid[0] ].id(); + idOppose = (legLoop == 0) ? event[ iPartonMin.back() ].id() + : event[ iPartonMid.back() ].id(); + double eInJRF = pInJRF[legNow].e(); + int statusHad = (legLoop == 0) ? 85 : 86; + + // Inner fallback loop, when a diquark comes in to junction. + double eUsed = 0.; + for ( int iTryInner = 0; ; ++iTryInner) { + if (iTryInner > NTRYJNMATCH) { + infoPtr->errorMsg("Error in StringFragmentation::fragment" + "ToJunction: caught in junction flavour loop"); + event.popBack( iPartonMin.size() + iPartonMid.size() ); + return false; + } + + // Set up two string ends, and begin fragmentation loop. + setStartEnds(idPos, idOppose, systemNow); + eUsed = 0.; + int nHadrons = 0; + bool noNegE = true; + for ( ; ; ++nHadrons) { + + // Construct trial hadron from positive end. + posEnd.newHadron(); + Vec4 pHad = posEnd.kinematicsHadron(systemNow); + + // Negative energy signals failure in construction. + if (pHad.e() < 0. ) { noNegE = false; break; } + + // Break if passed system midpoint ( = junction) in energy. + if (eUsed + pHad.e() > eInJRF) break; + + // Else construct kinematics of the new hadron and store it. + hadrons.append( posEnd.idHad, statusHad, iPos, iNeg, + 0, 0, 0, 0, pHad, posEnd.mHad); + + // Update string end and remaining momentum. + posEnd.update(); + eUsed += pHad.e(); + } + + // End of fragmentation loop. Inner loopback if ends on a diquark. + if ( noNegE && abs(posEnd.flavOld.id) < 10 ) break; + hadrons.popBack(nHadrons); + } + + // End of one-leg fragmentation. Store end quark and remnant energy. + if (legNow == legMin) { + idMin = posEnd.flavOld.id; + eLeftMin = eInJRF - eUsed; + } else { + idMid = posEnd.flavOld.id; + eLeftMid = eInJRF - eUsed; + } + } + + // End of both-leg fragmentation. Middle loopback if too much energy left. + double eTrial = eBothLeftJunction + Rndm::flat() * eMaxLeftJunction; + if (iTryMiddle > NTRYJNMATCH + || ( min( eLeftMin, eLeftMid) < eBothLeftJunction + && max( eLeftMin, eLeftMid) < eTrial ) ) break; + hadrons.clear(); + } + + // Boost hadrons away from the JRF to the original frame. + for (int i = 0; i < hadrons.size(); ++i) { + hadrons[i].rotbst(MfromJRF); + pJunctionHadrons += hadrons[i].p(); + } + + // Outer loopback if too little energy left in third leg. + pDiquark = pInLeg[legMin] + pInLeg[legMid] - pJunctionHadrons; + double m2Left = m2( pInLeg[legMax], pDiquark); + if (iTryOuter > NTRYJNMATCH + || m2Left > eMinLeftJunction * pInLeg[legMax].e() ) break; + hadrons.clear(); + pJunctionHadrons = 0.; + } + + // Now found solution; no more loopback. Remove temporary parton copies. + event.popBack( iPartonMin.size() + iPartonMid.size() ); + + // Construct and store an effective diquark string end from the + // two remnant quark ends, for temporary usage. + int idDiquark = flavSelPtr->makeDiquark( idMin, idMid); + double mDiquark = pDiquark.mCalc(); + int iDiquark = event.append( idDiquark, 78, 0, 0, 0, 0, 0, 0, + pDiquark, mDiquark); + + // Find the partons on the last leg, again in reverse order. + vector iPartonMax; + for (int i = legEnd[legMax]; i >= legBeg[legMax]; --i) + iPartonMax.push_back( iParton[i] ); + iPartonMax.push_back( iDiquark ); + + // Modify parton list to remaining leg + remnant of the first two. + iParton = iPartonMax; + + // Done. + return true; +} + +//********* + +// Find the boost matrix to the rest frame of a junction, +// given the three respective endpoint four-momenta. + +RotBstMatrix StringFragmentation::junctionRestFrame(Vec4& p0, Vec4& p1, + Vec4& p2) { + + // Calculate masses and other invariants. + Vec4 pSumJun = p0 + p1 + p2; + double sHat = pSumJun.m2Calc(); + double pp[3][3]; + pp[0][0] = p0.m2Calc(); + pp[1][1] = p1.m2Calc(); + pp[2][2] = p2.m2Calc(); + pp[0][1] = pp[1][0] = p0 * p1; + pp[0][2] = pp[2][0] = p0 * p2; + pp[1][2] = pp[2][1] = p1 * p2; + + // Requirement (eiMax)_j = pi*pj/mj < (eiMax)_k = pi*pk/mk, used below, + // here rewritten as pi*pj * mk < pi*pk * mj and squared. + double eMax01 = pow2(pp[0][1]) * pp[2][2]; + double eMax02 = pow2(pp[0][2]) * pp[1][1]; + double eMax12 = pow2(pp[1][2]) * pp[0][0]; + + // Initially pick i to be the most massive parton. but allow other tries. + int i = (pp[1][1] > pp[0][0]) ? 1 : 0; + if (pp[2][2] > max(pp[0][0], pp[1][1])) i = 2; + int j, k; + double ei = 0.; + double ej = 0.; + double ek = 0.; + for (int iTry = 0; iTry < 3; ++iTry) { + + // Pick j to give minimal eiMax, and k the third vector. + if (i == 0) j = (eMax02 < eMax01) ? 2 : 1; + else if (i == 1) j = (eMax12 < eMax01) ? 2 : 0; + else j = (eMax12 < eMax02) ? 1 : 0; + k = 3 - i - j; + + // Alternative names according to i, j, k conventions. + double m2i = pp[i][i]; + double m2j = pp[j][j]; + double m2k = pp[k][k]; + double pipj = pp[i][j]; + double pipk = pp[i][k]; + double pjpk = pp[j][k]; + + // Trivial to find new parton energies if all three partons are massless. + if (m2i < M2MAXJRF) { + ei = sqrt( 2. * pipk * pipj / (3. * pjpk) ); + ej = sqrt( 2. * pjpk * pipj / (3. * pipk) ); + ek = sqrt( 2. * pipk * pjpk / (3. * pipj) ); + + // Else find three-momentum range for parton i and values at extremes. + } else { + // Minimum when i is at rest. + double piMin = 0.; + double eiMin = sqrt(m2i); + double ejMin = pipj / eiMin; + double ekMin = pipk / eiMin; + double pjMin = sqrtpos( ejMin*ejMin - m2j ); + double pkMin = sqrtpos( ekMin*ekMin - m2k ); + double fMin = ejMin * ekMin + 0.5 * pjMin * pkMin - pjpk; + // Maximum estimated when j + k is at rest, alternatively j at rest. + double eiMax = (pipj + pipk) / sqrt(m2j + m2k + 2. * pjpk); + if (m2j > M2MAXJRF) eiMax = min( eiMax, pipj / sqrt(m2j) ); + double piMax = sqrtpos( eiMax*eiMax - m2i ); + double temp = eiMax*eiMax - 0.25 *piMax*piMax; + double pjMax = (eiMax * sqrtpos( pipj*pipj - m2j * temp ) + - 0.5 * piMax * pipj) / temp; + double pkMax = (eiMax * sqrtpos( pipk*pipk - m2k * temp ) + - 0.5 * piMax * pipk) / temp; + double ejMax = sqrt(pjMax*pjMax + m2j); + double ekMax = sqrt(pkMax*pkMax + m2k); + double fMax = ejMax * ekMax + 0.5 * pjMax * pkMax - pjpk; + + // If unexpected values at upper endpoint then pick another parton. + if (fMax > 0.) { + int iPrel = (i + 1)%3; + if (pp[iPrel][iPrel] > M2MAXJRF) {i = iPrel; continue;} + ++iTry; + iPrel = (i + 2)%3; + if (iTry < 3 && pp[iPrel][iPrel] > M2MAXJRF) {i = iPrel; continue;} + } + + // Start binary + linear search to find solution inside range. + int iterMin = 0; + int iterMax = 0; + double pi = 0.5 * (piMin + piMax); + for (int iter = 0; iter < NTRYJRFEQ; ++iter) { + + // Derive momentum of other two partons and distance to root. + ei = sqrt(pi*pi + m2i); + temp = ei*ei - 0.25 * pi*pi; + double pj = (ei * sqrtpos( pipj*pipj - m2j * temp ) + - 0.5 * pi * pipj) / temp; + double pk = (ei * sqrtpos( pipk*pipk - m2k * temp ) + - 0.5 * pi * pipk) / temp; + ej = sqrt(pj*pj + m2j); + ek = sqrt(pk*pk + m2k); + double fNow = ej * ek + 0.5 * pj * pk - pjpk; + + // Replace lower or upper bound by new value. + if (fNow > 0.) { ++iterMin; piMin = pi; fMin = fNow;} + else {++iterMax; piMax = pi; fMax = fNow;} + + // Pick next i momentum to explore, hopefully closer to root. + if (2 * iter < NTRYJRFEQ + && (iterMin < 2 || iterMax < 2 || 4 * iter < NTRYJRFEQ)) + { pi = 0.5 * (piMin + piMax); continue;} + if (fMin < 0. || fMax > 0. || abs(fNow) < CONVJRFEQ * sHat) break; + pi = piMin + (piMax - piMin) * fMin / (fMin - fMax); + } + + // If arrived here then either succeeded or exhausted possibilities. + } break; + } + + // Now we know the energies in the junction rest frame. + double eNew[3]; eNew[i] = ei; eNew[j] = ej; eNew[k] = ek; + + // Boost (copy of) partons to their rest frame. + RotBstMatrix Mmove; + Vec4 p0cm = p0; + Vec4 p1cm = p1; + Vec4 p2cm = p2; + Mmove.bstback(pSumJun); + p0cm.rotbst(Mmove); + p1cm.rotbst(Mmove); + p2cm.rotbst(Mmove); + + // Construct difference vectors and the boost to junction rest frame. + Vec4 pDir01 = p0cm / p0cm.e() - p1cm / p1cm.e(); + Vec4 pDir02 = p0cm / p0cm.e() - p2cm / p2cm.e(); + double pDiff01 = pDir01.pAbs2(); + double pDiff02 = pDir02.pAbs2(); + double pDiff0102 = dot3(pDir01, pDir02); + double eDiff01 = eNew[0] / p0cm.e() - eNew[1] / p1cm.e(); + double eDiff02 = eNew[0] / p0cm.e() - eNew[2] / p2cm.e(); + double denom = pDiff01 * pDiff02 - pDiff0102*pDiff0102; + double coef01 = (eDiff01 * pDiff02 - eDiff02 * pDiff0102) / denom; + double coef02 = (eDiff02 * pDiff01 - eDiff01 * pDiff0102) / denom; + Vec4 vJunction = coef01 * pDir01 + coef02 * pDir02; + vJunction.e( sqrt(1. + vJunction.pAbs2()) ); + + // Add two boosts, giving final result. + Mmove.bst(vJunction); + return Mmove; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/SusyLesHouches.cxx b/PYTHIA8/pythia8130/src/SusyLesHouches.cxx new file mode 100644 index 00000000000..e6859a9592f --- /dev/null +++ b/PYTHIA8/pythia8130/src/SusyLesHouches.cxx @@ -0,0 +1,1094 @@ +// SusyLesHouches.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Peter Skands, Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +#include "SusyLesHouches.h" + + +//********* + +// Main routine to read in SLHA and LHEF+SLHA files + +int SusyLesHouches::readFile(string slhaFile) { + + // Check that input file is OK. + int iFailFile=0; + spectrumFile=slhaFile; + const char* cstring = slhaFile.c_str(); + ifstream file(cstring); + if (!file) { + message(2,"readFile","SLHA file "+slhaFile+" not found",0); + return -1; + slhaRead=false; + } + + //Print header if not already done + if (! headerPrinted) printHeader(); + + if (verbose >= 2) message(0,"readFile","parsing "+slhaFile,0); + + //Initial values for read-in variables. + slhaRead=true; + lhefRead=false; + lhefSlha=false; + string line=""; + string blockIn=""; + string decay=""; + string comment=""; + string blockName=""; + string pdgName=""; + int pdgCode=0; + double width=0.0; + + //Initialize line counter + int iLine=0; + + // Read in one line at a time. + while ( getline(file, line) ) { + iLine++; + + //Rewrite string in lowercase + for (unsigned int i=0;i tag reached. + if (line.find(" tag not yet reached, skip + if (lhefRead && ! lhefSlha) continue; + } + + //Ignore comment lines with # as first character + if (line.find("#") == 0) continue; + + //Move comment to separate string + if (line.find("#") != string::npos) { + comment=line.substr(line.find("#")+1,line.length()-line.find("#")-1); + line.erase(line.find("#"),line.length()-line.find("#")); + } + + // Remove extra blanks, also remove before and after an = sign. + while (line.find(" ") != string::npos) line.erase( line.find(" "), 1); + while (line.find(" =") != string::npos) line.erase( line.find(" ="), 1); + while (line.find("= ") != string::npos) line.erase( line.find("= ")+1, 1); + + //New block. + if (line.find("block") <= 1) { + blockIn=line ; + decay=""; + int nameBegin=6 ; + int nameEnd=blockIn.find(" ",7); + blockName=line.substr(nameBegin,nameEnd-nameBegin); + + //Find Q=... for DRbar running blocks + if (blockIn.find("q=") != string::npos) { + int qbegin=blockIn.find("q=")+2; + istringstream qstream(blockIn.substr(qbegin,blockIn.length())); + double q=0.0; + qstream >> q; + if (qstream) { + // SLHA1 running blocks + if (blockName=="hmix") hmix.setq(q); + if (blockName=="yu") yu.setq(q); + if (blockName=="yd") yd.setq(q); + if (blockName=="ye") ye.setq(q); + if (blockName=="au") au.setq(q); + if (blockName=="ad") ad.setq(q); + if (blockName=="ae") ae.setq(q); + if (blockName=="msoft") msoft.setq(q); + if (blockName=="gauge") gauge.setq(q); + // SLHA2 running blocks + if (blockName=="vckm") vckm.setq(q); + if (blockName=="upmns") upmns.setq(q); + if (blockName=="msq2") msq2.setq(q); + if (blockName=="msu2") msu2.setq(q); + if (blockName=="msd2") msd2.setq(q); + if (blockName=="msl2") msl2.setq(q); + if (blockName=="mse2") mse2.setq(q); + if (blockName=="tu") tu.setq(q); + if (blockName=="td") td.setq(q); + if (blockName=="te") te.setq(q); + if (blockName=="rvlamlle") rvlamlle.setq(q); + if (blockName=="rvlamlqd") rvlamlqd.setq(q); + if (blockName=="rvlamudd") rvlamudd.setq(q); + if (blockName=="rvtlle") rvtlle.setq(q); + if (blockName=="rvtlqd") rvtlqd.setq(q); + if (blockName=="rvtudd") rvtudd.setq(q); + if (blockName=="rvkappa") rvkappa.setq(q); + if (blockName=="rvd") rvd.setq(q); + if (blockName=="rvm2lh1") rvm2lh1.setq(q); + if (blockName=="rvsnvev") rvsnvev.setq(q); + if (blockName=="imau") imau.setq(q); + if (blockName=="imad") imad.setq(q); + if (blockName=="imae") imae.setq(q); + if (blockName=="imtu") imtu.setq(q); + if (blockName=="imtd") imtd.setq(q); + if (blockName=="imte") imte.setq(q); + if (blockName=="imvckm") imvckm.setq(q); + if (blockName=="imupmns") imupmns.setq(q); + if (blockName=="immsq2") immsq2.setq(q); + if (blockName=="immsu2") immsu2.setq(q); + if (blockName=="immsd2") immsd2.setq(q); + if (blockName=="immsl2") immsl2.setq(q); + if (blockName=="immse2") immse2.setq(q); + }; + }; + + //Skip to next line. + continue ; + + } + + //New decay table + else if (line.find("decay") <= 1) { + + //Set decay block name + decay=line; + blockIn=""; + int nameBegin=6 ; + int nameEnd=decay.find(" ",7); + pdgName=decay.substr(nameBegin,nameEnd-nameBegin); + + //Extract PDG code and width + istringstream dstream(pdgName); + dstream >> pdgCode; + if (dstream) { + string widthName=decay.substr(nameEnd+1,decay.length()); + istringstream wstream(widthName); + wstream >> width; + if (wstream) { + //Set PDG code and width + if (width <= 0.0) { + message(0,"readFile","skipping stable particle "+pdgName,0); + width=0.0; + decay=""; + } else { + message(0,"readFile","skipping DECAY table for "+pdgName,0); + } + } else { + message(2,"readFile","WIDTH unreadable for "+pdgName,iLine); + message(0,"readFile","skipping stable particle "+pdgName,0); + width=0.0; + decay=""; + continue; + } + } + else { + message(2,"readFile","PDG Code unreadable. Ignoring this DECAY block",iLine); + decay=""; + continue; + } + + //Read in PDG code and width + //... + //Set stable if width = 0d0 + //... + //don't read in decay channels if width=0.0 + //if (width <= 0.0) decay=""; + + //Skip to next line + continue ; + } + + //Switch off SLHA read-in via LHEF if outside tag. + else if (line.find("") != string::npos) { + lhefSlha=false; + blockIn=""; + decay=""; + continue; + } + + //End of SLHA read-in (via LHEF) + else if (line.find("") != string::npos || + line.find("> i; + if (linestream) { + if (i == 12) {ifail=modsel12.set(0,linestream);} + else if (i == 21) {ifail=modsel21.set(0,linestream);} + else {ifail=modsel.set(i,linestream);};} + else { + ifail = -1;} + }; + if (blockName == "minpar") ifail=minpar.set(linestream); + if (blockName == "sminputs") ifail=sminputs.set(linestream); + if (blockName == "extpar") ifail=extpar.set(linestream); + if (blockName == "qextpar") ifail=qextpar.set(linestream); + //FLV + if (blockName == "vckmin") ifail=vckmin.set(linestream); + if (blockName == "upmnsin") ifail=upmnsin.set(linestream); + if (blockName == "msq2in") ifail=msq2in.set(linestream); + if (blockName == "msu2in") ifail=msu2in.set(linestream); + if (blockName == "msd2in") ifail=msd2in.set(linestream); + if (blockName == "msl2in") ifail=msl2in.set(linestream); + if (blockName == "mse2in") ifail=mse2in.set(linestream); + if (blockName == "tuin") ifail=tuin.set(linestream); + if (blockName == "tdin") ifail=tdin.set(linestream); + if (blockName == "tein") ifail=tein.set(linestream); + //RPV + if (blockName == "rvlamllein") ifail=rvlamllein.set(linestream); + if (blockName == "rvlamlqdin") ifail=rvlamlqdin.set(linestream); + if (blockName == "rvlamuddin") ifail=rvlamuddin.set(linestream); + if (blockName == "rvtllein") ifail=rvtllein.set(linestream); + if (blockName == "rvtlqdin") ifail=rvtlqdin.set(linestream); + if (blockName == "rvtuddin") ifail=rvtuddin.set(linestream); + if (blockName == "rvkappain") ifail=rvkappain.set(linestream); + if (blockName == "rvdin") ifail=rvdin.set(linestream); + if (blockName == "rvm2lh1in") ifail=rvm2lh1in.set(linestream); + if (blockName == "rvsnvevin") ifail=rvsnvevin.set(linestream); + //CPV + if (blockName == "imminpar") ifail=imminpar.set(linestream); + if (blockName == "imextpar") ifail=imextpar.set(linestream); + //CPV +FLV + if (blockName == "immsq2in") ifail=immsq2in.set(linestream); + if (blockName == "immsu2in") ifail=immsu2in.set(linestream); + if (blockName == "immsd2in") ifail=immsd2in.set(linestream); + if (blockName == "immsl2in") ifail=immsl2in.set(linestream); + if (blockName == "immse2in") ifail=immse2in.set(linestream); + if (blockName == "imtuin") ifail=imtuin.set(linestream); + if (blockName == "imtdin") ifail=imtdin.set(linestream); + if (blockName == "imtein") ifail=imtein.set(linestream); + //Info: + if (blockName == "spinfo" || blockName=="dcinfo") { + int i; + string entry; + linestream >> i >> entry; + string blockStr="RGE"; + if (blockName=="dcinfo") blockStr="DCY"; + + if (linestream) { + if ( i == 3 ) { + string warning=line.substr(line.find("3")+1,line.length()); + message(1,"readFile","(from "+blockStr+" program): "+warning,0); + if (blockName == "spinfo") spinfo3.set(warning); + else dcinfo3.set(warning); + } else if ( i == 4 ) { + string error=line.substr(line.find("4")+1,line.length()); + message(2,"readFile","(from "+blockStr+" program): "+error,0); + if (blockName == "spinfo") spinfo4.set(error); + else dcinfo4.set(error); + } else { + //Rewrite string in uppercase + for (unsigned int j=0;j spectrum from: "+spectrumFile); + else message(0,""," Read SLHA spectrum from: "+spectrumFile); + } + + // gluino + message(0,"",""); + cout<<" | ~g m"< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< 1e7) ? scientific : fixed)< SLHA2 interoperability + //Note: the mass basis is NOT mass-ordered in SLHA1, so be careful! + //Here, the mass basis is hence by PDG code, not by mass-ordered value. + + if (stopmix.exists() && ! usqmix.exists() ) { + //1000002 = ~uL, 1000004 = ~cL, 2000002 = ~uR, 2000004 = ~cR + usqmix.set(1,1, 1.0); + usqmix.set(2,2, 1.0); + usqmix.set(4,4, 1.0); + usqmix.set(5,5, 1.0); + //Fill (1000006,2000006) sector from stopmix + usqmix.set(3,3, stopmix(1,1)); + usqmix.set(3,6, stopmix(1,2)); + usqmix.set(6,3, stopmix(2,1)); + usqmix.set(6,6, stopmix(2,2)); + }; + if (sbotmix.exists() && ! dsqmix.exists() ) { + //1000001 = ~dL, 1000003 = ~sL, 2000001 = ~dR, 2000003 = ~sR + dsqmix.set(1,1, 1.0); + dsqmix.set(2,2, 1.0); + dsqmix.set(4,4, 1.0); + dsqmix.set(5,5, 1.0); + //Fill (1000005,2000005) sector from sbotmix + dsqmix.set(3,3, sbotmix(1,1)); + dsqmix.set(3,6, sbotmix(1,2)); + dsqmix.set(6,3, sbotmix(2,1)); + dsqmix.set(6,6, sbotmix(2,2)); + }; + if (staumix.exists() && ! selmix.exists() ) { + //1000011 = ~eL, 1000013 = ~muL, 2000011 = ~eR, 2000013 = ~muR + selmix.set(1,1, 1.0); + selmix.set(2,2, 1.0); + selmix.set(4,4, 1.0); + selmix.set(5,5, 1.0); + //Fill (1000015,2000015) sector from staumix + selmix.set(3,3, staumix(1,1)); + selmix.set(3,6, staumix(1,2)); + selmix.set(6,3, staumix(2,1)); + selmix.set(6,6, staumix(2,2)); + }; + if (! snumix.exists() && ! snsmix.exists()) { + //1000012 = ~nu_e, 1000014 = ~nu_mu, 1000016 = ~nu_tau + snumix.set(1,1, 1.0); + snumix.set(2,2, 1.0); + snumix.set(3,3, 1.0); + }; + + //----------------------------------------------------------------- + //4) Check unitarity/orthogonality of mixing matrices + + //NMIX + if (nmix.exists()) { + for (int i=1;i<=4;i++) { + double cn1=0.0; + double cn2=0.0; + for (int j=1;j<=4;j++) { + cn1 += pow(nmix(i,j),2); + cn2 += pow(nmix(j,i),2); + } + if (abs(1.0-cn1) > 1e-3 || abs(1.0-cn2) > 1e-3) { + ifail=2; + message(2,"checkSpectrum","inconsistent normalization of NMIX",0); + } + } + } + + //VMIX, UMIX + if (vmix.exists() && umix.exists()) { + for (int i=1;i<=2;i++) { + double cu1=0.0; + double cu2=0.0; + double cv1=0.0; + double cv2=0.0; + for (int j=1;j<=2;j++) { + cu1 += pow(umix(i,j),2); + cu2 += pow(umix(j,i),2); + cv1 += pow(vmix(i,j),2); + cv2 += pow(vmix(j,i),2); + } + if (abs(1.0-cu1) > 1e-3 || abs(1.0-cu2) > 1e-3) { + ifail=2; + message(2,"checkSpectrum","inconsistent normalization of UMIX",0); + } + if (abs(1.0-cv1) > 1e-3 || abs(1.0-cv2) > 1e-3) { + ifail=2; + message(2,"checkSpectrum","inconsistent normalization of VMIX",0); + } + } + + } + + //STOPMIX, SBOTMIX + if (stopmix.exists() && sbotmix.exists()) { + for (int i=1;i<=2;i++) { + double ct1=0.0; + double ct2=0.0; + double cb1=0.0; + double cb2=0.0; + for (int j=1;j<=2;j++) { + ct1 += pow(stopmix(i,j),2); + ct2 += pow(stopmix(j,i),2); + cb1 += pow(sbotmix(i,j),2); + cb2 += pow(sbotmix(j,i),2); + } + if (abs(1.0-ct1) > 1e-3 || abs(1.0-ct2) > 1e-3) { + ifail=2; + message(2,"checkSpectrum","inconsistent normalization of STOPMIX",0); + } + if (abs(1.0-cb1) > 1e-3 || abs(1.0-cb2) > 1e-3) { + ifail=2; + message(2,"checkSpectrum","inconsistent normalization of SBOTMIX",0); + } + } + } + + //STAUMIX + if (staumix.exists()) { + for (int i=1;i<=2;i++) { + double ct1=0.0; + double ct2=0.0; + for (int j=1;j<=2;j++) { + ct1 += pow(staumix(i,j),2); + ct2 += pow(staumix(j,i),2); + } + if (abs(1.0-ct1) > 1e-3 || abs(1.0-ct2) > 1e-3) { + ifail=2; + message(2,"checkSpectrum","inconsistent normalization of STAUMIX",0); + } + } + } + + //NMSSM: + if (modsel(3) == 1) { + //NMNMIX + if ( nmnmix.exists() ) { + for (int i=1;i<=5;i++) { + double cn1=0.0; + double cn2=0.0; + for (int j=1;j<=4;j++) { + cn1 += pow(nmnmix(i,j),2); + cn2 += pow(nmnmix(j,i),2); + } + if (abs(1.0-cn1) > 1e-3 || abs(1.0-cn2) > 1e-3) { + ifail=max(ifail,2); + message(2,"checkSpectrum","inconsistent normalization of NMNMIX",0); + } + } + } + else { + ifail=max(ifail,1); + message(1,"checkSpectrum","MODSEL 3 = 1 (NMSSM) but no NMNMIX found",0); + } + //NMAMIX + if ( nmamix.exists() ) { + for (int i=1;i<=2;i++) { + double cn1=0.0; + for (int j=1;j<=3;j++) { + cn1 += pow(nmamix(i,j),2); + } + if (abs(1.0-cn1) > 1e-3) { + ifail=max(ifail,2); + message(2,"checkSpectrum","inconsistent normalization of NMAMIX",0); + } + } + } + else { + ifail=max(ifail,1); + message(1,"checkSpectrum","MODSEL 3 = 1 (NMSSM) but no NMAMIX found",0); + } + //NMHMIX + if ( nmhmix.exists() ) { + for (int i=1;i<=3;i++) { + double cn1=0.0; + double cn2=0.0; + for (int j=1;j<=3;j++) { + cn1 += pow(nmhmix(i,j),2); + cn2 += pow(nmhmix(j,i),2); + } + if (abs(1.0-cn1) > 1e-3 || abs(1.0-cn2) > 1e-3) { + ifail=max(ifail,2); + message(2,"checkSpectrum","inconsistent normalization of NMHMIX",0); + } + } + } + else { + ifail=max(ifail,1); + message(1,"checkSpectrum","MODSEL 3 = 1 (NMSSM) but no NMHMIX found",0); + } + //NMSSMRUN + if (! nmssmrun.exists() ) { + ifail=max(ifail,1); + message(2,"checkSpectrum","MODSEL 3 = 1 (NMSSM) but no NMSSMRUN found", + 0); + } + } + + //Check for documentation + if (slhaRead && ! spinfo.exists(1)) spinfo.set(1,"unknown"); + if (slhaRead && ! spinfo.exists(2)) spinfo.set(2,"unknown"); + if (! slhaRead && ! spinfo.exists(1)) { + spinfo.set(1,"DEFAULT"); + spinfo.set(2,"n/a"); + } + + //Give status + if (ifail >= 2) + message(0,"checkSpectrum","one or more serious problems were found"); + + //Print Footer + printFooter(); + + //Return + return ifail; +} + +//********* + +// Simple utility to print messages, warnings, and errors + +void SusyLesHouches::message(int level, string place,string themessage,int line) { + //Send normal messages and warnings to stdout, errors to stderr. + ostream* outstream = &cerr; + if (level <= 1) outstream = &cout; + // if (level == 2) { *outstream< 2 * pTmin * sqrt(1/XMARGIN), +// i.e. will become problem roughly for E_CM > 10^6 GeV. +const double TimeShower::XMARGIN = 1e-12; +const double TimeShower::XMARGINCOMB = 1e-4; + +// Lower limit on PDF value in order to avoid division by zero. +const double TimeShower::TINYPDF = 1e-10; + +// Big starting value in search for smallest invariant-mass pair. +const double TimeShower::LARGEM2 = 1e20; + +// In g -> q qbar or gamma -> f fbar require m2_pair > this * m2_q/f. +const double TimeShower::THRESHM2 = 4.004; + +// Never pick pT so low that alphaS is evaluated too close to Lambda_3. +const double TimeShower::LAMBDA3MARGIN = 1.1; + +//********* + +// Initialize alphaStrong, alphaEM and related pTmin parameters. + +void TimeShower::init( BeamParticle* beamAPtrIn, + BeamParticle* beamBPtrIn) { + + // Store input pointers for future use. + beamAPtr = beamAPtrIn; + beamBPtr = beamBPtrIn; + + // Main flags. + doQCDshower = Settings::flag("TimeShower:QCDshower"); + doQEDshowerByQ = Settings::flag("TimeShower:QEDshowerByQ"); + doQEDshowerByL = Settings::flag("TimeShower:QEDshowerByL"); + doQEDshowerByGamma = Settings::flag("TimeShower:QEDshowerByGamma"); + doMEcorrections = Settings::flag("TimeShower:MEcorrections"); + doPhiPolAsym = Settings::flag("TimeShower:phiPolAsym"); + allowBeamRecoil = Settings::flag("TimeShower:allowBeamRecoil"); + + // Matching in pT of hard interaction to shower evolution. + pTmaxFudge = Settings::parm("TimeShower:pTmaxFudge"); + + // Charm and bottom mass thresholds. + mc = ParticleDataTable::m0(4); + mb = ParticleDataTable::m0(5); + m2c = mc * mc; + m2b = mb * mb; + + // Parameters of alphaStrong generation . + alphaSvalue = Settings::parm("TimeShower:alphaSvalue"); + alphaSorder = Settings::mode("TimeShower:alphaSorder"); + alphaS2pi = 0.5 * alphaSvalue / M_PI; + + // Initialize alphaStrong generation. + alphaS.init( alphaSvalue, alphaSorder); + + // Lambda for 5, 4 and 3 flavours. + Lambda3flav = alphaS.Lambda3(); + Lambda4flav = alphaS.Lambda4(); + Lambda5flav = alphaS.Lambda5(); + Lambda5flav2 = pow2(Lambda5flav); + Lambda4flav2 = pow2(Lambda4flav); + Lambda3flav2 = pow2(Lambda3flav); + + // Parameters of QCD evolution. + nGluonToQuark = Settings::mode("TimeShower:nGluonToQuark"); + pTcolCutMin = Settings::parm("TimeShower:pTmin"); + pTcolCut = max( pTcolCutMin, LAMBDA3MARGIN * Lambda3flav ); + pT2colCut = pow2(pTcolCut); + + // Parameters of alphaEM generation . + alphaEMorder = Settings::mode("TimeShower:alphaEMorder"); + + // Initialize alphaEM generation. + alphaEM.init( alphaEMorder); + + // Parameters of QED evolution. + nGammaToQuark = Settings::mode("TimeShower:nGammaToQuark"); + nGammaToLepton = Settings::mode("TimeShower:nGammaToLepton"); + pTchgQCut = Settings::parm("TimeShower:pTminChgQ"); + pT2chgQCut = pow2(pTchgQCut); + pTchgLCut = Settings::parm("TimeShower:pTminChgL"); + pT2chgLCut = pow2(pTchgLCut); + mMaxGamma = Settings::parm("TimeShower:mMaxGamma"); + m2MaxGamma = pow2(mMaxGamma); + + // Consisteny check for gamma -> f fbar variables. + if (nGammaToQuark <= 0 && nGammaToLepton <= 0) doQEDshowerByGamma = false; + + // Fraction and colorr factor of gluon emission off onium octat state. + octetOniumFraction = Settings::parm("TimeShower:octetOniumFraction"); + octetOniumColFac = Settings::parm("TimeShower:octetOniumColFac"); + + // Z0 properties needed for gamma/Z0 mixing. + mZ = ParticleDataTable::m0(23); + gammaZ = ParticleDataTable::mWidth(23); + thetaWRat = 1. / (16. * CoupEW::sin2thetaW() * CoupEW::cos2thetaW()); + +} + +//********* + +// Top-level routine to do a full time-like shower in resonance decay. + +int TimeShower::shower( int iBeg, int iEnd, Event& event, double pTmax) { + + // Add new system, with two empty beam slots. + int iSys = event.newSystem(); + event.addToSystem( iSys, 0); + event.addToSystem( iSys, 0); + + // Loop over allowed range to find all final-state particles. + for (int i = iBeg; i <= iEnd; ++i) + if (event[i].isFinal()) event.addToSystem( iSys, i); + + // Let prepare routine do the setup. + prepare( iSys, event); + + // Begin evolution down in pT from hard pT scale. + int nBranch = 0; + do { + double pTtimes = pTnext( event, pTmax, 0.); + + // Do a final-state emission (if allowed). + if (pTtimes > 0.) { + if (branch( event)) ++nBranch; + pTmax = pTtimes; + } + + // Keep on evolving until nothing is left to be done. + else pTmax = 0.; + } while (pTmax > 0.); + + // Return number of emissions that were performed. + return nBranch; + +} + +//********* + +// Prepare system for evolution; identify ME. + +void TimeShower::prepare( int iSys, Event& event) { + + // Reset dipole-ends list for first interaction and for resonance decays. + if (iSys == 0 || event.getInSystem( iSys, 0) == 0) dipEnd.resize(0); + int dipEndSizeBeg = dipEnd.size(); + + // Loop through final state of system to find possible dipole ends. + for (int i = 2; i < event.sizeSystem( iSys); ++i) { + int iRad = event.getInSystem( iSys, i); + if (event[iRad].isFinal() && event[iRad].scale() > 0.) { + + // Identify colour octet onium state. Check whether QCD shower allowed. + int idRad = event[iRad].id(); + bool isOctetOnium + = ( idRad == 9900441 || idRad == 9900443 || idRad == 9910441 + || idRad == 9900551 || idRad == 9900553 || idRad == 9910551 ); + bool doQCD = doQCDshower; + if (doQCD && isOctetOnium) doQCD = (Rndm::flat() < octetOniumFraction); + + // Find dipole end formed by colour index. + int colTag = event[iRad].col(); + if (doQCD && colTag > 0) + setupQCDdip( iSys, i, colTag, 1, event, isOctetOnium); + + // Find dipole end formed by anticolour index. + int acolTag = event[iRad].acol(); + if (doQCD && acolTag > 0) + setupQCDdip( iSys, i, acolTag, -1, event, isOctetOnium); + + // Find "charge-dipole" and "photon-dipole" ends. + int chgType = event[iRad].chargeType(); + bool doChgDip = (chgType != 0) + && ( ( doQEDshowerByQ && event[iRad].isQuark() ) + || ( doQEDshowerByL && event[iRad].isLepton() ) ); + int gamType = (event[iRad].id() == 22) ? 1 : 0; + bool doGamDip = (gamType == 1) && doQEDshowerByGamma; + if (doChgDip || doGamDip) setupQEDdip( iSys, i, chgType, gamType, event); + + // End loop over system final state. Have now found the dipole ends. + } + } + + // Loop through dipole ends to find matrix element corrections. + for (int iDip = dipEndSizeBeg; iDip < int(dipEnd.size()); ++iDip) + findMEtype( event, dipEnd[iDip]); + +} + +//********* + +// Update dipole list after each ISR emission (so not used for resonances). + +void TimeShower::update( int iSys, Event& event) { + + // Find new and old positions of partons in the system. + vector iNew, iOld; + int size = event.sizeSystem( iSys) - 1; + for (int i = 0; i < size; ++i) { + iNew.push_back( event.getInSystem( iSys, i) ); + if (i < 2) iOld.push_back( event[iNew[i]].daughter2() ); + else iOld.push_back( event[iNew[i]].mother1() ); + } + int iNewNew = event.getInSystem( iSys, size); + + // Swap beams to let 0 be side on which branching occured. + if (event[iNew[0]].status() != -41) { + swap( iNew[0], iNew[1]); + swap( iOld[0], iOld[1]); + } + + // Loop over all dipole ends belonging to the system. + for (int iDip = 0; iDip < int(dipEnd.size()); ++iDip) + if (dipEnd[iDip].system == iSys) { + TimeDipoleEnd& dipNow = dipEnd[iDip]; + + // Replace radiator (always in final state so simple). + for (int i = 2; i < size; ++i) + if (dipNow.iRadiator == iOld[i]) { + dipNow.iRadiator = iNew[i]; + break; + } + + // Replace ME partner (always in final state, if exists, so simple). + for (int i = 2; i < size; ++i) + if (dipNow.iMEpartner == iOld[i]) { + dipNow.iMEpartner = iNew[i]; + break; + } + + // Recoiler: by default pick old one, only moved. Note excluded beam. + int iRec = 0; + for (int i = 1; i < size; ++i) + if (dipNow.iRecoiler == iOld[i]) { + iRec = iNew[i]; + break; + } + + // QCD recoiler: check if colour hooks up with new final parton. + if ( dipNow.colType > 0 + && event[dipNow.iRadiator].col() == event[iNewNew].acol() ) { + iRec = iNewNew; + dipNow.isrType = 0; + } + if ( dipNow.colType < 0 + && event[dipNow.iRadiator].acol() == event[iNewNew].col() ) { + iRec = iNewNew; + dipNow.isrType = 0; + } + + // QCD recoiler: check if colour hooks up with new beam parton. + if ( iRec == 0 && dipNow.colType > 0 + && event[dipNow.iRadiator].col() == event[iNew[0]].col() ) + iRec = iNew[0]; + if ( iRec == 0 && dipNow.colType < 0 + && event[dipNow.iRadiator].acol() == event[iNew[0]].acol() ) + iRec = iNew[0]; + + // QED/photon recoiler: either to new particle or remains to beam. + if ( iRec == 0 && (dipNow.chgType != 0 || dipNow.gamType != 0) ) { + if ( event[iNew[0]].chargeType() == 0 ) { + iRec = iNewNew; + dipNow.isrType = 0; + } else { + iRec = iNew[0]; + } + } + + // Done. Kill dipole if failed to find new recoiler. + dipNow.iRecoiler = iRec; + if (iRec == 0) { + dipNow.colType = 0; + dipNow.chgType = 0; + dipNow.gamType = 0; + infoPtr->errorMsg("Error in TimeShower::update: " + "failed to locate new recoiling partner"); + } + } + + // Find new dipole end formed by colour index. + int colTag = event[iNewNew].col(); + if (doQCDshower && colTag > 0) setupQCDdip( iSys, size, colTag, 1, event); + + // Find new dipole end formed by anticolour index. + int acolTag = event[iNewNew].acol(); + if (doQCDshower && acolTag > 0) setupQCDdip( iSys, size, acolTag, -1, event); + + // Find new "charge-dipole" and "photon-dipole" ends. + int chgType = event[iNewNew].chargeType(); + bool doChgDip = (chgType != 0) + && ( ( doQEDshowerByQ && event[iNewNew].isQuark() ) + || ( doQEDshowerByL && event[iNewNew].isLepton() ) ); + int gamType = (event[iNewNew].id() == 22) ? 1 : 0; + bool doGamDip = (gamType == 1) && doQEDshowerByGamma; + if (doChgDip || doGamDip) setupQEDdip( iSys, size, chgType, gamType, event); + +} + +//********* + +// Setup a dipole end for a QCD colour charge. + +void TimeShower::setupQCDdip( int iSys, int i, int colTag, int colSign, + Event& event, bool isOctetOnium) { + + // Initial values. Find if allowed to hook up beams. + int iRad = event.getInSystem( iSys, i); + int iRec = 0; + int size = event.sizeSystem( iSys); + int jMin = ( allowBeamRecoil && (event.getInSystem( iSys, 0) > 0) + && (event.getInSystem( iSys, 1) > 0) ) ? 0 : 2; + + // Colour: other end by same index in beam or opposite in final state. + if (colSign > 0) + for (int j = jMin; j < size; ++j) if (j != i) { + int iRecNow = event.getInSystem( iSys, j); + if ( (j < 2 && event[iRecNow].col() == colTag) + || (i > 1 && event[iRecNow].acol() == colTag) ) { + iRec = iRecNow; + break; + } + } + + // Anticolour: other end by same index in beam or opposite in final state. + if (colSign < 0) + for (int j = jMin; j < size; ++j) if (j != i) { + int iRecNow = event.getInSystem( iSys, j); + if ( (j < 2 && event[iRecNow].acol() == colTag) + || (i > 1 && event[iRecNow].col() == colTag) ) { + iRec = iRecNow; + break; + } + } + + // If fail, then other end to nearest recoiler in final state, + // by (p_i + p_j)^2 - (m_i + m_j)^2 = 2 (p_i p_j - m_i m_j). + if (iRec == 0) { + double ppMin = LARGEM2; + for (int j = 2; j < size; ++j) if (j != i) { + int iRecNow = event.getInSystem( iSys, j); + double ppNow = event[iRecNow].p() * event[iRad].p() + - event[iRecNow].m() * event[iRad].m(); + if (ppNow < ppMin) { + iRec = iRecNow; + ppMin = ppNow; + } + } + } + + // Store dipole colour end. + if (iRec > 0) { + double pTmax = event[iRad].scale(); + if (iSys == 0) pTmax *= pTmaxFudge; + int colType = (event[iRad].id() == 21) ? 2 * colSign : colSign; + int isrType = (event[iRec].isFinal()) ? 0 : event[iRec].mother1(); + dipEnd.push_back( TimeDipoleEnd( iRad, iRec, pTmax, + colType, 0, 0, isrType, iSys, -1, -1, isOctetOnium) ); + } + +} + +//********* + +// Setup a dipole end for a QED colour charge or a photon. + +void TimeShower::setupQEDdip( int iSys, int i, int chgType, int gamType, + Event& event) { + + // Initial values. Find if allowed to hook up beams. + int iRad = event.getInSystem( iSys, i); + int iRec = 0; + int size = event.sizeSystem( iSys); + int jMin = ( allowBeamRecoil && (event.getInSystem( iSys, 0) > 0) + && (event.getInSystem( iSys, 1) > 0) ) ? 0 : 2; + + // Find nearest recoiler, charge-squared-weighted + // (p_i + p_j)^2 - (m_i + m_j)^2 = 2 (p_i p_j - m_i m_j). + double ppMin = LARGEM2; + for (int j = jMin; j < size; ++j) if (j != i) { + int iRecNow = event.getInSystem( iSys, j); + int chgTypeRecNow = event[iRecNow].chargeType(); + if (chgTypeRecNow != 0) { + double ppNow = (event[iRecNow].p() * event[iRad].p() + - event[iRecNow].m() * event[iRad].m()) + / pow2(chgTypeRecNow); + if (ppNow < ppMin) { + iRec = iRecNow; + ppMin = ppNow; + } + } + } + + // If fail find any nearest recoiler in final state. + if (iRec == 0) + for (int j = 2; j < size; ++j) if (j != i) { + int iRecNow = event.getInSystem( iSys, j); + double ppNow = event[iRecNow].p() * event[iRad].p() + - event[iRecNow].m() * event[iRad].m(); + if (ppNow < ppMin) { + iRec = iRecNow; + ppMin = ppNow; + } + } + + // Fill charge-dipole or photon-dipole end. + if (iRec > 0) { + double pTmax = event[iRad].scale(); + if (iSys == 0) pTmax *= pTmaxFudge; + int isrType = (event[iRec].isFinal()) ? 0 : event[iRec].mother1(); + dipEnd.push_back( TimeDipoleEnd(iRad, iRec, pTmax, + 0, chgType, gamType, isrType, iSys, -1) ); + } + +} + +//********* + +// Select next pT in downwards evolution of the existing dipoles. + +double TimeShower::pTnext( Event& event, double pTbegAll, double pTendAll) { + + // Begin loop over all possible radiating dipole ends. + dipSel = 0; + double pT2sel = pTendAll * pTendAll; + for (int iDip = 0; iDip < int(dipEnd.size()); ++iDip) { + TimeDipoleEnd& dip = dipEnd[iDip]; + + // Dipole properties. (Could partly be moved up to prepare??) + dip.mRad = event[dip.iRadiator].m(); + dip.m2Rad = pow2(dip.mRad); + dip.mRec = event[dip.iRecoiler].m(); + dip.m2Rec = pow2(dip.mRec); + dip.mDip = m( event[dip.iRadiator], event[dip.iRecoiler] ); + dip.m2Dip = pow2(dip.mDip); + + // Find maximum evolution scale for dipole. + dip.m2DipCorr = pow2(dip.mDip - dip.mRec) - dip.m2Rad; + double pTbegDip = min( pTbegAll, dip.pTmax ); + double pT2begDip = min( pow2(pTbegDip), 0.25 * dip.m2DipCorr); + + // Do QCD or QED evolution if it makes sense. + dip.pT2 = 0.; + if (pT2begDip > pT2sel) { + if (dip.colType != 0) + pT2nextQCD(pT2begDip, pT2sel, dip, event); + else if (dip.chgType != 0 || dip.gamType != 0) + pT2nextQED(pT2begDip, pT2sel, dip, event); + + // Update if found larger pT than current maximum. + if (dip.pT2 > pT2sel) { + pT2sel = dip.pT2; + dipSel = &dip; + } + } + } + + // Return nonvanishing value if found pT bigger than already found. + return (dipSel == 0) ? 0. : sqrt(pT2sel); + +} + +//********* + +// Evolve a QCD dipole end. + +void TimeShower::pT2nextQCD(double pT2begDip, double pT2sel, + TimeDipoleEnd& dip, Event& event) { + + // Lower cut for evolution. Return if no evolution range. + double pT2endDip = max( pT2sel, pT2colCut ); + if (pT2begDip < pT2endDip) return; + + // Upper estimate for matrix element weighting and colour factor. + // Special cases for triplet recoiling against gluino and octet onia. + // Note that g -> g g and g -> q qbar are split on two sides. + int colTypeAbs = abs(dip.colType); + double wtPSglue = 2.; + double colFac = (colTypeAbs == 1) ? 4./3. : 3./2.; + if (dip.MEgluinoRec) colFac = 3.; + if (dip.isOctetOnium) colFac *= 0.5 * octetOniumColFac; + double wtPSqqbar = (colTypeAbs == 2) ? 0.25 * nGluonToQuark : 0.; + + // Variables used inside evolution loop. (Mainly dummy start values.) + dip.pT2 = pT2begDip; + int nFlavour = 3; + double zMinAbs = 0.5; + double pT2min = pT2endDip; + double b0 = 4.5; + double Lambda2 = Lambda3flav2; + double emitCoefGlue = 0.; + double emitCoefQqbar = 0.; + double emitCoefTot = 0.; + double wt = 0.; + bool mustFindRange = true; + + // Begin evolution loop towards smaller pT values. + do { + + // Initialize evolution coefficients at the beginning and + // reinitialize when crossing c and b flavour thresholds. + if (mustFindRange) { + + // Determine overestimated z range; switch at c and b masses. + if (dip.pT2 > m2b) { + nFlavour = 5; + pT2min = m2b; + b0 = 23./6.; + Lambda2 = Lambda5flav2; + } else if (dip.pT2 > m2c) { + nFlavour = 4; + pT2min = m2c; + b0 = 25./6.; + Lambda2 = Lambda4flav2; + } else { + nFlavour = 3; + pT2min = pT2endDip; + b0 = 27./6.; + Lambda2 = Lambda3flav2; + } + zMinAbs = 0.5 - sqrtpos( 0.25 - pT2min / dip.m2DipCorr ); + if (zMinAbs < SIMPLIFYROOT) zMinAbs = pT2min / dip.m2DipCorr; + + // Find emission coefficients for X -> X g and g -> q qbar. + emitCoefGlue = wtPSglue * colFac * log(1. / zMinAbs - 1.); + emitCoefTot = emitCoefGlue; + if (colTypeAbs == 2 && event[dip.iRadiator].id() == 21) { + emitCoefQqbar = wtPSqqbar * (1. - 2. * zMinAbs); + emitCoefTot += emitCoefQqbar; + } + + // Initialization done for current range. + mustFindRange = false; + } + + // Pick pT2 (in overestimated z range) for fixed alpha_strong. + if (alphaSorder == 0) { + dip.pT2 = dip.pT2 * pow( Rndm::flat(), + 1. / (alphaS2pi * emitCoefTot) ); + + // Ditto for first-order alpha_strong. + } else if (alphaSorder == 1) { + dip.pT2 = Lambda2 * pow( dip.pT2 / Lambda2, + pow( Rndm::flat(), b0 / emitCoefTot) ); + + // For second order reject by second term in alpha_strong expression. + } else { + do dip.pT2 = Lambda2 * pow( dip.pT2 / Lambda2, + pow( Rndm::flat(), b0 / emitCoefTot) ); + while (alphaS.alphaS2OrdCorr(dip.pT2) < Rndm::flat() + && dip.pT2 > pT2min); + } + wt = 0.; + + // If crossed c or b thresholds: continue evolution from threshold. + if (nFlavour == 5 && dip.pT2 < m2b) { + mustFindRange = true; + dip.pT2 = m2b; + } else if ( nFlavour == 4 && dip.pT2 < m2c) { + mustFindRange = true; + dip.pT2 = m2c; + + // Abort evolution if below cutoff scale, or below another branching. + } else { + if ( dip.pT2 < pT2endDip) { dip.pT2 = 0.; return; } + + // Pick kind of branching: X -> X g or g -> q qbar. + dip.flavour = 21; + dip.mFlavour = 0.; + if (colTypeAbs == 2 && emitCoefQqbar > Rndm::flat() + * emitCoefTot) dip.flavour = 0; + + // Pick z: either dz/(1-z) or flat dz. + if (dip.flavour == 21) { + dip.z = 1. - zMinAbs * pow( 1. / zMinAbs - 1., Rndm::flat() ); + } else { + dip.z = zMinAbs + (1. - 2. * zMinAbs) * Rndm::flat(); + } + + // Do not accept branching if outside allowed z range. + double zMin = 0.5 - sqrtpos( 0.25 - dip.pT2 / dip.m2DipCorr ); + if (zMin < SIMPLIFYROOT) zMin = dip.pT2 / dip.m2DipCorr; + dip.m2 = dip.m2Rad + dip.pT2 / (dip.z * (1. - dip.z)); + if (dip.z > zMin && dip.z < 1. - zMin + && dip.m2 * dip.m2Dip < dip.z * (1. - dip.z) + * pow2(dip.m2Dip + dip.m2 - dip.m2Rec) ) { + + // Flavour choice for g -> q qbar. + if (dip.flavour == 0) { + dip.flavour = min(5, 1 + int(nGluonToQuark * Rndm::flat())); + dip.mFlavour = ParticleDataTable::m0(dip.flavour); + } + + // No z weight, except threshold, if to do ME corrections later on. + if (dip.MEtype > 0) { + wt = 1.; + if (dip.flavour < 10 && dip.m2 < THRESHM2 * pow2(dip.mFlavour)) + wt = 0.; + + // z weight for X -> X g. + } else if (dip.flavour == 21 && colTypeAbs == 1) { + wt = (1. + pow2(dip.z)) / wtPSglue; + } else if (dip.flavour == 21) { + wt = (1. + pow3(dip.z)) / wtPSglue; + + // z weight for g -> q qbar. + } else { + double beta = sqrtpos( 1. - 4. * pow2(dip.mFlavour) / dip.m2 ); + wt = beta * ( pow2(dip.z) + pow2(1. - dip.z) ); + } + + // For dipole to beam remnant reduce by PDF ratio (approximate!??). + if (dip.isrType != 0) { + BeamParticle& beam = (dip.isrType == 1) ? *beamAPtr : *beamBPtr; + int iSys = dip.system; + double xOld = beam[iSys].x(); + double xNew = xOld * (1. + (dip.m2 - dip.m2Rad) / + (dip.m2Dip - dip.m2Rad)); + if (xNew > beam.xMax(iSys)) wt = 0.; + else { + int idRec = event[dip.iRecoiler].id(); + double pdfOld = max ( TINYPDF, + beam.xfISR( iSys, idRec, xOld, dip.pT2) ); + double pdfNew = beam.xfISR( iSys, idRec, xNew, dip.pT2); + wt *= min( 1., pdfNew / pdfOld); + } + } + } + } + + // Iterate until acceptable pT (or have fallen below pTmin). + } while (wt < Rndm::flat()); + +} + +//********* + +// Evolve a QED dipole end, either charged or photon. + +void TimeShower::pT2nextQED(double pT2begDip, double pT2sel, + TimeDipoleEnd& dip, Event& event) { + + // Lower cut for evolution. Return if no evolution range. + double pT2chgCut = (dip.chgType != 0 && abs(dip.chgType) != 3) + ? pT2chgQCut : pT2chgLCut; + double pT2endDip = max( pT2sel, pT2chgCut ); + if (pT2begDip < pT2endDip) return; + + // Emission of photon or photon branching. + bool hasCharge = (dip.chgType != 0); + + // Default values. + double wtPSgam = 0.; + double chg2Sum = 0.; + double chg2SumL = 0.; + double chg2SumQ = 0.; + double zMinAbs = 0.; + double emitCoefTot = 0.; + + // alpha_em at maximum scale provides upper estimate. + double alphaEMmax = alphaEM.alphaEM(pT2begDip); + double alphaEM2pi = alphaEMmax / (2. * M_PI); + + // Emission: upper estimate for matrix element weighting; charge factor. + if (hasCharge) { + wtPSgam = 2.; + double chg2 = pow2(dip.chgType / 3.); + + // Determine overestimated z range. Find evolution coefficient. + zMinAbs = 0.5 - sqrtpos( 0.25 - pT2endDip / dip.m2DipCorr ); + if (zMinAbs < SIMPLIFYROOT) zMinAbs = pT2endDip / dip.m2DipCorr; + emitCoefTot = alphaEM2pi * chg2 * wtPSgam * log(1. / zMinAbs - 1.); + + // Branching: sum of squared charge factors for lepton and quark daughters. + } else { + chg2SumL = max(0, min(3, nGammaToLepton)); + if (nGammaToQuark > 4) chg2SumQ = 11. / 9.; + else if (nGammaToQuark > 3) chg2SumQ = 10. / 9.; + else if (nGammaToQuark > 2) chg2SumQ = 6. / 9.; + else if (nGammaToQuark > 1) chg2SumQ = 5. / 9.; + else if (nGammaToQuark > 0) chg2SumQ = 1. / 9.; + + // Total sum of squared charge factors. Find evolution coefficient. + chg2Sum = chg2SumL + 3. * chg2SumQ; + emitCoefTot = alphaEM2pi * chg2Sum; + } + + // Variables used inside evolution loop. + dip.pT2 = pT2begDip; + double wt; + + // Begin evolution loop towards smaller pT values. + do { + + // Pick pT2 (in overestimated z range). + dip.pT2 = dip.pT2 * pow(Rndm::flat(), 1. / emitCoefTot); + wt = 0.; + + // Abort evolution if below cutoff scale, or below another branching. + if ( dip.pT2 < pT2endDip) { dip.pT2 = 0.; return; } + + // Pick z according to dz/(1-z) or flat. + if (hasCharge) dip.z = 1. - zMinAbs + * pow( 1. / zMinAbs - 1., Rndm::flat() ); + else dip.z = Rndm::flat(); + + // Do not accept branching if outside allowed z range. + double zMin = 0.5 - sqrtpos( 0.25 - dip.pT2 / dip.m2DipCorr ); + if (zMin < SIMPLIFYROOT) zMin = dip.pT2 / dip.m2DipCorr; + dip.m2 = dip.m2Rad + dip.pT2 / (dip.z * (1. - dip.z)); + if (dip.z > zMin && dip.z < 1. - zMin + && dip.m2 * dip.m2Dip < dip.z * (1. - dip.z) + * pow2(dip.m2Dip + dip.m2 - dip.m2Rec) + // For gamma -> f fbar also impose maximum mass. + && (hasCharge || dip.m2 < m2MaxGamma) ) { + + // Photon emission: unique flavour choice. + if (hasCharge) { + dip.flavour = 22; + dip.mFlavour = 0.; + + // Photon branching: either lepton or quark flavour choice. + } else { + if (Rndm::flat() * chg2Sum < chg2SumL) + dip.flavour = 9 + 2 * min(3, 1 + int(chg2SumL * Rndm::flat())); + else { + double rndmQ = 9. * chg2SumQ * Rndm::flat(); + if (rndmQ < 1.) dip.flavour = 1; + else if (rndmQ < 5.) dip.flavour = 2; + else if (rndmQ < 6.) dip.flavour = 3; + else if (rndmQ < 10.) dip.flavour = 4; + else dip.flavour = 5; + } + dip.mFlavour = ParticleDataTable::m0(dip.flavour); + } + + + // No z weight, except threshold, if to do ME corrections later on. + if (dip.MEtype > 0) { + wt = 1.; + if (dip.flavour < 20 && dip.m2 < THRESHM2 * pow2(dip.mFlavour)) + wt = 0.; + + // z weight for X -> X gamma. + } else if (hasCharge) { + wt = (1. + pow2(dip.z)) / wtPSgam; + + // z weight for gamma -> f fbar. + } else { + double beta = sqrtpos( 1. - 4. * pow2(dip.mFlavour) / dip.m2 ); + wt = beta * ( pow2(dip.z) + pow2(1. - dip.z) ); + } + + // Correct to current value of alpha_EM. + double alphaEMnow = alphaEM.alphaEM(dip.pT2); + wt *= (alphaEMnow / alphaEMmax); + + // For dipole to beam remnant reduce by PDF ratio (approximate!??). + if (dip.isrType != 0) { + BeamParticle& beam = (dip.isrType == 1) ? *beamAPtr : *beamBPtr; + int iSys = dip.system; + double xOld = beam[iSys].x(); + double xNew = xOld * (1. + (dip.m2 - dip.m2Rad) / + (dip.m2Dip - dip.m2Rad)); + if (xNew > beam.xMax(iSys)) wt = 0.; + else { + int idRec = event[dip.iRecoiler].id(); + double pdfOld = max ( TINYPDF, + beam.xfISR( iSys, idRec, xOld, dip.pT2) ); + double pdfNew = beam.xfISR( iSys, idRec, xNew, dip.pT2); + wt *= min( 1., pdfNew / pdfOld); + } + } + } + + // Iterate until acceptable pT (or have fallen below pTmin). + } while (wt < Rndm::flat()); + +} + +//********* + +// ME corrections and kinematics that may give failure. +// Notation: radBef, recBef = radiator, recoiler before emission, +// rad, rec, emt = radiator, recoiler, emitted efter emission. +// (rad, emt distinguished by colour flow for g -> q qbar.) + +bool TimeShower::branch( Event& event) { + + // Find initial particles in dipole branching. + int iRadBef = dipSel->iRadiator; + int iRecBef = dipSel->iRecoiler; + Particle& radBef = event[iRadBef]; + Particle& recBef = event[iRecBef]; + + // Default flavours and colour tags for new particles in dipole branching. + int idRad = radBef.id(); + int idEmt = dipSel->flavour; + int colRad = radBef.col(); + int acolRad = radBef.acol(); + int colEmt = 0; + int acolEmt = 0; + iSysSel = dipSel->system; + + // Default OK for photon emission. + if (dipSel->flavour == 22) { + // New colour tag required for gluon emission. + } else if (dipSel->flavour == 21 && dipSel->colType > 0) { + colEmt = colRad; + colRad = event.nextColTag(); + acolEmt = colRad; + } else if (dipSel->flavour == 21) { + acolEmt = acolRad; + acolRad = event.nextColTag(); + colEmt = acolRad; + // New flavours for g -> q qbar; split colours. + } else if (dipSel->colType > 0) { + idEmt = dipSel->flavour ; + idRad = -idEmt; + colEmt = colRad; + colRad = 0; + } else if (dipSel->colType < 0) { + idEmt = -dipSel->flavour ; + idRad = -idEmt; + acolEmt = acolRad; + acolRad = 0; + // New flavours for gamma -> f fbar, and maybe also colours. + } else if (dipSel->gamType == 1 && Rndm::flat() > 0.5) { + idEmt = -dipSel->flavour ; + idRad = -idEmt; + if (idRad < 10) colRad = event.nextColTag(); + acolEmt = colRad; + } else if (dipSel->gamType == 1) { + idEmt = dipSel->flavour ; + idRad = -idEmt; + if (idEmt < 10) colEmt = event.nextColTag(); + acolRad = colEmt; + } + + // Construct kinematics in dipole rest frame: + // begin simple (like g -> g g). + double eRadPlusEmt = 0.5 * (dipSel->m2Dip + dipSel->m2 - dipSel->m2Rec) + / dipSel->mDip; + double e2RadPlusEmt = pow2(eRadPlusEmt); + double pzRadPlusEmt = 0.5 * sqrtpos( pow2(dipSel->m2Dip - dipSel->m2 + - dipSel->m2Rec) - 4. * dipSel->m2 * dipSel->m2Rec ) / dipSel->mDip; + double pT2corr = dipSel->m2 * (e2RadPlusEmt * dipSel->z * (1. - dipSel->z) + - 0.25 * dipSel->m2) / pow2(pzRadPlusEmt); + double pTcorr = sqrtpos( pT2corr ); + double pzRad = (e2RadPlusEmt * dipSel->z - 0.5 * dipSel->m2) + / pzRadPlusEmt; + double pzEmt = (e2RadPlusEmt * (1. - dipSel->z) - 0.5 * dipSel->m2) + / pzRadPlusEmt; + double mRad = dipSel->mRad; + double mEmt = 0.; + + // Kinematics reduction for q -> q g or q -> q gamma when m_q > 0. + if (abs(dipSel->colType) == 1 || dipSel->chgType != 0) { + pTcorr *= 1. - dipSel->m2Rad / dipSel->m2; + pzRad += pzEmt * dipSel->m2Rad / dipSel->m2; + pzEmt *= 1. - dipSel->m2Rad / dipSel->m2; + // Kinematics reduction for g -> q qbar or gamma -> f fbar when m_f > 0; + } else if (abs(dipSel->flavour) < 20) { + mEmt = dipSel->mFlavour; + mRad = mEmt; + double beta = sqrtpos( 1. - 4. * pow2(mEmt) / dipSel->m2 ); + pTcorr *= beta; + pzRad = 0.5 * ( (1. + beta) * pzRad + (1. - beta) * pzEmt ); + pzEmt = pzRadPlusEmt - pzRad; + } + + // Find rest frame and angles of original dipole. + RotBstMatrix M; + M.fromCMframe(radBef.p(), recBef.p()); + + // Evaluate coefficient of azimuthal asymmetry from gluon polarization. + findAsymPol( event, dipSel); + + // Begin construction of new dipole kinematics: pick azimuthal angle. + Vec4 pRad, pEmt, pRec; + double wtPhi = 1.; + do { + double phi = 2. * M_PI * Rndm::flat(); + + // Define kinematics of branching in dipole rest frame. + pRad = Vec4( pTcorr * cos(phi), pTcorr * sin(phi), pzRad, + sqrt( pow2(pTcorr) + pow2(pzRad) + pow2(mRad) ) ); + pEmt = Vec4( -pRad.px(), -pRad.py(), pzEmt, + sqrt( pow2(pTcorr) + pow2(pzEmt) + pow2(mEmt) ) ); + pRec = Vec4( 0., 0., -pzRadPlusEmt, sqrt( pow2(pzRadPlusEmt) + + dipSel->m2Rec ) ); + + // Rotate and boost dipole products to the event frame. + pRad.rotbst(M); + pEmt.rotbst(M); + pRec.rotbst(M); + + // Azimuthal phi weighting: loop to new phi value if required. + if (dipSel->asymPol != 0.) { + Vec4 pRadBef = event[iRadBef].p(); + Vec4 pAunt = event[dipSel->iAunt].p(); + double cosPhi = cosphi( pRad, pAunt, pRadBef ); + wtPhi = ( 1. + dipSel->asymPol * (2. * pow2(cosPhi) - 1.) ) + / ( 1. + abs(dipSel->asymPol) ); + } + } while (wtPhi < Rndm::flat()) ; + + // Kinematics when recoiler is initial-state parton. + int isrTypeNow = dipSel->isrType; + if (isrTypeNow != 0) pRec = 2. * recBef.p() - pRec; + + // Define new particles from dipole branching. + double pTsel = sqrt(dipSel->pT2); + Particle rad = Particle(idRad, 51, iRadBef, 0, 0, 0, + colRad, acolRad, pRad, mRad, pTsel); + Particle emt = Particle(idEmt, 51, iRadBef, 0, 0, 0, + colEmt, acolEmt, pEmt, mEmt, pTsel); + + // Recoiler either in final or in initial state + Particle rec = (isrTypeNow == 0) + ? Particle(recBef.id(), 52, iRecBef, iRecBef, 0, 0, + recBef.col(), recBef.acol(), pRec, dipSel->mRec, pTsel) + : Particle(recBef.id(), -53, 0, 0, iRecBef, iRecBef, + recBef.col(), recBef.acol(), pRec, 0., 0.); + + // ME corrections can lead to branching being rejected. + if (dipSel->MEtype > 0) { + Particle& partner = (dipSel->iMEpartner == iRecBef) + ? rec : event[dipSel->iMEpartner]; + if ( findMEcorr( dipSel, rad, partner, emt) < Rndm::flat() ) + return false; + } + + // Put new particles into the event record. + int iRad = event.append(rad); + int iEmt = event.append(emt); + int iRec = event.append(rec); + + // Mark original dipole partons as branched and set daughters/mothers. + event[dipSel->iRadiator].statusNeg(); + event[dipSel->iRadiator].daughters( iRad, iEmt); + if (isrTypeNow == 0) { + event[dipSel->iRecoiler].statusNeg(); + event[dipSel->iRecoiler].daughters( iRec, iRec); + } else { + int mother1 = event[dipSel->iRecoiler].mother1(); + int mother2 = event[dipSel->iRecoiler].mother2(); + event[dipSel->iRecoiler].mothers( iRec, iRec); + event[iRec].mothers( mother1, mother2); + if (mother1 == 1) event[1].daughter1( iRec); + if (mother1 == 2) event[2].daughter1( iRec); + // For initial-state recoiler also update beam info. + BeamParticle& beamRec = (mother1 == 1) ? *beamAPtr : *beamBPtr; + double xRec = pRec.e() / beamRec.e(); + beamRec[iSysSel].iPos( iRec); + beamRec[iSysSel].x( xRec); + } + + // Photon emission: update to new dipole ends; add new photon "dipole". + if (dipSel->flavour == 22) { + dipSel->iRadiator = iRad; + dipSel->iRecoiler = iRec; + dipSel->pTmax = pTsel; + if (doQEDshowerByGamma) dipEnd.push_back( TimeDipoleEnd(iEmt, iRad, + pTsel, 0, 0, 1, 0, iSysSel, 0)); + + // Gluon emission: update both dipole ends and add two new ones. + } else if (dipSel->flavour == 21) { + dipSel->iRadiator = iRad; + dipSel->iRecoiler = iEmt; + dipSel->isrType = 0; + dipSel->pTmax = pTsel; + for (int i = 0; i < int(dipEnd.size()); ++i) { + if (dipEnd[i].iRadiator == iRecBef && dipEnd[i].iRecoiler == iRadBef + && dipEnd[i].colType != 0) { + dipEnd[i].iRadiator = iRec; + dipEnd[i].iRecoiler = iEmt; + // Strive to match colour to anticolour inside closed system. + if (dipEnd[i].colType * dipSel->colType > 0) + dipEnd[i].iRecoiler = iRad; + dipEnd[i].pTmax = pTsel; + } + } + int colType = (dipSel->colType > 0) ? 2 : -2 ; + dipEnd.push_back( TimeDipoleEnd(iEmt, iRec, pTsel, + colType, 0, 0, isrTypeNow, iSysSel, 0)); + dipEnd.push_back( TimeDipoleEnd(iEmt, iRad, pTsel, + -colType, 0, 0, 0, iSysSel, 0)); + + // Gluon branching to q qbar: update current dipole and other of gluon. + } else if (dipSel->colType != 0) { + for (int i = 0; i < int(dipEnd.size()); ++i) { + if (dipEnd[i].iRadiator == iRadBef && abs(dipEnd[i].colType) == 2) { + dipEnd[i].colType /= 2; + // Note: gluino -> quark + squark gives a deeper radiation dip than + // the more obvious alternative photon decay, so is more realistic. + dipEnd[i].MEtype = 66; + if (&dipEnd[i] == dipSel) dipEnd[i].iMEpartner = iRad; + else dipEnd[i].iMEpartner = iEmt; + } + // Strive to match colour to anticolour inside closed system. + if ( dipEnd[i].iRecoiler == iRadBef + && dipEnd[i].colType * dipSel->colType < 0 ) + dipEnd[i].iRecoiler = iEmt; + } + dipSel->iRadiator = iEmt; + dipSel->iRecoiler = iRec; + dipSel->pTmax = pTsel; + + // Gluon branching to q qbar: also add two charge dipole ends. + // Note: gluino -> quark + squark gives a deeper radiation dip than + // the more obvious alternative photon decay, so is more realistic. + if (doQEDshowerByQ) { + int chgType = event[iRad].chargeType(); + dipEnd.push_back( TimeDipoleEnd(iRad, iEmt, pTsel, + 0, chgType, 0, 0, iSysSel, 66, iEmt)); + dipEnd.push_back( TimeDipoleEnd(iEmt, iRad, pTsel, + 0, -chgType, 0, 0, iSysSel, 66, iRad)); + } + + // Photon branching to f fbar: inactivate photon "dipole"; + // optionally add new charge and colour dipole ends. + } else if (dipSel->gamType != 0) { + dipSel->gamType = 0; + int chgType = event[iRad].chargeType(); + int colType = event[iRad].colType(); + // MEtype = 102 for charge in vector decay. + if ( chgType != 0 && ( ( doQEDshowerByQ && colType != 0 ) + || ( doQEDshowerByL && colType == 0 ) ) ) { + dipEnd.push_back( TimeDipoleEnd(iRad, iEmt, pTsel, + 0, chgType, 0, 0, iSysSel, 102, iEmt)); + dipEnd.push_back( TimeDipoleEnd(iEmt, iRad, pTsel, + 0, -chgType, 0, 0, iSysSel, 102, iRad)); + } + // MEtype = 11 for colour in vector decay. + if (colType != 0 && doQCDshower) { + dipEnd.push_back( TimeDipoleEnd(iRad, iEmt, pTsel, + colType, 0, 0, 0, iSysSel, 11, iEmt)); + dipEnd.push_back( TimeDipoleEnd(iEmt, iRad, pTsel, + -colType, 0, 0, 0, iSysSel, 11, iRad)); + } + } + + // Now update other dipoles that also involved the radiator or recoiler. + for (int i = 0; i < int(dipEnd.size()); ++i) { + if (dipEnd[i].iRadiator == iRadBef) dipEnd[i].iRadiator = iRad; + if (dipEnd[i].iRadiator == iRecBef) dipEnd[i].iRadiator = iRec; + if (dipEnd[i].iRecoiler == iRadBef) dipEnd[i].iRecoiler = iRad; + if (dipEnd[i].iRecoiler == iRecBef) dipEnd[i].iRecoiler = iRec; + if (dipEnd[i].iMEpartner == iRadBef) dipEnd[i].iMEpartner = iRad; + if (dipEnd[i].iMEpartner == iRecBef) dipEnd[i].iMEpartner = iRec; + } + + // Finally update the list of all partons in all systems. + event.replaceInSystem(iSysSel, iRadBef, iRad); + event.addToSystem(iSysSel, iEmt); + event.replaceInSystem(iSysSel, iRecBef, iRec); + + // Done. + return true; + +} + +//********* + +// Find class of QCD ME correction. +// MEtype classification follow codes in Norrbin article, +// additionally -1 = try to find type, 0 = no ME corrections. +// Warning: not yet tried out to do a correct assignment in +// arbitrary multiparton configurations! ?? + +void TimeShower::findMEtype( Event& event, TimeDipoleEnd& dip) { + + // Initial value. Mark if no ME corrections to be applied. + bool setME = true; + if (!doMEcorrections) setME = false; + + // No ME corrections in 2 -> n processes. + int iMother = event[dip.iRadiator].mother1(); + int iMother2 = event[dip.iRadiator].mother2(); + if (iMother2 != iMother && iMother2 != 0) setME = false; + if (event[dip.iRecoiler].mother1() != iMother) setME = false; + if (event[dip.iRecoiler].mother2() != iMother2) setME = false; + + // No ME corrections for recoiler in initial state. + if (event[dip.iRecoiler].status() < 0) setME = false; + + // Done if no ME to be set. + if (!setME) { + dip.MEtype = 0; + return; + } + + // If no ME partner set, assume it is the recoiler. + if (dip.iMEpartner < 0) dip.iMEpartner = dip.iRecoiler; + + // Now begin processing of colour dipole. + if (dip.colType != 0) { + + // Find daughter types (may or may not be used later on). + int idDau1 = event[dip.iRadiator].id(); + int idDau2 = event[dip.iMEpartner].id(); + int dau1Type = findMEparticle(idDau1); + int dau2Type = findMEparticle(idDau2); + int minDauType = min(dau1Type, dau2Type); + int maxDauType = max(dau1Type, dau2Type); + + // Reorder dipole ends in kinematics. Split ME expression in two sides. + dip.MEorder = (dau2Type >= dau1Type); + dip.MEsplit = (maxDauType <= 6); + dip.MEgluinoRec = false; + + // If type already set (or set not to have) then done. + if (minDauType == 0 && dip.MEtype < 0) dip.MEtype = 0; + if (dip.MEtype >= 0) return; + dip.MEtype = 0; + + // For H -> gg -> ggg we found that DGLAP kernels do better than eikonal. + if (dau1Type == 4 && dau2Type == 4) return; + + // Find mother type. + int idMother = 0; + if ( event[dip.iRecoiler].mother1() == iMother && iMother >= 0) + idMother = event[iMother].id(); + int motherType = (idMother != 0) ? findMEparticle(idMother) : 0; + + // When a mother if not known then use colour and spin content to guess. + if (motherType == 0) { + int col1 = event[dip.iRadiator].col(); + int acol1 = event[dip.iRadiator].acol(); + int col2 = event[dip.iMEpartner].col(); + int acol2 = event[dip.iMEpartner].acol(); + // spinT = 0/1 = integer or half-integer. + int spinT = ( event[dip.iRadiator].spinType() + + event[dip.iMEpartner].spinType() )%2; + // Colour singlet mother. + if ( col1 == acol2 && acol1 == col2 ) + motherType = (spinT == 0) ? 7 : 9; + // Colour octet mother. + else if ( (col1 == acol2 && acol1 != 0 && col2 != 0) + || (acol1 == col2 && col1 != 0 && acol2 != 0) ) + motherType = (spinT == 0) ? 4 : 5; + // Colour triplet mother. + else if ( (col1 == acol2 && acol1 != col2) + || (acol1 == col2 && col1 != acol2) ) + motherType = (spinT == 0) ? 2 : 1; + // If no colours are matched then cannot have common mother, so done. + else return; + } + + // Now start from default, which is eikonal ME corrections, + // and try to find matching ME cases below. + int MEkind = 0; + int MEcombi = 4; + dip.MEmix = 0.5; + + // Triplet recoiling against gluino needs enhanced radiation + // to match to matrix elements. + dip.MEgluinoRec = (dau1Type >= 1 && dau1Type <= 3 && dau2Type == 5); + + // Vector/axial vector -> q + qbar. + if (minDauType == 1 && maxDauType == 1 && + (motherType == 4 || motherType == 7) ) { + MEkind = 2; + if (idMother == 21 || idMother == 22) MEcombi = 1; + else if (idMother == 23 || idDau1 + idDau2 == 0) { + MEcombi = 3; + dip.MEmix = gammaZmix( event, iMother, dip.iRadiator, dip.iRecoiler ); + } + else if (idMother == 24) MEcombi = 4; + } + // For chi -> chi q qbar, use V/A -> q qbar as first approximation. + else if (minDauType == 1 && maxDauType == 1 && motherType == 9) + MEkind = 2; + + // q -> q + V. + else if (minDauType == 1 && maxDauType == 7 && motherType == 1) + MEkind = 3; + if (idDau1 == 22 || idDau2 == 22) MEcombi = 1; + + // Scalar/pseudoscalar -> q + qbar; q -> q + S. + else if (minDauType == 1 && maxDauType == 1 && motherType == 8) { + MEkind = 4; + if (idMother == 25 || idMother == 35 || idMother == 37) MEcombi = 1; + else if (idMother == 36) MEcombi = 2; + } + else if (minDauType == 1 && maxDauType == 8 && motherType == 1) + MEkind = 5; + + // V -> ~q + ~qbar; ~q -> ~q + V; S -> ~q + ~qbar; ~q -> ~q + S. + else if (minDauType == 2 && maxDauType == 2 && (motherType == 4 + || motherType == 7) ) MEkind = 6; + else if (minDauType == 2 && (maxDauType == 4 || maxDauType == 7) + && motherType == 2) MEkind = 7; + else if (minDauType == 2 && maxDauType == 2 && motherType == 8) + MEkind = 8; + else if (minDauType == 2 && maxDauType == 8 && motherType == 2) + MEkind = 9; + + // chi -> q + ~qbar; ~q -> q + chi; q -> ~q + chi. + else if (minDauType == 1 && maxDauType == 2 && motherType == 9) + MEkind = 10; + else if (minDauType == 1 && maxDauType == 9 && motherType == 2) + MEkind = 11; + else if (minDauType == 2 && maxDauType == 9 && motherType == 1) + MEkind = 12; + + // ~g -> q + ~qbar; ~q -> q + ~g; q -> ~q + ~g. + else if (minDauType == 1 && maxDauType == 2 && motherType == 5) + MEkind = 13; + else if (minDauType == 1 && maxDauType == 5 && motherType == 2) + MEkind = 14; + else if (minDauType == 2 && maxDauType == 5 && motherType == 1) + MEkind = 15; + + // g (+V, S) -> ~g + ~g (eikonal approximation). + else if (minDauType == 5 && maxDauType == 5) MEkind = 16; + + // Save ME type and gamma_5 admixture. + dip.MEtype = 5 * MEkind + MEcombi; + + // Now begin processing of charge dipole - still primitive. + } else if (dip.chgType != 0) { + + // Set defaults for QED case; then possibly done. + dip.MEorder = true; + dip.MEsplit = true; + if (dip.MEtype >= 0) return; + + // So far only ME corrections for q qbar or l lbar. + int idDau1 = event[dip.iRadiator].id(); + int idDau2 = event[dip.iMEpartner].id(); + if (abs(idDau1) < 9 && abs(idDau2) < 9 && idDau1 * idDau2 < 0) ; + else if (abs(idDau1) > 10 && abs(idDau1) < 19 && abs(idDau2) > 10 + && abs(idDau2) < 19 && idDau1 * idDau2 < 0) ; + else { dip.MEtype = 0; return; } + + // Distinguish charge sum != 0 or = 0; in latter assume vector source. + dip.MEtype = 101; + if (idDau1 + idDau2 == 0) dip.MEtype = 102; + dip.MEmix = 1.; + } + +} + +//********* + +// Find type of particle for ME type: 0 = unknown, 1 = quark, 2 = squark, +// 3 = spare triplet, 4 = gluon, 5 = gluino, 6 = spare octet, +// 7 = vector boson, 8 = colourless scalar, 9 = colourless spin 1/2. + +int TimeShower::findMEparticle( int id) { + + // find colour and spin of particle. + int type = 0; + int colType = abs(ParticleDataTable::colType(id)); + int spinType = ParticleDataTable::spinType(id); + + // Find particle type from colour and spin. + if (colType == 1 && spinType == 2) type = 1; + else if (colType == 1 && spinType == 1) type = 2; + else if (colType == 1) type = 3; + else if (colType == 2 && spinType == 3) type = 4; + else if (colType == 2 && spinType == 2) type = 5; + else if (colType == 2) type = 6; + else if (colType == 0 && spinType == 3) type = 7; + else if (colType == 0 && spinType == 1) type = 8; + else if (colType == 0 && spinType == 2) type = 9; + + // Done. + return type; + +} + +//********* + +// Find mixture of V and A in gamma/Z: energy- and flavour-dependent. + +double TimeShower::gammaZmix( Event& event, int iRes, int iDau1, int iDau2) { + + // Try to identify initial flavours; use e+e- as default. + int idIn1 = -11; + int idIn2 = 11; + int iIn1 = (iRes >= 0) ? event[iRes].mother1() : -1; + int iIn2 = (iRes >= 0) ? event[iRes].mother2() : -1; + if (iIn1 >=0) idIn1 = event[iIn1].id(); + if (iIn2 >=0) idIn2 = event[iIn1].id(); + + // In processes f + g/gamma -> f + Z only need find one fermion. + if (idIn1 == 21 || idIn1 == 22) idIn1 = -idIn2; + if (idIn2 == 21 || idIn2 == 22) idIn2 = -idIn1; + + // Initial flavours and couplings; return if don't make sense. + if (idIn1 + idIn2 != 0 ) return 0.5; + int idInAbs = abs(idIn1); + if (idInAbs == 0 || idInAbs > 18 ) return 0.5; + double ei = CoupEW::ef(idInAbs); + double vi = CoupEW::vf(idInAbs); + double ai = CoupEW::af(idInAbs); + + // Final flavours and couplings; return if don't make sense. + if (event[iDau1].id() + event[iDau2].id() != 0) return 0.5; + int idOutAbs = abs(event[iDau1].id()); + if (idOutAbs == 0 || idOutAbs >18 ) return 0.5; + double ef = CoupEW::ef(idOutAbs); + double vf = CoupEW::vf(idOutAbs); + double af = CoupEW::af(idOutAbs); + + // Calculate prefactors for interference and resonance part. + Vec4 psum = event[iDau1].p() + event[iDau2].p(); + double sH = psum.m2Calc(); + double intNorm = 2. * thetaWRat * sH * (sH - mZ*mZ) + / ( pow2(sH - mZ*mZ) + pow2(sH * gammaZ / mZ) ); + double resNorm = pow2(thetaWRat * sH) + / ( pow2(sH - mZ*mZ) + pow2(sH * gammaZ / mZ) ); + + // Calculate vector and axial expressions and find mix. + double vect = ei*ei * ef*ef + ei*vi * intNorm * ef*vf + + (vi*vi + ai*ai) * resNorm * vf*vf; + double axiv = (vi*vi + ai*ai) * resNorm * af*af; + return vect / (vect + axiv); +} + +//********* + +// Set up to calculate QCD ME correction with calcMEcorr. +// Normally for primary particles, but also from g/gamma -> f fbar. + +double TimeShower::findMEcorr(TimeDipoleEnd* dip, Particle& rad, + Particle& partner, Particle& emt) { + + // Initial values and matrix element kind. + //cout << "\n enter findMEcorr " << dip->MEtype << " " << rad.id() + // << " " << partner.id() << " " << emt.id() << endl; + double wtME = 1.; + double wtPS = 1.; + int MEkind = dip->MEtype / 5; + int MEcombi = dip->MEtype % 5; + + // Construct ME variables. + Vec4 sum = rad.p() + partner.p() + emt.p(); + double eCMME = sum.mCalc(); + double x1 = 2. * (sum * rad.p()) / pow2(eCMME); + double x2 = 2. * (sum * partner.p()) / pow2(eCMME); + double r1 = rad.m() / eCMME; + double r2 = partner.m() / eCMME; + + // Derived ME variables, suitably protected. + double x1minus = max(XMARGIN, 1. + r1*r1 - r2*r2 - x1); + double x2minus = max(XMARGIN, 1. + r2*r2 - r1*r1 - x2) ; + double x3 = max(XMARGIN, 2. - x1 - x2); + //cout << scientific << setprecision(6) << "x_i = " << x1 << " " << x2 + // << " " << x3 << " " << r1 << " " << r2 << endl; + + // Begin processing of QCD dipoles. + if (dip->colType !=0) { + + // Evaluate normal ME, for proper order of particles. + if (dip->MEorder) + wtME = calcMEcorr(MEkind, MEcombi, dip->MEmix, x1, x2, r1, r2); + else wtME = calcMEcorr(MEkind, MEcombi, dip->MEmix, x2, x1, r2, r1); + //cout << " ME direct " << dip->MEorder << " " << wtME << endl; + + // Split up total ME when two radiating particles. + if (dip->MEsplit) wtME = wtME * x1minus / x3; + //cout << " ME modif " << dip->MEsplit << " " << wtME << endl; + + // Evaluate shower rate to be compared with. + wtPS = 2. / ( x3 * x2minus ); + if (dip->MEgluinoRec) wtPS *= 9./4.; + //cout << " PS " << dip->MEgluinoRec << " " << wtPS << endl; + + // For generic charge combination currently only massless expression. + // (Masses included only to respect phase space boundaries.) + } else if (dip->chgType !=0 && dip->MEtype == 101) { + double chg1 = ParticleDataTable::charge(rad.id()); + double chg2 = ParticleDataTable::charge(partner.id()); + wtME = (x1*x1 + x2*x2) * pow2( chg1 * x1minus / x3 + - chg2 * x2minus / x3 ); + wtPS = 2. * ( chg1*chg1 * x1minus / x3 + chg2*chg2 * x2minus / x3 ); + + // For flavour neutral system assume vector source and include masses. + } else if (dip->chgType !=0 && dip->MEtype == 102) { + wtME = calcMEcorr(2, 1, dip->MEmix, x1, x2, r1, r2) * x1minus / x3; + wtPS = 2. / ( x3 * x2minus ); + } + if (wtME > wtPS) infoPtr->errorMsg("Warning in TimeShower::findMEcorr: " + "ME weight above PS one"); + + // Return ratio of actual ME to assumed PS rate of emission. + return wtME / wtPS; +} + +//********* + +// Matrix elements for gluon (or photon) emission from +// a two-body state; to be used by the parton shower routine. +// Here x_i = 2 E_i/E_cm, r_i = m_i/E_cm and +// 1/sigma_0 d(sigma)/d(x_1)d(x_2) = (alpha-strong/2 pi) * C_F * (this), +// i.e. normalization is such that one recovers the familiar +// (x_1^2 + x_2^2)/((1-x_1)*(1-x_2)) for the massless case. +// Coupling structure: +// kind = 1 : eikonal soft-gluon expression (spin-independent) +// = 2 : V -> q qbar (V = vector/axial vector colour singlet) +// = 3 : q -> q V +// = 4 : S -> q qbar (S = scalar/pseudoscalar colour singlet) +// = 5 : q -> q S +// = 6 : V -> ~q ~qbar (~q = squark) +// = 7 : ~q -> ~q V +// = 8 : S -> ~q ~qbar +// = 9 : ~q -> ~q S +// = 10 : chi -> q ~qbar (chi = neutralino/chargino) +// = 11 : ~q -> q chi +// = 12 : q -> ~q chi +// = 13 : ~g -> q ~qbar +// = 14 : ~q -> q ~g +// = 15 : q -> ~q ~g +// = 16 : (9/4)*(eikonal) for gg -> ~g ~g +// Note that the order of the decay products is important. +// combi = 1 : pure non-gamma5, i.e. vector/scalar/... +// = 2 : pure gamma5, i.e. axial vector/pseudoscalar/.... +// = 3 : mixture mix*(combi=1) + (1-mix)*(combi=2) +// = 4 : mixture (combi=1) +- (combi=2) + +double TimeShower::calcMEcorr( int kind, int combiIn, double mixIn, + double x1, double x2, double r1, double r2) { + + // Frequent variable combinations. + double x3 = 2. - x1 - x2; + double x1s = x1 * x1; + double x2s = x2 * x2; + double x3s = x3 * x3; + double x1c = x1 * x1s; + double x2c = x2 * x2s; + double x3c = x3 * x3s; + double r1s = r1 * r1; + double r2s = r2 * r2; + double r1c = r1 * r1s; + double r2c = r2 * r2s; + double r1q = r1s * r1s; + double r2q = r2s * r2s; + double prop1 = 1. + r1s - r2s - x1; + double prop2 = 1. + r2s - r1s - x2; + double prop1s = prop1 * prop1; + double prop2s = prop2 * prop2; + double prop12 = prop1 * prop2; + double prop13 = prop1 * x3; + double prop23 = prop2 * x3; + + // Check input values. Return zero outside allowed phase space. + if (x1 - 2.*r1 < XMARGIN || prop1 < XMARGIN) return 0.; + if (x2 - 2.*r2 < XMARGIN || prop2 < XMARGIN) return 0.; + if (x1 + x2 - 1. - pow2(r1+r2) < XMARGIN) return 0.; + // Note: equivalent rewritten form 4. * ( (1. - x1) * (1. - x2) + // * (1. - r1s - r2s - x3) + r1s * (1. - x2s - x3) + r2s + // * (1. - x1s - x3) - pow2(r1s - r2s) ) gives abot same result. + if ( (x1s - 4.*r1s) * (x2s - 4.*r2s) + - pow2( 2. * (1. - x1 - x2 + r1s + r2s) + x1*x2 ) + < XMARGIN * (XMARGINCOMB + r1 + r2) ) return 0.; + + // Initial values; phase space. + int combi = max(1, min(4, combiIn) ); + double mix = max(0., min(1., mixIn) ); + bool isSet1 = false; + bool isSet2 = false; + bool isSet4 = false; + double ps = sqrtpos( pow2(1. - r1*r1 - r2*r2) - pow2(2. * r1 * r2) ); + double rLO = 0., rFO = 0., rLO1 = 0., rFO1 = 0., rLO2 = 0., + rFO2 = 0., rLO4 = 0., rFO4 = 0.; + double offset = 0; + + // Select which kind of ME to use. + switch (kind) { + + // case 1 is equal to default, i.e. eikonal expression. + + // V -> q qbar (V = gamma*/Z0/W+-/...). + case 2: + if (combi == 1 || combi == 3) { + rLO1 = ps*(2.-r1s-r1q+6.*r1*r2-r2s+2.*r1s*r2s-r2q)/2.; + rFO1 = -(3.+6.*r1s+r1q-6.*r1*r2+6.*r1c*r2-2.*r2s-6.*r1s*r2s + +6.*r1*r2c+r2q-3.*x1+6.*r1*r2*x1+2.*r2s*x1+x1s-2.*r1s*x1s + +3.*r1s*x3+6.*r1*r2*x3-r2s*x3-2.*x1*x3-5.*r1s*x1*x3 + +r2s*x1*x3+x1s*x3-3.*x3s-3.*r1s*x3s+r2s*x3s + +2.*x1*x3s+x3c-x2) + /prop2s + -2.*(-3.+r1s-6.*r1*r2+6.*r1c*r2+3.*r2s-4.*r1s*r2s + +6.*r1*r2c+2.*x1+3.*r1s*x1+r2s*x1-x1s-r1s*x1s + -r2s*x1s+4.*x3+2.*r1s*x3+3.*r1*r2*x3-r2s*x3-3.*x1*x3 + -2.*r1s*x1*x3+x1s*x3-x3s-r1s*x3s+r1*r2*x3s+x1*x3s) + /prop12 + -(-1.+2.*r1s+r1q+6.*r1*r2+6.*r1c*r2-2.*r2s-6.*r1s*r2s + +6.*r1*r2c+r2q-x1-2.*r1s*x1-6.*r1*r2*x1+8.*r2s*x1+x1s + -2.*r2s*x1s-r1s*x3+r2s*x3-r1s*x1*x3+r2s*x1*x3+x1s*x3+x2) + /prop1s; + rFO1 = rFO1/2.; + isSet1 = true; + } + if (combi == 2 || combi == 3) { + rLO2 = ps*(2.-r1s-r1q-6.*r1*r2-r2s+2.*r1s*r2s-r2q)/2.; + rFO2 = -(3.+6.*r1s+r1q+6.*r1*r2-6.*r1c*r2-2.*r2s-6.*r1s*r2s + -6.*r1*r2c+r2q-3.*x1-6.*r1*r2*x1+2.*r2s*x1+x1s-2.*r1s*x1s + +3.*r1s*x3-6.*r1*r2*x3-r2s*x3-2.*x1*x3-5.*r1s*x1*x3 + +r2s*x1*x3+x1s*x3-3.*x3s-3.*r1s*x3s+r2s*x3s+2.*x1*x3s+x3c-x2) + /prop2s + -2.*(-3+r1s+6.*r1*r2-6.*r1c*r2+3.*r2s-4.*r1s*r2s-6.*r1*r2c + +2.*x1+3.*r1s*x1+r2s*x1-x1s-r1s*x1s-r2s*x1s+4.*x3+2.*r1s*x3 + -3.*r1*r2*x3-r2s*x3-3.*x1*x3-2.*r1s*x1*x3+x1s*x3-x3s-r1s*x3s + -r1*r2*x3s+x1*x3s) + /prop12 + -(-1.+2.*r1s+r1q-6.*r1*r2-6.*r1c*r2-2.*r2s-6.*r1s*r2s + -6.*r1*r2c+r2q-x1-2.*r1s*x1+6.*r1*r2*x1+8.*r2s*x1+x1s + -2.*r2s*x1s-r1s*x3+r2s*x3-r1s*x1*x3+r2s*x1*x3+x1s*x3+x2) + /prop1s; + rFO2 = rFO2/2.; + isSet2 = true; + } + if (combi == 4) { + rLO4 = ps*(2.-r1s-r1q-r2s+2.*r1s*r2s-r2q)/2.; + rFO4 = (1.-r1q+6.*r1s*r2s-r2q+x1+3.*r1s*x1-9.*r2s*x1-3.*x1s + -r1s*x1s+3.*r2s*x1s+x1c-x2-r1s*x2+r2s*x2-r1s*x1*x2+r2s*x1*x2 + +x1s*x2) + /prop1s + -2.*(1.+r1s+r2s-4.*r1s*r2s+r1s*x1+2.*r2s*x1-x1s-r2s*x1s + +2.*r1s*x2+r2s*x2-3.*x1*x2+x1s*x2-x2s-r1s*x2s+x1*x2s) + /prop12 + +(1.-r1q+6.*r1s*r2s-r2q-x1+r1s*x1-r2s*x1+x2-9.*r1s*x2 + +3.*r2s*x2+r1s*x1*x2-r2s*x1*x2-3.*x2s+3.*r1s*x2s-r2s*x2s + +x1*x2s+x2c) + /prop2s; + rFO4 = rFO4/2.; + isSet4 = true; + } + break; + + // q -> q V. + case 3: + if (combi == 1 || combi == 3) { + rLO1 = ps*(1.-2.*r1s+r1q+r2s-6.*r1*r2s+r1s*r2s-2.*r2q); + rFO1 = -2.*(-1.+r1-2.*r1s+2.*r1c-r1q+pow5(r1)-r2s+r1*r2s + -5.*r1s*r2s+r1c*r2s-2.*r1*r2q+2.*x1-2.*r1*x1+2.*r1s*x1 + -2.*r1c*x1+2.*r2s*x1+5.*r1*r2s*x1+r1s*r2s*x1+2.*r2q*x1 + -x1s+r1*x1s-r2s*x1s+3.*x2+4.*r1s*x2+r1q*x2+2.*r2s*x2 + +2.*r1s*r2s*x2-4.*x1*x2-2.*r1s*x1*x2-r2s*x1*x2+x1s*x2 + -2.*x2s-2.*r1s*x2s+x1*x2s) + /prop23 + +(2.*r2s+6.*r1*r2s-6.*r1s*r2s+6.*r1c*r2s+2.*r2q+6.*r1*r2q + -r2s*x1+r1s*r2s*x1-r2q*x1+x2-r1q*x2-3.*r2s*x2-6.*r1*r2s*x2 + +9.*r1s*r2s*x2-2.*r2q*x2-x1*x2+r1s*x1*x2-x2s-3.*r1s*x2s + +2.*r2s*x2s+x1*x2s) + /prop2s + +(-4.-8.*r1s-4.*r1q+4.*r2s-4.*r1s*r2s+8.*r2q+9.*x1+10.*r1s*x1 + +r1q*x1-3.*r2s*x1+6.*r1*r2s*x1+r1s*r2s*x1-2.*r2q*x1-6.*x1s- + 2.*r1s*x1s+x1c+7.*x2+8.*r1s*x2+r1q*x2-7.*r2s*x2+6.*r1*r2s*x2 + +r1s*r2s*x2-2.*r2q*x2-9.*x1*x2-3.*r1s*x1*x2+2.*r2s*x1*x2 + +2.*x1s*x2-3.*x2s-r1s*x2s+2.*r2s*x2s+x1*x2s) + /x3s; + isSet1 = true; + } + if (combi == 2 || combi == 3) { + rLO2 = ps*(1.-2.*r1s+r1q+r2s+6.*r1*r2s+r1s*r2s-2.*r2q); + rFO2 = 2*(1.+r1+2.*r1s+2.*r1c+r1q+pow5(r1)+r2s+r1*r2s + +5.*r1s*r2s+r1c*r2s-2.*r1*r2q-2.*x1-2.*r1*x1-2.*r1s*x1 + -2.*r1c*x1-2.*r2s*x1+5.*r1*r2s*x1-r1s*r2s*x1-2.*r2q*x1+x1s + +r1*x1s+r2s*x1s-3.*x2-4.*r1s*x2-r1q*x2-2.*r2s*x2 + -2.*r1s*r2s*x2+4.*x1*x2+2.*r1s*x1*x2+r2s*x1*x2-x1s*x2 + +2.*x2s+2.*r1s*x2s-x1*x2s) + /prop23 + +(2.*r2s-6.*r1*r2s-6.*r1s*r2s-6.*r1c*r2s+2.*r2q-6.*r1*r2q + -r2s*x1+r1s*r2s*x1-r2q*x1+x2-r1q*x2-3.*r2s*x2+6.*r1*r2s*x2 + +9.*r1s*r2s*x2-2.*r2q*x2-x1*x2+r1s*x1*x2-x2s-3.*r1s*x2s + +2.*r2s*x2s+x1*x2s) + /prop2s + +(-4.-8.*r1s-4.*r1q+4.*r2s-4.*r1s*r2s+8.*r2q+9.*x1+10.*r1s*x1 + +r1q*x1-3.*r2s*x1-6.*r1*r2s*x1+r1s*r2s*x1-2.*r2q*x1-6.*x1s + -2.*r1s*x1s+x1c+7.*x2+8.*r1s*x2+r1q*x2-7.*r2s*x2-6.*r1*r2s*x2 + +r1s*r2s*x2-2.*r2q*x2-9.*x1*x2-3.*r1s*x1*x2+2.*r2s*x1*x2 + +2.*x1s*x2-3.*x2s-r1s*x2s+2.*r2s*x2s+x1*x2s) + /x3s; + isSet2 = true; + } + if (combi == 4) { + rLO4 = ps*(1.-2.*r1s+r1q+r2s+r1s*r2s-2.*r2q); + rFO4 = 2*(1.+2.*r1s+r1q+r2s+5.*r1s*r2s-2.*x1-2.*r1s*x1 + -2.*r2s*x1-r1s*r2s*x1-2.*r2q*x1+x1s+r2s*x1s-3.*x2-4.*r1s*x2 + -r1q*x2-2.*r2s*x2-2.*r1s*r2s*x2+4.*x1*x2+2.*r1s*x1*x2+r2s*x1*x2 + -x1s*x2+2.*x2s+2.*r1s*x2s-x1*x2s) + /prop23 + +(2.*r2s-6.*r1s*r2s+2.*r2q-r2s*x1+r1s*r2s*x1-r2q*x1+x2-r1q*x2 + -3.*r2s*x2+9.*r1s*r2s*x2-2.*r2q*x2-x1*x2+r1s*x1*x2-x2s-3.*r1s*x2s + +2.*r2s*x2s+x1*x2s) + /prop2s + +(-4.-8.*r1s-4.*r1q+4.*r2s-4.*r1s*r2s+8.*r2q+9.*x1+10.*r1s*x1 + +r1q*x1-3.*r2s*x1+r1s*r2s*x1-2.*r2q*x1-6.*x1s-2.*r1s*x1s+x1c + +7.*x2+8.*r1s*x2+r1q*x2-7.*r2s*x2+r1s*r2s*x2-2.*r2q*x2-9.*x1*x2 + -3.*r1s*x1*x2+2.*r2s*x1*x2+2.*x1s*x2-3.*x2s-r1s*x2s+2.*r2s*x2s + +x1*x2s) + /x3s; + isSet4 = true; + } + break; + + // S -> q qbar (S = h0/H0/A0/H+-/...). + case 4: + if (combi == 1 || combi == 3) { + rLO1 = ps*(1.-r1s-r2s-2.*r1*r2); + rFO1 = -(-1.+r1q-2.*r1*r2-2.*r1c*r2-6.*r1s*r2s-2.*r1*r2c+r2q+x1 + -r1s*x1+2.*r1*r2*x1+3.*r2s*x1+x2+r1s*x2-r2s*x2-x1*x2) + /prop1s + -2.*(r1s+r1q-2.*r1c*r2+r2s-6.*r1s*r2s-2.*r1*r2c+r2q-r1s*x1 + +r1*r2*x1+2.*r2s*x1+2.*r1s*x2+r1*r2*x2-r2s*x2-x1*x2) + /prop12 + -(-1.+r1q-2.*r1*r2-2.*r1c*r2-6.*r1s*r2s-2.*r1*r2c+r2q+x1-r1s*x1 + +r2s*x1+x2+3.*r1s*x2+2.*r1*r2*x2-r2s*x2-x1*x2) + /prop2s; + isSet1 = true; + } + if (combi == 2 || combi == 3) { + rLO2 = ps*(1.-r1s-r2s+2.*r1*r2); + rFO2 = -(-1.+r1q+2.*r1*r2+2.*r1c*r2-6.*r1s*r2s+2.*r1*r2c+r2q+x1 + -r1s*x1-2.*r1*r2*x1+3.*r2s*x1+x2+r1s*x2-r2s*x2-x1*x2) + /prop1s + -(-1.+r1q+2.*r1*r2+2.*r1c*r2-6.*r1s*r2s+2.*r1*r2c+r2q+x1 + -r1s*x1+r2s*x1+x2+3.*r1s*x2-2.*r1*r2*x2-r2s*x2-x1*x2) + /prop2s + +2.*(-r1s-r1q-2.*r1c*r2-r2s+6.*r1s*r2s-2.*r1*r2c-r2q+r1s*x1 + +r1*r2*x1-2.*r2s*x1-2.*r1s*x2+r1*r2*x2+r2s*x2+x1*x2) + /prop12; + isSet2 = true; + } + if (combi == 4) { + rLO4 = ps*(1.-r1s-r2s); + rFO4 = -(-1.+r1q-6.*r1s*r2s+r2q+x1-r1s*x1+3.*r2s*x1+x2 + +r1s*x2-r2s*x2-x1*x2) + /prop1s + -2.*(r1s+r1q+r2s-6.*r1s*r2s+r2q-r1s*x1 + +2.*r2s*x1+2.*r1s*x2-r2s*x2-x1*x2) + /prop12 + -(-1.+r1q-6.*r1s*r2s+r2q+x1-r1s*x1+r2s*x1 + +x2+3.*r1s*x2-r2s*x2-x1*x2) + /prop2s; + isSet4 = true; + } + break; + + // q -> q S. + case 5: + if (combi == 1 || combi == 3) { + rLO1 = ps*(1.+r1s-r2s+2.*r1); + rFO1 = (4.-4.*r1s+4.*r2s-3.*x1-2.*r1*x1+r1s*x1-r2s*x1-5.*x2 + -2.*r1*x2+r1s*x2-r2s*x2+x1*x2+x2s) + /x3s + -2.*(3.-r1-5.*r1s-r1c+3.*r2s+r1*r2s-2.*x1-r1*x1 + +r1s*x1-4.*x2+2.*r1s*x2-r2s*x2+x1*x2+x2s) + /prop23 + +(2.-2.*r1-6.*r1s-2.*r1c+2.*r2s-2.*r1*r2s-x1+r1s*x1 + -r2s*x1-3.*x2+2.*r1*x2+3.*r1s*x2-r2s*x2+x1*x2+x2s) + /prop2s; + isSet1 = true; + } + if (combi == 2 || combi == 3) { + rLO2 = ps*(1.+r1s-r2s-2.*r1); + rFO2 = (4.-4.*r1s+4.*r2s-3.*x1+2.*r1*x1+r1s*x1-r2s*x1-5.*x2 + +2.*r1*x2+r1s*x2-r2s*x2+x1*x2+x2s) + /x3s + -2.*(3.+r1-5.*r1s+r1c+3.*r2s-r1*r2s-2.*x1+r1*x1 + +r1s*x1-4.*x2+2.*r1s*x2-r2s*x2+x1*x2+x2s) + /prop23 + +(2.+2.*r1-6.*r1s+2.*r1c+2.*r2s+2.*r1*r2s-x1+r1s*x1 + -r2s*x1-3.*x2-2.*r1*x2+3.*r1s*x2-r2s*x2+x1*x2+x2s) + /prop2s; + isSet2 = true; + } + if (combi == 4) { + rLO4 = ps*(1.+r1s-r2s); + rFO4 = (4.-4.*r1s+4.*r2s-3.*x1+r1s*x1-r2s*x1-5.*x2+r1s*x2 + -r2s*x2+x1*x2+x2s) + /x3s + -2.*(3.-5.*r1s+3.*r2s-2.*x1+r1s*x1-4.*x2+2.*r1s*x2 + -r2s*x2+x1*x2+x2s) + /prop23 + +(2.-6.*r1s+2.*r2s-x1+r1s*x1-r2s*x1-3.*x2+3.*r1s*x2 + -r2s*x2+x1*x2+x2s) + /prop2s; + isSet4 = true; + } + break; + + // V -> ~q ~qbar (~q = squark). + case 6: + rLO1 = ps*(1.-2.*r1s+r1q-2.*r2s-2.*r1s*r2s+r2q); + rFO1 = 2.*3.+(1.+r1s+r2s-x1)*(4.*r1s-x1s) + /prop1s + +2.*(-1.-3.*r1s-r2s+x1+x1s*0.5+x2-x1*x2*0.5) + /prop1 + +(1.+r1s+r2s-x2)*(4.*r2s-x2s) + /prop2s + +2.*(-1.-r1s-3.*r2s+x1+x2-x1*x2*0.5+x2s*0.5) + /prop2 + -(-4.*r1s-4.*r1q-4.*r2s-8.*r1s*r2s-4.*r2q+2.*x1+6.*r1s*x1 + +6.*r2s*x1-2.*x1s+2.*x2+6.*r1s*x2+6.*r2s*x2-4.*x1*x2 + -2.*r1s*x1*x2-2.*r2s*x1*x2+x1s*x2-2.*x2s+x1*x2s) + /prop12; + isSet1 = true; + break; + + // ~q -> ~q V. + case 7: + rLO1 = ps*(1.-2.*r1s+r1q-2.*r2s-2.*r1s*r2s+r2q); + rFO1 = 16.*r2s-8.*(4.*r2s+2.*r2s*x1+x2+r1s*x2+r2s*x2-x1*x2 + -2.*x2s) + /(3.*prop2) + +8.*(1.+r1s+r2s-x2)*(4.*r2s-x2s) + /(3.*prop2s) + +8.*(x1+x2)*(-1.-2.*r1s-r1q-2.*r2s+2.*r1s*r2s-r2q+2.*x1 + +2.*r1s*x1+2.*r2s*x1-x1s+2.*x2+2.*r1s*x2+2.*r2s*x2-2.*x1*x2-x2s) + /(3.*x3s) + +8.*(-1.-r1s+r2s-x1)*(2.*r2s*x1+x2+r1s*x2+r2s*x2-x1*x2-x2s) + /(3.*prop2*x3) + -8.*(1.+2.*r1s+r1q+2.*r2s-2.*r1s*r2s+r2q-2.*x1-2.*r1s*x1 + -4.*r2s*x1+x1s-3.*x2-3.*r1s*x2-3.*r2s*x2+3.*x1*x2+2.*x2s) + /(3.*x3); + rFO1 = 3.*rFO1/8.; + isSet1 = true; + break; + + // S -> ~q ~qbar. + case 8: + rLO1 = ps; + rFO1 = (-1.-2.*r1s-r1q-2.*r2s+2.*r1s*r2s-r2q+2.*x1+2.*r1s*x1 + +2.*r2s*x1-x1s-r2s*x1s+2.*x2+2.*r1s*x2+2.*r2s*x2-3.*x1*x2 + -r1s*x1*x2-r2s*x1*x2+x1s*x2-x2s-r1s*x2s+x1*x2s) + /(prop1s*prop2s); + rFO1 = 2.*rFO1; + isSet1 = true; + break; + + // ~q -> ~q S. + case 9: + rLO1 = ps; + rFO1 = (-1.-r1s-r2s+x2) + /prop2s + +(1.+r1s-r2s+x1) + /prop23 + -(x1+x2) + /x3s; + isSet1 = true; + break; + + // chi -> q ~qbar (chi = neutralino/chargino). + case 10: + if (combi == 1 || combi == 3) { + rLO1 = ps*(1.+r1s-r2s+2.*r1); + rFO1 = (2.*r1+x1)*(-1.-r1s-r2s+x1) + /prop1s + +2.*(-1.-r1s-2.*r1c-r2s-2.*r1*r2s+3.*x1*0.5+r1*x1 + -r1s*x1*0.5-r2s*x1*0.5+x2+r1*x2+r1s*x2-x1*x2*0.5) + /prop12 + +(2.-2.*r1-6.*r1s-2.*r1c+2.*r2s-2.*r1*r2s-x1+r1s*x1 + -r2s*x1-3.*x2+2.*r1*x2+3.*r1s*x2-r2s*x2+x1*x2+x2s) + /prop2s; + isSet1 = true; + } + if (combi == 2 || combi == 3) { + rLO2 = ps*(1.-2.*r1+r1s-r2s); + rFO2 = (2.*r1-x1)*(1.+r1s+r2s-x1) + /prop1s + +2.*(-1.-r1s+2.*r1c-r2s+2.*r1*r2s+3.*x1*0.5-r1*x1 + -r1s*x1*0.5-r2s*x1*0.5+x2-r1*x2+r1s*x2-x1*x2*0.5) + /prop12 + +(2.+2.*r1-6.*r1s+2.*r1c+2.*r2s+2.*r1*r2s-x1+r1s*x1 + -r2s*x1-3.*x2-2.*r1*x2+3.*r1s*x2-r2s*x2+x1*x2+x2s)/ + prop2s; + isSet2 = true; + } + if (combi == 4) { + rLO4 = ps*(1.+r1s-r2s); + rFO4 = x1*(-1.-r1s-r2s+x1) + /prop1s + +2.*(-1.-r1s-r2s+3.*x1*0.5-r1s*x1*0.5-r2s*x1*0.5 + +x2+r1s*x2-x1*x2*0.5) + /prop12 + +(2.-6.*r1s+2.*r2s-x1+r1s*x1-r2s*x1-3.*x2+3.*r1s*x2 + -r2s*x2+x1*x2+x2s) + /prop2s; + isSet4 = true; + } + break; + + // ~q -> q chi. + case 11: + if (combi == 1 || combi == 3) { + rLO1 = ps*(1.-pow2(r1+r2)); + rFO1 = (1.+r1s+2.*r1*r2+r2s-x1-x2)*(x1+x2) + /x3s + -(-1.+r1q-2.*r1*r2-2.*r1c*r2-6.*r1s*r2s-2.*r1*r2c+r2q+x1 + -r1s*x1+r2s*x1+x2+3.*r1s*x2+2.*r1*r2*x2-r2s*x2-x1*x2) + /prop2s + +(-1.-2.*r1s-r1q-2.*r1*r2-2.*r1c*r2+2.*r1*r2c+r2q+x1+r1s*x1 + -2.*r1*r2*x1-3.*r2s*x1+2.*r1s*x2-2.*r2s*x2+x1*x2+x2s) + /prop23; + isSet1 = true; + } + if (combi == 2 || combi == 3) { + rLO2 = ps*(1.-pow2(r1-r2)); + rFO2 = (1.+r1s-2.*r1*r2+r2s-x1-x2)*(x1+x2) + /x3s + -(-1.+r1q+2.*r1*r2+2.*r1c*r2-6.*r1s*r2s+2.*r1*r2c+r2q+x1 + -r1s*x1+r2s*x1+x2+3.*r1s*x2-2.*r1*r2*x2-r2s*x2-x1*x2) + /prop2s + +(-1.-2.*r1s-r1q+2.*r1*r2+2.*r1c*r2-2.*r1*r2c+r2q+x1+r1s*x1 + +2.*r1*r2*x1-3.*r2s*x1+2.*r1s*x2-2.*r2s*x2+x1*x2+x2s) + /prop23; + isSet2 = true; + } + if (combi == 4) { + rLO4 = ps*(1.-r1s-r2s); + rFO4 = (1.+r1s+r2s-x1-x2)*(x1+x2) + /x3s + -(-1.+r1q-6.*r1s*r2s+r2q+x1-r1s*x1+r2s*x1+x2 + +3.*r1s*x2-r2s*x2-x1*x2) + /prop2s + +(-1.-2.*r1s-r1q+r2q+x1+r1s*x1-3.*r2s*x1 + +2.*r1s*x2-2.*r2s*x2+x1*x2+x2s) + /prop23; + isSet4 = true; + } + break; + + // q -> ~q chi. + case 12: + if (combi == 1 || combi == 3) { + rLO1 = ps*(1.-r1s+r2s+2.*r2); + rFO1 = (2.*r2+x2)*(-1.-r1s-r2s+x2) + /prop2s + +(4.+4.*r1s-4.*r2s-5.*x1-r1s*x1-2.*r2*x1+r2s*x1+x1s + -3.*x2-r1s*x2-2.*r2*x2+r2s*x2+x1*x2) + /x3s + +2.*(-1.-r1s+r2+r1s*r2-r2s-r2c+x1+r2*x1+r2s*x1+2.*x2 + +r1s*x2-x1*x2*0.5-x2s*0.5) + /prop23; + isSet1 = true; + } + if (combi == 2 || combi == 3) { + rLO2 = ps*(1.-r1s+r2s-2.*r2); + rFO2 = (2.*r2-x2)*(1.+r1s+r2s-x2) + /prop2s + +(4.+4.*r1s-4.*r2s-5.*x1-r1s*x1+2.*r2*x1+r2s*x1+x1s + -3.*x2-r1s*x2+2.*r2*x2+r2s*x2+x1*x2) + /x3s + +2.*(-1.-r1s-r2-r1s*r2-r2s+r2c+x1-r2*x1+r2s*x1+2.*x2 + +r1s*x2-x1*x2*0.5-x2s*0.5) + /prop23; + isSet2 = true; + } + if (combi == 4) { + rLO4 = ps*(1.-r1s+r2s); + rFO4 = x2*(-1.-r1s-r2s+x2) + /prop2s + +(4.+4.*r1s-4.*r2s-5.*x1-r1s*x1+r2s*x1+x1s + -3.*x2-r1s*x2+r2s*x2+x1*x2) + /x3s + +2.*(-1.-r1s-r2s+x1+r2s*x1+2.*x2 + +r1s*x2-x1*x2*0.5-x2s*0.5) + /prop23; + isSet4 = true; + } + break; + + // ~g -> q ~qbar. + case 13: + if (combi == 1 || combi == 3) { + rLO1 = ps*(1.+r1s-r2s+2.*r1); + rFO1 = 4.*(2.*r1+x1)*(-1.-r1s-r2s+x1) + /(3.*prop1s) + -(-1.-r1s-2.*r1c-r2s-2.*r1*r2s+3.*x1*0.5+r1*x1-r1s*x1*0.5 + -r2s*x1*0.5+x2+r1*x2+r1s*x2-x1*x2*0.5) + /(3.*prop12) + +3.*(-1.+r1-r1s-r1c-r2s+r1*r2s+2.*x1+r2s*x1-x1s*0.5+x2+r1*x2 + +r1s*x2-x1*x2*0.5) + /prop13 + +3.*(4.-4.*r1s+4.*r2s-3.*x1-2.*r1*x1+r1s*x1-r2s*x1-5.*x2 + -2.*r1*x2+r1s*x2-r2s*x2+x1*x2+x2s) + /x3s + -3.*(3.-r1-5.*r1s-r1c+3.*r2s+r1*r2s-2.*x1-r1*x1+r1s*x1 + -4.*x2+2.*r1s*x2-r2s*x2+x1*x2+x2s) + /prop23 + +4.*(2.-2.*r1-6.*r1s-2.*r1c+2.*r2s-2.*r1*r2s-x1+r1s*x1-r2s*x1 + -3.*x2+2.*r1*x2+3.*r1s*x2-r2s*x2+x1*x2+x2s) + /(3.*prop2s); + rFO1 = 3.*rFO1/4.; + isSet1 = true; + } + if (combi == 2 || combi == 3) { + rLO2 = ps*(1.+r1s-r2s-2.*r1); + rFO2 = 4.*(2.*r1-x1)*(1.+r1s+r2s-x1) + /(3.*prop1s) + +3.*(-1.-r1-r1s+r1c-r2s-r1*r2s+2.*x1+r2s*x1-x1s*0.5 + +x2-r1*x2+r1s*x2-x1*x2*0.5) + /prop13 + +(2.+2.*r1s-4.*r1c+2.*r2s-4.*r1*r2s-3.*x1+2.*r1*x1 + +r1s*x1+r2s*x1-2.*x2+2.*r1*x2-2.*r1s*x2+x1*x2) + /(6.*prop12) + +3.*(4.-4.*r1s+4.*r2s-3.*x1+2.*r1*x1+r1s*x1-r2s*x1-5.*x2 + +2.*r1*x2+r1s*x2-r2s*x2+x1*x2+x2s) + /x3s + -3.*(3.+r1-5.*r1s+r1c+3.*r2s-r1*r2s-2.*x1+r1*x1+r1s*x1-4.*x2 + +2.*r1s*x2-r2s*x2+x1*x2+x2s) + /prop23 + +4.*(2.+2.*r1-6.*r1s+2.*r1c+2.*r2s+2.*r1*r2s-x1+r1s*x1-r2s*x1 + -3.*x2-2.*r1*x2+3.*r1s*x2-r2s*x2+x1*x2+x2s) + /(3.*prop2s); + rFO2 = 3.*rFO2/4.; + isSet2 = true; + } + if (combi == 4) { + rLO4 = ps*(1.+r1s-r2s); + rFO4 = 8.*x1*(-1.-r1s-r2s+x1) + /(3.*prop1s) + +6.*(-1-r1s-r2s+2.*x1+r2s*x1-x1s*0.5+x2+r1s*x2-x1*x2*0.5) + /prop13 + +(2.+2.*r1s+2.*r2s-3.*x1+r1s*x1+r2s*x1-2.*x2-2.*r1s*x2+x1*x2) + /(3.*prop12) + +6.*(4.-4.*r1s+4.*r2s-3.*x1+r1s*x1-r2s*x1-5.*x2+r1s*x2-r2s*x2 + +x1*x2+x2s) + /x3s + -6.*(3.-5.*r1s+3.*r2s-2.*x1+r1s*x1-4.*x2+2.*r1s*x2-r2s*x2+x1*x2+x2s) + /prop23 + +8.*(2.-6.*r1s+2.*r2s-x1+r1s*x1-r2s*x1-3.*x2+3.*r1s*x2-r2s*x2 + +x1*x2+x2s) + /(3.*prop2s); + rFO4 = 3.*rFO4/8.; + isSet4 = true; + } + break; + + // ~q -> q ~g. + case 14: + if (combi == 1 || combi == 3) { + rLO1 = ps*(1.-r1s-r2s-2.*r1*r2); + rFO1 = 64.*(1.+r1s+2.*r1*r2+r2s-x1-x2)*(x1+x2) + /(9.*x3s) + -16.*(-1.+r1q-2.*r1*r2-2.*r1c*r2-6.*r1s*r2s-2.*r1*r2c+r2q + +x1-r1s*x1+2.*r1*r2*x1+3.*r2s*x1+x2+r1s*x2-r2s*x2-x1*x2) + /prop1s + -16.*(r1s+r1q-2.*r1c*r2+r2s-6.*r1s*r2s-2.*r1*r2c+r2q-r1s*x1 + +r1*r2*x1+2.*r2s*x1+2.*r1s*x2+r1*r2*x2-r2s*x2-x1*x2) + /prop12 + -64.*(-1.+r1q-2.*r1*r2-2.*r1c*r2-6.*r1s*r2s-2.*r1*r2c+r2q+x1 + -r1s*x1+r2s*x1+x2+3.*r1s*x2+2.*r1*r2*x2-r2s*x2-x1*x2) + /(9.*prop2s) + +8.*(-1.+r1q-2.*r1*r2+2.*r1c*r2-2.*r2s-2.*r1*r2c-r2q-2.*r1s*x1 + +2.*r2s*x1+x1s+x2-3.*r1s*x2-2.*r1*r2*x2+r2s*x2+x1*x2) + /prop13 + -8.*(-1.-2.*r1s-r1q-2.*r1*r2-2.*r1c*r2+2.*r1*r2c+r2q+x1+r1s*x1 + -2.*r1*r2*x1-3.*r2s*x1+2.*r1s*x2-2.*r2s*x2+x1*x2+x2s) + /(9.*prop23); + rFO1 = 9.*rFO1/64.; + isSet1 = true; + } + if (combi == 2 || combi == 3) { + rLO2 = ps*(1.-r1s-r2s+2.*r1*r2); + rFO2 = 64.*(1.+r1s-2.*r1*r2+r2s-x1-x2)*(x1+x2) + /(9.*x3s) + -16.*(-1.+r1q+2.*r1*r2+2.*r1c*r2-6.*r1s*r2s+2.*r1*r2c+r2q+x1 + -r1s*x1-2.*r1*r2*x1+3.*r2s*x1+x2+r1s*x2-r2s*x2-x1*x2) + /prop1s + -64.*(-1.+r1q+2.*r1*r2+2.*r1c*r2-6.*r1s*r2s+2.*r1*r2c+r2q+x1 + -r1s*x1+r2s*x1+x2+3.*r1s*x2-2.*r1*r2*x2-r2s*x2-x1*x2) + /(9.*prop2s) + +16.*(-r1s-r1q-2.*r1c*r2-r2s+6.*r1s*r2s-2.*r1*r2c-r2q+r1s*x1 + +r1*r2*x1-2.*r2s*x1-2.*r1s*x2+r1*r2*x2+r2s*x2+x1*x2) + /prop12 + +8.*(-1.+r1q+2.*r1*r2-2.*r1c*r2-2.*r2s+2.*r1*r2c-r2q-2.*r1s*x1 + +2.*r2s*x1+x1s+x2-3.*r1s*x2+2.*r1*r2*x2+r2s*x2+x1*x2) + /prop13 + -8.*(-1.-2.*r1s-r1q+2.*r1*r2+2.*r1c*r2-2.*r1*r2c+r2q+x1+r1s*x1+ + 2.*r1*r2*x1-3.*r2s*x1+2.*r1s*x2-2.*r2s*x2+x1*x2+x2s) + /(9.*prop23); + rFO2 = 9.*rFO2/64.; + isSet2 = true; + } + if (combi == 4) { + rLO4 = ps*(1.-r1s-r2s); + rFO4 = 128.*(1.+r1s+r2s-x1-x2)*(x1+x2) + /(9.*x3s) + -32*(-1.+r1q-6.*r1s*r2s+r2q+x1-r1s*x1+3.*r2s*x1+x2 + +r1s*x2-r2s*x2-x1*x2) + /prop1s + -32.*(r1s+r1q+r2s-6.*r1s*r2s+r2q-r1s*x1+2.*r2s*x1+2.*r1s*x2 + -r2s*x2-x1*x2) + /prop12 + -128.*(-1.+r1q-6.*r1s*r2s+r2q+x1-r1s*x1+r2s*x1+x2+3.*r1s*x2 + -r2s*x2-x1*x2) + /(9.*prop2s) + +16.*(-1.+r1q-2.*r2s-r2q-2.*r1s*x1+2.*r2s*x1+x1s + +x2-3.*r1s*x2+r2s*x2+x1*x2) + /prop13 + -16.*(-1.-2.*r1s-r1q+r2q+x1+r1s*x1-3.*r2s*x1 + +2.*r1s*x2-2.*r2s*x2+x1*x2+x2s) + /(9.*prop23); + rFO4 = 9.*rFO4/128.; + isSet4 = true; + } + break; + + // q -> ~q ~g. + case 15: + if (combi == 1 || combi == 3) { + rLO1 = ps*(1.-r1s+r2s+2.*r2); + rFO1 = 32*(2.*r2+x2)*(-1.-r1s-r2s+x2) + /(9.*prop2s) + +8.*(-1.-r1s-2.*r1s*r2-r2s-2.*r2c+x1+r2*x1+r2s*x1 + +3.*x2*0.5-r1s*x2*0.5+r2*x2-r2s*x2*0.5-x1*x2*0.5) + /prop12 + +8.*(2.+2.*r1s-2.*r2-2.*r1s*r2-6.*r2s-2.*r2c-3.*x1-r1s*x1 + +2.*r2*x1+3.*r2s*x1+x1s-x2-r1s*x2+r2s*x2+x1*x2) + /prop1s + +32.*(4.+4.*r1s-4.*r2s-5.*x1-r1s*x1-2.*r2*x1+r2s*x1+x1s + -3.*x2-r1s*x2-2.*r2*x2+r2s*x2+x1*x2) + /(9.*x3s) + -8.*(3.+3.*r1s-r2+r1s*r2-5.*r2s-r2c-4.*x1-r1s*x1 + +2.*r2s*x1+x1s-2.*x2-r2*x2+r2s*x2+x1*x2) + /prop13 + -8.*(-1.-r1s+r2+r1s*r2-r2s-r2c+x1+r2*x1+r2s*x1+2.*x2+r1s*x2 + -x1*x2*0.5-x2s*0.5) + /(9.*prop23); + rFO1 = 9.*rFO1/32.; + isSet1 = true; + } + if (combi == 2 || combi == 3) { + rLO2 = ps*(1.-r1s+r2s-2.*r2); + rFO2 = 32*(2.*r2-x2)*(1.+r1s+r2s-x2) + /(9.*prop2s) + +8.*(-1.-r1s+2.*r1s*r2-r2s+2.*r2c+x1-r2*x1+r2s*x1 + +3.*x2*0.5-r1s*x2*0.5-r2*x2-r2s*x2*0.5-x1*x2*0.5) + /prop12 + +8.*(2.+2.*r1s+2.*r2+2.*r1s*r2-6.*r2s+2.*r2c-3.*x1-r1s*x1 + -2.*r2*x1+3.*r2s*x1+x1s-x2-r1s*x2+r2s*x2+x1*x2) + /prop1s + -8.*(3.+3.*r1s+r2-r1s*r2-5.*r2s+r2c-4.*x1-r1s*x1+2.*r2s*x1+x1s + -2.*x2+r2*x2+r2s*x2+x1*x2) + /prop13 + +32*(4.+4.*r1s-4.*r2s-5.*x1-r1s*x1+2.*r2*x1+r2s*x1 + +x1s-3.*x2-r1s*x2+2.*r2*x2+r2s*x2+x1*x2) + /(9.*x3s) + -8.*(-1.-r1s-r2-r1s*r2-r2s+r2c+x1-r2*x1+r2s*x1+2.*x2+r1s*x2 + -x1*x2*0.5-x2s*0.5) + /(9.*prop23); + rFO2 = 9.*rFO2/32.; + isSet2 = true; + } + if (combi == 4) { + rLO4 = ps*(1.-r1s+r2s); + rFO4 = 64.*x2*(-1.-r1s-r2s+x2) + /(9.*prop2s) + +16.*(-1.-r1s-r2s+x1+r2s*x1+3.*x2*0.5-r1s*x2*0.5 + -r2s*x2*0.5-x1*x2*0.5) + /prop12 + -16.*(3.+3.*r1s-5.*r2s-4.*x1-r1s*x1+2.*r2s*x1+x1s-2.*x2+r2s*x2 + +x1*x2) + /prop13 + +64.*(4.+4.*r1s-4.*r2s-5.*x1-r1s*x1+r2s*x1+x1s-3.*x2 + -r1s*x2+r2s*x2+x1*x2) + /(9.*x3s) + +16.*(2.+2.*r1s-6.*r2s-3.*x1-r1s*x1+3.*r2s*x1+x1s + -x2-r1s*x2+r2s*x2+x1*x2) + /prop1s + -16.*(-1.-r1s-r2s+x1+r2s*x1+2.*x2+r1s*x2-x1*x2*0.5-x2s*0.5) + /(9.*prop23); + rFO4 = 9.*rFO4/64.; + isSet4 = true; + } + break; + + // g -> ~g ~g. Use (9/4)*eikonal. May be changed in the future. + case 16: + rLO = ps; + if (combi == 2) offset = x3s; + else if (combi == 3) offset = mix * x3s; + else if (combi == 4) offset = 0.5 * x3s; + rFO = ps * 4.5 * ( (x1+x2-1.+offset-r1s-r2s)/prop12 + - r1s/prop2s - r2s/prop1s ); + break; + + // Eikonal expression for kind == 1; also acts as default. + default: + rLO = ps; + if (combi == 2) offset = x3s; + else if (combi == 3) offset = mix * x3s; + else if (combi == 4) offset = 0.5 * x3s; + rFO = ps * 2. * ( (x1+x2-1.+offset-r1s-r2s)/prop12 + - r1s/prop2s - r2s/prop1s ); + break; + + // End of ME cases. + } + + // Find relevant leading and first order expressions. + if (combi == 1 && isSet1) { + rLO = rLO1; + rFO = rFO1; } + else if (combi == 2 && isSet2) { + rLO = rLO2; + rFO = rFO2; } + else if (combi == 3 && isSet1 && isSet2) { + rLO = mix * rLO1 + (1.-mix) * rLO2; + rFO = mix * rFO1 + (1.-mix) * rFO2; } + else if (isSet4) { + rLO = rLO4; + rFO = rFO4; } + else if (combi == 4 && isSet1 && isSet2) { + rLO = 0.5 * (rLO1 + rLO2); + rFO = 0.5 * (rFO1 + rFO2); } + else if (isSet1) { + rLO = rLO1; + rFO = rFO1; } + + // Return ratio of first to leading order cross section. + return rFO / rLO; +} + +//********* + +// Find coefficient of azimuthal asymmetry from gluon polarization. + +void TimeShower::findAsymPol( Event& event, TimeDipoleEnd* dip) { + + // Default is no asymmetry. Only gluons are studied. + dip->asymPol = 0.; + dip->iAunt = 0; + int iRad = dip->iRadiator; + if (!doPhiPolAsym || event[iRad].id() != 21) return; + + // Trace grandmother via possibly intermediate recoil copies. + int iMother = event.iTopCopy(iRad); + int iGrandM = event[iMother].mother1(); + + // Check grandmother flavour and set aunt. + if (!event[iGrandM].isQuark() && !event[iGrandM].isGluon()) return; + dip->iAunt = (event[iGrandM].daughter1() == iMother) + ? event[iGrandM].daughter2() : event[iGrandM].daughter1(); + + // Coefficient from gluon production (approximate z by energy). + double zProd = event[iRad].e() / (event[iRad].e() + + event[dip->iAunt].e()); + if (event[iGrandM].id() != 21) dip->asymPol = 2. * (1. - zProd) + / (1. + pow2(1. - zProd) ); + else dip->asymPol = pow2( (1. - zProd) / (1. - zProd * (1. - zProd) ) ); + + // Coefficients from gluon decay. + if (dip->flavour == 21) dip->asymPol *= pow2( (1. - dip->z) + / (1. - dip->z * (1. - dip->z) ) ); + else dip->asymPol *= -2. * dip->z *( 1. - dip->z ) + / (1. - 2. * dip->z * (1. - dip->z) ); + +} + +//********* + +// Print the list of dipoles. + +void TimeShower::list(ostream& os) { + + // Header. + os << "\n -------- PYTHIA TimeShower Dipole Listing ----------------" + << "----------------------------------- \n \n i rad rec " + << " pTmax col chg gam oni isr sys type MErec mix or" + << "d spl ~gR \n" << fixed << setprecision(3); + + // Loop over dipole list and print it. + for (int i = 0; i < int(dipEnd.size()); ++i) + os << setw(5) << i << setw(7) << dipEnd[i].iRadiator + << setw(7) << dipEnd[i].iRecoiler << setw(12) << dipEnd[i].pTmax + << setw(5) << dipEnd[i].colType << setw(5) << dipEnd[i].chgType + << setw(5) << dipEnd[i].gamType << setw(5) << dipEnd[i].isOctetOnium + << setw(5) << dipEnd[i].isrType << setw(5) << dipEnd[i].system + << setw(5) << dipEnd[i].MEtype << setw(7) << dipEnd[i].iMEpartner + << setw(8) << dipEnd[i].MEmix << setw(5) << dipEnd[i].MEorder + << setw(5) << dipEnd[i].MEsplit << setw(5) << dipEnd[i].MEgluinoRec + << "\n"; + + // Done. + os << "\n -------- End PYTHIA TimeShower Dipole Listing ------------" + << "-----------------------------------" << endl; + +} + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/src/UserHooks.cxx b/PYTHIA8/pythia8130/src/UserHooks.cxx new file mode 100644 index 00000000000..31984ad0eb3 --- /dev/null +++ b/PYTHIA8/pythia8130/src/UserHooks.cxx @@ -0,0 +1,161 @@ +// UserHooks.cc is a part of the PYTHIA event generator. +// Copyright (C) 2008 Torbjorn Sjostrand. +// PYTHIA is licenced under the GNU GPL version 2, see COPYING for details. +// Please respect the MCnet Guidelines, see GUIDELINES for details. + +// Function definitions (not found in the header) for the UserHooks class. + +#include "UserHooks.h" + +namespace Pythia8 { + +//************************************************************************** + +// The UserHooks class. + +//********* + +// multiplySigmaBy allows the user to introduce a multiplicative factor +// that modifies the cross section of a hard process. Since it is called +// from before the event record is generated in full, the normal analysis +// does not work. The code here provides a rather extensive summary of +// which methods actually do work. It is a convenient starting point for +// writing your own derived routine. + +double UserHooks::multiplySigmaBy( const SigmaProcess* sigmaProcessPtr, + const PhaseSpace* phaseSpacePtr, bool inEvent) { + + // Process code, necessary when some to be treated differently. + //int code = sigmaProcessPtr->code(); + + // Final multiplicity, i.e. whether 2 -> 1 or 2 -> 2. + //int nFinal = sigmaProcessPtr->nFinal(); + + // Incoming x1 and x2 to the hard collision, and factorization scale. + //double x1 = phaseSpacePtr->x1(); + //double x2 = phaseSpacePtr->x2(); + //double Q2Fac = sigmaProcessPtr->Q2Fac(); + + // Renormalization scale and assumed alpha_strong and alpha_EM. + //double Q2Ren = sigmaProcessPtr->Q2Ren(); + //double alphaS = sigmaProcessPtr->alphaSRen(); + //double alphaEM = sigmaProcessPtr->alphaEMRen(); + + // Subprocess mass-square. + //double sHat = phaseSpacePtr->sHat(); + + // Now methods only relevant for 2 -> 2. + //if (nFinal == 2) { + + // Mandelstam variables and hard-process pT. + //double tHat = phaseSpacePtr->tHat(); + //double uHat = phaseSpacePtr->uHat(); + //double pTHat = phaseSpacePtr->pTHat(); + + // Masses of the final-state particles. (Here 0 for light quarks.) + //double m3 = sigmaProcessPtr->m(3); + //double m4 = sigmaProcessPtr->m(4); + //} + + // Dummy statement to avoid compiler warnings. + return ((inEvent && sigmaProcessPtr->code() == 0 + && phaseSpacePtr->sHat() < 0.) ? 0. : 1.); + +} + +//********* + +// subEvent extracts currently resolved partons in the hard process. + +void UserHooks::subEvent(const Event& event, bool isHardest) { + + // Reset work event to be empty. + workEvent.clear(); + + // Find which subsystem to study. + int iSys = 0; + if (!isHardest) iSys = event.sizeSystems() - 1; + + // Loop through all the final partons of the given subsystem. + for (int i = 2; i < event.sizeSystem(iSys); ++i) { + int iOld = event.getInSystem( iSys, i); + + // Copy partons to work event. + int iNew = workEvent.append( event[iOld]); + + // No mothers. Position in full event as daughters. + workEvent[iNew].mothers( 0, 0); + workEvent[iNew].daughters( iOld, iOld); + } + +} + +//************************************************************************** + +// The SuppressSmallPT class, derived from UserHooks. + +//********* + +// Modify event weight at the trial level, before selection. + +double SuppressSmallPT::multiplySigmaBy( const SigmaProcess* sigmaProcessPtr, + const PhaseSpace* phaseSpacePtr, bool ) { + + // Need to initialize first time this method is called. + if (!isInit) { + + // Calculate pT0 as for multiple interactions. + // Fudge factor allows offset relative to MI framework. + double eCM = phaseSpacePtr->ecm(); + double pT0Ref = Settings::parm("MultipleInteractions:pT0Ref"); + double ecmRef = Settings::parm("MultipleInteractions:ecmRef"); + double ecmPow = Settings::parm("MultipleInteractions:ecmPow"); + double pT0 = pT0timesMI * pT0Ref * pow(eCM / ecmRef, ecmPow); + pT20 = pT0 * pT0; + + // Initialize alpha_strong object as for multiple interactions, + // alternatively as for hard processes. + double alphaSvalue; + int alphaSorder; + if (useSameAlphaSasMI) { + alphaSvalue = Settings::parm("MultipleInteractions:alphaSvalue"); + alphaSorder = Settings::mode("MultipleInteractions:alphaSorder"); + } else { + alphaSvalue = Settings::parm("SigmaProcess:alphaSvalue"); + alphaSorder = Settings::mode("SigmaProcess:alphaSorder"); + } + alphaS.init( alphaSvalue, alphaSorder); + + // Initialization finished. + isInit = true; + } + + // Only modify 2 -> 2 processes. + int nFinal = sigmaProcessPtr->nFinal(); + if (nFinal != 2) return 1.; + + // pT scale of process. Weight pT^4 / (pT^2 + pT0^2)^2 + double pTHat = phaseSpacePtr->pTHat(); + double pT2 = pTHat * pTHat; + double wt = pow2( pT2 / (pT20 + pT2) ); + + if (numberAlphaS > 0) { + // Renormalization scale and assumed alpha_strong. + double Q2RenOld = sigmaProcessPtr->Q2Ren(); + double alphaSOld = sigmaProcessPtr->alphaSRen(); + + // Reweight to new alpha_strong at new scale. + double Q2RenNew = pT20 + Q2RenOld; + double alphaSNew = alphaS.alphaS(Q2RenNew); + wt *= pow( alphaSNew / alphaSOld, numberAlphaS); + } + + // End weight calculation. + return wt; + +} + + +//************************************************************************** + +} // end namespace Pythia8 diff --git a/PYTHIA8/pythia8130/xmldoc/ASecondHardProcess.xml b/PYTHIA8/pythia8130/xmldoc/ASecondHardProcess.xml new file mode 100644 index 00000000000..f08bd2a483e --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ASecondHardProcess.xml @@ -0,0 +1,334 @@ + + +

A Second Hard Process

+ +When you have selected a set of hard processes for hadron beams, the +multiple interactions +framework can add further interactions to build up a realistic +underlying event. These further interactions can come from a wide +variety of processes, and will occasionally be quite hard. They +do represent a realistic random mix, however, which means one cannot +predetermine what will happen. Occasionally there may be cases +where one wants to specify also the second hard interaction rather +precisely. The options on this page allow you to do precisely that. + + +Generate two hard scatterings in a collision between hadron beams. +You must further specify which set of processes to allow for +the second, see below. + + +

+In principle the whole process +selection allowed for the first process could be repeated +for the second one. However, this would probably be overkill. +Therefore here a more limited set of prepackaged process collections +are made available, that can then be further combined at will. +Since the description is almost completely symmetric between the +first and the second process, you always have the possibility +to pick one of the two processes according to the complete list +of possibilities. + +

+Here comes the list of allowed sets of processes, to combine at will: + + +Standard QCD 2 -> 2 processes involving gluons and +d, u, s, c, b quarks. + + + +A prompt photon recoiling against a quark or gluon jet. + + +Two prompt photons recoiling against each other. + + + +Scattering q qbar -> gamma^*/Z^0, with full interference +between the gamma^* and Z^0. + + + +Scattering q qbar' -> W^+-. + + + +Scattering q qbar -> gamma^*/Z^0 g and +q g -> gamma^*/Z^0 q. + + + +Scattering q qbar' -> W^+- g and +q g -> W^+- q'. + + +

+A further process collection comes with a warning flag: + + +The q qbar -> b bbar and g g -> b bbar processes. +These are already included in the TwoJets sample above, +so it would be doublecounting to include both, but we assume there +may be cases where the b subsample will be of special interest. +This subsample does not include flavour-excitation or gluon-splitting +contributions to the b rate, however, so, depending +on the topology if interest, it may or may not be a good approximation. + + +

+The second hard process obeys exactly the same selection rules for +phase space cuts and +couplings and scales +as the first one does. Specifically, a pTmin cut for +2 -> 2 processes would apply to the first and the second hard +process alike, and ballpark half of the time the second could be +generated with a larger pT than the first. (Exact numbers +depending on the relative shape of the two cross sections.) That is, +first and second is only used as an administrative distinction between +the two, not as a physics ordering one. + +

Cross-section calculation

+ +As an introduction, a brief reminder of Poissonian statistics. +Assume a stochastic process in time, for now not necessarily a +high-energy physics one, where the probability for an event to occur +at any given time is independent of what happens at other times. +Then the probability for n events to occur in a finite +time interval is + +P_n = <n>^n exp(-<n>) / n! + +where <n> is the average number of events. If this +number is small we can approximate exp(-<n>) = 1 , +so that P_1 = <n> and +P_2 = <n>^2 / 2 = P_1^2 / 2. + +

+Now further assume that the events actually are of two different +kinds a and b, occuring independently of each +other, such that <n> = <n_a> + <n_b>. +It then follows that the probability of having one event of type +a (or b) and nothing else is +P_1a = <n_a> (or P_1b = <n_b>). +From + +P_2 = (<n_a> + <n_b>)^2 / 2 = (P_1a + P_1b)^2 / 2 = +(P_1a^2 + 2 P_1a P_1b + P_1b^2) / 2 + +it is easy to read off that the probability to have exactly two +events of kind a and none of b is +P_2aa = P_1a^2 / 2 whereas that of having one a +and one b is P_2ab = P_1a P_1b. Note that the +former, with two identical events, contains a factor 1/2 +while the latter, with two different ones, does not. If viewed +in a time-ordered sense, the difference is that the latter can be +obtained two ways, either first an a and then a b +or else first a b and then an a. + +

+To translate this language into cross-sections for high-energy +events, we assume that interactions can occur at different pT +values independently of each other inside inelastic nondiffractive +(= "minbias") events. Then the above probabilities translate into +P_n = sigma_n / sigma_ND where sigma_ND is the +total nondiffractive cross section. Again we want to assume that +exp(-<n>) is close to unity, i.e. that the total +hard cross section above pTmin is much smaller than +sigma_ND. The hard cross section is dominated by QCD +jet production, and a reasonable precaution is to require a +pTmin of at least 20 GeV at LHC energies. +(For 2 -> 1 processes such as +q qbar -> gamma^*/Z^0 (-> f fbar) one can instead make a +similar cut on mass.) Then the generic equation +P_2 = P_1^2 / 2 translates into +sigma_2/sigma_ND = (sigma_1 / sigma_ND)^2 / 2 or +sigma_2 = sigma_1^2 / (2 sigma_ND). + +

+Again different processes a, b, c, ... contribute, +and by the same reasoning we obtain +sigma_2aa = sigma_1a^2 / (2 sigma_ND), +sigma_2ab = sigma_1a sigma_1b / sigma_ND, +and so on. + +

+There is one important correction to this picture: all collisions +do no occur under equal conditions. Some are more central in impact +parameter, others more peripheral. This leads to a further element of +variability: central collisions are likely to have more activity +than the average, peripheral less. Integrated over impact +parameter standard cross sections are recovered, but correlations +are affected by a "trigger bias" effect: if you select for events +with a hard process you favour events at small impact parameter +which have above-average activity, and therefore also increased +chance for further interactions. (In PYTHIA this is the origin +of the "pedestal effect", i.e. that events with a hard interaction +have more underlying activity than the level found in minimum-bias +events.) When you specify a matter overlap profile in the +multiple-interactions scenario, such an enhancement/depletion factor +f_impact is chosen event-by-event and can be averaged +during the course of the run. As an example, the double Gaussian +form used in Tune A gives approximately +<f_impact> = 2.5. The above equations therefore +have to be modified to +sigma_2aa = <f_impact> sigma_1a^2 / (2 sigma_ND), +sigma_2ab = <f_impact> sigma_1a sigma_1b / sigma_ND. +Experimentalists often instead use the notation +sigma_2ab = sigma_1a sigma_1b / sigma_eff, +from which we see that PYTHIA "predicts" +sigma_eff = sigma_ND / <f_impact>. +When the generation of multiple interactions is switched off it is +not possible to calculate <f_impact> and therefore +it is set to unity. + +

+When this recipe is to be applied to calculate +actual cross sections, it is useful to distinguish three cases, +depending on which set of processes are selected to study for +the first and second interaction. + +

+(1) The processes a for the first interaction and +b for the second one have no overlap at all. +For instance, the first could be TwoJets and the +second TwoPhotons. In that case, the two interactions +can be selected independently, and cross sections tabulated +for each separate subprocess in the two above classes. At the +end of the run, the cross sections in a should be multiplied +by <f_impact> sigma_1b / sigma_ND to bring them to +the correct overall level, and those in b by +<f_impact> sigma_1a / sigma_ND. + +

+(2) Exactly the same processes a are selected for the +first and second interaction. In that case it works as above, +with a = b, and it is only necessary to multiply by an +additional factor 1/2. A compensating factor of 2 +is automatically obtained for picking two different subprocesses, +e.g. if TwoJets is selected for both interactions, +then the combination of the two subprocesses q qbar -> g g +and g g -> g g can trivially be obtained two ways. + +

+(3) The list of subprocesses partly but not completely overlap. +For instance, the first process is allowed to contain a +or c and the second b or c, where +there is no overlap between a and b. Then, +when an independent selection for the first and second interaction +both pick one of the subprocesses in c, half of those +events have to be thrown, and the stored cross section reduced +accordingly. Considering the four possible combinations of first +and second process, this gives a + +sigma'_1 = sigma_1a + sigma_1c * (sigma_2b + sigma_2c/2) / +(sigma_2b + sigma_2c) + +with the factor 1/2 for the sigma_1c sigma_2c term. +At the end of the day, this sigma'_1 should be multiplied +by the normalization factor + +f_1norm = <f_impact> (sigma_2b + sigma_2c) / sigma_ND + +here without a factor 1/2 (or else it would have been +doublecounted). This gives the correct + +(sigma_2b + sigma_2c) * sigma'_1 = sigma_1a * sigma_2b ++ sigma_1a * sigma_2c + sigma_1c * sigma_2b + sigma_1c * sigma_2c/2 + +The second interaction can be handled in exact analogy. + +

+The listing obtained with the pythia.statistics() +already contain these corrections factors, i.e. cross sections +are for the occurence of two interactions of the specified kinds. +There is not a full tabulation of the matrix of all the possible +combinations of a specific first process together with a specific +second one (but the information is there for the user to do that, +if desired). Instead pythia.statistics() shows this +matrix projected onto the set of processes and associated cross +sections for the first and the second interaction, respectively. +Up to statistical fluctuations, these two sections of the +pythia.statistics() listing both add up to the same +total cross section for the event sample. + +

+There is a further special feature to be noted for this listing, +and that is the difference between the number of "selected" events +and the number of "accepted" ones. Here is how that comes about. +Originally the first and second process are selected completely +independently. The generation (in)efficiency is reflected in the +different number of intially tried events for the first and second +process, leading to the same number of selected events. While +acceptable on their own, the combination of the two processes may +be unacceptable, however. It may be that the two processes added +together use more energy-momentum than kinematically allowed, or, +even if not, are disfavoured when the PYTHIA approach to provide +correlated parton densities is applied. Alternatively, referring +to case (3) above, it may be because half of the events should +be thrown for identical processes. Taken together, it is these +effects that reduced the event number from "selected" to "accepted". +(A further reduction may occur if a +user hook rejects some events.) + +

+In the cross section calculation above, the sigma'_1 +cross sections are based on the number of accepted events, while +the f_1norm factor is evaluated based on the cross sections +for selected events. That way the suppression by correlations +between the two processes does not get to be doublecounted. + +

+The pythia.statistics() listing contains two final +lines, indicating the summed cross sections sigma_1sum and +sigma_2sum for the first and second set of processes, at +the "selected" stage above, plus information on the sigma_ND +and <f_impact> used. The total cross section +generated is related to this by + +<f_impact> * (sigma_1sum * sigma_2sum / sigma_ND) * +(n_accepted / n_selected) + + with an additional factor of 1/2 for case 2 above. + +

+The error quoted for the cross section of a process is a combination +in quadrature of the error on this process alone with the error on +the normalization factor, including the error on +<f_impact>. As always it is a purely statistical one +and of course hides considerably bigger systematic uncertainties. + +

Event information

+ +Normally the process event record only contains the +hardest interaction, but in this case also the second hardest +is stored there. If both of them are 2 -> 2 ones, the +first would be stored in lines 3 - 6 and the second in 7 - 10. +For both, status codes 21 - 29 would be used, as for a hardest +process. Any resonance decay chains would occur after the two +main processes, to allow normal parsing. The beams in 1 and 2 +only appear in one copy. This structure is echoed in the +full event event record. + +

+Most of the properties accessible by the +pythia.info +methods refer to the first process, whether that happens to be the +hardest or not. The code and pT scale of the second process +are accessible by the info.codeMI(1) and +info.pTMI(1), however. + +

+The sigmaGen() and sigmaErr() methods provide +the cross section and its error for the event sample as a whole, +combining the information from the two hard processes as described +above. In particular, the former should be used to give the +weight of the generated event sample. The statitical error estimate +is somewhat cruder and gives a larger value than the +subprocess-by-subprocess one employed in +pythia.statistics(), but this number is +anyway less relevant, since systematical errors are likely to dominate. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/AccessPYTHIA6Processes.xml b/PYTHIA8/pythia8130/xmldoc/AccessPYTHIA6Processes.xml new file mode 100644 index 00000000000..fc092dcbe61 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/AccessPYTHIA6Processes.xml @@ -0,0 +1,110 @@ + + +

Access PYTHIA 6 Processes

+ +Gradually all relevant processes from PYTHIA 6 are being +re-implemented in PYTHIA 8, but this transition is not finished. +For a while longer it may therefore at times be convenient to +access the Fortran PYTHIA 6 process library. In order to give +this access at runtime, and not only by writing/reading event files, +an interface is provided to C++. This interface is residing in +Pythia6Interface.h, and in addition the PYTHIA 6 library +must be linked. The latter should normally be the most recent +Fortran PYTHIA version, but must be at least 6.314, since this is +the first version that allows processes to be output in the Les +Houches format (and not only input). + +

+The routines interfaced are +

    +
  • pygive(command) to give in a command to change a +setting, e.g. to decide which processes should be generated, +
  • pyinit( frame, beam, target, wIn) to initialize +the event generation chain,
  • +
  • pyupin() to fill this initialization information +in the HEPRUP commonblock,
  • +
  • pyupev() to generate the next hard process and +fill the event information in the HEPEUP commonblock,
  • +
  • pylist( mode) to list the event at the process +level,
  • +
  • pystat( mode) to print statistics on the event +generation process.
  • +
+Details on allowed arguments are given in the PYTHIA 6.4 manual. + +

+These methods can be used in context of the +LHAupFortran class. +The existing code there takes care of converting HEPRUP +and HEPEUP commonblock information from Fortran to C++, +and of making it available to the PYTHIA 8 methods. What needs to be +supplied are the two LHAupFortran::fillHepRup() and +LHAupFortran::fillHepEup() methods. The first can +contain an arbitrary number of pygive(...), followed +by pyinit(...) and pyupin() in that order. +The second only needs to contain pyupev(). Finally, +the use of pylist(...) and pystat(...) +is entirely optional, and calls are best put directly in the +main program. + +

+This means that all other Fortran routines have not been interfaced +and cannot be accessed directly from the C++ code; there is no need +for them in the current setup. + +

+PYTHIA 6.4 does its own rejection of events internally, according to +the strategy option 3. However, the current runtime interface does not +take cross-section information from PYTHIA 6.4. This means that both +the initial maxima and the final cross sections printed by the PYTHIA 8 +routines are irrelevant in this case. Instead you have to study the +standard PYTHIA 6.4 initialization printout and call on +pystat(...) at the end of the run to obtain this information. +It also means that you cannot mix with internally generated events, +unlike what could have been allowed for strategy 3. Should a strong need +arise, PYTHIA 6.4 could be modified to work with strategy option 1 and +thus allow a mixing with internal processes, but we do not expect this +to happen. + +

+An example of a fillHepRup() method to set up +Z^0 production at LHC, with masses above 50 GeV, would be +

+bool LHAinitFortran::fillHepRup() { 
+  Pythia6Interface::pygive("msel = 11"); 
+  Pythia6Interface::pygive("ckin(1) = 50."); 
+  Pythia6Interface::pyinit("cms","p","p",14000.);   
+  Pythia6Interface::pyupin();
+  return true;
+}
+
+and the process-generic fillHepEup() method would be +
+bool LHAupFortran::fillHepEup() { 
+  Pythia6Interface::pyupev();
+  return true;
+}
+
+Note that, of all parameters that could be set with the +PYGIVE, only those that influence the generation of the +hard processes have any impact, since this is the only part of the +Fortran code that is used. Also, if you want to set many parameters, +you can easily collect them in one file (separate from PYTHIA 8 +input) and parse that file. + +

+All hard PYTHIA 6 processes should be available for full generation +in PYTHIA 8, at least to the extent that they are defined for beams +of protons and antiprotons, which is the key application for PYTHIA 8 +so far. Soft processes, i.e. elastic and diffractive scattering, as well +as minimum-bias events, require a different kinematics machinery, and +can only be generated with the internal PYTHIA 8 processes. + +

+A simple example is found in main51.cc, another with parsed +input in main52.cc and a third with HepMC output in +main54.cc. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/BeamParameters.xml b/PYTHIA8/pythia8130/xmldoc/BeamParameters.xml new file mode 100644 index 00000000000..c19b49d4e17 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/BeamParameters.xml @@ -0,0 +1,253 @@ + + +

Beam Parameters

+ +The settings on this page relate to the beam identities and energies, +to a beam momentum spread and to a beam interaction spot. +As always, momenta and energies are to be given in units of GeV, +and of space and time in mm. + +

Incoming beams

+ +There are two ways to set the identities and energies of the two incoming +beam particles. One is to use the init() method with no +arguments. Then the settings variables below will be read and used. The +alternative is to call init(...) with arguments that provide +this information. Then you need not use the variables below (although it +would still be possible). Note that, if nothing is done, you will default +to LHC at the nominal energy. + + +The PDG id code for the first incoming particle. + + + +The PDG id code for the second incoming particle. + + + +Choice of frame for the two colliding particles. + + + + + + + +Collision CM energy, to be set if Beams:frameType = 1. + + + +The energy of the first incoming particle, moving in the ++z direction, to be set if Beams:frameType = 2. +If the particle energy is smaller than its mass +it is assumed to be at rest. + + + +The energy of the second incoming particle, moving in the +-z direction, to be set if Beams:frameType = 2. +If the particle energy is smaller than its mass +it is assumed to be at rest. + + + +The p_x component of the first incoming particle, +to be set if Beams:frameType = 3. + + + +The p_y component of the first incoming particle, +to be set if Beams:frameType = 3. + + + +The p_z component of the first incoming particle, +to be set if Beams:frameType = 3. + + + +The p_x component of the second incoming particle, +to be set if Beams:frameType = 3. + + + +The p_y component of the second incoming particle, +to be set if Beams:frameType = 3. + + + +The p_z component of the second incoming particle, +to be set if Beams:frameType = 3. + + + +The name of a Les Houches Event File, +to be set if Beams:frameType = 4. + + +

Beam momentum spread

+ +This framework currently is intended for a modest beam spread, such as +experienced at hadron colliders. Thus it can be safely assumed that the +physics does not change over the CM energy range probed, so that the +parameters of the physics initialization at the nominal energy can be +used as is. Currently it can not be used for the more extensive +energy spread expected at linear e^+ e^- colliders. Also, +any attempt to combine it with external Les Houches input of +parton-level events is at own risk. + +

+On this page you can set the momentum spread according to a simple +Gaussian distribution. If you instead want a more sophisticated +parametrization, you can write and link your own +BeamShape class. + + +Allow the beam momenta to be smeared around their initialization +nominal values. + + + +The width of a Gaussian distribution of the p_x spread of the +first incoming particle. + + + +The width of a Gaussian distribution of the p_y spread of the +first incoming particle. + + + +The width of a Gaussian distribution of the p_z spread of the +first incoming particle. + + + +The triply Gaussian distribution (p_x, p_y, p_z) is restricted to +a maximal total deviation from the nominal values (p_x0, p_y0, p_z0) +for the first incoming particle, like + +(p_x - p_x0)^2/sigma_px^2 + (p_y - p_y0)^2/sigma_py^2 + +(p_z - p_z0)^2/sigma_pz^2 < maxDev^2 + +(Note the absence of a factor 2 in the denominator, unlike the Gaussians +used to pick (p_x, p_y, p_z).) + + + +The width of a Gaussian distribution of the p_x spread of the +second incoming particle. + + + +The width of a Gaussian distribution of the p_y spread of the +second incoming particle. + + + +The width of a Gaussian distribution of the p_z spread of the +second incoming particle. + + + +The triply Gaussian distribution (p_x, p_y, p_z) is restricted to +a maximal total deviation from the nominal values (p_x0, p_y0, p_z0), +for the second incoming particle, like + +(p_x - p_x0)^2/sigma_px^2 + (p_y - p_y0)^2/sigma_py^2 + +(p_z - p_z0)^2/sigma_pz^2 < maxDev^2 + +(Note the absence of a factor 2 in the denominator, unlike the Gaussians +used to pick (p_x, p_y, p_z).) + + +

Beam interaction vertex

+ +On this page you can set the spread of the interaction vertex according to +a simple Gaussian distribution. If you instead want a more sophisticated +parametrization, you can write and link your own +BeamShape class. + + +Allow the interaction vertex of the two colliding beams to be smeared. +If off, then the vertex is set to be the origin. + + + +The width of a Gaussian distribution of the x location of the +interaction vertex. + + + +The width of a Gaussian distribution of the y location of the +interaction vertex. + + + +The width of a Gaussian distribution of the z location of the +interaction vertex. + + + +The triply Gaussian distribution of interaction vertex position +(x, y, z) is restricted to a maximal total deviation from the +origin, like + +x^2/sigma_x^2 + y^2/sigma_y^2 + z^2/sigma_z^2 < maxDevVertex^2 + +(Note the absence of a factor 2 in the denominator, unlike the Gaussians +used to pick (x, y, z).) + + + +The width of a Gaussian distribution of the collision time (in units of +mm/c). Note that, if the above space parametrization is viewed as the +effect of two incoming beams along the +-z axis, with each beam +having a Gaussian spread, then the spread of the time would also become +a Gaussian with the same width as the z one (times the +velocity of the beams, which we expect is close to unity). For flexibility +we have not enforced any such relation, however. + + + +The collision time is restricted to be in the range +|t| < sigma_t * maxDevTime. + + +

+The distributions above are all centered at the origin. It is also +possible to shift the above distributions to be centered around another +nominal position. You must have Beams:allowVertexSpread = on +to use this possibility. + + +The x location of the interaction vertex is centered at this value. + + + +The y location of the interaction vertex is centered at this value. + + + +The z location of the interaction vertex is centered at this value. + + + +The time t of the interaction vertex is centered at this value. + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/BeamRemnants.xml b/PYTHIA8/pythia8130/xmldoc/BeamRemnants.xml new file mode 100644 index 00000000000..b7e89ff2bc9 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/BeamRemnants.xml @@ -0,0 +1,313 @@ + + +

Beam Remnants

+ +

Introduction

+ +The BeamParticle class contains information on all partons +extracted from a beam (so far). As each consecutive multiple interaction +defines its respective incoming parton to the hard scattering a +new slot is added to the list. This information is modified when +the backwards evolution of the spacelike shower defines a new +initiator parton. It is used, both for the multiple interactions +and the spacelike showers, to define rescaled parton densities based +on the x and flavours already extracted, and to distinguish +between valence, sea and companion quarks. Once the perturbative +evolution is finished, further beam remnants are added to obtain a +consistent set of flavours. The current physics framework is further +described in Sjo04. + +

+Much of the above information is stored in a vector of +ResolvedParton objects, which each contains flavour and +momentum information, as well as valence/companion information and more. +The BeamParticle method list() shows the +contents of this vector, mainly for debug purposes. + +

+The BeamRemnants class takes over for the final step +of adding primordial kT to the initiators and remnants, +assigning the relative longitudinal momentum sharing among the +remnants, and constructing the overall kinematics and colour flow. +This step couples the two sides of an event, and could therefore +not be covered in the BeamParticle class, which only +considers one beam at a time. + +

+The methods of these classes are not intended for general use, +and so are not described here. + +

+In addition to the parameters described on this page, note that the +choice of parton densities is made +in the Pythia class. Then pointers to the pdf's are handed +on to BeamParticle at initialization, for all subsequent +usage. + +

Primordial kT

+ +The primordial kT of initiators of hard-scattering subsystems +are selected according to Gaussian distributions in p_x and +p_y separately. The widths of these distributions are chosen +to be dependent on the hard scale of the central process and on the mass +of the whole subsystem defined by the two initiators: + +sigma = (sigma_soft * Q_half + sigma_hard * Q) / (Q_half + Q) + * m / (m_half + m) + +Here Q is the hard-process renormalization scale for the +hardest process and the pT scale for subsequent multiple +interactions, m the mass of the system, and +sigma_soft, sigma_hard, Q_half and +m_half parameters defined below. Furthermore each separately +defined beam remnant has a distribution of width sigma_remn, +independently of kinematical variables. + + +Allow or not selection of primordial kT according to the +parameter values below. + + + +The width sigma_soft in the above equation, assigned as a +primordial kT to initiators in the soft-interaction limit. + + + +The width sigma_hard in the above equation, assigned as a +primordial kT to initiators in the hard-interaction limit. + + + +The scale Q_half in the equation above, defining the +half-way point between hard and soft interactions. + + + +The scale m_half in the equation above, defining the +half-way point between low-mass and high-mass subsystems. +(Kinematics construction can easily fail if a system is assigned +a primordial kT value higher than its mass, so the +mass-dampening is intended to reduce some troubles later on.) + + + +The width sigma_remn, assigned as a primordial kT +to beam-remnant partons. + + +

+A net kT imbalance is obtained from the vector sum of the +primordial kT values of all initiators and all beam remnants. +This quantity is compensated by a shift shared equally between +all partons, except that the dampening factor m / (m_half + m) +is again used to suppress the role of small-mass systems. + +

+Note that the current sigma definition implies that +<pT^2> = <p_x^2>+ <p_y^2> = 2 sigma^2. +It thus cannot be compared directly with the sigma +of nonperturbative hadronization, where each quark-antiquark +breakup corresponds to <pT^2> = sigma^2 and only +for hadrons it holds that <pT^2> = 2 sigma^2. +The comparison is further complicated by the reduction of +primordial kT values by the overall compensation mechanism. + +

Colour flow

+ +The colour flows in the separate subprocesses defined in the +multiple-interactions scenario are tied together via the assignment +of colour flow in the beam remnant. This is not an unambiguous +procedure, but currently no parameters are directly associated with it. +However, a simple "minimal" procedure of colour flow only via the beam +remnants does not result in a scenario in +agreement with data, notably not a sufficiently steep rise of +<pT>(n_ch). The true origin of this behaviour and the +correct mechanism to reproduce it remains one of the big unsolved issues +at the borderline between perturbative and nonperturbative QCD. +As a simple attempt, an additional step is introduced, wherein the gluons +of a lower-pT system are merged with the ones in a higher-pT one. + + +Allow or not a system to be merged with another one. + + + +A system with a hard scale pT can be merged with one of a +harder scale with a probability that is +pT0_Rec^2 / (pT0_Rec^2 + pT^2), where +pT0_Rec is reconnectRange times pT0, +the latter being the same energy-dependent dampening parameter as +used for multiple interactions. +Thus it is easy to merge a low-pT system with any other, +but difficult to merge two high-pT ones with each other. + + +

+The procedure is used iteratively. Thus first the reconnection probability +P = pT0_Rec^2 / (pT0_Rec^2 + pT^2) of the lowest-pT +system is found, and gives the probability for merger with the +second-lowest one. If not merged, it is tested with the third-lowest one, +and so on. For the m'th higher system the reconnection +probability thus becomes (1 - P)^(m-1) P. That is, there is +no explicit dependence on the higher pT scale, but implicitly +there is via the survival probability of not already having been merged +with a lower-pT system. Also note that the total reconnection +probability for the lowest-pT system in an event with n +systems becomes 1 - (1 - P)^(n-1). Once the fate of the +lowest-pT system has been decided, the second-lowest is considered +with respect to the ones above it, then the third-lowest, and so on. + +

+Once it has been decided which systems should be joined, the actual merging +is carried out in the opposite direction. That is, first the hardest +system is studied, and all colour dipoles in it are found (including to +the beam remnants, as defined by the holes of the incoming partons). +Next each softer system to be merged is studied in turn. Its gluons are, +in decreasing pT order, inserted on the colour dipole i,j +that gives the smallest (p_g p_i)(p_g p_j)/(p_i p_j), i.e. +minimizes the "disturbance" on the existing dipole, in terms of +pT^2 or Lambda measure (string length). The insertion +of the gluon means that the old dipole is replaced by two new ones. +Also the (rather few) quark-antiquark pairs that can be traced back to +a gluon splitting are treated in close analogy with the gluon case. +Quark lines that attach directly to the beam remnants cannot be merged +but are left behind. + +

+The joining procedure can be viewed as a more sophisticated variant of +the one introduced already in Sjo87. Clearly it is ad hoc. +It hopefully captures some elements of truth. The lower pT scale +a system has the larger its spatial extent and therefore the larger its +overlap with other systems. It could be argued that one should classify +individual initial-state partons by pT rather than the system +as a whole. However, for final-state radiation, a soft gluon radiated off +a hard parton is actually produced at late times and therefore probably +less likely to reconnect. In the balance, a classification by system +pT scale appears sensible as a first try. + +

+Note that the reconnection is carried out before resonance decays are +considered. Colour inside a resonance therefore is not reconnected. +This is a deliberate choice, but certainly open to discussion and +extensions at a later stage, as is the rest of this procedure. + +

Further variables

+ + +The maximum valence quark kind allowed in acceptable incoming beams, +for which multiple interactions are simulated. Default is that hadrons +may contain u, d and s quarks, +but not c and b ones, since sensible +kinematics has not really been worked out for the latter. + + + +When a sea quark has been found, a companion antisea quark ought to be +nearby in x. The shape of this distribution can be derived +from the gluon mother distribution convoluted with the +g -> q qbar splitting kernel. In practice, simple solutions +are only feasible if the gluon shape is assumed to be of the form +g(x) ~ (1 - x)^p / x, where p is an integer power, +the parameter above. Allowed values correspond to the cases programmed. +
+Since the whole framework is approximate anyway, this should be good +enough. Note that companions typically are found at small Q^2, +if at all, so the form is supposed to represent g(x) at small +Q^2 scales, close to the lower cutoff for multiple interactions. +
+ +

+When assigning relative momentum fractions to beam-remnant partons, +valence quarks are chosen according to a distribution like +(1 - x)^power / sqrt(x). This power is given below +for quarks in mesons, and separately for u and d +quarks in the proton, based on the approximate shape of low-Q^2 +parton densities. The power for other baryons is derived from the +proton ones, by an appropriate mixing. The x of a diquark +is chosen as the sum of its two constituent x values, and can +thus be above unity. (A common rescaling of all remnant partons and +particles will fix that.) An additional enhancement of the diquark +momentum is obtained by its x value being rescaled by the +valenceDiqEnhance factor. + + +The abovementioned power for valence quarks in mesons. + + + +The abovementioned power for valence u quarks in protons. + + + +The abovementioned power for valence d quarks in protons. + + + +Enhancement factor for valence diqaurks in baryons, relative to the +simple sum of the two constituent quarks. + + + +The off option is intended for debug purposes only, as +follows. When more than one valence quark is kicked out of a baryon +beam, as part of the multiple interactions scenario, the subsequent +hadronization is described in terms of a junction string topology. +This description involves a number of technical complications that +may make the program more unstable. As an alternative, by switching +this option off, junction configurations are rejected (which gives +an error message that the remnant flavour setup failed), and the +multiple interactions and showers are redone until a +junction-free topology is found. + + +

Diffractive system

+ +When an incoming hadron beam is diffractively excited, it is modeled +as if either a valence quark or a gluon is kicked out from the hadron. +In the former case this produces a simple string to the leftover +remnant, in the latter it gives a hairpin arrangement where a string +is stretched from one quark in the remnant, via the gluon, back to the +rest of the remnant. The latter ought to dominate at higher mass of +the diffractive system. Therefore an approximate behaviour like + +P_q / P_g = N / m^p + +is assumed. + + +The abovementioned normalization N for the relative quark +rate in diffractive systems. + + + +The abovementioned mass-dependence power p for the relative +quark rate in diffractive systems. + + +

+When a gluon is kicked out from the hadron, the longitudinal momentum +sharing between the the two remnant partons is determined by the +same parameters as above. It is plausible that the primordial +kT may be lower than in perturbative processes, however: + + +The width of Gaussian distributions in p_x and p_y +separately that is assigned as a primordial kT to the two +beam remnants when a gluon is kicked out of a diffractive system. + + + +The choice of longitudinal and transverse structure of a diffractive +beam remnant for a kicked-out gluon implies a remnant mass +m_rem distribution (i.e. quark plus diquark invariant mass +for a baryon beam) that knows no bounds. A suppression like +(1 - m_rem^2 / m_diff^2)^p is therefore introduced, where +p is the diffLargeMassSuppress parameter. + + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/BeamShape.xml b/PYTHIA8/pythia8130/xmldoc/BeamShape.xml new file mode 100644 index 00000000000..4378aee38d6 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/BeamShape.xml @@ -0,0 +1,56 @@ + + +

Beam Shape

+ +The Beam Parameters +page explains how you can set a momentum spread of the two incoming +beams, and a spread and offset for the location of the interaction +vertex. The spread is based on a simple parametrization in terms of +independent Gaussians, however, which is likely to be too primitive +for realistic applications. + +

+It is therefore possible to define your own class, derived from the +BeamShape base class, and hand it in to Pythia with the + +pythia.setBeamShapePtr( BeamShape*) method. +Below we describe what such a class has to do. An explicit toy example +is shown in main27.cc. + +

+The BeamShape base class has a very simple structure. +It only has two virtual methods. The first, init(), is +used for initialization. The second, pick(), selects +beam momentum and production vertex in the current event. + +

+The base-class init() method simply reads in the values +stored in the Settings data base. You are free to +write your own derived initialization routine, or use the existing one. +In the latter case you can then give your own modified interpretation +to the beam spread parameters defined there. + +

+The two flags Beams:allowMomentumSpread and +Beams:allowVertexSpread should not be tampered with, +however. These are checked elsewhere to determine whether the beam +shape should be set or not, whereas the other momentum-spread +and vertex-spread parameters are local to this class. + +

+The pick() method is the key one to supply in the derived +class. Here you are free to pick whatever parametrization you desire +for beam momenta and vertex position, including correlations between +the two. At the end of the day, you should set +
deltaPxA, deltaPyA, deltaPzA for the three-momentum +deviation of the first incoming beam, relative to the nominal values; +
deltaPxB, deltaPyB, deltaPzB for the three-momentum +deviation of the second incoming beam, relative to the nominal values; +
vertexX, vertexY, vertexZ, vertexT for the +production-vertex position and time. +
These values will then be read out with the three base-class methods +deltaPA(), deltaPB() and vertex(). + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/Bibliography.xml b/PYTHIA8/pythia8130/xmldoc/Bibliography.xml new file mode 100644 index 00000000000..737667f4df2 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/Bibliography.xml @@ -0,0 +1,155 @@ + + +

Bibliography

+ +
+ +
Alt89
+
G. Altarelli, B. Mele and M. Ruiz-Altaba, +Z. Phys. C45 (1989) 109
+ +
Alw06
+
J. Alwall et al., Computer Physics Commun. 176 (2007) 300 +[hep-ph/0609017]
+ +
And83
+
B. Andersson, G. Gustafson, G. Ingelman and T. Sjöstrand, +Phys. Rep. 97 (1983) 31
+ +
Bar06
+
M. Bargiotti, talk at the HERA4LHC workshop, +http://mbargiot.web.cern.ch/mbargiot/talks/ + +
Bau90
+
U. Baur, M. Spira and P. M. Zerwas, Phys. Rev. D42 (1990) 815
+ +
Ben85
+
H.-U. Bengtsson, W.-S. Hou, A. Soni and D.H. Stork, +Phys. Rev. Lett. 55 (1985) 2762
+ +
Ben87
+
M. Bengtsson and T. Sjöstrand, Nucl. Phys. B289 (1987) 810
+ +
Ber87
+
UA4 Collaboration, D. Bernard et al., Phys. Lett. B198 (1987) 583
+ +
Boo01
+
E. Boos et al., in the Proceedings of the Workshop on Physics +at TeV Colliders, Les Houches, France, 21 May - 1 Jun 2001 +[hep-ph/0109068]
+ +
Bow81
+
M.G. Bowler, Z. Phys. C11 (1981) 169
+ +
Cah82
+
R. Cahn, Z. Physik C15 (1982) 253
+ +
Dob01
+
M. Dobbs and J.B. Hansen, Computer Physics Comm. 134 (2001) 41
+ +
Don92
+
A. Donnachie and P.V. Landshoff, Phys. Lett. B296 (1992) 227
+ +
Ede97
+
P. Eden and G. Gustafson, Z. Phys. C75 (1997) 41
+ +
Glu95
+
M. Glück, E. Reya and A. Vogt, Z. Phys. C67 (1995) 433
+ +
Gus86
+
G. Gustafson, Phys. Lett. B175 (1986) 453; +
G. Gustafson and U. Pettersson, Nucl. Phys. B306 (1988) 746; +
L. Lönnblad, Computer Physics Commun. 71 (1992) 15
+ +
Hew88
+
J.L. Hewett and S. Pakvasa, Phys. Rev. D37 (1988) 3165
+ +
Hui97
+
K. Huitu, J. Maalampi, A. Pietilä and M. Raidal, +Nucl. Phys. B487 (1997) 27 and private communication; +
G. Barenboim, K. Huitu, J. Maalampi and M. Raidal, +Phys. Lett. B394 (1997) 132
+ +
Kle89
+
R. Kleiss et al., in `Z physics at LEP 1', +eds. G. Altarelli, R. Kleiss and C. Verzegnassi, +CERN 89-08 (Geneva, 1989), Vol. 3, p. 143
+ +
Lai00
+
CTEQ Collaboration, H.L. Lai et al., +Eur. Phys. J. C12 (2000) 375
+ +
Lon95
+
L. Lönnblad and T. Sjöstrand, Phys. Lett. B351 (1995) 293, +Eur. Phys. J. C2 (1998) 165
+ +
Mar90
+
G. Marsaglia, A. Zaman and W.-W. Tsang, +Stat. Prob. Lett. 9 (1990) 35
+ +
Miu99
+
G. Miu and T. Sjöstrand, Phys. Lett. B449 (1999) 313
+ +
Nas00
+
P. Nason et al., in "Standard model physics (and more) at the LHC", +eds. G. Altarelli and M.L. Mangano, CERN 2000-004, p. 231 +[hep-ph/0003142]
+ +
Nor00
+
E. Norrbin and T. Sjöstrand, Eur. Phys. J. C17 (2000) 137
+ +
Nor01
+
E. Norrbin and T. Sjöstrand, Nucl. Phys. B603 (2001) 297
+ +
Pet83
+
C. Peterson, D. Schlatter, I. Schmitt and P. Zerwas, +Phys. Rev. D27 (1983) 105
+ +
Sch97
+
G.A. Schuler and T. Sjöstrand, Phys. Rev. D49 (1994) 2257, +Z. Phys. C73 (1997) 677
+ +
Sjo84
+
T. Sjöstrand, Nucl. Phys. B248 (1984) 469
+ +
Sey95
+
M. Seymour, Phys. Lett. B354 (1995) 409
+ +
Sjo85
+
T. Sjöstrand, Phys. Lett. 157B (1985) 321; +
M. Bengtsson, T. Sjöstrand and M. van Zijl, Z. Phys. C32 (1986) 67 +
+ +
Sjo87
+
T. Sjöstrand and M. van Zijl, Phys. Rev. D36 (1987) 2019
+ +
Sjo03
+
T. Sjöstrand and P.Z. Skands, Nucl. Phys. B659 (2003) 243
+ +
Sjo04
+
T. Sjöstrand and P.Z. Skands, JHEP 03 (2004) 053
+ +
Sjo05
+
T. Sjöstrand and P.Z. Skands, Eur. Phys. J. C39 (2005) 129
+ +
Sjo06
+
T. Sjöstrand, S. Mrenna and P.Z. Skands, +JHEP 05 (2006) 026 [hep-ph/0603175]
+ +
Ska04
+
P. Skands et al., JHEP 07 (2004) 036 [hep-ph/0311123]
+ +
Wha05
+
M.R. Whalley, D. Bourilkov and R.C. Group, +in `HERA and the LHC', eds. A. De Roeck and H. Jung, +CERN-2005-014, p. 575 [hep-ph/0508110]
+ +
Yao06
+
Particle Data Group, W.-M. Yao et al., +J. Phys. G33 (2006) 1
+ +
+ +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/BoseEinsteinEffects.xml b/PYTHIA8/pythia8130/xmldoc/BoseEinsteinEffects.xml new file mode 100644 index 00000000000..6894623ad90 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/BoseEinsteinEffects.xml @@ -0,0 +1,116 @@ + + +

Bose-Einstein Effects

+ +The BoseEinstein class performs shifts of momenta +of identical particles to provide a crude estimate of +Bose-Einstein effects. The algorithm is the BE_32 one described in +Lon95, with a Gaussian parametrization of the enhancement. +We emphasize that this approach is not based on any first-principles +quantum mechanical description of interference phenomena; such +approaches anyway have many problems to contend with. Instead a cruder +but more robust approach is adopted, wherein BE effects are introduced +after the event has already been generated, with the exception of the +decays of long-lived particles. The trick is that momenta of identical +particles are shifted relative to each other so as to provide an +enhancement of pairs closely separated, which is compensated by a +depletion of pairs in an intermediate region of separation. + +

+More precisely, the intended target form of the BE corrrelations in +BE_32 is + +f_2(Q) = (1 + lambda * exp(-Q^2 R^2)) + * (1 + alpha * lambda * exp(-Q^2 R^2/9) * (1 - exp(-Q^2 R^2/4))) + +where Q^2 = (p_1 + p_2)^2 - (m_1 + m_2)^2. +Here the strength lambda and effective radius R +are the two main parameters. The first factor of the +equation is implemented by pulling pairs of identical hadrons closer +to each other. This is done in such a way that three-monentum is +conserved, but at the price of a small but non-negligible negative +shift in the energy of the event. The second factor compensates this +by pushing particles apart. The negative alpha parameter is +determined iteratively, separately for each event, so as to restore +energy conservation. The effective radius parameter is here R/3, +i.e. effects extend further out in Q. Without the dampening +(1 - exp(-Q^2 R^2/4)) in the second factor the value at the +origin would become f_2(0) = (1 + lambda) * (1 + alpha * lambda), +with it the desired value f_2(0) = (1 + lambda) is restored. +The end result can be viewed as a poor man's rendering of a rapidly +dampened oscillatory behaviour in Q. + +

+Further details can be found in Lon95. For instance, the +target is implemented under the assumption that the initial distribution +in Q can be well approximated by pure phase space at small +values, and implicitly generates higher-order effects by the way +the algorithm is implemented. The algorithm is applied after the decay +of short-lived resonances such as the rho, but before the decay +of longer-lived particles. + +

+This algorithm is known to do a reasonable job of describing BE +phenomena at LEP. It has not been tested against data for hadron +colliders, to the best of our knowledge, so one should exercise some +judgement before using it. Therefore by default the master switch +HadronLevel:BoseEinstein is off. +Furthermore, the implementation found here is not (yet) as +sophisticated as the one used at LEP2, in that no provision is made +for particles from separate colour singlet systems, such as +W's and Z's, interfering only at a reduced rate. + +

+Warning: The algorithm will create a new copy of each particle +with shifted momentum by BE effects, with status code 99, while the +original particle with the original momentum at the same time will be +marked as decayed. This means that if you e.g. search for all +pi+- in an event you will often obtain the same particle twice. +One way to protect yourself from unwanted doublecounting is to +use only particles with a positive status code, i.e. ones for which +event[i].isFinal() is true. + + +

Main parameters

+ + +Include effects or not for identical pi^+, pi^- +and pi^0. + + + +Include effects or not for identical K^+, K^-, +K_S^0 and K_L^0. + + + +Include effects or not for identical eta and eta'. + + + +The strength parameter for Bose-Einstein effects. On physical grounds +it should not be above unity, but imperfections in the formalism +used may require that nevertheless. + + + +The size parameter of the region in Q space over which +Bose-Einstein effects are significant. Can be thought of as +the inverse of an effective distance in normal space, +R = hbar / QRef, with R as used in the above equation. +That is, f_2(Q) = (1 + lambda * exp(-(Q/QRef)^2)) * (...). + + + +Particle species with a width above this value (in GeV) are assumed +to be so short-lived that they decay before Bose-Einstein effects +are considered, while otherwise they do not. In the former case the +decay products thus can obtain shifted momenta, in the latter not. +The default has been picked such that both rho and +K^* decay products would be modified. + + +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/CompositenessProcesses.xml b/PYTHIA8/pythia8130/xmldoc/CompositenessProcesses.xml new file mode 100644 index 00000000000..2da6a8022cc --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/CompositenessProcesses.xml @@ -0,0 +1,150 @@ + + +

Compositeness Processes

+ +Compositeness scenarios may give rise to sharp resonances of excited +quarks and leptons. An excited copy of the first generation is +implemented, consisting of spin 1/2 particles. + +

+The current implementation contains gauge interaction production +by quark-gluon fusion or lepton-photon fusion and contact interaction +production by quark-quark or quark-antiquark scattering. In additions +to the compositness scale and couplings listed below, you are expected +to change the excited-fermion masses in accordance with what is desired. +See Bau90 for conventions. + +

+A non-trivial angular dependence is included in the decay for the +2 -> 1 processes, but has not been included for the +2 -> 2 ones. + +

Production processes

+ +A few different production processes have been implemented, which normally +would not overlap and therefore could be run together. + + +Common switch for the group of implemented processes that produce an +excited fermion. + + + +Scatterings d g -> d^*. +Code 4001. + + + +Scatterings u g -> u^*. +Code 4002. + + + +Scatterings s g -> s^*. +Code 4003. + + + +Scatterings c g -> c^*. +Code 4004. + + + +Scatterings b g -> b^*. +Code 4005. + + + +Scatterings e gamma -> e^*. +Code 4011. + + + +Scatterings mu gamma -> mu^*. +Code 4013. + + + +Scatterings tau gamma -> tau^*. +Code 4015. + + + +Scatterings q q(bar) -> d^* q(bar). +Code 4021. + + + +Scatterings q q(bar) -> u^* q(bar). +Code 4022. + + + +Scatterings q q(bar) -> s^* q(bar). +Code 4023. + + + +Scatterings q q(bar) -> c^* q(bar). +Code 4024. + + + +Scatterings q q(bar) -> b^* q(bar). +Code 4025. + + + +Scatterings q qbar -> e^*+- e^-+. +Code 4031. + + + +Scatterings q qbar -> nu_e^* nu_ebar. +Code 4032. + + + +Scatterings q qbar -> mu^*+- mu^-+. +Code 4033. + + + +Scatterings q qbar -> nu_mu^* nu_mubar. +Code 4034. + + + +Scatterings q qbar -> tau^*+- tau^-+. +Code 4035. + + + +Scatterings q qbar -> nu_tau^* nu_taubar. +Code 4036. + + +

Parameters

+ +The basic couplings of the model are + + +compositeness scale Lambda in GeV. + + + +strength f of the SU(2) coupling. + + + +strength f' of the U(1) coupling. + + + +strength f_c of the SU(3) coupling. + + +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/CouplingsAndScales.xml b/PYTHIA8/pythia8130/xmldoc/CouplingsAndScales.xml new file mode 100644 index 00000000000..d8e32cbd42e --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/CouplingsAndScales.xml @@ -0,0 +1,287 @@ + + +

Couplings and Scales

+ +Here is collected some possibilities to modify the scale choices +of couplings and parton densities for all internally implemented +hard processes. This is based on them all being derived from the +SigmaProcess base class. The matrix-element coding is +also used by the multiple-interactions machinery, but there with a +separate choice of alpha_strong(M_Z^2) value and running, +and separate PDF scale choices. Also, in 2 -> 2 and +2 -> 3 processes where resonances are produced, their +couplings and thereby their Breit-Wigner shapes are always evaluated +with the resonance mass as scale, irrespective of the choices below. + +

Couplings and K factor

+ +The size of QCD cross sections is mainly determined by + +The alpha_strong value at scale M_Z^2. + + +

+The actual value is then regulated by the running to the Q^2 +renormalization scale, at which alpha_strong is evaluated + +Order at which alpha_strong runs, + + + + + +

+QED interactions are regulated by the alpha_electromagnetic +value at the Q^2 renormalization scale of an interaction. + +The running of alpha_em used in hard processes. + + + + + +

+In addition there is the possibility of a global rescaling of +cross sections (which could not easily be accommodated by a +changed alpha_strong, since alpha_strong runs) + +Multiply almost all cross sections by this common fix factor. Excluded +are only unresolved processes, where cross sections are better +set directly, and +multiple interactions, which have a separate K factor +of their own. +This degree of freedom is primarily intended for hadron colliders, and +should not normally be used for e^+e^- annihilation processes. + + +

Renormalization scales

+ +The Q^2 renormalization scale can be chosen among a few different +alternatives, separately for 2 -> 1, 2 -> 2 and two +different kinds of 2 -> 3 processes. In addition a common +multiplicative factor may be imposed. + + +The Q^2 renormalization scale for 2 -> 1 processes. +The same options also apply for those 2 -> 2 and 2 -> 3 +processes that have been specially marked as proceeding only through +an s-channel resonance, by the isSChannel() virtual +method of SigmaProcess. + + + + + +The Q^2 renormalization scale for 2 -> 2 processes. + + + + + + + + +The Q^2 renormalization scale for "normal" 2 -> 3 +processes, i.e excepting the vector-boson-fusion processes below. +Here it is assumed that particle masses in the final state either match +or are heavier than that of any t-channel propagator particle. +(Currently only g g / q qbar -> H^0 Q Qbar processes are +implemented, where the "match" criterion holds.) + + + + + + + + + +The Q^2 renormalization scale for 2 -> 3 +vector-boson-fusion processes, i.e. f_1 f_2 -> H^0 f_3 f_4 +with Z^0 or W^+- t-channel propagators. +Here the transverse masses of the outgoing fermions do not reflect the +virtualities of the exchanged bosons. A better estimate is obtained +by replacing the final-state fermion masses by the vector-boson ones +in the definition of transverse masses. We denote these combinations +mT_Vi^2 = m_V^2 + pT_i^2. + + + + + + + + + +The Q^2 renormalization scale for 2 -> 1, +2 -> 2 and 2 -> 3 processes is multiplied by +this factor relative to the scale described above (except for the options +with a fix scale). Should be use sparingly for 2 -> 1 processes. + + + +A fix Q^2 value used as renormalization scale for 2 -> 1, +2 -> 2 and 2 -> 3 processes in some of the options above. + + +

Factorization scales

+ +Corresponding options exist for the Q^2 factorization scale +used as argument in PDF's. Again there is a choice of form for +2 -> 1, 2 -> 2 and 2 -> 3 processes separately. +For simplicity we have let the numbering of options agree, for each event +class separately, between normalization and factorization scales, and the +description has therefore been slightly shortened. The default values are +not necessarily the same, however. + + +The Q^2 factorization scale for 2 -> 1 processes. +The same options also apply for those 2 -> 2 and 2 -> 3 +processes that have been specially marked as proceeding only through +an s-channel resonance. + + + + + +The Q^2 factorization scale for 2 -> 2 processes. + + + + + + + + +The Q^2 factorization scale for "normal" 2 -> 3 +processes, i.e excepting the vector-boson-fusion processes below. + + + + + + + + + +The Q^2 factorization scale for 2 -> 3 +vector-boson-fusion processes, i.e. f_1 f_2 -> H^0 f_3 f_4 +with Z^0 or W^+- t-channel propagators. +Here we again introduce the combinations mT_Vi^2 = m_V^2 + pT_i^2 +as replacements for the normal squared transverse masses of the two +outgoing quarks. + + + + + + + + + +The Q^2 factorization scale for 2 -> 1, +2 -> 2 and 2 -> 3 processes is multiplied by +this factor relative to the scale described above (except for the options +with a fix scale). Should be use sparingly for 2 -> 1 processes. + + + +A fix Q^2 value used as factorization scale for 2 -> 1, +2 -> 2 and 2 -> 3 processes in some of the options above. + + +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/ElectroweakProcesses.xml b/PYTHIA8/pythia8130/xmldoc/ElectroweakProcesses.xml new file mode 100644 index 00000000000..64adf8e3717 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ElectroweakProcesses.xml @@ -0,0 +1,225 @@ + + +

Electroweak Processes

+ +This page contains processes involving Prompt-photon, gamma^*/Z^0 +and W^+- production, plus a few with t-channel boson +exchange. + +

Prompt photon processes

+ +This group collects the processes where one or two photons are +produced by the hard process. Additional sources of photons +include parton showers and hadron decays. A pT cut +is required to stay away from the unphysical low-pT region. +An eikonalized description, intended to be valid at all pT, +is included as part of the multiple-interactions framework. + + +Common switch for the group of all prompt photon processes, +as listed separately in the following. + + + +Scattering q g -> q gamma. +Code 201. + + + +Scattering q qbar -> g gamma. +Code 202. + + + +Scattering g g -> g gamma. +Note: This is a box graph. The full quark-mass dependence +in the loop leads to very complicated expressions. The current +implementation is based on assuming five massless quarks (see below), +and thus is questionable at small (pT < m_b) or large +(pT > m_t) transverse momenta. +Code 203. + + + +Scattering q qbar -> gamma gamma. +Code 204. + + + +Scattering g g -> gamma gamma. +Note: This is a box graph. The full quark-mass dependence +in the loop leads to very complicated expressions. The current +implementation is based on assuming five massless quarks (see below), +and thus is questionable at small (pT < m_b) or large +(pT > m_t) transverse momenta. +Code 205. + + + +Number of quark flavours included in the box graphs resposible for +g g -> g gamma and g g-> gamma gamma processes. +Owing to the complexity if the massive expressions, quarks are treated +as massless. The default value should be applicable in the range of +transverse momenta above the b mass but below the t one. + + +

Weak boson processes

+ +Under this heading we group processes involving the production +of a single electroweak gauge boson, i.e. a gamma^*/Z^0 +or a W^+-, or a pair of them, or one of them in +combination with a parton. Since the three sets are partly +conflicting, each is associated with its own group flag. +In addition, t-channel exchange of such a boson +between two fermions form a separate group. + +

+There is one flag that can be used to influence the gamma^*/Z^0 +structure in all the processes below where it is produced, unless +otherwise stated. + +Choice of full gamma^*/Z^0 structure or not in relevant +processes. + + + +Note: irrespective of the option used, the particle produced +will always be assigned code 23 for Z^0, and open decay channels +is purely dictated by what is set for the Z^0. + + +

Boson exchange

+ +The two processes in this subgroup is included as part of the +multiple-interactions framework. + + +Common switch for the group of gamma^*/Z^0 +or W^+- exchange between two fermions. + + + +Scattering f f' -> f f' via gamma^*/Z^0 +t-channel exchange, with full interference +between the gamma^* and Z^0. +Code 211. + + + +Scattering f_1 f_2 -> f_3 f_4 via W^+- +t-channel exchange. +Code 212. + + +

Single boson

+ + +Common switch for the group of a single gamma^*/Z^0 +or W^+- production. + + + +Scattering f fbar -> gamma^*/Z^0, with full interference +between the gamma^* and Z^0. +Code 221. + + + +Scattering f fbar' -> W^+-. +Code 222. + + + +Scattering f fbar -> gamma^* -> f' fbar'. Subset of +process 221, but written as a 2 -> 2 process, so that +pT can be used as ordering variable, e.g. in multiple +interactions. Hardcoded for the final state being either of the +five quark flavours or three lepton ones. Not included in the +WeakSingleBoson:all set, but included in the +multiple-interactions framework. +Code 223. + + +

Boson pair

+ + +Common switch for the group of pair production of gamma^*/Z^0 +and W^+-. + + + +Scattering f fbar' -> gamma^*/Z^0 gamma^*/Z^0. +Code 231. + + + +Scattering f fbar' -> Z^0 W^+-. Note that here the +gamma^* contribution is not (currently) included. +Code 232. + + + +Scattering f fbar -> W^+ W^-. +Code 233. + + +

Boson and parton

+ + +Common switch for the group of production of a single electroweak +gauge boson, i.e. a gamma^*/Z^0 or a W^+-, in +association with a parton, i.e. a quark, gluon, photon or lepton. +These processes give first-order corrections to the ones in the +WeakSingleBoson class, and both sets cannot be used +simultaneously without unphysical doublecounting. The current class +should only be used to study the high-pT tail of the +gauge-boson production processes (for LHC applications at least +pT > 20 GeV), while the ones in WeakSingleBoson +should be used for inclusive production. + + + +Scattering q qbar -> gamma^*/Z^0 g. +Code 241. + + + +Scattering q g -> gamma^*/Z^0 q . +Code 242. + + + +Scattering f fbar -> gamma^*/Z^0 gamma. +Code 243. + + + +Scattering f gamma -> gamma^*/Z^0 f. +Code 244. + + + +Scattering q qbar -> W^+- g. +Code 251. + + + +Scattering q g -> W^+- q. +Code 252. + + + +Scattering f fbar -> W^+- gamma. +Code 253. + + + +Scattering f gamma -> W^+- f. +Code 254. + + +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/ErrorChecks.xml b/PYTHIA8/pythia8130/xmldoc/ErrorChecks.xml new file mode 100644 index 00000000000..888a2b0cb0d --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ErrorChecks.xml @@ -0,0 +1,71 @@ + + +

Error Checks

+ +There is a few settings related to error checking during program +execution. Many other checks are performed as well, but do not +have any specific setting related to themselves. + + +Check the particle data tables for potential problems during +initialization. This includes inconsistent use of charge in particle +names, inconsistent setup of mass, mass range, width and lifetime, +sum of branching ratios not unity (allowed but discouraged) or charge +not conserved in a decay channel. Warnings should be viewed as reasons +to check further, but need not indicate a true problem, and also not all +problems may be caught. +The pythia.particleData.checkTable(level) method, +used for these checks, may also be called directly. + + + +The level of verbosity and checks of particle data, if switched on. + + + + + + + + +When an event has been successfully generated, check that the +final event record in event does not contain any +unphysical particles, or nonconserved charge or energy-momentum. +If this check fails, then pythia.next() obtains the +value false, i.e. the event is counted as aborted. + + + +The number of erroneous events, in the above check, for which +event listing and other detailed information will be printed. +After that, only the normal error messages will be issued. +Error counters are always updated, and accumulated numbers can be +shown with pythia.statistics() at the end of the run. + + + +Maximum allowed summed deviation of E, p_x, +p_y and p_z between the incoming beams and the +final state, as a fraction of the initial energy, above which the +event is counted as aborted. +(Unfortunetely roundoff errors do not scale linearly with the energy, +and also have a very long tail. So while most events at lower energies +may be correct to better than 1e-10, at LHC it does not have to signal +any fundamental bug if also the default tolerance above is violated +occasionally.) + + + +A check on the same summed deviation as above, but counted as a +warning rather than an error, and not leading to the event being +classified as aborted. + + +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/EventAnalysis.xml b/PYTHIA8/pythia8130/xmldoc/EventAnalysis.xml new file mode 100644 index 00000000000..b6b3370d3f9 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/EventAnalysis.xml @@ -0,0 +1,389 @@ + + +

Event Analysis

+ +

Introduction

+ +The routines in this section are intended to be used to analyze +event properties. As such they are not part of the main event +generation chain, but can be used in comparisons between Monte +Carlo events and real data. They are rather free-standing, but +assume that input is provided in the PYTHIA 8 +Event format, and use a few basic facilities such +as four-vectors. + +

Sphericity

+ +The standard sphericity tensor is + + S^{ab} = (sum_i p_i^a p_i^b) / (sum_i p_i^2) + +where the sum i runs over the particles in the event, +a, b = x, y, z, and p without such an index is +the absolute size of the three-momentum . This tensor can be +diagonalized to find eigenvalues and eigenvectors. + +

+The above tensor can be generalized by introducing a power +r, such that + + S^{ab} = (sum_i p_i^a p_i^b p_i^{r-2}) / (sum_i p_i^r) + +In particular, r = 1 gives a linear dependence on momenta +and thus a collinear safe definition, unlike sphericity. + +

+A sphericity analysis object is declared by + +where + +is the power r defined above, i.e. +gives Spericity, and +gives the linear form. + + +tells which particles are analyzed, +all final-state particles, +all observable final-state particles, +i.e. excluding neutrinos and other particles without strong or +electromagnetic interactions (the isVisible() +particle method), and + +only charged final-state particles. + + + +

+The analysis is performed by a call to the method + +where +is an object of the Event class, +most likely the pythia.event one. + +
If the routine returns false the analysis failed, +e.g. if too few particles are present to analyze. +
+ +

+After the analysis has been performed, a few Sphericity +class methods are available to return the result of the analysis: + +gives the sphericity (or equivalent if r is not 2), + + +gives the aplanarity (with the same comment), + + +gives one of the three eigenvalues for i = 1, 2 or 3, in +descending order, + + +gives the matching eigenvector, as a Vec4 with vanishing +time/energy component. + + +provides a listing of the above information. + + +tells the number of times analyze failed to analyze events. + + +

Thrust

+ +Thrust is obtained by varying the thrust axis so that the longitudinal +momentum component projected onto it is maximized, and thrust itself is +then defined as the sum of absolute longitudinal momenta divided by +the sum of absolute momenta. The major axis is found correspondingly +in the plane transverse to thrust, and the minor one is then defined +to be transverse to both. Oblateness is the difference between the major +and the minor values. + +

+The calculation of thrust is more computer-time-intensive than e.g. +linear sphericity, introduced above, and has no specific advantages except +historical precedent. In the PYTHIA 6 implementation the search was +speeded up at the price of then not being guaranteed to hit the absolute +maximum. The current implementation studies all possibilities, but at +the price of being slower, with time consumption for an event with +n particles growing like n^3. + +

+A thrust analysis object is declared by + +where + +tells which particles are analyzed, +all final-state particles, +all observable final-state particles, +i.e. excluding neutrinos and other particles without strong or +electromagnetic interactions (the isVisible() +particle method), and + +only charged final-state particles. + + + +

+The analysis is performed by a call to the method + +where +is an object of the Event class, +most likely the pythia.event one. + +
If the routine returns false the analysis failed, +e.g. if too few particles are present to analyze. +
+ +

+After the analysis has been performed, a few Thrust +class methods are available to return the result of the analysis: + +gives the thrust, major, minor and oblateness values, respectively, + +gives the matching event-axis vectors, for i = 1, 2 or 3 +corresponding to thrust, major or minor, as a Vec4 with +vanishing time/energy component. + + +provides a listing of the above information. + + +tells the number of times analyze failed to analyze events. + + +

ClusterJet

+ +ClusterJet (a.k.a. LUCLUS and +PYCLUS) is a clustering algorithm of the type used for +analyses of e^+e^- events, see the PYTHIA 6 manual. A few +options are available for some well-known distance measures. Cutoff +distances can either be given in terms of a scaled quadratic quantity +like y = pT^2/E^2 or an unscaled linear one like pT. + +

+A cluster-jet analysis object is declared by + +where +distance measure, to be provided +as a character string (actually, only the first character is necessary) +the Lund pT distance, +the JADE mass distance, and +the Durham kT measure. + + +tells which particles are analyzed, +all final-state particles, +all observable final-state particles, +i.e. excluding neutrinos and other particles without strong or +electromagnetic interactions (the isVisible() particle +method), and + +only charged final-state particles. + +masses assumed for the particles +used in the analysis +all massless, +photons are massless while all others are +assigned the pi+- mass, and + +all given their correct masses. + + +perform or not a early preclustering step, where nearby particles +are lumped together so as to speed up the subsequent normal clustering. + + +reassign all particles to the nearest jet each time after two jets +have been joined. + + + +

+The analysis is performed by a + +where +is an object of the Event class, +most likely the pythia.event one. + + +is the cutoff joining scale, below which jets are joined. Is given +in quadratic dimensionless quantities. Either yScale +or pTscale must be set nonvanishing, and the larger of +the two dictates the actual value. + + +is the cutoff joining scale, below which jets are joined. Is given +in linear quantities, such as pT or m depending on +the measure used, but always in units of GeV. Either yScale +or pTscale must be set nonvanishing, and the larger of +the two dictates the actual value. + + +the minimum number of jets to be reconstructed. If used, it can override +the yScale and pTscale values. + + +the maximum number of jets to be reconstructed. Is not used if below +nJetMin. If used, it can override the yScale +and pTscale values. Thus e.g. +nJetMin = nJetMax = 3 can be used to reconstruct exactly +3 jets. + +
If the routine returns false the analysis failed, +e.g. because the number of particles was smaller than the minimum number +of jets requested. +
+ +

+After the analysis has been performed, a few ClusterJet +class methods are available to return the result of the analysis: + +gives the number of jets found, with jets numbered 0 through +size() - 1, + + +gives a Vec4 corresponding to the four-momentum defined by +the sum of all the contributing particles to the i'th jet, + + +gives the index of the jet that the particle i of the event +record belongs to, + + +provides a listing of the reconstructed jets. + + +tells the number of times analyze failed to analyze events. + + +

CellJet

+ +CellJet (a.k.a. PYCELL) is a simple cone jet +finder in the UA1 spirit, see the PYTHIA 6 manual. It works in an +(eta, phi, eT) space, where eta is pseudorapidity, +phi azimuthal angle and eT transverse energy. +It will draw cones in R = sqrt(Delta-eta^2 + Delta-phi^2) +around seed cells. If the total eT inside the cone exceeds +the threshold, a jet is formed, and the cells are removed from further +analysis. There are no split or merge procedures, so later-found jets +may be missing some of the edge regions already used up by previous +ones. + +

+A cell-jet analysis object is declared by + +where + +the maximum +-pseudorapidity that the detector is assumed to cover. + + +the number of equal-sized bins that the +-etaMax range +is assumed to be divided into. + + +the number of equal-sized bins that the phi range ++-pi is assumed to be divided into. + + +tells which particles are analyzed, +all final-state particles, +all observable final-state particles, +i.e. excluding neutrinos and other particles without strong or +electromagnetic interactions (the isVisible() particle +method), +and +only charged final-state particles. + + +strategy to smear the actual eT bin by bin, +no smearing, +smear the eT according to a Gaussian +with width resolution * sqrt(eT), with the Gaussian truncated +at 0 and upperCut * eT, +smear the e = eT * cosh(eta) according +to a Gaussian with width resolution * sqrt(e), with the +Gaussian truncated at 0 and upperCut * e. + + +see above + + +see above + + +completely neglect all bins with an eT < threshold. + + + +

+The analysis is performed by a + +where +is an object of the Event class, +most likely the pythia.event one. + + +is the minimum transverse energy inside a cone for this to be +accepted as a jet. + + + is the size of the cone in (eta, phi) space drawn around +the geometric center of the jet. + + +the mimimum eT in a cell for this to be acceptable as +the trial center of a jet. + +
If the routine returns false the analysis failed, +but currently this is not foreseen ever to happen. +
+ +

+After the analysis has been performed, a few CellJet +class methods are available to return the result of the analysis: + +gives the number of jets found, with jets numbered 0 through +size() - 1, + + +gives the eT of the i'th jet, where jets have been +ordered with decreasing eT values, + + +gives the eta and phi coordinates of the geometrical +center of the i'th jet, + + +gives the eta and phi coordinates of the +eT-weighted center of the i'th jet, + + +gives the number of particles clustered into the i'th jet, + + +gives a Vec4 corresponding to the four-momentum defined by the +eT and the weighted center of the i'th jet, + + +gives a Vec4 corresponding to the four-momentum defined by +the sum of all the contributing cells to the i'th jet, where +each cell contributes a four-momentum as if all the eT is +deposited in the center of the cell, + + +gives the invariant mass of the i'th jet, defined by the +pMassive above, + + +provides a listing of the above information (except pMassless, +for reasons of space). + + +tells the number of times analyze failed to analyze events. + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/EventInformation.xml b/PYTHIA8/pythia8130/xmldoc/EventInformation.xml new file mode 100644 index 00000000000..6674de93a9c --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/EventInformation.xml @@ -0,0 +1,221 @@ + + +

Event Information

+ +The Info class collects various one-of-a-kind information, +some relevant for all events and others for the current event. +An object info is a public member of the Pythia +class, so if you e.g. have declared Pythia pythia, the +Info methods can be accessed by +pythia.info.method(). Most of this is information that +could also be obtained e.g. from the event record, but is here more +directly available. It is primarily intended for processes generated +internally in PYTHIA, but many of the methods would work also for +events fed in via the Les Houches Accord. + +

+Here are the currently available methods related to each event: + + +a listing of most of the information set for the current event. + + + +the identities of the two beam particles. + + + +the longitudinal momenta of the two beam particles. + + + +the energies of the two beam particles. + + + +the masses of the two beam particles. + + + +the cm energy and its square for the two beams. + + + +the name and code of the process that occured. + + + +the number of final-state partons in the hard process. + + + +are beam particles resolved, i.e. were PDF's used for the process? + + + +is either beam diffractively excited? + + + +is the process a minimum-bias one? + + + +has the process been generated from external Les Houches Accord +information? + + + +true if a linked Les Houches class refuses to return any further +events, presumably because it has reached the end of the file from +which events have been read in. + + + +does the process have a subprocess classification? +Currently only true for minbias and Les Houches events, where it allows +the hardest collision to be identified. + + + +the name, code and number of final-state partons in the subprocess +that occured when hasSub() is true. For a minimum-bias event +the code would always be 101, while codeSub() +would vary depending on the actual hardest interaction, e.g. 111 for +g g -> g g. For a Les Houches event the code would +always be 9999, while codeSub() would be the external +user-defined classification code. The methods below would also provide +information for such particular subcollisions. + + + +the identities of the two partons coming in to the hard process. + + + +x fractions of the two partons coming in to the hard process. + + + +rapidity and scaled mass-squared of the hard-process subsystem, as +defined by the above x values. + + + +parton densities x*f(x,Q^2 )evaluated for the two incoming +partons; could be used e.g. for reweighting purposes. + + + +the Q^2 or Q^2 factorization scale at which the +densities were evaluated. + + + +true if the two hard incoming partons have been picked +to belong to the valence piece of the parton-density distribution, +else false. Should be interpreted with caution. +Information is not set if you switch off parton-level processing. + + + +the alpha_strong and alpha_electromagnetic values used +for the hard process. + + + +the Q or Q^2 renormalization scale at which +alpha_strong and alpha_electromagnetic were evaluated. + + + +the invariant mass and its square for the hard process. + + + +the remaining two Mandelstam variables; only defined for 2 -> 2 +processes. + + + +transverse momentum and its square in the rest frame of a 2 -> 2 +processes. + + + +the masses of the two outgoing particles in a 2 -> 2 processes. + + + +the polar and azimuthal scattering angles in the rest frame of +a 2 -> 2 process. + + + +weight assigned to the current event. Is normally 1 and thus uninteresting. +However, for Les Houches events some strategies allow negative weights, +which then after unweighting lead to events with weight -1. There are also +strategies where no unweighting is done, and therefore a nontrivial event +weight must be used e.g. when filling histograms. + + + +the impact parameter b assumed for the current collision when +multiple interactions are simulated. Is not expressed in any physical +size (like fm), but only rescaled so that the average should be unity +for minimum-bias events (meaning less than that for events with hard +processes). + + + +The choice of impact parameter implies an enhancement or depletion of +the rate of subsequent interactions, as given by this number. Again +the average is normalized be unity for minimum-bias events (meaning +more than that for events with hard processes). + + + +the number of hard interactions in the current event. Is 0 for elastic +and diffractive events, and else at least 1, with more possible from +multiple interactions. + + + +the process code and transverse momentum of the i'th +subprocess, with i in the range from 0 to +nMI() - 1. The values for subprocess 0 is redundant with +information already provided above. + + + +the number of emissions in the initial-state showering, in the final-state +showering excluding resonance decys, and in the final-state showering +inside resonance decays, respectively. + + +

+Here are the currently available methods related to the event sample +as a whole. While continuously updated during the run, it is recommended +only to study these properties at the end of the event generation, +when the full statistics is available. + + +the total number of tried phase-space points, selected hard processes +and finally accepted events, summed over all allowed subprocesses. +The first number is only intended for a study of the phase-space selection +efficiency. The last two numbers usually only disagree if the user introduces +some veto during the event-generation process; then the former is the number +of acceptable events found by PYTHIA and the latter the number that also +were approved by the user. If you set a +second hard process there may also be a mismatch. + + + +the estimated cross section and its estimated error, +summed over all allowed subprocesses, in units of mb. The numbers refer to +the accepted event sample above, i.e. after any user veto. + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/EventRecord.xml b/PYTHIA8/pythia8130/xmldoc/EventRecord.xml new file mode 100644 index 00000000000..77d9c9bb344 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/EventRecord.xml @@ -0,0 +1,312 @@ + + +

The Event Record

+ +The Event class for event records basically is a vector of +Particles, so that it can expand to fit the event size. +The index operator is overloaded, so that event[i] +corresponds to the i'th particle of an Event +object event. Thus event[i].id() returns the +identity of the i'th particle. References to the first, +i'th and last particle are obtained with +event.front(), event.at(i) and +event.back(), respectively. + +

+The event size can be found with size(), i.e. valid +particles are stored in 0 <= i < event.size(). + +

+Line 0 is used to represent the event as a whole, with its total +four-momentum and invariant mass, but does not form part of the +event history. Lines 1 and 2 contains the two incoming beams, and +only from here on history tracing works as could be expected. That +way unassigned mother and daughter indices can be put 0 without +ambiguity. Depending on the task at hand, a loop may therefore start +at an index 1 without any loss. Specifically, for translation to other +event record formats such as HepMC Dob01, where the first +index is 1, the Pythia entry 0 definitely ought to be skipped in order +to minimize the danger of errors. + +

+New particles can be added to the end of the current event record +with append(Particle), or +append(id, status, mother1, mother2, daughter1, daughter2, +col, acol, p, m, scale) +where p is the four-momentum vector, and everything except +id defaults to 0. The append method returns +the index of the new particle position. + +

+The existing particle at index iCopy can be copied to the end +with copy(iCopy, newStatus = 0). By default, i.e. with +newStatus = 0, everything is copied precisely as it is, +which means that history information has to be modified further by hand +to make sense. With a positive newStatus, the new copy is set +up to be the daughter of the old, with status code newStatus, +and the status code of iCopy is negated. With a negative +newStatus, the new copy is instead set up to be the mother +of iCopy. + +

+The event record can be emptied for the next event by a +clear(). The last n entries can be removed by +popBack(n), where n = 1 by default. +The = operator is overloaded to allow a copying of +an event record, and += to append an event to an +existing one. In the latter case mother, daughter and colour tags are +shifted to make a consistent record. The zeroth particle of the +appended event is not copied, but the zeroth particle of the combined +event is updated to the full energy-momentum content. + +

+A listing of the whole event is obtained with list(). +The basic id, status, mother, daughter, colour, four-momentum +and mass data are always given, but the method can also be called with +a few optional arguments for further information: + +where + optionally give a +second line for each particle, with the production scale (in GeV), the +production vertex (in mm or mm/c) and the invariant lifetime +(also in mm/c). + + +gives a list of all daughters and mothers of a particle, as defined by +the motherList(i) and daughterList(i) methods +described below. It is mainly intended for debug purposes. + + a reference to the ostream +object to which the event listing will be directed. + + + +

+Each particle in the event record has a pointer to the corresponding +particle species in the particle database, used to find some particle +properties. This pointer is automatically set whenever the particle +identity is set by one of the normal methods. Of course its value is +specific to the memory location of the current run, and so it has no +sense to save it if events are written to file. Should you use some +persistency scheme that bypasses the normal methods when the event is +read back in, you can use restorePtrs() afterwards to set +these pointers appropriately. + +

+The user would normally be concerned with the Event object +that is a public member event of the Pythia class. +Thus, having declared a Pythia object pythia, +pythia.event[i].id() would be used to return the identity +of the i'th particle, and pythia.event.size() to +give the size of the event record. + +

+A Pythia object contains a second event record for the +hard process alone, called process, used as input for the +generation of the complete event. Thus one may e.g. call either +pythia.process.list() or pythia.event.list(). +To distinguish those two rapidly at visual inspection, the +"Pythia Event Listing" header is printed out differently, +in one case adding "(hard process)" and in the other +"(complete event)". When += is used to +append an event, the modified event is printed with +"(combination of several events)" as a reminder. + +

+One data member in an Event object is used to keep track of the +largest col() or acol() tag set so far, so that +new ones do not clash. The lastcolTag() method returns the +last tag assigned, i.e. largest value in the current event, and +nextColTag() ups it by one before returing the value. The +latter method thus is used when a new colour tag is needed. + + +This sets the initial value used, so that the first one assigned is +startColTag+1, etc. The Les Houches accord Boo01 +suggests this number to be 500, but 100 works equally well. + + +

+The scale() methods can be used to set or get the scale +(in GeV) of the event as a whole. Further methods for event properties +may be added in the future. + +

+A few methods exist to rotate and boost events. These derive from the +Vec4 methods, and affect both the +momentum and the vertex (position) components of all particles. + + +rotate by this polar and azimuthal angle (expressed in radians). + + + +boost by this vector. Optionally you may provide the gamma +value as a fourth argument, if you deem this may help avoid roundoff +errors for big boosts. You may alternatively supply a Vec4 +four-vector, in which case the boost vector beta = p/E. + + + +rotate and boost by the combined action encoded in the +RotBstMatrix M. + + +

+There are also a few methods with an individual particle index +i as input, but requiring some search operations in +the event record, and therefore not possible to define inside the +Particle class: + + +returns a vector<int> containing a list of all the +mothers of a particle. This list is empty for entries 0, 1 and 2, +i.e. the "system" in line 0 is not counted as part of the history. +Normally the list contains one or two mothers, but it can also be more, +e.g. in string fragmentation the whole fragmenting system is counted +as mothers to the primary hadrons. Mothers are listed in ascending order. + + + +returns a vector<int> containing a list of all the +daughters of a particle. This list is empty for a particle that did +not decay (or, if the evolution is stopped early enough, a parton +that did not branch), while otherwise it can contain a list of +varying length, from one to many. Many partons may have the same +daughterList, e.g. in the hard process and fragmentation +steps. For the two incoming beam particles, all shower initiators and +beam remnants are counted as daughters, with the one in slot 0 being +the one leading up to the hardest interaction. The "system" in line 0 +does not have any daughters, i.e. is not counted as part of the history. + + + +are used to trace carbon copies of the particle at index i up +to its top mother or down to its bottom daughter. If there are no such +carbon copies, i itself will be returned. + + + +also trace top mother and bottom daughter, but do not require carbon +copies, only that one can find an unbroken chain, of mothers or daughters, +with the same flavour id code. When it encounters ambiguities, +say a g -> g g branching or a u u -> u u hard scattering, +it will stop the tracing and return the current position. It can be confused +by nontrivial flavour changes, e.g. a hard process u d -> d u +by W^+- exchange will give the wrong answer. These methods +therefore are of limited use for common particles, in particular for the +gluon, but should work well for "rare" particles. + + + +returns a vector<int> containing a list of all the +sisters of a particle, i.e. all the daughters of the first mother, +except the particle itself. + + + +returns a vector<int> containing a list of all the +sisters of a particle, tracking up and back down through carbon copies +if required. That is, the particle is first traced up with +iTopCopy() before its mother is found, and then all +the particles in the daughterList() of this mother are +traced down with iBotCopy(), omitting the original +particle itself. Any non-final particles are removed from the list. +Should this make the list empty the search criterion is widened so that +all final daughters are allowed, not only carbon-copy ones. A second +argument false inhibits the second step, and increases +the risk that an empty list is returned. A typical example of this +is for ISR cascades, e.g. e -> e gamma where the photon +may not have any obvious sister in the final state if the bottom copy +of the photon is an electron that annihilates and thus is not part of +the final state. + + + +traces the particle i upwards through mother, grandmother, +and so on, until either iAncestor is found or the top of +the record is reached. Normally one unique mother is required, +as is the case e.g. in decay chains or in parton showers, so that +e.g. the tracing through a hard scattering would not work. For +hadronization, first-rank hadrons are identified with the respective +string endpoint quark, which may be useful e.g. for b physics, +while higher-rank hadrons give false. Currently also +ministrings that collapsed to one single hadron and junction topologies +give false. + + +

The Junction Class

+ +The event record also contains a vector of junctions, which often +is empty or else contains only a very few per event. Methods are +available to add further junctions or query the current junction list. +This is only for the expert user, however, and is not discussed +further here, but only the main points. + +

+A junction stores the properites associated with a baryon number that +is fully resolved, i.e. where three different colour indices are +involved. There are two main applications, +

    +
  1. baryon beams, where at least two valence quarks are kicked out, +and so the motion of the baryon number is notrivial;
  2. +
  3. baryon-number violating processes, e.g. in SUSY with broken +R-parity.
  4. +
+Information on junctions is set, partly in the process generation, +partly in the beam remnants machinery, and used by the fragmentation +routines, but the normal user does not have to know the details. + +

+For each junction, information is stored on the kind of junction, and +on the three (anti)colour indices that are involved in the junction. +The possibilities foreseen are: +

    +
  • kind = 1 : incoming colourless particle to three +outgoing colours (e.g. baryon beam remnant or +neutralino -> q q q);
  • +
  • kind = 2 : incoming colourless particle to three +outgoing anticolours;
  • +
  • kind = 3 : one incoming anticolor (stored first) +and two outgoing colours (e.g. antisquark decaying to quark);
  • +
  • kind = 4 : one incoming color (stored first) and two +outgoing anticolours;
  • +
  • kind = 5 : incoming colour octet to three colours, +where the incoming colour passes through unchanged and so need not +be bokkept here, while the incoming anticolor (stored first) and the +two outgoing colours are (e.g. gluino decay to three quarks);
  • +
  • kind = 6 : incoming colour octet to three anticolours, +where the incoming anticolour passes through unchanged and so need not +be bookkept here, while the incoming color (stored first) and the two +outgoing colours are.
  • +
+The odd (even) kind codes corresponds to a +1 (-1) change in +baryon number across the junction. +Warning: Currently only kind = 1, 2 are +implemented. + +

+The kind and colour information in the list of junctions can be set +or read with methods of the Event class, but are not of +common interest and so not described here. + +

+A listing of current junctions can be obtained with the +listJunctions() method. + +

Subsystems

+ +The event record also contains a few vectors where parton indices can be +stored, classified by subsystem. Such information is needed to interleave +multiple interactions, initial-state showers, final-state showers +and beam remnants. It could also be used in other places. It is intended +to be accessed only by experts, such as implementors of +new showering models. + +

+A listing of current subsystems can be obtained with the +listSystems() method. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/EventStatistics.xml b/PYTHIA8/pythia8130/xmldoc/EventStatistics.xml new file mode 100644 index 00000000000..fd69515503e --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/EventStatistics.xml @@ -0,0 +1,116 @@ + + +

Event Statistics

+ +At the end of the run you will want to write out the final statistics +on number of events generated, the corresponding cross sections and +the number of errors encountered. This is done with +
+    pythia.statistics(all = false, reset = false);
+
+assuming pythia is an instance of the Pythia +class. +
    +
  • The optional argument all, if true, +allows a more extensive listing than the default one, see +multiple-interactions statistics below.
  • +
  • The optional argument reset, if true, +implies that all counters, e.g on events generated and errors experienced, +are reset to zero whenever the routine is called. The default instead is +that all stored statistics information is unaffected by the call. +Counters are automatically reset in each new pythia.init() +call, however, so the only time the reset option makes a +difference is if statistics is called several times in a +(sub)run.
  • +
+ +

+The pythia.statistics(...) method in its turn calls on the +methods below, for the different kinds of information. + +

Cross-section statistics

+ +The ProcessLevel::statistics() member will loop over the +list of existing processes, and for each write out name, code, +the number of tried, selected and accepted events, the cross section and +the estimated error on the latter. The three different event numbers are +related to the Monte Carlo method used, whereby an initial upper estimate +of the cross section is used to select a large number of trial phase-space +points, whereof then not all survive. Rejections are normally done by the +internal machinery, but can also be obtained by +user hooks. +Therefore: +
    +
  • tried events reflect the original number of +phase-space points probed, as part of the upper estimate;
  • +
  • selected events correspond to those that survive +the internal Monte-Carlo selection procedure;
  • +
  • accepted events are those that also survive +the additional user cuts.
  • +
+In most runs there would be no user hooks implemented, and then the +numbers of selected and of accepted events will agree. Aborted events +(see below) usually appear in the selected statistics but not in the +accepted one. + +

+For Les Houches events the total cross section will be correctly +displayed; however the (optional) error value will not be used, so that +the reported error will be smaller than the correct statistical ones, +and often vanish completely. Furthermore, while the number of events +is shown for each user process, the cross section is only for the sum +of them. + +

Error messages

+ +When Pythia is run, errors may occur, and give rise to warning messages. +These may be of varying severity, as follows: +
    +
  • Abort means things went seriously wrong, and the +initialization or event generation failed. In the former case it is +not possible to generate events at all, in the latter the current +event is flawed and should be skipped. In either case the respective +method, pythia.init(...) or pythia.next(), +then also returns the value false. There are occasions +where an abort may be deliberate, such as when a file of Les Houches +Events is read and the end of the file is reached.
  • +
  • Error normally is less severe. Typically the program will +back up one step and try again. There are cases where this is not possible, +in particular during the initialization and the generation of a hard +process, and then the error may be followed by an abort as a direct +consequence (with two separate messages).
  • +
  • Warning is even less severe. In some cases the program will +try again, with good chances of success, in others no measure at all +need to be taken.
  • +
+ +

+The error messages is handled by a small part of the Info +class. It is handed any abort, error or warning messages during the event +generation phase, and will store each distinct message, with a counter +for how many times it is issued. Thus it is possible to limit the number +of identical messages issued, currently hardcoded so that each kind of +error message is only printed once +(static const int TIMESTOPRINT = 1). +The summary table printed by pythia.statistics() +provides a table with all the different messages issued, in +alphabetical order, with the total number of times each was generated. + +

Multiple-interactions statistics

+ +If you call pythia.statistics(true), i.e. with the first +optional argument true, also statistics on multiple +interactions is printed, comprising a list of all allowed subprocesses +with how many times each of them has been generated. For the minimum-bias +process this also includes the hardest interaction, while else the +hardest process is excluded from the statistics. (This is because +the hardest process is of the same character and generated by the same +machinery in the former case but not in the latter. Also, for the +former case only, the standard statistics listing only lists +minimum bias as one single process, i.e. does not further specify +the character of the hardest subprocess, so there is not any overlap +between the two.) + +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/ExternalDecays.xml b/PYTHIA8/pythia8130/xmldoc/ExternalDecays.xml new file mode 100644 index 00000000000..161df412343 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ExternalDecays.xml @@ -0,0 +1,71 @@ + + +

External Decays

+ +DecayHandler is a base class for the external handling of +decays. It is intended for normal particle decays, primarily +B mesons and tau, and cannot be used to redirect +decays of heavy resonances like t or Z^0. +The user-written derived class is called if a pointer to it has +been given with the +pythia.decayPtr() +method, where it also is specified which particles it will be called for. +This particle information is accessible with the +doExternalDecay() +method. + +

+There is only one pure virtual method in DecayHandler, +to do the decay: + +where + is a list of particle PDG identity codes, + + is a list of their respective masses (in GeV), and + + is a list of their respective four-momenta. + + + +

+At input, these vectors each have size one, so that idProd[0], +mProd[0] and pProd[0] contain information on the +particle that is to be decayed. At output, the vectors should have +increased by the addition of all the decay products. Even if initially +defined in the rest frame of the mother, the products should have been +boosted so that their four-momenta add up to the pProd[0] of +the decaying particle. + +

+Should it be of interest to know the prehistory of the decaying +particle, e.g. to set some helicity information affecting the +decay angular distribution, the full event record is available +read-only, with info in which slot iDec the decaying particle +is stored. + +

+The routine should return true if it managed the decay and +false otherwise, in which case Pythia will try +to do the decay itself. This e.g. means you can choose to do some decay +channels yourself, and leave others to Pythia. To avoid +doublecounting, the channels you want to handle should be switched off +in the Pythia particle database. In the beginning of the +external decay method you should then return +false with a probability given by the sum of the branching +ratios for those channels you do not want to handle yourself. + +

+Note that the decay vertex is always set by Pythia, and that +B-Bbar oscillations have already been taken into account, +if they were switched on. Thus idProd[0] may be the opposite +of event[iDec].id(), where the latter provides the code at +production. + +

+A sample test program is available in main23.cc, providing +a simple example of how to use this facility. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/ExtraDimensionalProcesses.xml b/PYTHIA8/pythia8130/xmldoc/ExtraDimensionalProcesses.xml new file mode 100644 index 00000000000..7c85f8de5f7 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ExtraDimensionalProcesses.xml @@ -0,0 +1,73 @@ + + +

Extra-Dimensional Processes

+ +Scenarios with extra dimensions allow a multitude of processes. +Currently the only ones implemented involve the production of an +excited graviton state G^* within a Randall-Sundrum scenario. +This state is assigned PDG code 5000039. Decays into fermion, gluon +and photon pairs are handled with the correct angular distributions, +while other decay channels currently are handled isotropically. + +

Production processes

+ +There are two lowest-order processes that together normally should be +sufficient for a simulation of G^* production. + + +Common switch for the group of lowest-order G^* production +processes, i.e. the two ones below. + + + +Scatterings g g -> G^*. +Code 5001. + + + +Scatterings f fbar -> G^*. +Code 5002. + + +

+In addition there are three first-order processes included. These are of +less interest, but can be used for dedicated studies of the high-pT +tail of G^* producton. As usual, it would be doublecounting to +include the lowest-order and first-order processes simultaneously. +Therefore the latter ones are not included with the +ExtraDimensionsG*:all = on option. In this set of processes +all decay angles are assumed istropic. + + +Scatterings g g -> G^* g. +Code 5003. + + + +Scatterings q g -> G^* q. +Code 5004. + + + +Scatterings q qbar -> G^* g. +Code 5005. + + + +

Parameters

+ +In the above scenario the main free parameter is the G^* mass, +which is set as usual. In addition there is one further parameter. + + +dimensionless coupling, which enters quadratically in all partial +widths of the G^*. Is +kappa m_G* = sqrt(2) x_1 k / Mbar_Pl, +where x_1 = 3.83 is the first zero of the J_1 Bessel +function and Mbar_Pl is the modified Planck mass. + + +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/FlavourSelection.xml b/PYTHIA8/pythia8130/xmldoc/FlavourSelection.xml new file mode 100644 index 00000000000..da377189cd1 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/FlavourSelection.xml @@ -0,0 +1,356 @@ + + +

Flavour Selection

+ +The StringFlav class handles the choice of a new flavour +in the fragmentation process, and the production of a new hadron +from a set of input flavours. It is mainly used by the string +fragmentation machinery (including ministrings), but also e.g. +in some particle decays and for some beam-remnant cases. The basic +concepts are in agreement with And83. The baryon-sector +implementation is based on the MSTJ(12)=3 option of +PYTHIA 6, i.e. new SU(6) weights scheme with at most one popcorn meson. + +

+The relative production rates of different particle species is +influenced by the parameters below. Some have only an impact on +one specific quantity, but most directly or indirectly have +consequences for many observables. Therefore the values to use have +to be viewed in the context of a complete tune. + +

New flavours

+ +The main parameters of the selection of a new flavour are + + +the suppression of s quark production relative to ordinary +u or d one. + + + +the suppression of diquark production relative to quark production, +i.e. of baryon relative to meson production. + + + +the suppression of strange diquark production relative to light +diquark production, over and above the one already given by +probStoU. + + + +the suppression of spin 1 diquark production relative to spin 0 one, +apart from the factor of 3 enhancement of spin 0 from counting the +number of states. + + +

Standard-meson production

+ +The bulk of the particle production corresponds to the lowest-lying +pseudoscalar and vector multiplets. Their production rates are +determined by the parameters in this section. + +

+For a given set of flavours, produced according to the probabilities +outlined above, the ratio of vector-to-pseudocalar meson production +is described by the parameters below. +The maximum allowed rate for each case has been set according to +spin-counting rules, but we expect the real rates to be lower, +especially for lighter mesons, owing to the vector-pseudoscalar +mass splitting. + + +the relative production ratio vector/pseudoscalar for light +(u, d) mesons. + + +the relative production ratio vector/pseudoscalar for strange mesons. + + +the relative production ratio vector/pseudoscalar for charm mesons. + + +the relative production ratio vector/pseudoscalar for bottom mesons. + + +

+Inside each light-quark meson nonet, an octet-singlet mixing angle +describes the mixing of the two flavour-diagonal isoscalar = 0 states. +(For terminology and details see Yao06, chapter 14 on the +quark model.) +This angle is needed to specify the probability for such a q qbar +state to project onto a specific meson. More transparent formuale are +obtained by introducing the angle alpha = theta + 54.7 degrees: + + f = (uubar + ddbar)/sqrt(2) * sin(alpha) + ssbar * cos(alpha)
+ f' = (uubar + ddbar)/sqrt(2) * cos(alpha) - ssbar * sin(alpha) +
+ + +gives the mixing angle theta_PS in the pseudoscalar meson sector +(which is rather poorly determined), expressed in degrees. +Here f is associated with eta' and f' with +eta. (This standard but counterintuitive choice is fixed up +in the code by replacing alpha -> 90^0 - alpha so that +eta <-> eta'; relative signs do not matter since we are +interested in probabilities only.) + + + +gives the mixing angle theta_V in the vector meson sector +(which is somewhat better determined), expressed in degrees. +Here f is associated with omega and f' +with phi. + + +

+Further, the simple model overestimates the production of eta +and, in particular, eta' mesons, which can be rectified by + + +the additional suppression of eta production, multiplying the +normal production probability. Thus 0 means no eta at all +are produced, while 1 means full rate. + + + +the additional suppression of eta' production, multiplying the +normal production probability. Thus 0 means no eta' at all +are produced, while 1 means full rate. + + +

Excited-meson production

+ +Several excited mesons, ie. with radial or orbital excitations, have been +observed at non-negligible production rates. Extrapolated to all states +a fair fraction of all particle production might proceed through such +states. There are big uncertainties, however, since these excited +mesons in many cases are extremely poorly known. This also means that +the modelling of their production and decay is very primitive, and +even that the inclusion of the production of such states may lead to a +degraded agreement with data. Currently the default is that all such +production is switched off. + +

+Parameters are provided to switch them on. By demand, this machinery +has been made more flexible than in the past. Therefore one parameter is +provided for each combination of heaviest flavour +(u/d, s, c or b) and +multiplet produced. In each case the production rate is normalized to +that of the lowest-lying pseudoscalar of the same flavour content, as for +the vector-meson rates introduced above. The multiplets available are the +four obtained for one unit of orbital angular momentum, in the +nonrelativistic classification. Using J to denote the sum of +quark spin S and orbital angular momentum L, i.e. what +would normally be called the spin of the meson, one has: +

    +
  • a pseudovector multiplet with L=1, S=0, J=1;
  • +
  • a scalar multiplet with L=1, S=1, J=0;
  • +
  • a pseudovector multiplet with L=1, S=1, J=1;
  • +
  • a tensor multiplet with L=1, S=1, J=2.
  • +
+ +The maximum allowed rate for each case has been set according to +spin-counting rules, but we expect the real rates to be significantly +lower, owing to mass suppression. + + +the relative pseudovector production ratio +(L=1,S=0,J=1)/pseudoscalar +for light (u, d) mesons. + + + +the relative scalar production ratio +(L=1,S=1,J=0)/pseudoscalar +for light (u, d) mesons. + + + +the relative pseudovector production ratio +(L=1,S=1,J=1)/pseudoscalar +for light (u, d) mesons. + + + +the relative tensor production ratio +(L=1,S=1,J=2)/pseudoscalar +for light (u, d) mesons. + + + +the relative pseudovector production ratio +(L=1,S=0,J=1)/pseudoscalar +for strange mesons. + + + +the relative scalar production ratio +(L=1,S=1,J=0)/pseudoscalar +for strange mesons. + + + +the relative pseudovector production ratio +(L=1,S=1,J=1)/pseudoscalar +for strange mesons. + + + +the relative tensor production ratio +(L=1,S=1,J=2)/pseudoscalar +for strange mesons. + + + +the relative pseudovector production ratio +(L=1,S=0,J=1)/pseudoscalar +for charm mesons. + + + +the relative scalar production ratio +(L=1,S=1,J=0)/pseudoscalar +for charm mesons. + + + +the relative pseudovector production ratio +(L=1,S=1,J=1)/pseudoscalar +for charm mesons. + + + +the relative tensor production ratio +(L=1,S=1,J=2)/pseudoscalar +for charm mesons. + + + +the relative pseudovector production ratio +(L=1,S=0,J=1)/pseudoscalar +for bottom mesons. + + + +the relative scalar production ratio +(L=1,S=1,J=0)/pseudoscalar +for bottom mesons. + + + +the relative pseudovector production ratio +(L=1,S=1,J=1)/pseudoscalar +for bottom mesons. + + + +the relative tensor production ratio +(L=1,S=1,J=2)/pseudoscalar +for bottom mesons. + + +

+In addition, an octet-singlet mixing angle is needed for each multiplet, +as for the pseudoscalar and vector multiplets above. Only for the +tensor multiplet does any determination exist; for the other multiplets +default has been chose so that ssbar does not mix with the light +quarks, and so that the ssbar state is the heavier of the two. + + +gives the mixing angle theta in the (L=1,S=0,J=1) +pseudovector meson sector, expressed in degrees. + + + +gives the mixing angle theta in the (L=1,S=1,J=0) +scalar meson sector, expressed in degrees. + + + +gives the mixing angle theta in the (L=1,S=1,J=1) +pseudovector meson sector, expressed in degrees. + + + +gives the mixing angle theta in the (L=1,S=1,J=2) +tensor meson sector, expressed in degrees. + + +

Baryon production

+ +The relative rate of baryon production is mainly given by the quark +and diquark production parameters above, plus SU(6) Clebsch-Gordans. +The one modifiable parameter related to these coefficients is + + +the suppression, relative to default SU(6) factors, of decuplet +baryon production. Default corresponds to no suppression, while 0 +corresponds to no decuplet production at all. + + +

+In addition, if popcorn production is allowed, wherein a set of mesons +(M) may be producted in between the baryon (B) and +the antibaryon (Bbar), a set of further parameters is introduced. +Currently only the simplest scenario is implemented, wherein at most +one intermediate meson may be produced. + + +gives the relative rates of B Bbar and B M Bbar +production, roughly as + +Prob(B M Bbar) / (Prob(B Bbar) + Prob(B M Bbar)) = +popcornRate / (0.5 + popcornRate) + +(the complete expression depends on all the quark and diquark production +parameters and is therefore not so useful). + + + +extra suppression for having an s sbar pair shared between +the B and Bbar in a B M Bbar configuration. + + + +extra suppression for having a strange meson M in a +B M Bbar configuration. + + +

+Finally, there are some indications that leading-baryon production +may be further suppressed. A proper description should probably be +based on a suppression of early production times Ede97, +but we here only implement a simpler version where production near +the end of a string, as defined by rank, is suppressed. The more +detailed studies suggest that leading c and b baryon +production will be less suppressed, so we leave it open to set +light- and heavy-baryon suppression separately. + + +Suppress leading-baryon production. + + + + + +extra suppression of leading-baryon production for a light-quark +jet, i.e. d, u or s, when +suppressLeadingB = on. Thus 0 means no leading-baryon +production at all, while 1 means full rate. + + + +extra suppression of leading-baryon production for a heavy-quark +jet, i.e. c or b, when +suppressLeadingB = on. Thus 0 means no leading-baryon +production at all, while 1 means full rate. + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/FourVectors.xml b/PYTHIA8/pythia8130/xmldoc/FourVectors.xml new file mode 100644 index 00000000000..05a808ed7b8 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/FourVectors.xml @@ -0,0 +1,133 @@ + + +

Four-Vectors

+ +The Vec4 class gives an implementation of four-vectors. +The member function names are based on the assumption that these +represent momentum vectors. Thus one can get or set +px(), py(), pz() and +e(), but not x, y, z or t. (When +production vertices are defined in the particle class, this is +partly circumvented by new methods that hide a Vec4.) +All four values can be set in the constructor, or later by the +p method, with input in the order +(px, py, pz, e). + +

+The Particle object contains a Vec4 p that +stores the particle four-momentum, and another Vec4 vProd +for the production vertex. Therefore a user would not normally access the +Vec4 class directly, but by using the similarly-named methods +of the Particle class, see +Particle Properties. +(The latter also stores the particle mass separately, offering an element +of redundancy, helpful in avoiding some roundoff errors.) +However, you may find some knowledge of the four-vectors +convenient, e.g. as part of some simple analysis code based +directly on the PYTHIA output, say to define the four-vector sum +of a set of particles. + +

+A set of overloaded operators are defined for four-vectors, so that +one may naturally add, subtract, multiply or divide four-vectors with +each other or with double numbers, for all the cases that are +meaningful. Of course the equal sign also works as expected. +The << operator is overloaded to write out the values of the +four components of a Vec4. + +

+A number of methods provides output of derived quantities, such as: +

    +
  • mCalc(), m2Calc() the (squared) mass, calculated from +the four-vectors. If m^2 < 0 the mass is given with a +minus sign, -sqrt(-m^2). +
  • pT(), pT2() the (squared) transverse momentum.
  • +
  • pAbs(), pAbs2() the (squared) absolute momentum.
  • +
  • theta() the polar angle, in the range 0 through +pi.
  • +
  • phi() the azimuthal angle, in the range -pi +through pi.
  • +
  • thetaXZ() the angle in the xz plane, in the +range -pi through pi, with 0 along the +z +axis.
  • +
  • pPlus(), pMinus() the combinations E+-p_z.
  • +
+ +

+There are also some friend methods that take two or three +four-vectors as argument: +

    +
  • m(Vec4&, Vec4&), m2(Vec4&, Vec4&) the (squared) +invariant mass.
  • +
  • dot3(Vec4&, Vec4&) the three-product.
  • +
  • cross3(Vec4&, Vec4&) the cross-product.
  • +
  • theta(Vec4&, Vec4&), costheta(Vec4&, Vec4&) the +(cosine) of the opening angle between the vectors.
  • +
  • phi(Vec4&, Vec4&), cosphi(Vec4&, Vec4&) the +(cosine) of the azimuthal angle between the vectors around the +z axis, in the range 0 through pi.
  • +
  • phi(Vec4&, Vec4&, Vec4&), cosphi(Vec4&, Vec4&, Vec4&) +the (cosine) of the azimuthal angle between the first two vectors +around the direction of the third, in the range 0 through pi.
  • +
+ +

+Some member functions can be used to modify vectors, including some +for rotations and boosts: +

    +
  • rescale3(factor), rescale4(factor) multiply the +three-vector or all components by this factor.
  • +
  • flip3(), flip4() flip the sign of the +three-vector or all components.
  • +
  • rot(theta, phi) rotate by this polar and azimuthal +angle.
  • +
  • rotaxis(phi, nx, ny, nz), rotaxis(phi, n) rotate +by this azimuthal angle around the axis provided either by the +three-vector (nx, ny, nz) or the four-vector +n.
  • +
  • bst(betaX, betaY, betaZ), bst(betaX, betaY, betaZ, gamma) +boost the particle by this beta vector. Sometimes it may be +convenient also to provide the gamma value, especially for large +boosts where numerical accuracy may suffer.
  • +
  • bst(Vec4&), bstback(Vec4&) boost with a +beta = p/E or beta = -p/E, respectively. +
+ +

+For a longer sequence of rotations and boosts, and where several +Vec4 are to be rotated and boosted in the same way, +a more efficient approach is to define a RotBstMatrix, +which forms a separate auxiliary class. You can build up this matrix +by successive calls to the methods +

    +
  • rot(theta, phi) rotate by this polar and azimuthal +angle.
  • +
  • rot(Vec4& p) rotate so that a vector originally along +the +z axis becomes parallel with p. More specifically, +rotate by -phi, theta and phi, with angles +defined by p.
  • +
  • bst(betaX, betaY, betaZ) boost the particle by this +beta vector.
  • +
  • bst(Vec4&), bstback(Vec4&) boost with a +beta = p/E or beta = -p/E, respectively.
  • +
  • bst(Vec4& p1, Vec4& p2) boost so that p_1 +is transformed to p_2. It is assumed that the two vectors +obey p_1^2 = p_2^2.
  • +
  • toCMframe(Vec4& p1, Vec4& p2) boost and rotate to the +rest frame of p_1 and p_2, with p_1 along +the +z axis.
  • +
  • fromCMframe(Vec4& p1, Vec4& p2) rotate and boost from the +rest frame of p_1 and p_2, with p_1 along +the +z axis, to the actual frame of p_1 and p_2, +i.e. the inverse of the above.
  • +
  • rotbst(RotBstMatrix&) combine an existing matrix with +another one.
  • +
  • invert() invert the matrix, which corresponds to an +opposite sequence and sign of rotations and boosts.
  • +
  • reset() reset to no rotation/boost; default at +creation.
  • +
+ +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/FourthGenerationProcesses.xml b/PYTHIA8/pythia8130/xmldoc/FourthGenerationProcesses.xml new file mode 100644 index 00000000000..a28d128f425 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/FourthGenerationProcesses.xml @@ -0,0 +1,176 @@ + + +

Fourth-Generation Processes

+ +A fourth generation could have been accommodated within the +Standard Model, without the introduction of any new concepts. +Given the experimental constraints, however, its existence by now +is very unlikely. Nevertheless we offer a simple implementation, +along the lines of the top, since it could be useful also as a +template for studies of other new particles with similar +characteristics. + +

+The fourth generation are given names as in the third, but with a prime, +i.e. b' with PDG code 7, t' with code 8, +tau' with code 17, and nu'_tau with code 18. +Most important for you is to assign a mass hierarchy, to decide which +fermions can decay into which. The current implementation assumes that +mass splittings are big enough that fourth-generation fermions can +decay to third-generation ones by the emission of an on-shell W. +To this end, the standard three-generation CKM mixing matrix has been +extended to include a fourth generation, see below. Since no mixing has +been implemented in the neutrino sector it would be assumed that the +lighter of tau' and nu'_tau is stable. No decay modes +have been implemented that go beyond the Standard Model, so +modifications would be needed if e.g. also SUSY is included in the game. + +

Production processes

+ +

1) b' processes

+ +Different ways to produce b' quarks, singly or in pairs. +For a b' t' pair see section 3 below. + + +Common switch for the group of b' production. +Also includes the process f fbar' -> t' b'bar in section 3 below. + + + +Scatterings g g -> b' b'bar. +Code 801. + + + +Scatterings q qbar -> b' b'bar by gluon exchange. +Code 802. + + + +Scatterings q q' -> b' q'' by t-channel exchange +of a W^+- boson. +Code 803. + + + +Scatterings f fbar -> b' b'bar by s-channel exchange +of a gamma^*/Z^0 boson. +Code 804. + + + +Scatterings f fbar' -> b' qbar'' by s-channel exchange +of a W^+- boson. Here q'' is either u or +c. +Code 805. + + + +Scatterings f fbar' -> b' tbar by s-channel exchange +of a W^+- boson. +Code 806. + + +

2) t' processes

+ +Different ways to produce t' quarks, singly or in pairs. +For a b' t' pair see section 3 below. + + +Common switch for the group of t' production. +Also includes the process f fbar' -> t' b'bar in section 3 below. + + + +Scatterings g g -> t' t'bar. +Code 821. + + + +Scatterings q qbar -> t' t'bar by gluon exchange. +Code 822. + + + +Scatterings q q' -> t' q'' by t-channel exchange +of a W^+- boson. +Code 823. + + + +Scatterings f fbar -> t' t'bar by s-channel exchange +of a gamma^*/Z^0 boson. +Code 824. + + + +Scatterings f fbar' -> t' qbar'' by s-channel exchange +of a W^+- boson. +Code 825. + + +

3) Pair-processes with different flavours

+ +Different ways to produce two different fourth-generation fermions. + + +Scatterings f fbar' -> t' b'bar by s-channel exchange +of a W^+- boson. +Code 841. + + + +Scatterings f fbar' -> tau' nu'_taubar by s-channel +exchange of a W^+- boson. +Code 842. + + +

+Missing in this list is scatterings q q' -> t' b' by +t-channel exchange of a W^+- boson, since currently +the matrix element for such processes have not been implemented for +two massive particles in the final state. Since this process would +involve two CKM-suppressed vertices it ought to be small. + +

Parameters

+ +The Cabibbo-Kobayashi-Maskawa matrix is extended by seven further values. +So as not to mess up the Standard Model, the normal 3 * 3 matrix is +kept unitary, and so the new off-diagonal elements lead to a slight +breaking of this. For exploratory studies this should be good enough; +more detailed 4 * 4 tunes to data would only make sense the day there +are evidence for the existence of a fourth generation. + + +The V_ub' matrix element in the 4 * 4 CKM matrix. + + + +The V_cb' matrix element in the 4 * 4 CKM matrix. + + + +The V_tb' matrix element in the 4 * 4 CKM matrix. + + + +The V_t'd matrix element in the 4 * 4 CKM matrix. + + + +The V_t's matrix element in the 4 * 4 CKM matrix. + + + +The V_t'b matrix element in the 4 * 4 CKM matrix. + + + +The V_t'b' matrix element in the 4 * 4 CKM matrix. + + +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/Fragmentation.xml b/PYTHIA8/pythia8130/xmldoc/Fragmentation.xml new file mode 100644 index 00000000000..d143ffa9a04 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/Fragmentation.xml @@ -0,0 +1,310 @@ + + +

Fragmentation

+ +Fragmentation in PYTHIA is based on the Lund string model +And83, Sjo84. Several different aspects are involved in +the physics description, which here therefore is split accordingly. +This also, at least partly, reflect the set of classes involved in +the fragmentation machinery. + +

+The variables collected here have a very wide span of usefulness. +Some would be central in any hadronization tuning exercise, others +should not be touched except by experts. + +

+The fragmentation flavour-choice machinery is also used in a few +other places of the program, notably particle decays, and is thus +described on the separate Flavour +Selection page. + +

Fragmentation functions

+ +The StringZ class handles the choice of longitudinal +lightcone fraction z according to one of two possible +shape sets. + +

+The Lund symmetric fragmentation function And83 is the +only alternative for light quarks. It is of the form + + f(z) = (1/z) * (1-z)^a * exp(-b m_T^2 / z) + +with the two main free parameters a and b to be +tuned to data. They are stored in + + +The a parameter of the Lund symmetric fragmentation function. + + + +The b parameter of the Lund symmetric fragmentation function. + + +

+In principle, each flavour can have a different a. Then, +for going from an old flavour i to a new j one +the shape is + + f(z) = (1/z) * z^{a_i} * ((1-z)/z)^{a_j} * exp(-b * m_T^2 / z) + +This is only implemented for diquarks relative to normal quarks: + + +allows a larger a for diquarks, with total +a = aLund + aExtraDiquark. + + +

+Finally, the Bowler modification Bow81 introduces an extra +factor + + 1/z^{r_Q * b * m_Q^2} + +for heavy quarks. To keep some flexibility, a multiplicative factor +r_Q is introduced, which ought to be unity (provided that +quark masses were uniquely defined) but can be set in + + +r_c, i.e. the above parameter for c quarks. + + + +r_b, i.e. the above parameter for b quarks. + + + +r_h, i.e. the above parameter for heavier hypothetical quarks, +or in general any new coloured particle long-lived enough to hadronize. + + +

+As an alternative, it is possible to switch over to the +Peterson/SLAC formula Pet83 + + f(z) = 1 / ( z * (1 - 1/z - epsilon/(1-z))^2 ) + +for charm, bottom and heavier (defined as above) by the three flags + + +use Peterson for c quarks. + + + +use Peterson for b quarks. + + + +use Peterson for hypothetical heavier quarks. + + +

+When switched on, the corresponding epsilon values are chosen to be + + +epsilon_c, i.e. the above parameter for c quarks. + + + +epsilon_b, i.e. the above parameter for b quarks. + + + +epsilon_h, i.e. the above parameter for hypothetical heavier +quarks, normalized to the case where m_h = m_b. The actually +used parameter is then epsilon = epsilon_h * (m_b^2 / m_h^2). +This allows a sensible scaling to a particle with an unknown higher +mass without the need for a user intervention. + + +

Fragmentation pT

+ +The StringPT class handles the choice of fragmentation +pT. At each string breaking the quark and antiquark of the pair are +supposed to receive opposite and compensating pT kicks according +to a Gaussian distribution in p_x and p_y separately. +Call sigma_q the width of the p_x and p_y +distributions separately, i.e. + + d(Prob) = exp( -(p_x^2 + p_y^2) / 2 sigma_q^2). + +Then the total squared width is + + <pT^2> = <p_x^2> + <p_y^2> = 2 sigma_q^2 = sigma^2. + +It is this latter number that is stored in + + +the width sigma in the fragmentation process. + + +

+Since a normal hadron receives pT contributions for two string +breakings, it has a <p_x^2>_had = <p_y^2>_had = sigma^2, +and thus <pT^2>_had = 2 sigma^2. + +

+Some studies on isolated particles at LEP has indicated the need for +a slightly enhanced rate in the high-pT tail of the above +distribution. This would have to be reviewed in the context of a +complete retune of parton showers and hadronization, but for the +moment we stay with the current recipe, to boost the above pT +by a factor enhancedWidth for a small fraction +enhancedFraction of the breakups, where + + +enhancedFraction,the fraction of string breaks with enhanced +width. + + + +enhancedWidth,the enhancement of the width in this fraction. + + +

Jet joining procedure

+ +String fragmentation is carried out iteratively from both string ends +inwards, which means that the two chains of hadrons have to be joined up +somewhere in the middle of the event. This joining is described by +parameters that in principle follows from the standard fragmentation +parameters, but in a way too complicated to parametrize. The dependence +is rather mild, however, so for a sensible range of variation the +parameters in this section should not be touched. + + +Is used to define a W_min = m_q1 + m_q2 + stopMass, +where m_q1 and m_q2 are the masses of the two +current endpoint quarks or diquarks. + + + +Add to W_min an amount stopNewFlav * m_q_last, +where q_last is the last q qbar pair produced +between the final two hadrons. + + + +The W_min above is then smeared uniformly in the range +W_min_smeared = W_min * [ 1 - stopSmear, 1 + stopSmear ]. + + +

+This W_min_smeared is then compared with the current remaining +W_transverse to determine if there is energy left for further +particle production. If not, i.e. if +W_transverse < W_min_smeared, the final two particles are +produced from what is currently left, if possible. (If not, the +fragmentation process is started over.) + +

Simplifying systems

+ +There are a few situations when it is meaningful to simplify the +original task, one way or another. + + +Decides whether a partonic system should be considered as a normal +string or a ministring, the latter only producing one or two primary +hadrons. The system mass should be above mStringMin plus the +sum of quark/diquark constituent masses for a normal string description, +else the ministring scenario is used. + + + +When two colour-connected partons are very nearby, with at least +one being a gluon, they can be joined into one, to avoid technical +problems of very small string regions. The requirement for joining is +that the invariant mass of the pair is below mJoin, where a +gluon only counts with half its momentum, i.e. with its contribution +to the string region under consideration. (Note that, for technical +reasons, the 0.2 GeV lower limit is de facto hardcoded.) + + + +When the invariant mass of two of the quarks in a three-quark junction +string system becomes too small, the system is simplified to a +quark-diquark simple string. The requirement for this simplification +is that the diquark mass, minus the two quark masses, falls below +mJoinJunction. Gluons on the string between the junction and +the respective quark, if any, are counted as part of the quark +four-momentum. Those on the two combined legs are clustered with the +diquark when it is formed. + + +

Ministrings

+ +The MiniStringFragmentation machinery is only used when a +string system has so small invariant mass that normal string fragmentation +is difficult/impossible. Instead one or two particles are produced, +in the former case shuffling energy-momentum relative to another +colour singlet system in the event, while preserving the invariant +mass of that system. With one exception parameters are the same as +defined for normal string fragmentation, to the extent that they are +at all applicable in this case. + +A discussion of the relevant physics is found in Nor00. +The current implementation does not completely abide to the scheme +presented there, however, but has in part been simplified. (In part +for greater clarity, in part since the class is not quite finished yet.) + + +Whenever the machinery is called, first this many attempts are made +to pick two hadrons that the system fragments to. If the hadrons are +too massive the attempt will fail, but a new subsequent try could +involve other flavour and hadrons and thus still succeed. +After nTry attempts, instead an attempt is made to produce a +single hadron from the system. Should also this fail, some further +attempts at obtaining two hadrons will be made before eventually +giving up. + + +

Junction treatment

+ +A junction topology corresponds to an Y arrangement of strings +i.e. where three string pieces have to be joined up in a junction. +Such topologies can arise if several valence quarks are kicked out +from a proton beam, or in baryon-number-violating SUSY decays. +Special attention is necessary to handle the region just around +the junction, where the baryon number topologically is located. +The junction fragmentation scheme is described in Sjo03. +The parameters in this section should not be touched except by experts. + + +Used to find the effective rest frame of the junction, which is +complicated when the three string legs may contain additional +gluons between the junction and the endpoint. To this end, +a pull is defined as a weighed sum of the momenta on each leg, +where the weight is exp(- eSum / eNormJunction), with +eSum the summed energy of all partons closer to the junction +than the currently considered one (in the junction rest frame). +Should in principle be (close to) sqrt((1 + a) / b), with +a and b the parameters of the Lund symmetric +fragmentation function. + + + +Retry (up to 10 times) when the first two considered strings in to a +junction both have a remaining energy (in the junction rest frame) +above this number. + + + +Retry (up to 10 times) when the first two considered strings in to a +junction has a highest remaining energy (in the junction rest frame) +above a random energy evenly distributed between +eBothLeftJunction and +eBothLeftJunction + eMaxLeftJunction +(drawn anew for each test). + + + +Retry (up to 10 times) when the invariant mass-squared of the final leg +and the leftover momentum of the first two treated legs falls below +eMinLeftJunction times the energy of the final leg (in the +junction rest frame). + + +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/Frontpage.xml b/PYTHIA8/pythia8130/xmldoc/Frontpage.xml new file mode 100644 index 00000000000..398f9583fef --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/Frontpage.xml @@ -0,0 +1,102 @@ + + +

PYTHIA 8

+ +

Welcome to PYTHIA - The Lund Monte Carlo!

+ +

+PYTHIA 8 is the successor to PYTHIA 6, rewritten from scratch in C++. +With the release of PYTHIA 8.1 it now becomes the official "current" +PYTHIA version, although PYTHIA 6.4 will be supported in parallel +with it for some time to come. Specifically, the new version has not +yet been enough tested and tuned for it to have reached the same level +of reliability as the older one. This testing will only happen if +people begin to work with the program, however, which is why we +encourage a gradual transition to the new version, starting now. +There are some new physics features in PYTHIA 8.1, that would make +use of it more attractive, but also some topics still missing, where +6.4 would have to be used. Further, many obsolete features will not +be carried over, so for some backwards compatibility studies again +6.4 would be the choice. + +

Documentation

+ +On these webpages you will find the up-to-date manual for PYTHIA 8.1. +Use the left-hand index to navigate this documentation of program +elements, especially of all possible program settings. All parameters +are provided with sensible default values, however, so you need only +change those of relevance to your particular study, such as choice of +beams, processes and phase space cuts. The pages also contain a fairly +extensive overview of all methods available to the user, e.g. to study +the produced events. What is lacking on these webpages is an overview, +on the one hand, and an in-depth physics description, on the other. + +

+The overview can be found in the attached PDF file +
A Brief Introduction +to PYTHIA 8.1 +
T. Sjöstrand, S. Mrenna and P. Skands, arXiv:0710.3820, +to appear in Computer Physics Communications. +
You are strongly recommended to read this summary when you +start out to learn how to use PYTHIA 8.1. + +

+For the physics description we refer to the complete +
PYTHIA 6.4 Physics and Manual +
T. Sjöstrand, S. Mrenna and P. Skands, JHEP05 (2006) 026, +
which in detail describes the physics (largely) implemented also in +PYTHIA 8, and also provides a more extensive bibliography than found +here. + +

+When you use PYTHIA 8.1, you should therefore cite both, e.g. like +
T. Sjöstrand, S. Mrenna and P. Skands, JHEP05 (2006) 026, +arXiv:0710.3820. + +

Program Authors and Licence

+ +

+Main author: Torbjörn Sjöstrand
+Department of Theoretical Physics, Lund University, +SE-223 62 Lund, Sweden
+phone: + 46 - 46 - 222 48 16, e-mail: torbjorn@thep.lu.se + +

+Author: Stephen Mrenna
+Computing Division, Simulations Group, +Fermi National Accelerator Laboratory,
+MS 234, Batavia, IL 60510, USA
+phone: + 1 - 630 - 840 - 2556, e-mail: mrenna@fnal.gov + +

+Author: Peter Skands
+CERN/PH, CH-1211 Geneva, Switzerland, and
+Theoretical Physics Department, +Fermi National Accelerator Laboratory,
+MS 106, Batavia, IL 60510, USA
+phone: + 41 - 22 - 767 24 59, e-mail: skands@fnal.gov + +

+Makefiles, configure scripts and HepMC interface by Mikhail Kirsanov. +
Conversion of XML files to PHP ones by Ben Lloyd. +
Simple Makefile for Win32/NMAKE by Bertrand Bellenot. +
Extended Higgs sector partly implemented by Marc Montull. +
Parts of charm and bottom decay tables courtesy DELPHI and +LHCb collaborations. + +

+PYTHIA 8 is licensed under the +GNU General Public Licence +version 2. +
Please respect the +MCnet Guidelines +for Event Generator Authors and Users. + +

+The program and the documentation is +Copyright © 2008 Torbjörn Sjöstrand + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/Glossary.xml b/PYTHIA8/pythia8130/xmldoc/Glossary.xml new file mode 100644 index 00000000000..151928ceaf3 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/Glossary.xml @@ -0,0 +1,92 @@ + + +

Glossary

+ +
+ +
BR
+
Beam Remnants; not much used since it may be confused with +Branching Ratio
+ +
BSM
+
Beyond-the-Standard-Model physics, as a generic term for anything +not contained within the SM
+ +
FSR
+
Final-State Radiation, implemented in terms of timelike showers
+ +
LHA
+
Les Houches Accord for user processes, describing which process-level +information should be stored to allow further showering and hadronization +of "skeleton" hard processes
+ +
LHAPDF
+
Les Houches Accord Parton Distribution Functions, originally a standard +format for defining PDF's and later a library with such PDF's
+ +
LHEF
+
Les Houches Event File(s), a file format for storing LHA process and +event information
+ +
ISR
+
Initial-State Radiation, implemented in terms of spacelike showers
+ +
MI
+
Multiple Interactions, i.e. several (more or less) independent +parton-parton subcollisions as part of a hadron-hadron event (sometimes +also called MPI, with P for parton or parton-parton)
+ +
MSSM
+
Minimal Supersymmetric extension of the Standard Model
+ +
PDF
+
Parton Distribution Function (alternatively Parton Density +Function)
+ +
PDG code
+
a scheme for assigning unique integers, particle identity codes, +to known and hypothetical particles; code rules and tables are published +in the RPP (see below).
+ +
pileup
+
several hadron-hadron collisions in a bunch crossing; not to +be confused with MI
+ +
RPP
+
Review of Particle Physics, the biannual review by the ParticleData Group +(PDG) from which many Standard-Model parameter values and much particle data +has been taken (but, given the poor data on many hadron resonances, a lot of +extra (guess)work is needed)
+ +
setting
+
collectively used to denote all the boolean flag, +integer mode, double-precision parm +and string word variables that can be set by the user +to steer the behaviour of a run; normally particle data are considered +separately but clearly are closely related
+ +
SLHA
+
SUSY Les Houchs Accord for interchange of mass and coupling information +in SUSY scenarios, via a well-defined file format
+ +
SM
+
the Standard Model of particle physics
+ +
SUSY
+
SUperSYmmetry
+ +
units
+
Normal PYTHIA input, internal operations and output is based on a set of +standard units, such as: +
GeV for all energies, momenta and masses, always with c = 1; +
mm for all distances and mm/c for all times, +so that again they match for c = 1; +
mb for all cross sections (but input or output via the Les Houches +Accord takes into account that the unit there is pb) +
+ +
+ +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/HadronLevelStandalone.xml b/PYTHIA8/pythia8130/xmldoc/HadronLevelStandalone.xml new file mode 100644 index 00000000000..cff58818e7d --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/HadronLevelStandalone.xml @@ -0,0 +1,160 @@ + + +

Hadron-Level Standalone

+ +The Les Houches Accord allows external process-level configurations +to be fed in, for subsequent parton-level and hadron-level generation +to be handled internally by PYTHIA. There is no correspondingly +standardized interface if you have external events that have also +been generated through the parton-level stage, so that only the +hadron-level remains to be handled. A non-standard way to achieve this +exists, however, and can be useful both for real applications and +for various tests of the hadronization model on its own. + +

+The key trick is to set the flag ProcessLevel:all = off. +When pythia.next() is called it then does not try to +generate a hard process, and therefore also cannot do anything on the +parton level. Instead only the HadronLevel methods are +called, to take the current content of the event record stored in +pythia.event as a starting point for any hadronization +and decays that are allowed by the normal parameters of this step. +Often the input would consist solely of partons grouped into colour +singlets, but also (colour-singlet) particles are allowed. + +

+To set up all the parameters, a pythia.init() call has +to be used, without any arguments. In brief, the structure of the +main program therefore should be something like +

+  Pythia pythia;                               // Declare generator.
+  Event& event = pythia.event                  // Convenient shorthand.
+  pythia.readString("ProcessLevel:all = off"); // The trick!
+  pythia.init();                               // Initialization.
+  for (int iEvent = 0; iEvent < nEvent; ++iEvent) {
+    // Insert filling of event here!
+    pythia.next();                             // Do the hadron level.
+  }
+
+Of course this should be supplemented by analysis of events, error checks, +and so on, as for a normal PYTHIA run. The unique aspect is how to fill +the event inside the loop, before pythia.next() +is called. + +

Input configuration

+ +To set up a new configuration the first step is to throw away the current +one, with event.reset(). This routine will also reserve +the zeroth entry in the even record to represent the event as a whole. + +

+With the event.append(...) methods a new entry is added at the +bottom of the current record, i.e. the first time it is called entry +number 1 is filled, and so on. The append method basically +exists in four variants, either without or with history information, +and with four-momentum provided either as a Vec4 four-vector +or as four individual components: +

+  append( id, status, col, acol, p, m)
+  append( id, status, col, acol, px, py, pz, e, m)
+  append( id, status, mother1, mother2, daughter1, daughter2, col, acol, p, m)
+  append( id, status, mother1, mother2, daughter1, daughter2, col, acol, px, py, pz, e, m)
+
+The methods return the index at which the entry has been stored, +but normally you would not use this feature. + +

+You can find descriptions of the input variables +here. +The PDG particle code id and the Les Houches Accord colour +col and anticolour acol tags must be set +correctly. The four-momentum and mass have to be provided in units of GeV; +if you omit the mass it defaults to 0. + +

+The status code can normally be simplified, however; you only need to recall +that positive numbers correspond to particles that are still around, while +negative numbers denote ones that already hadronized or decayed, so usually ++-1 is good enough. When pythia.next() is called +those positive-status particles that hadronize/decay get the sign of the +status code flipped to negative but the absolute value is retained. The +new particles are added with normal PYTHIA status codes. + +

+For normal hadronization/decays in pythia.next() the +history encoded in the mother and daughter indices is not used. +Therefore the first two append methods, which set all these +indices vanishing, should suffice. The subsequent hadronization/decays +will still be properly documented. + +

+The exception is when you want to include junctions in your string +topology, i.e. have three string pieces meet. Then you must insert in +your event record the (decayed) particle that is the reason for the +presence of a junction, e.g. a baryon beam remnant from which several +valence quarks have been kicked out, or a neutralino that underwent a +baryon-number-violating decay. This particle must have as daughters +the three partons that together carry the baryon number. + +

+The sample program in main21.cc illustrates how you can work +with this facility, both for simple parton configurations and for more +complicated ones with junctions. + +

Repeated hadronization or decay

+ +An alternative approach is possible with the +pythia.forceHadronLevel() routine. This method does +a call to the HadronLevel methods, irrespective of the +value of the HadronLevel:all flag. If you hadronize +externally generated events it is equivalent to a +pythia.next() call with +ProcessLevel:all = off. + +

+The real application instead is for repeated hadronization of the same +PYTHIA process- and parton-level event. This may for some studies +help to save time, given that these two first step are more +time-consuming than the hadronization one. + +

+For repeated hadronization you should first generate an event as usual, +but with HadronLevel:all = off. This event you can save +in a temporary copy, e.g. Event savedEvent = pythia.event. +Inside a loop you copy back with pythia.event = savedEvent, +and call pythia.forceHadronLevel() to obtain a new +hadronization history. + +

+A more limited form of repetition is if you want to decay a given kind +of particle repeatedly, without having to generate the rest of the event +anew. This could be the case e.g. in B physics applications. +Then you can use the pythia.moreDecays() method, which +decays all particles in the event record that have not been decayed +but should have been done so. The +ParticleDataTable::mayDecay( id, false/true) method +may be used to switch off/on the decays of a particle species +id, so that it is not decayed in the +pythia.next() call but only inside a loop over a number of +tries. + +

+Between each loop the newly produced decay products must be +removed and the decayed particle status restored to undecayed. +The former is simple, since the new products are appended to the +end of the event record: event.saveSize() saves the +initial size of the event record, and event.restoreSize() +can later be used repeatedly to restore this original size, which means +that the new particles at the end are thrown away. The latter is more +complicated, and requires the user to identify the positions of all +particles of the species and restore a positive status code with +event[i].statusPos(). + +

+The main15.cc program illustrates both these methods, +i.e. either repeated hadronization or repeated decay of PYTHIA +events. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/HepMCInterface.xml b/PYTHIA8/pythia8130/xmldoc/HepMCInterface.xml new file mode 100644 index 00000000000..214b94ad6b7 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/HepMCInterface.xml @@ -0,0 +1,44 @@ + + +

HepMC Interface

+ +An interface to the HepMC Dob01 standard event record +format has been provided by M. Kirsanov. To use it, the relevant +libraires need to be linked, as explained in the README +file. Only version 2 of HepMC is supported. (Version 1 requires +a different interface structure, which was only supported up until +Pythia 8.107.) + +

+The (simple) procedure to translate PYTHIA 8 events into HepMC ones +is illustrated in the main31.cc, main32.cc +and main54.cc main programs. At the core is a call to +the +

+HepMC::I_Pythia8::fill_next_event( pythia, hepmcevt, ievnum = -1, convertGluonTo0 = false ) 
+
+which takes a reference of the generator object and uses it, on the one +hand, to read out and covert the event record in pythia.event +and, on the other hand, to extract and store parton-density (PDF) +information for the hard subprocess from pythia.info. +The optional last argument, if true, allows you to store +gluons as "PDG" code 0 rather than the normal 21; this only applies to +the PDF information, not the event record. + +

+The earlier version of this routine, +

+HepMC::I_Pythia8::fill_next_event( pythia.event, hepmcevt, ievnum = -1 ) 
+
+is retained (for now) for backwards compatibility. It takes a PYTHIA event +as input and returns a HepMC one, but without storing the PDF information. +The latter could then instead be stored by a separate call +
+HepMC::I_Pythia8::pdf_put_info( hepmcevt, pythia, convertGluonTo0 = false ) 
+
+or not, as wished. + + +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/HiggsProcesses.xml b/PYTHIA8/pythia8130/xmldoc/HiggsProcesses.xml new file mode 100644 index 00000000000..7f565d70d40 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/HiggsProcesses.xml @@ -0,0 +1,910 @@ + + +

Higgs Processes

+ +This page documents Higgs production within and beyond the Standard Model +(SM and BSM for short). This includes several different processes and, +for the BSM scenarios, a large set of parameters that would only be fixed +within a more specific framework such as MSSM. Two choices can be made +irrespective of the particular model: + + +The partial width of a Higgs particle to a pair of gauge bosons, +W^+ W^- or Z^0 Z^0, depends cubically on the +Higgs mass. When selecting the Higgs according to a Breit-Wigner, +so that the actual mass mHat does not agree with the +nominal m_Higgs one, an ambiguity arises which of the +two to use Sey95. The default is to use a linear +dependence on mHat, i.e. a width proportional to +m_Higgs^2 * mHat, while on gives a +mHat^3 dependence. This does not affect the widths to +fermions, which only depend linearly on mHat. +This flag is used both for SM and BSM Higgses. + + + +The partial width of a Higgs particle to a pair of gluons or photons, +or a gamma Z^0 pair, proceeds in part through quark loops, +mainly b and t. There is some ambiguity what kind +of masses to use. Default is running MSbar ones, but alternatively +fixed pole masses are allowed (as was standard in PYTHIA 6), which +typically gives a noticeably higher cross section for these channels. +(For a decay to a pair of fermions, such as top, the running mass is +used for couplings and the fixed one for phase space.) + + +

Standard-Model Higgs, basic processes

+ +This section provides the standard set of processes that can be +run together to provide a reasonably complete overview of possible +production channels for a single SM Higgs. +The main parameter is the choice of Higgs mass, which can be set in the +normal ParticleDataTable database; thereafter the properties +within the SM are essentially fixed. + + +Common switch for the group of Higgs production within the Standard Model. + + + +Scattering f fbar -> H^0, where f sums over available +flavours except top. Related to the mass-dependent Higgs point coupling +to fermions, so at hadron colliders the bottom contribution will +dominate. +Code 901. + + + +Scattering g g -> H^0 via loop contributions primarily from +top. +Code 902. + + + +Scattering gamma gamma -> H^0 via loop contributions primarily +from top and W. +Code 903. + + + +Scattering f fbar -> H^0 Z^0 via s-channel Z^0 +exchange. +Code 904. + + + +Scattering f fbar -> H^0 W^+- via s-channel W^+- +exchange. +Code 905. + + + +Scattering f f' -> H^0 f f' via Z^0 Z^0 fusion. +Code 906. + + + +Scattering f_1 f_2 -> H^0 f_3 f_4 via W^+ W^- fusion. +Code 907. + + + +Scattering g g -> H^0 t tbar via t tbar fusion +(or, alternatively put, Higgs radiation off a top line). +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 908. + + + +Scattering q qbar -> H^0 t tbar via t tbar fusion +(or, alternatively put, Higgs radiation off a top line). +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 909. + + +

Standard-Model Higgs, further processes

+ +A number of further production processes has been implemented, that +are specializations of some of the above ones to the high-pT +region. The sets therefore could not be used simultaneously +without unphysical doublecounting, as further explained below. +They are not switched on by the HiggsSM:all flag, but +have to be switched on for each separate process after due consideration. + +

+The first three processes in this section are related to the Higgs +point coupling to fermions, and so primarily are of interest for +b quarks. It is here useful to begin by reminding that +a process like b bbar -> H^0 implies that a b/bbar +is taken from each incoming hadron, leaving behind its respective +antiparticle. The initial-state showers will then add one +g -> b bbar branching on either side, so that effectively +the process becomes g g -> H0 b bbar. This would be the +same basic process as the g g -> H^0 t tbar one used for top. +The difference is that (a) no PDF's are defined for top and +(b) the shower approach would not be good enough to provide sensible +kinematics for the H^0 t tbar subsystem. By contrast, owing +to the b being much lighter than the Higgs, multiple +gluon emissions must be resummed for b, as is done by PDF's +and showers, in order to obtain a sensible description of the total +production rate, when the b quarks predominantly are produced +at small pT values. + + +Scattering q g -> H^0 q. This process gives first-order +corrections to the f fbar -> H^0 one above, and should only be +used to study the high-pT tail, while f fbar -> H^0 +should be used for inclusive production. Only the dominant c +and b contributions are included, and generated separately +for technical reasons. Note that another first-order process would be +q qbar -> H^0 g, which is not explicitly implemented here, +but is obtained from showering off the lowest-order process. It does not +contain any b at large pT, however, so is less +interesting for many applications. +Code 911. + + + +Scattering g g -> H^0 b bbar. This process is yet one order +higher of the b bbar -> H^0 and b g -> H^0 b chain, +where now two quarks should be required above some large pT +threshold. +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 912. + + + +Scattering q qbar -> H^0 b bbar via an s-channel +gluon, so closely related to the previous one, but typically less +important owing to the smaller rate of (anti)quarks relative to +gluons. +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 913. + + +

+The second set of processes are predominantly first-order corrections +to the g g -> H^0 process, again dominated by the top loop. +We here only provide the kinematical expressions obtained in the +limit that the top quark goes to infinity, but scaled to the +finite-top-mass coupling in g g -> H^0. (Complete loop +expressions are available e.g. in PYTHIA 6.4 but are very lengthy.) +This provides a reasonably accurate description for "intermediate" +pT values, but fails when the pT scale approaches +the top mass. + + +Scattering g g -> H^0 g via loop contributions primarily +from top. +Code 914. + + + +Scattering q g -> H^0 q via loop contributions primarily +from top. Not to be confused with the HiggsSM:bg2Hb +process above, with its direct fermion-to-Higgs coupling. +Code 915. + + + +Scattering q qbar -> H^0 g via an s-channel gluon +and loop contributions primarily from top. Is strictly speaking a +"new" process, not directly derived from g g -> H^0, and +could therefore be included in the standard mix without doublecounting, +but is numerically negligible. +Code 916. + + +

Beyond-the-Standard-Model Higgs, introduction

+ +Further Higgs multiplets arise in a number of scenarios. We here +concentrate on the MSSM scenario with two Higgs doublets, but with +flexibility enough that also other two-Higgs-doublet scenarios could +be represented by a suitable choice of parameters. Conventionally the +Higgs states are labelled h^0, H^0, A^0 and H^+-. +If the scalar and pseudocalar states mix the resulting states are +labelled H_1^0, H_2^0, H_3^0. In process names and parameter +explanations both notations will be used, but for settings labels +we have adapted the shorthand hybrid notation H1 for +h^0(H_1^0), H2 for H^0(H_2^0) and +A3 for A^0(H_3^0). (Recall that the +Settings database does not distinguish upper- and lowercase +characters, so that the user has one thing less to worry about, but here +it causes probles with h^0 vs. H^0.) We leave the issue +of mass ordering between H^0 and A^0 open, and thereby +also that of H_2^0 and H_3^0. + + +Master switch to initialize and use the two-Higgs-doublet states. +If off, only the above SM Higgs processes can be used, with couplings +as predicted in the SM. If on, only the below BSM Higgs processes can +be used, with couplings that can be set freely, also found further down +on this page. + + +

Beyond-the-Standard-Model Higgs, basic processes

+ +This section provides the standard set of processes that can be +run together to provide a reasonably complete overview of possible +production channels for a single neutral Higgs state in a two-doublet +scenarios such as MSSM. The list of processes for neutral states closely +mimics the one found for the SM Higgs. Some of the processes +vanish for a pure pseudoscalar A^0, but are kept for flexiblity +in cases of mixing with the scalar h^0 and H^0 states, +or for use in the context of non-MSSM models. This should work well to +represent e.g. that a small admixture of the "wrong" parity would allow +a process such as q qbar -> A^0 Z^0, which otherwise is forbidden. +However, note that the loop integrals e.g. for g g -> h^0/H^0/A^0 +are hardcoded to be for scalars for the former two particles and for a +pseudoscalar for the latter one, so absolute rates would not be +correctly represented in the case of large scalar/pseudoscalar mixing. + + +Common switch for the group of Higgs production beyond the Standard Model, +as listed below. + + +

1) h^0(H_1^0) processes

+ + +Common switch for the group of h^0(H_1^0) production processes. + + + +Scattering f fbar -> h^0(H_1^0), where f sums over available +flavours except top. +Code 1001. + + + +Scattering g g -> h^0(H_1^0) via loop contributions primarily from +top. +Code 1002. + + + +Scattering gamma gamma -> h^0(H_1^0) via loop contributions primarily +from top and W. +Code 1003. + + + +Scattering f fbar -> h^0(H_1^0) Z^0 via s-channel Z^0 +exchange. +Code 1004. + + + +Scattering f fbar -> h^0(H_1^0) W^+- via s-channel W^+- +exchange. +Code 1005. + + + +Scattering f f' -> h^0(H_1^0) f f' via Z^0 Z^0 fusion. +Code 1006. + + + +Scattering f_1 f_2 -> h^0(H_1^0) f_3 f_4 via W^+ W^- fusion. +Code 1007. + + + +Scattering g g -> h^0(H_1^0) t tbar via t tbar fusion +(or, alternatively put, Higgs radiation off a top line). +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1008. + + + +Scattering q qbar -> h^0(H_1^0) t tbar via t tbar fusion +(or, alternatively put, Higgs radiation off a top line). +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1009. + + +

2) H^0(H_2^0) processes

+ + +Common switch for the group of H^0(H_2^0) production processes. + + + +Scattering f fbar -> H^0(H_2^0), where f sums over available +flavours except top. +Code 1021. + + + +Scattering g g -> H^0(H_2^0) via loop contributions primarily from +top. +Code 1022. + + + +Scattering gamma gamma -> H^0(H_2^0) via loop contributions primarily +from top and W. +Code 1023. + + + +Scattering f fbar -> H^0(H_2^0) Z^0 via s-channel Z^0 +exchange. +Code 1024. + + + +Scattering f fbar -> H^0(H_2^0) W^+- via s-channel W^+- +exchange. +Code 1025. + + + +Scattering f f' -> H^0(H_2^0) f f' via Z^0 Z^0 fusion. +Code 1026. + + + +Scattering f_1 f_2 -> H^0(H_2^0) f_3 f_4 via W^+ W^- fusion. +Code 1027. + + + +Scattering g g -> H^0(H_2^0) t tbar via t tbar fusion +(or, alternatively put, Higgs radiation off a top line). +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1028. + + + +Scattering q qbar -> H^0(H_2^0) t tbar via t tbar fusion +(or, alternatively put, Higgs radiation off a top line). +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1029. + +

3) A^0(H_3^0) processes

+ + +Common switch for the group of A^0(H_3^0) production processes. + + + +Scattering f fbar -> A^0(H_3^0), where f sums over available +flavours except top. +Code 1041. + + + +Scattering g g -> A^0(A_3^0) via loop contributions primarily from +top. +Code 1042. + + + +Scattering gamma gamma -> A^0(A_3^0) via loop contributions primarily +from top and W. +Code 1043. + + + +Scattering f fbar -> A^0(A_3^0) Z^0 via s-channel Z^0 +exchange. +Code 1044. + + + +Scattering f fbar -> A^0(A_3^0) W^+- via s-channel W^+- +exchange. +Code 1045. + + + +Scattering f f' -> A^0(A_3^0) f f' via Z^0 Z^0 fusion. +Code 1046. + + + +Scattering f_1 f_2 -> A^0(A_3^0) f_3 f_4 via W^+ W^- fusion. +Code 1047. + + + +Scattering g g -> A^0(A_3^0) t tbar via t tbar fusion +(or, alternatively put, Higgs radiation off a top line). +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1048. + + + +Scattering q qbar -> A^0(A_3^0) t tbar via t tbar fusion +(or, alternatively put, Higgs radiation off a top line). +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1049. + +

4) H+- processes

+ + +Common switch for the group of H^+- production processes. + + + +Scattering f fbar' -> H^+-, where f, fbar' sums over +available incoming flavours. Since couplings are assumed +generation-diagonal, in practice this means c sbar -> H^+ +and s cbar -> H^-. +Code 1061. + + + +Scattering b g -> H^+ tbar. At hadron colliders this is the +dominant process for single-charged-Higgs production. +Code 1062. + + +

5) Higgs-pair processes

+ + +Common switch for the group of Higgs pair-production processes. + + + +Scattering f fbar -> A^0(H_3) h^0(H_1). +Code 1081. + + + +Scattering f fbar -> A^0(H_3) H^0(H_2). +Code 1082. + + + +Scattering f fbar -> H^+- h^0(H_1). +Code 1083. + + + +Scattering f fbar -> H^+- H^0(H_2). +Code 1084. + + + +Scattering f fbar -> H+ H-. +Code 1085. + + +

Beyond-the-Standard-Model Higgs, further processes

+ +This section mimics the above section on "Standard-Model Higgs, +further processes", i.e. it contains higher-order corrections +to the processes already listed. The two sets therefore could not +be used simultaneously without unphysical doublecounting. +They are not controlled by any group flag, but have to be switched +on for each separate process after due consideration. We refer to +the standard-model description for a set of further comments on +the processes. + +

1) h^0(H_1^0) processes

+ + +Scattering q g -> h^0 q. This process gives first-order +corrections to the f fbar -> h^0 one above, and should only be +used to study the high-pT tail, while f fbar -> h^0 +should be used for inclusive production. Only the dominant c +and b contributions are included, and generated separately +for technical reasons. Note that another first-order process would be +q qbar -> h^0 g, which is not explicitly implemented here, +but is obtained from showering off the lowest-order process. It does not +contain any b at large pT, however, so is less +interesting for many applications. +Code 1011. + + + +Scattering g g -> h^0 b bbar. This process is yet one order +higher of the b bbar -> h^0 and b g -> h^0 b chain, +where now two quarks should be required above some large pT +threshold. +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1012. + + + +Scattering q qbar -> h^0 b bbar via an s-channel +gluon, so closely related to the previous one, but typically less +important owing to the smaller rate of (anti)quarks relative to +gluons. +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1013. + + + +Scattering g g -> h^0 g via loop contributions primarily +from top. +Code 1014. + + + +Scattering q g -> h^0 q via loop contributions primarily +from top. Not to be confused with the HiggsBSM:bg2H1b +process above, with its direct fermion-to-Higgs coupling. +Code 1015. + + + +Scattering q qbar -> h^0 g via an s-channel gluon +and loop contributions primarily from top. Is strictly speaking a +"new" process, not directly derived from g g -> h^0, and +could therefore be included in the standard mix without doublecounting, +but is numerically negligible. +Code 1016. + + +

2) H^0(H_2^0) processes

+ + +Scattering q g -> H^0 q. This process gives first-order +corrections to the f fbar -> H^0 one above, and should only be +used to study the high-pT tail, while f fbar -> H^0 +should be used for inclusive production. Only the dominant c +and b contributions are included, and generated separately +for technical reasons. Note that another first-order process would be +q qbar -> H^0 g, which is not explicitly implemented here, +but is obtained from showering off the lowest-order process. It does not +contain any b at large pT, however, so is less +interesting for many applications. +Code 1031. + + + +Scattering g g -> H^0 b bbar. This process is yet one order +higher of the b bbar -> H^0 and b g -> H^0 b chain, +where now two quarks should be required above some large pT +threshold. +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1032. + + + +Scattering q qbar -> H^0 b bbar via an s-channel +gluon, so closely related to the previous one, but typically less +important owing to the smaller rate of (anti)quarks relative to +gluons. +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1033. + + + +Scattering g g -> H^0 g via loop contributions primarily +from top. +Code 1034. + + + +Scattering q g -> H^0 q via loop contributions primarily +from top. Not to be confused with the HiggsBSM:bg2H1b +process above, with its direct fermion-to-Higgs coupling. +Code 1035. + + + +Scattering q qbar -> H^0 g via an s-channel gluon +and loop contributions primarily from top. Is strictly speaking a +"new" process, not directly derived from g g -> H^0, and +could therefore be included in the standard mix without doublecounting, +but is numerically negligible. +Code 1036. + + +

3) A^0(H_3^0) processes

+ + +Scattering q g -> A^0 q. This process gives first-order +corrections to the f fbar -> A^0 one above, and should only be +used to study the high-pT tail, while f fbar -> A^0 +should be used for inclusive production. Only the dominant c +and b contributions are included, and generated separately +for technical reasons. Note that another first-order process would be +q qbar -> A^0 g, which is not explicitly implemented here, +but is obtained from showering off the lowest-order process. It does not +contain any b at large pT, however, so is less +interesting for many applications. +Code 1051. + + + +Scattering g g -> A^0 b bbar. This process is yet one order +higher of the b bbar -> A^0 and b g -> A^0 b chain, +where now two quarks should be required above some large pT +threshold. +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1052. + + + +Scattering q qbar -> A^0 b bbar via an s-channel +gluon, so closely related to the previous one, but typically less +important owing to the smaller rate of (anti)quarks relative to +gluons. +Warning: unfortunately this process is rather slow, owing to a +lengthy cross-section expression and inefficient phase-space selection. +Code 1053. + + + +Scattering g g -> A^0 g via loop contributions primarily +from top. +Code 1054. + + + +Scattering q g -> A^0 q via loop contributions primarily +from top. Not to be confused with the HiggsBSM:bg2H1b +process above, with its direct fermion-to-Higgs coupling. +Code 1055. + + + +Scattering q qbar -> A^0 g via an s-channel gluon +and loop contributions primarily from top. Is strictly speaking a +"new" process, not directly derived from g g -> A^0, and +could therefore be included in the standard mix without doublecounting, +but is numerically negligible. +Code 1056. + + +

Parameters for Beyond-the-Standard-Model Higgs production and decay

+ +This section offers a big flexibility to set couplings of the various +Higgs states to fermions and gauge bosons, and also to each other. +The intention is that, for scenarios like MSSM, you should use standard +input from the SUSY Les Houches +Accord, rather than having to set it all yourself. In other cases, +however, the freedom is there for you to use. Kindly note that some +of the internal calculations of partial widths from the parameters provided +do not include mixing between the scalar and pseudoscalar states. + +

+Masses would be set in the ParticleDataTable database, +while couplings are set below. When possible, the couplings of the Higgs +states are normalized to the corresponding coupling within the SM. +When not, their values within the MSSM are indicated, from which +it should be straightforward to understand what to use instead. +The exception is some couplings that vanish also in the MSSM, where the +normalization has been defined in close analogy with nonvanishing ones. +Some parameter names are asymmetric but crossing can always be used, +i.e. the coupling for A^0 -> H^0 Z^0 obviously is also valid +for H^0 -> A^0 Z^0 and Z^0 -> H^0 A^0. +Note that couplings usually appear quadratically in matrix elements. + + +The h^0(H_1^0) coupling to down-type quarks. + + + +The h^0(H_1^0) coupling to up-type quarks. + + + +The h^0(H_1^0) coupling to (charged) leptons. + + + +The h^0(H_1^0) coupling to Z^0. + + + +The h^0(H_1^0) coupling to W^+-. + + + +The h^0(H_1^0) coupling to H^+- (in loops). +Is sin(beta - alpha) + cos(2 beta) sin(beta + alpha) / +(2 cos^2theta_W) in the MSSM. + + + +The H^0(H_2^0) coupling to down-type quarks. + + + +The H^0(H_2^0) coupling to up-type quarks. + + + +The H^0(H_2^0) coupling to (charged) leptons. + + + +The H^0(H_2^0) coupling to Z^0. + + + +The H^0(H_2^0) coupling to W^+-. + + + +The H^0(H_2^0) coupling to H^+- (in loops). +Is cos(beta - alpha) + cos(2 beta) cos(beta + alpha) / +(2 cos^2theta_W) in the MSSM. + + + +The H^0(H_2^0) coupling to a h^0(H_1^0) pair. +Is cos(2 alpha) cos(beta + alpha) - 2 sin(2 alpha) +sin(beta + alpha) in the MSSM. + + + +The H^0(H_2^0) coupling to an A^0(H_3^0) pair. +Is cos(2 beta) cos(beta + alpha) in the MSSM. + + + +The H^0(H_2^0) coupling to a h^0(H_1^0) Z^0 pair. +Vanishes in the MSSM. + + + +The H^0(H_2^0) coupling to an A^0(H_3^0) h^0(H_1^0) pair. +Vanishes in the MSSM. + + + +The H^0(H_2^0) coupling to a H^+- W-+ pair. +Vanishes in the MSSM. + + + +The A^0(H_3^0) coupling to down-type quarks. + + + +The A^0(H_3^0) coupling to up-type quarks. + + + +The A^0(H_3^0) coupling to (charged) leptons. + + + +The A^0(H_3^0) coupling to a h^0(H_1^0) Z^0 pair. +Is cos(beta - alpha) in the MSSM. + + + +The A^0(H_3^0) coupling to a H^0(H_2^0) Z^0 pair. +Is sin(beta - alpha) in the MSSM. + + + +The A^0(H_3^0) coupling to Z^0. +Vanishes in the MSSM. + + + +The A^0(H_3^0) coupling to W^+-. +Vanishes in the MSSM. + + + +The A^0(H_3^0) coupling to a h^0(H_1^0) pair. +Vanishes in the MSSM. + + + +The A^0(H_3^0) coupling to H^+-. +Vanishes in the MSSM. + + + +The A^0(H_3^0) coupling to a H^+- W-+ pair. +Vanishes in the MSSM. + + + +The tan(beta) value, which leads to an enhancement of the +H^+- coupling to down-type fermions and suppression to +up-type ones. The same angle also appears in many other places, +but this particular parameter is only used for the charged-Higgs case. + + + +The H^+- coupling to a h^0(H_1^0) W^+- pair. +Is cos(beta - alpha) in the MSSM. + + + +The H^+- coupling to a H^0(H_2^0) W^+- pair. +Is 1 - cos(beta - alpha) in the MSSM. + + +

+Another set of parameters are not used in the production stage but +exclusively for the description of angular distributions in decays. + + +possibility to modify angular decay correlations in the decay of a +h^0(H_1) decay Z^0 Z^0 or W^+ W^- to four +fermions. Currently it does not affect the partial width of the +channels, which is only based on the above parameters. + + + + + + + +The eta value of CP-violation in the +HiggsSM:parity = 3 option. + + + +possibility to modify angular decay correlations in the decay of a +H^0(H_2) decay Z^0 Z^0 or W^+ W^- to four +fermions. Currently it does not affect the partial width of the +channels, which is only based on the above parameters. + + + + + + + +The eta value of CP-violation in the +HiggsSM:parity = 3 option. + + + +possibility to modify angular decay correlations in the decay of a +A^0(H_3) decay Z^0 Z^0 or W^+ W^- to four +fermions. Currently it does not affect the partial width of the +channels, which is only based on the above parameters. + + + + + + + +The eta value of CP-violation in the +HiggsSM:parity = 3 option. + + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/Histograms.xml b/PYTHIA8/pythia8130/xmldoc/Histograms.xml new file mode 100644 index 00000000000..70acb22a177 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/Histograms.xml @@ -0,0 +1,176 @@ + + +

Histograms

+ +The Hist class gives a simple implementation of +one-dimensional histograms, useful for quick-and-dirty testing, +without the need to link to more sophisticated packages. +For this reson it is used in many of the sample main programs +found in the examples subdirectory. + + +

+A Histogram is declared by a + +where + +is a string with the title of the histogram at output, + + +is the number of bin the x range will be subdivided into, + + +is the lower edge of the histogram, + + +is the upper edge of the histogram. + + + +

+For instance +

+   Hist ZpT( "Z0 pT spectrum", 100, 0., 100.);
+
+Alternatively you can first declare it and later define it: +
+   Hist ZpT;
+   ZpT.book( "Z0 pT spectrum", 100, 0., 100.);
+
+ +Once declared, its contents can be added by repeated calls to +fill + +where + +is the x position where the filling should occur, and + + +is the amount of weight to be added at this x value. + + + +

+For instance +

+   ZpT.fill( 22.7, 1.); 
+
+Since the weight defaults to 1 the last argument could have been +omitted in this case. + +

+A set of overloaded operators have been defined, so that histograms +can be added, subtracted, divided or multiplied by each other. Then the +contents are modified accordingly bin by bin. Thus the relative +deviation between two histograms can be found as +

+  diff = (data - theory) / (data + theory);
+
+assuming that diff, data and theory +have been booked with the same number of bins and x range. That +responsibility rests on the user; some checks are made for compatibility, +but not enough to catch all possible mistakes. + +

+Also overloaded operations with double real numbers are available. +Again these four operations are defined bin by bin, i.e. the +corresponding amount is added to, subtracted from, multiplied by or +divided by each bin. The double number can come before or after the +histograms, with obvious results. Thus the inverse of a histogram +result is given by 1. / result. +The two kind of operations can be combined, e.g. +

+  allpT = ZpT + 2. * WpT
+
+Finally, also the +=, -+, *=, /= are overloaded, with +the right-hand side being either a histogram or a real number. + +

+A histogram can be printed by making use of the overloaded << +operator, e.g.: +

+   cout << ZpT;
+
+The printout format is inspired by the old HBOOK one. To understand +how to read this format, consider the simplified example +
+                                    
+        3.50*10^ 2  9                     
+        3.00*10^ 2  X   7               
+        2.50*10^ 2  X  1X               
+        2.00*10^ 2  X6 XX                
+        1.50*10^ 2  XX5XX                 
+        1.00*10^ 2  XXXXX                
+        0.50*10^ 2  XXXXX        
+
+          Contents 
+            *10^ 2  31122
+            *10^ 1  47208
+            *10^ 0  79373
+
+          Low edge  -- 
+            *10^ 1  10001 
+            *10^ 0  05050
+
+The key feature is that the Contents and +Low edge have to be read vertically. For instance, +the first bin has the contents +3 * 10^2 + 4 * 10^1 + 7 * 10^0 = 347. Correspondingly, +the other bins have contents 179, 123, 207 and 283. The first bin +stretches from -(1 * 10^1 + 0 * 10^0) = -10 to the +beginning of the second bin, at -(0 * 10^1 + 5 * 10^0) = -5. + +

+The visual representation above the contents give a simple impression +of the shape. An X means that the contents are filled up +to this level, a digit in the topmost row the fraction to which the +last level is filled. So the 9 of the first column indicates this bin +is filled 9/10 of the way from 3.00*10^2 = 300 to +3.50*10^2 = 350, i.e. somewhere close to 345, +or more precisely in the range 342.5 to 347.5. + +

+The printout also provides some other information, such as the +number of entries, i.e. how many times the histogram has been filled, +the total weight inside the histogram, the total weight in underflow +and overflow, and the mean value and root-mean-square width (disregarding +underflow and overflow). The mean and width assumes that all the +contents is in the middle of the respective bin. This is especially +relevant when you plot a integer quantity, such as a multiplicity. +Then it makes sense to book with limits that are half-integers, e.g. +

+   Hist multMI( "number of multiple interactions", 20, -0.5, 19.5);
+
+so that the bins are centered at 0, 1, 2, ..., respectively. This also +avoids ambiguities which bin gets to be filled if entries are +exactly at the border between two bins. Also note that the +fill( xValue) method automatically performs a cast +to double precision where necessary, i.e. xValue +can be an integer. + +

+Some further metods are: +

    +
  • getBinContent(iBin) returns the value in bin +iBin, ranging from 1 through nBin, +with 0 for underflow and nBin + 1 for +overflow.
  • +
  • getEntries() returns the number of entries.
  • +
  • table(ostream& = cout) prints a two-column table, +where the first gives the center of each bin and the second the +corresponding bin contents. This may be useful for plotting e.g. with +Gnuplot.
  • +
  • null() resets bin contents.
  • +
  • name( title) resets the title to the new string.
  • +
  • sameSize( Hist&) checks that the number of bins and +upper and lower limits are the same as in the histogram in the +argument.
  • +
  • takeLog(true) take 10-logarithm of contents +bin by bin.
  • +
  • takeLog(false) take e-logarithm of contents +bin by bin.
  • +
+ +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/ImplementNewShowers.xml b/PYTHIA8/pythia8130/xmldoc/ImplementNewShowers.xml new file mode 100644 index 00000000000..e08c341b497 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ImplementNewShowers.xml @@ -0,0 +1,530 @@ + + +

Implement New Showers

+ +In case you want to replace the PYTHIA initial- and final-state +showers by your own, it is possible but not trivial. The point is +that multiple interactions (MI), initial-state radiation (ISR) and +final-state radiation (FSR) in general appear in one single +interleaved sequence of decreasing pT values. Therefore +shower replacements would have to be able to play the game by such +rules, as we will outline further below. Of course, this still +leaves the field open exactly how to define what to mean by +pT, how to handle recoil effects, how the colour flow is +affected, and so on, so there is certainly room for alternative +showers. + +

+For the moment we assume you want to keep the MI part of the story +unchanged, and make use of the existing beam-remnants (BR) machinery. +If you want to replace both MI, ISR, FSR and BR then you had better +replace the whole PartonLevel module of the code. +If, in addition, you want to produce your own hard processes, +then you only need the +hadron-level standalone +part of the machinery. + +

+In order to write replacement codes for ISR and/or FSR it is useful +to be aware of which information has to be shared between the +different components, and which input/output structure is required +of the relevant methods. For details, nothing beats studying the +existing code. However, here we provide an overview, that should +serve as a useful introduction. + +

+It should be noted that we here primarily address the problem in +its full generality, with interleaved MI, ISR and FSR. There exists +an option TimeShower:interleave = off where only +MI and ISR would be interleaved and FSR be considered after these +two, but still before BR. Most of the aspects described here would +apply also for that case. By contrast, resonance decays are only +considered after all the four above components, and timelike +showers in those decays would never be interleaved with anything +else, so are much simpler to administrate. + +

+Therefore the +pythia.setShowerPtr( timesDecPtr, timesPtr, spacePtr) +method allows two separate pointers to be set to instances of +derived TimeShower classes. The first is only required +to handle decays, say of Z^0 or Upsilon, with no +dependence on beam remnants or ISR. The second, as well as +spacePtr, has to handle the interleaved evolution of MI, +ISR and FSR. Therefore you are free to implement only the first, and +let the PYTHIA default showers take care of the latter two. But, if +you wanted to, you could also set timesDecPtr = 0 and +only provide a timesPtr, or only a spacePtr. +If your timelike shower does both cases, the first two pointers +can agree. The only tiny point to take into account then is that +init( beamAPtr, beamBPtr) is called twice, a first time +to timesDecPtr with beam pointers 0, and a second time +to timesPtr with nonvanishing beam pointers. + +

The event record

+ +Obviously the main place for sharing information is the event +record, specifically the Event event member of +Pythia, passed around as a reference. It is +assumed you already studied how it works, so here we only draw +attention to a few aspects of special relevance. + +

+One basic principle is that existing partons should not be +overwritten. Instead new partons should be created, even when a +parton only receives a slightly shifted momentum and for the rest +stays the same. Such "carbon copies" by final-state branchings +should be denoted by both daughter indices of the original parton +pointing to the copy, and both mother indices of the copy to the +original. If the copy instead is intended to represent an earlier +step, e.g. in ISR backwards evolution, the role of mothers and +daughters is interchanged. The +event.copy( iCopy, newStatus) +routine can take care of this tedious task; the sign of +newStatus tells the program which case to assume. + +

+To make the event record legible it is essential that the +status codes +are selected appropriately to represent the reason why each new +parton is added to the record. Also remember to change the +status of a parton to be negative whenever an existing parton +is replaced by a set of new daughter partons. + +

+Another important parton property is scale(), +which does not appear in the normal event listing, but only +if you use the extended +Event:listScaleAndVertex = on option. +This property is supposed to represent the production scale +(in GeV) of a parton. In the current FSR and ISR algorithms +it is used to restrict from above the allowed pT +values for branchings of this particular parton. +Beam remnants and other partons that should not radiate are +assigned scale 0. + +

The subsystems

+ +One aspect that complicates administration is that an event +can contain several subsystems, consisting of one MI and its +associated ISR and FSR, which to first approximation are assumed +to evolve independently, but to second are connected by the +interleaved evolution. The partons of a given subsystem +therefore do not have to be stored consecutively. Some simple +vectors put inside the event record can be used to keep track of +the current position, i.e. index iPos for parton +event[iPos], of all partons of all systems. + +

+The number of systems is given by sizeSystems(), +with systems numbered 0 through sizeSystems() - 1. +The size of a given subsystem iSys is given by +sizeSystem(iSys), with analogous numbering. +The method getInSystem( iSys, iMem) returns the +position iPos of the iMem'th member of +the iSys'th system. For each system, the slots +iMem = 0 and 1 are intended for the incoming partons +from beam A and B, respectively. If there are no beams, such as +in resonance decays, these should be assigned value 0. +Slots 2 onwards are intended for all the outgoing partons. These +latter partons are not guaranteed to appear in any particular order. + +

+New systems are created from the hard process and by the MI, +not from any of the other components, by the newSystem() +method, which returns the iSys code of the new system. +Both FSR and ISR modify the position of partons, however. +Since an FSR or ISR branching typically implies a new state with +one more parton than before, the method +addToSystem( iSys, iPos) appends a new slot to the +given system and stores the iPos value there. Furthermore, +in a branching, several existing partons may also be moved to new +slots. The method setInSystem( iSys, iMem, iPos) +replaces the current iPos value in the given slot +by the provided one. If you do not know the iMem value, +replaceInSystem( iSys, iPosOld, iPosNew) +will replace any ocurence of iPosOld by +iPosNew wherever it is found in the +iSys'th system. In a FSR 1 -> 2 branching +it is irrelevant which parton position you let overwrite the +existing slot and which is added to the end of the system. + +

+Finally, clearSystems() empties the information, and +listSystems() provides a simple listing of all the +iPos values by system, intended for debugging purposes only. + +

+The system information must be kept up-to-date. The MI component only +writes, but both ISR, FSR and BR make extensive use of the existing +information. As an example, the introduction of primordial kT +in the beam remnants will fail if the information on which +final-state partons belong to which system is out-of-date. + +

+Currently the system information is kept throughout the continued +history of the event. Resonance decays create new systems, appended +to the existing ones. This could be useful during the hadronization +stage, to collect the partons that belong to a resonace with +preserved mass when a small string collapses to one particle, +but is not yet used for that. + +

The beams

+ +The different subsystems are tied together by them sharing the same +initial beam particles, and thereby being restricted by energy-momentum +and flavour conservation issues. The information stored in the two +beam particles, here called beamA and beamB, +is therefore as crucial to keep correct as the above subsystem list. + +

+Both beam objects are of the BeamParticle class. +Each such object contains a vector with the partons extracted from it. +The number of such partons, beamX.size() (X = A or B), +of course is the same as the above number of subsystems in the event +record. (The two diverge at the BR step, where further beam remnants +are added to the beams without corresponding to new subsystems.) +The individual partons are accessed by an overloaded indexing +operator to a vector of ResolvedParton objects. The +iPos() property corresponds to the iPos +one above, i.e. providing the position in the main event record of +a parton. In particular, +beamA[iSys].iPos() = event.getInSystem( iSys, 0) and +beamB[iSys].iPos() = event.getInSystem( iSys, 1). +Whereas thus the indices of the two incoming partons to a subsystem +are stored in two places, the ones of the outgoing partons only +appear in the system part of the Event class. + +

+Just as the subsystems in Event must be updated, so must +the information in the two BeamParticle's, e.g. with methods +beamX[iSys].iPos( iPosIn) when an incoming parton is +replaced by a new one in line iPosIn. Furthermore the new +parton identity should be set by beamX[iSys].id( idIn) +and the new x energy-momentum fraction by +beamX[iSys].x( xIn). The three can be combined in one go +by beamX[iSys].update( iPosIn, idIn, xIn). + +

+To be specific, it is assumed that, at each step, the two incoming +partons are moving along the +-z axis and are massless. +Since the event is constructed in the c.m. frame of the incoming +beams this implies that x = 2 E / E_cm. +If the x values are not defined accordingly or not kept +up-to-date the BR treatment will not conserve energy-momentum. + +

+In return, the BeamParticle objects give access to some +useful methods. The beamX.xf( id, x, Q2) returns the +standard PDF weight x f_id(x, Q^2). More intererstingly, +beamX.xfISR( iSys, id, x, Q2) returns the modified weight +required when several subsystems have to share the energy and flavours. +Thus iSys is added as an extra argument, and the momentum +already assigned to the other subsystems is not available for evolution, +i.e. the maximal x is correspondingly smaller than unity. +Also flavour issues are handled in a similar spirit. + +

+An additional complication is that a parton can be either valence or +sea, and in the latter case the BR treatment also distinguishes +companion quarks, i.e. quark-antiquark pairs that are assumed to +come from the same original g -> q qbar branching, whether +perturbative or not. This can be queried either with the +beamX[iSys].companion() method, for detailed information, +or with the beamX[iSys].isValence(), +beamX[iSys].isUnmatched() and +beamX[iSys].isCompanion() metods for yes/no answers +whether a parton is valence, unmatched sea or matched sea. +This choice should affect the ISR evolution; e.g., a valence quark +cannot be constructed back to come from a gluon. + +

+To keep this info up-to-date, the beamX.pickValSeaComp() +method should be called whenever a parton of a new flavour has been +picked in the ISR backwards evolution, but not if the flavour has not +been changed, since then one should not be allowed to switch back and +forth between the same quark being considered as valence or as sea. +Since the pickValSeaComp() method makes use of the +current parton-density values, it should be preceded by a call +to beamX.xfISR( iSys, id, x, Q2), where the values in +the call are the now finally accepted ones for the newly-found mother. +(Such a call is likely to have been made before, during the evolution, +but is not likely to be the most recent one, i.e. still in memory, and +therefore had better be redone.) + +

+Most of the issues in this section are related to the ISR algorithm, +i.e. it is possible to write an FSR algorithm that is completely +decoupled. Alternatively the FSR may change the position where an +incoming parton is stored, or its assumed momentum, e.g. by recoil +effects inside dipoles stretched from the scattered back to the +incoming partons. In that case some of the methods above would have +to be used also inside the FSR algorithm. + +

The TimeShower interface

+ +If you want to replace the TimeShower class this would +involve replacing the following methods. + + +The constructor does not need to do anything. + + + +You have to store your local copy of the pointers to these objects, +since they have to be used during the generation, as explained above. +The pointers could be zero; e.g. a local copy of TimeShower +is created to handle showers in decays such as Upsilon -> q qbar +from inside the ParticleDecays class. This is also the +place to do initialization of whatever parameters you plan to use, +e.g. by reading in them from a user-accessible database like the +Settings one. + + + +Relative to the default pT_max evolution scale of the process, +it may still be convenient to vary the matching slightly for the hardest +interaction in an event, to probe the sensitivity to such details. The +base-class implementation returns the value of the +TimeShower:pTmaxFudge parameter. + + + +This is an all-in-one call for shower evolution, and as such cannot be +used for the normal interleaved evolution, where only the routines below +are used. It also cannot be used in resonance decays that form part of +the hard process, since there the +user hooks insert a potential +veto step. Currently this routine is therefore only used in the +hadron-level decays, e.g. Upsilon -> g g g. +
iBeg and iEnd is the position of the +first and last parton of a separate system, typically produced by a +resonance decay. Such a system only evolves in isolation, and in +particular does not relate to the beams. +
The pTmax value sets the maximum scale for evolution, +but normally you would restrict that further for each individual +parton based on its respective scale value. +
The routine is expected to return the number of FSR branchings that +were generated, but only for non-critical statistics purposes. +
Since the real action typically is delegated to the routines +below, it may well be that the existing code need not be replaced. +
+ + +This method is called immediately after a new interaction (or the +products of a resonance decay) has been added, and should then be used +to prepare the subsystem of partons for subsequent evolution. In +the current code this involves identifying all colour and charge +dipole ends: the position of radiating and recoiling partons, maximum +pT scales, possible higher-order matrix elements matchings +to apply, and so on. +
The iSys parameter specifies which parton system +is to be prepared. It is used to extract the set of partons to be +treated, with rules as described in the above section on subsystems. +Specifically, the first two partons represent the incoming state, +or are 0 for resonance decays unrelated to the beams, while the +rest are not required to be in any particular order. +
+ + +This method is called immediately after a spacelike branching in the +iSys'th subsystem. Thus the information for that system is +out-of-date, while that of the others is unchanged. If you want, you are +free to throw away all information for the affected subsystem and call +prepare( iSys, event) to create new one. Alternatively +you may choose only to update the information that has changed. + + + +This is the main driver routine for the downwards evolution. A new +pT is to be selected based on the current information set up +by the routines above, and along with that a branching parton or dipole. +The pTbegAll scale is the maximum scale allowed, from which +the downwards evolution should be begun (usually respecting the maximum +scale of each individual parton). If no emission is found above +pTendAll (and above the respective shower cutoff scales) +then 0. should be returned and no emissions will be allowed. +Both scales can vary from one event to the next: if a scale has +already been selected for MI or ISR it makes no sense to look for +a scale smaller than that from FSR, since it would not be able to +compete, so pTendAll is set correspondingly. As it happens, +FSR is tried before ISR and MI in the interleaved evolution, +but this is an implementational detail that could well change. +
Typically the implementation of this routine would be to set +up a loop over all possible radiating objects (dipoles, dipole ends, ...), +for each pick its possible branching scale and then pick the one +with largest scale as possible winner. At this stage no branching should +actually be carried out, since MI, ISR and FSR still have to be compared +to assign the winner. +
+ + +This method will be called once FSR has won the competition with +MI and ISR to do the next branching. The candidate branching found +in the previous step should here be carried out in full. The +pre-branching partons should get a negative status code and new +replacement ones added to the end of the event record. Also the +subsystem information should be updated, and possibly also the +beams. +
Should some problem be encountered in this procedure, e.g. if +some not-previously-considered kinematics requirement fails, it is +allowed to return false to indicate that no branching +could be carried out. +
+ + +This method is not virtual. If a branching is constructed by the +previous routine this tiny method should be able to return the number +of the selected subsystem iSysSel where it occured, +so that the spacelike shower can be told which system to update, +if necessary. Therefore iSysSel must be set in +branch (or already in pTnext). + + + +This method is not at all required. In the current implementation it +outputs a list of all the dipole ends, with information on the +respective dipole. The routine is not called anywhere in the public +code, but has been inserted at various places during the +development/debug phase. + + +

The SpaceShower interface

+ +If you want to replace the SpaceShower class this would +involve replacing the following methods. You will find that much of +the story reminds of TimeShower above, and actually some +cut-and-paste of text is involved. In some respects the description +is simpler, since there are no special cases for resonance decays +and non-interleaved evolution. Thus there is no correspondence to the +TimeShower::shower(...) routine. + + +The constructor does not need to do anything. + + + +You have to store your local copy of the pointers to these objects, +since they have to be used during the generation, as explained above. +This is also the place to do initialization of whatever parameters +you plan to use, e.g. by reading in them from a user-accessible +database like the Settings one. + + + +The question is whether the ISR should be allowed to occur at larger +scales than the hard process it surrounds. This is process-dependent. +For instance, if the hard process is Z^0 production we know +that ISR should be allowed to go right up to the kinematical limit. +If it is a 2 -> 2 QCD process the ISR should not exceed +the scale of the hard process, since if so one would doublecount. +The SpaceShower:pTmaxMatch switch allows you to force the +behaviour, or else to program your own logic. The current implementation +limits pT whenever the final state contains a quark (except top), +gluon or photon, since then the danger of doublecounting is there. +You may replace by your own logic, or leave as is. +
The internal PYTHIA implementation also allows intermediate options, +where emissions can go up to the kinematical limit but be dampened above +the factorization or renormalization scale. Therefore the (square of the) +latter two are provided as optional input parameters. +
+ + +When the above method limits pT_max to the scale of the process, +it may still be convenient to vary the matching slightly for the hardest +interaction in an event, to probe the sensitivity to such details. The +base-class implementation returns the value of the +SpaceShower:pTmaxFudge parameter. + + + +This method is called immediately after a new interaction has been +added, and should then be used to prepare the subsystem of partons +for subsequent evolution. In the current code this involves identifying +the colour and charge dipole ends: the position of radiating and recoiling +partons, maximum pT scales, and possible higher-order matrix +elements matchings to apply. Depending on what you have in mind you may +choose to store slightly different quantities. You have to use the +subsystem information described above to find the positions of the two +incoming partons (and the outgoing ones) of the system, and from there +the scales at which they were produced. +
The limitPTmax input agrees with the output of the +previous method for the hardest process, and is always true for +subsequent MI, since there an unlimited pT for sure +would lead to doublecounting. +
+ + +This method is called immediately after a timelike branching in the +iSys'th subsystem. Thus the information for that system may +be out-of-date, and to be updated. For the standard PYTHIA showers +this routine does not need to do anything, but that may be different +in another implementation. + + + +This is the main driver routine for the downwards evolution. A new +pT is to be selected based on the current information set up +by the routines above, and along with that a branching parton or dipole. +The pTbegAll scale is the maximum scale allowed, from which +the downwards evolution should be begun (usually respecting the maximum +scale of each individual parton). If no emission is found above +pTendAll (and above the respective shower cutoff scales) +then 0. should be returned and no emissions will be allowed. +Both scales can vary from one event to the next: if a scale has +already been selected for MI or ISR it makes no sense to look for +a scale smaller than that from FSR, since it would not be able to +compete, so pTendAll is set correspondingly. As it happens, +FSR is tried before ISR and MI in the interleaved evolution, +but this is an implementational detail that could well change. +
Typically the implementation of this routine would be to set +up a loop over all possible radiating objects (dipoles, dipole ends, ...), +for each pick its possible branching scale and then pick the one +with largest scale as possible winner. At this stage no branching should +actually be carried out, since MI, ISR and FSR still have to be compared +to assign the winner. +
The final input nRadIn provides the total number of +ISR and FSR emissions already generated in the event, and so allows a +special treatment for the very first emission, if desired. +
+ + +This method will be called once FSR has won the competition with +MI and ISR to do the next branching. The candidate branching found +in the previous step should here be carried out in full. The +pre-branching partons should get a negative status code and new +replacement ones added to the end of the event record. Also the +subsystem information should be updated, and possibly also the +beams. +
Should some problem be encountered in this procedure, e.g. if +some not-previously-considered kinematics requirement fails, it is +allowed to return false to indicate that no branching +could be carried out. +
+ + +This method is not virtual. If a branching is constructed by the +previous routine this tiny method should be able to return the number +of the selected subsystem iSysSel where it occured, +so that the spacelike shower can be told which system to update, +if necessary. Therefore iSysSel must be set in +branch (or already in pTnext). + + + +This method is not at all required. In the current implementation it +outputs a list of all the dipole ends, with information on the +respective dipole. The routine is not called anywhere in the public +code, but has been inserted at various places during the +development/debug phase. + + +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/Index.xml b/PYTHIA8/pythia8130/xmldoc/Index.xml new file mode 100644 index 00000000000..946f004b829 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/Index.xml @@ -0,0 +1,111 @@ + + +Pythia logo + +

PYTHIA 8 Index

+ +

Brief Introduction (pdf)

+ +

Program Overview

+ +Frontpage
+Program Flow
+Settings Scheme
+Particle Data Scheme
+Program Files
+Sample Main Programs
+ +

Setup Run Tasks

+ + +Save Settings
+Main-Program Settings
+Beam Parameters
+Random-Number Seed
+PDF Selection
+Master Switches
+Process Selection
+  --   +QCD
+  --   +Electroweak
+  --   +Onia
+  --   +Top
+  --   +Fourth Generation
+  --   +Higgs
+  --   +SUSY
+  --   +New Gauge Bosons
+  --   +Left-Right Symmetry
+  --   +Leptoquark
+  --   +Compositeness
+  --   +Extra Dimensions
+A Second Hard Process
+Phase Space Cuts
+Couplings and Scales
+Standard-Model Parameters
+Total Cross Sections
+Resonance Decays
+Timelike Showers
+Spacelike Showers
+Multiple Interactions
+Beam Remnants
+Fragmentation
+Flavour Selection
+Particle Decays
+Bose-Einstein Effects
+Particle Data
+Error Checks
+Tunes
+
+ +

Study Output

+ + +Four-Vectors
+Particle Properties
+Event Record
+Event Information
+Event Statistics
+Histograms
+Event Analysis
+HepMC Interface
+
+ +

Link to Other Programs

+ + +Les Houches Accord
+Access PYTHIA 6 Processes
+Semi-Internal Processes
+Semi-Internal Resonances
+Hadron-Level Standalone
+SUSY Les Houches Accord
+Beam Shape
+Parton Distributions
+External Decays
+User Hooks
+Random Numbers
+Implement New Showers
+
+ +

Reference Materiel

+ +PYTHIA 6 Translation Table
+Update History
+Bibliography
+Glossary
+Version + +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/LeftRightSymmetryProcesses.xml b/PYTHIA8/pythia8130/xmldoc/LeftRightSymmetryProcesses.xml new file mode 100644 index 00000000000..cc361fcc251 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/LeftRightSymmetryProcesses.xml @@ -0,0 +1,183 @@ + + +

Left-Right-Symmetry Processes

+ +At current energies, the world is left-handed, i.e. the Standard Model +contains an SU(2)_L group. Left-right symmetry at some larger +scale implies the need for an SU(2)_R group. Thus the particle +content is expanded by right-handed Z_R^0 and W_R^+- +and right-handed neutrinos. The Higgs fields have to be in a triplet +representation, leading to doubly-charged Higgs particles, one set for +each of the two SU(2) groups. Also the number of neutral and +singly-charged Higgs states is increased relative to the Standard Model, +but a search for the lowest-lying states of this kind is no different +from e.g. the freedom already accorded by the MSSM Higgs scenarios. + +

+PYTHIA implements the scenario of Hui97. + +

+The W_R^+- has been implemented as a simple copy of the +ordinary W^+-, with the exception that it couples to +right-handed neutrinos instead of the ordinary left-handed ones. +Thus the standard CKM matrix is used in the quark sector, and the +same vector and axial coupling strengths, leaving only the mass as +free parameter. The Z_R^0 implementation (without interference +with the photon or the ordinary Z^0) allows decays both to +left- and right-handed neutrinos, as well as other fermions, according +to one specific model ansatz. Obviously both the W_R^+- +and the Z_R^0 descriptions are likely to be simplifications, +but provide a starting point. + +

+For the doubly-charged Higgses, the main decay modes implemented are +H_L^++ -> W_L^+ W_L^+, l_i^+ l_j^+ (i, j generation +indices) and H_R^++ -> W_R^+ W_R^+, l_i^+ l_j^+. + +

+The right-handed neutrinos can be allowed to decay further. Assuming them +to have a mass below that of W_R^+-, they decay to three-body +states via a virtual W_R^+-, nu_Rl -> l+- f fbar', +where both lepton charges are allowed owing to the Majorana character +of the neutrinos. If there is a significant mass splitting, also +sequential decays nu_Rl -> l+- l'-+ nu'_Rl are allowed. +Currently the decays are isotropic in phase space. If the neutrino +masses are close to or above the W_R^ ones, this description +has to be substituted by a sequential decay via a real W_R^ +(not implemented, but actually simpler to do than the one here). + + +

Production processes

+ +A few different production processes have been implemented, which normally +would not overlap and therefore could be run together. + + +Common switch for the group of implemented processes within a +left-right-symmetric scenario. + + + +Scatterings f fbar -> Z_R^0. +Code 3101. + + + +Scatterings W_R^+. +Code 3102. + + + +Scatterings l_i l_j -> H_L^--. +Code 3121. + + + +Scatterings l_i gamma -> H_L^-- e^+. +Code 3122. + + + +Scatterings l_i gamma -> H_L^-- mu^+. +Code 3123. + + + +Scatterings l_i gamma -> H_L^-- tau^+. +Code 3124. + + + +Scatterings f_1 f_2 -> H_L^-- f_3 f_4 via WW fusion. +Code 3125. + + + +Scatterings f fbar -> H_L^++ H_L^--. +Code 3126. + + + +Scatterings l_i l_j -> H_R^--. +Code 3141. + + + +Scatterings l_i gamma -> H_R^-- e^+. +Code 3142. + + + +Scatterings l_i gamma -> H_R^-- mu^+. +Code 3143. + + + +Scatterings l_i gamma -> H_R^-- tau^+. +Code 3144. + + + +Scatterings f_1 f_2 -> H_R^-- f_3 f_4 via WW fusion. +Code 3145. + + + +Scatterings f fbar -> H_R^++ H_L^--. +Code 3146. + + +

Parameters

+ +The basic couplings of the model are + + +lefthanded coupling g_L = e / sin(theta). + + + +righthanded coupling g_R, assumed the same as g_L. + + + +vacuum expectation value v_L (in GeV) for the left-triplet. + + +

+The corresponding vacuum expectation value v_R is assumed +given by v_R = sqrt(2) M_WR / g_R and is not stored explicitly. + +

+The Yukawa couplings of a lepton pair to a H^--, assumed the +same for H_L^-- and H_R^--, is described by a symmetric +3-by-3 matrix. The default matrix is dominated by the diagonal elements +and especially by the tau tau one. + + +Yukawa coupling for H^-- -> e- e-. + + + +Yukawa coupling for H^-- -> mu- e-. + + + +Yukawa coupling for H^-- -> mu- mu-. + + + +Yukawa coupling for H^-- -> tau- e-. + + + +Yukawa coupling for H^-- -> tau- mu-. + + + +Yukawa coupling for H^-- -> tau- tau-. + + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/LeptoquarkProcesses.xml b/PYTHIA8/pythia8130/xmldoc/LeptoquarkProcesses.xml new file mode 100644 index 00000000000..6020d4811b3 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/LeptoquarkProcesses.xml @@ -0,0 +1,84 @@ + + +

Leptoquark Processes

+ +Leptoquarks arise in many scenarios, and can have widely different +characteristics, with respect to spin, isospin amd flavour. +The current implentation in no sense attempts to exhaust these +possibilities, but only to encode one of the simplest possibilities, +with a single scalar leptoquark, denoted LQ and assigned PDG +code 42. The leptoquark is assumed to carry specific quark +and lepton quantum numbers, by default u quark plus electron. +These flavour numbers are conserved, i.e. a process such as +u e^- -> LQ -> d nu_e is not allowed. + +

+Although only one leptoquark is implemented, its flavours may be +changed arbitrarily to study the different possibilities. The +flavours of the leptoquark are defined by the quark and lepton +flavours in the decay mode list. Therefore, to change from the +current u e^- to c mu^+, say, you only need +a line +
pythia.readString("42:0:products = 4 -13"); +
in your main program, or the equivalent in a command file. +The former must always be a quark, while the latter could be a lepton +or an antilepton; a charge-conjugate partner is automatically defined +by the program. At initialization, the charge is recalculated as a +function of the flavours defined; also the leptoquark name is redefined +to be of the type LQ_q,l, where actual quark and lepton +flavours are displayed. + +

+The leptoquark is likely to be fairly long-lived, in which case it +could have time to fragment into a mesonic- or baryonic-type state, which +would decay later on. Currently this posibility is not handled; therefore +the leptoquark is always assumed to decay before fragmentation. +For that reason the leptoquark can also not be put stable. + +

Production processes

+ +Four production processes have been implemented, which normally would +not overlap and therefore could be run together. + + +Common switch for the group of lowest-order LQ production +processes, i.e. the four ones below. + + + +Scatterings q l -> LQ. +Code 3201. + + + +Scatterings q g -> LQ l. +Code 3202. + + + +Scatterings g g -> LQ LQbar. +Code 3203. + + + +Scatterings q qbar -> LQ LQbar. +Code 3204. + + +

Parameters

+ +In the above scenario the main free parameters are the leptoquark flavour +content, set as already described, and the LQ mass, set as usual. +In addition there is one further parameter. + + +multiplicative factor in the LQ -> q l squared Yukawa coupling, +and thereby in the LQ width and the q l -> LQ and +other cross sections. Specifically, lambda^2/(4 pi) = k alpha_em, +i.e. it corresponds to the $k$ factor of Hew88. + + +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/LesHouchesAccord.xml b/PYTHIA8/pythia8130/xmldoc/LesHouchesAccord.xml new file mode 100644 index 00000000000..8bd773550cf --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/LesHouchesAccord.xml @@ -0,0 +1,437 @@ + + +

Les Houches Accord

+ +The Les Houches Accord (LHA) for user processes Boo01 is the +standard way to input parton-level information from a +matrix-elements-based generator into PYTHIA. The conventions for +which information should be stored has been defined in a Fortran context, +as two commonblocks. Here a C++ equivalent is defined, as a single class. + +

+The LHAup class is a base class, containing reading and +printout functions, plus two pure virtual functions, one to set +initialization information and one to set information on each new event. +Derived classes have to provide these two virtual functions to do +the actual work. The existing derived classes are for reading information +from a Les Houches Event File (LHEF), from the respective Fortran +commonblocks, or from PYTHIA 8 itself. + +

+Normally, pointers to objects of the derived classes should be handed in +with the pythia.init( LHAup*) +method. However, with the LHEF format a filename can replace the pointer, +see below. + +

Initialization

+ +The LHAup class stores information equivalent to the +/HEPRUP/ commonblock, as required to initialize the event +generation chain. The main difference is that the vector container +now allows a flexible number of subprocesses to be defined. For the +rest, names have been modified, since the 6-character-limit does not +apply, and variables have been regrouped for clarity, but nothing +fundamental is changed. + +

+The pure virtual function setInit() has to be implemented in +the derived class, to set relevant information when called. It should +return false if it fails to set the info. + +

+Inside setInit(), such information can be set by the following +methods: + +sets the properties of the first incoming beam (cf. the Fortran +IDBMUP(1), EBMUP(1), PDFGUP(1), PDFSUP(1)), and similarly +a setBeamB method exists. The parton distribution information +defaults to zero. These numbers can be used to tell which PDF sets were +used when the hard process was generated, while the normal +PDF Selection is used for the further +event generation in PYTHIA. + + + +sets the event weighting and cross section strategy. The default, +provided in the class constructor, is 3, which is the natural value +e.g. for an LHEF. + +chosen strategy (cf. IDWTUP; see Sjo06 +section 9.9.1 for extensive comments). + events come with non-negative weight, given in units +of pb, with an average that converges towards the cross section of the +process. PYTHIA is in charge of the event mixing, i.e. for each new +try decides which process should be generated, and then decides whether +is should be kept, based on a comparison with xMax. +Accepted events therefore have unit weight. + as option 1, except that cross sections can now be +negative and events after unweighting have weight +-1. You can use +pythia.info.weight() +to find the weight of the current event. A correct event mixing requires +that a process that can take both signs should be split in two, one limited +to positive or zero and the other to negative or zero values, with +xMax chosen appropriately for the two. + events come with non-negative weight, in unspecified +units, but such that xMax can be used to unweight the events +to unit weight. Again PYTHIA is in charge of the event mixing. +The total cross section of a process is stored in +xSec. + as option 2, except that cross sections can now be +negative and events after unweighting have weight +-1. As for option -1 +processes with indeterminate sign should be split in two. + events come with unit weight, and are thus accepted +as is. The total cross section of the process is stored in +xSec. + as option 3, except that events now come with weight ++-1. Unlike options -1 and -2 processes with indeterminate sign need not be +split in two, unless you intend to mix with internal PYTHIA processes +(see below). + events come with non-negative weight, given in units +of pb, with an average that converges towards the cross section of the +process, like for option 1. No attempt is made to unweight the events, +however, but all are generated in full, and retain their original weight. +For consistency with normal PYTHIA units, the weight stored in +pythia.info.weight() has been converted to mb, however. + + as option 4, except that events now can come +either with positive or negative weights. +Note 1: if several processes have already been mixed and +stored in a common event file, either LHEF or some private format, it +would be problematical to read back events in a different order. Since it +is then not feasible to let PYTHIA pick the next process type, strategies ++-1 and +-2 would not work. Instead strategy 3 would be the recommended +choice, or -3 if negative-weight events are required. +Note 2: it is possible to switch on internally implemented +processes and have PYTHIA mix these with LHA ones according to their relative +cross sections for strategies +-1, +-2 and 3. It does not work for strategy +-3 unless the positive and negative sectors of the cross sections are in +separate subprocesses (as must always be the case for -1 and -2), since +otherwise the overall mixture of PYTHIA and LHA processes will be off. +Mixing is not possible for strategies +-4, since the weighting procedure +is not specified by the standard. (For instance, the intention may be to +have events biased towards larger pT values in some particular +functional form.) + + + + +sets info on an allowed process (cf. LPRUP, XSECUP, XERRUP, +XMAXUP). +Each new call will append one more entry to the list of processes. +The choice of strategy determines which quantities are mandatory: +xSec for strategies +-2 and +-3, +xErr never, and +xMax for strategies +-1 and +-2. + + +Note: PYTHIA does not make active use of the (optional) +xErr values, but calculates a statistical cross section +error based on the spread of event-to-event weights. This should work +fine for strategy options +-1, but not for the others. Specifically, +for options +-2 and +-3 the weight spread may well vanish, and anyway +is likely to be an underestimate of the true error. If the author of the +LHA input information does provide error information you may use that - +this information is displayed at initialization. If not, then a relative +error decreasing like 1/sqrt(n_acc), where n_acc +is the number of accepted events, should offer a reasonable estimate. + + +update the xSec value of the i'th process +added with addProcess method (i.e. i runs +from 0 through sizeProc() - 1, see below). + + + +update the xErr value of the i'th process +added with addProcess method. + + + +update the xMax value of the i'th process +added with addProcess method. + + +

+Information is handed back by the following methods: + +and similarly with A -> B, for the two beam particles. + + +for the strategy choice. + + +for the number of subprocesses. + + +for process i in the range 0 <= i < +sizeProc(). + + +

+The information can also be printed using the listInit() +method, e.g. LHAupObject->listInit(). +This is automatically done by the pythia.init call. + +

Event input

+ +The LHAup class also stores information equivalent to the +/HEPEUP/ commonblock, as required to hand in the next +parton-level configuration for complete event generation. The main +difference is that the vector container now allows a flexible number +of partons to be defined. For the rest, names have been modified, +since the 6-character-limit does not apply, and variables have been +regrouped for clarity, but nothing fundamental is changed. + +

+The LHA standard is based on Fortran arrays beginning with +index 1, and mother information is defined accordingly. In order to +be compatible with this convention, the zeroth line of the C++ particle +array is kept empty, so that index 1 also here corresponds to the first +particle. One small incompatibility is that the sizePart() +method returns the full size of the particle array, including the +empty zeroth line, and thus is one larger than the true number of +particles (NUP). + +

+The pure virtual function setEvent(idProcess) has to be +implemented in the derived class, to set relevant information when +called. For strategy options +-1 and +-2 the input +idProcess value specifies which process that should be +generated by setEvent(idProcess), while +idProcess is irrelevant for strategies +-3 and +-4. +The setEvent(idProcess) function should return +false if it fails to set the info, i.e. normally that the +supply of events in a file is exhausted. If so, no event is generated, +and pythia.next() returns false. You can then +interrogate +pythia.info.atEndOfFile() +to confirm that indeed the failure is caused in the +setEvent(idProcess) function, and decide to break out of +the event generation loop. + +

+Inside a normal setEvent(...) call, information can be set +by the following methods: + +tells which kind of process occured, with what weight, at what scale, +and which alpha_EM and alpha_strong were used +(cf. IDPRUP, XWTGUP, SCALUP, AQEDUP, AQCDUP). This method +also resets the size of the particle list, and adds the empty zeroth +line, so it has to be called before the addParticle method below. + + +gives the properties of the next particle handed in (cf. IDUP, ISTUP, +MOTHUP(1,..), MOTHUP(2,..), ICOLUP(1,..), ICOLUP(2,..), PUP(J,..), +VTIMUP, SPINUP) . + + +

+Information is handed back by the following methods: +. +Note that the weight stored in pythia.info.weight() as a rule +is not the same as the above weight(): the method here gives +the value before unweighting while the one in info gives +the one after unweighting and thus normally is 1 or -1. Only with strategy +options +-3 and +-4 would the value in info be the same as +here, except for a conversion from pb to mb for +-4. + + +for the size of the particle array, which is one larger than the number +of particles in the event, since the zeroth entry is kept empty +(see above). Thus a typical loop would be +
for (int i = 1; i < sizePart(); ++i) {...} +
+ +for particle i in the range +0 <= i < size(). (But again note that +i = 0 is an empty line, so the true range begins at 1.) + + +

+In the LHEF description Alw06 an extension to +include information on the parton densities of the colliding partons +is suggested. This optional further information can be set by + +which gives the flavours , the x and the Q scale +(in GeV) at which the parton densities x*f_i(x, Q) have been +evaluated. + + +

+This information is returned by the methods + +where the first one tells whether this optional information has been set +for the current event. (setPdf(...) must be called after the +setProcess(...) call of the event for this to work.) + + +

+The information can also be printed using the listEvent() +method, e.g. LHAupObject->listEvent(). +In cases where the LHAupObject is not available to the +user, the pythia.LHAeventList() method can be used, which +is a wrapper for the above. + +

+The LHA expects the decay of resonances to be included as part of the +hard process, i.e. if unstable particles are produced in a process then +their decays are also described. This includes Z^0, W^+-, H^0 +and other short-lived particles in models beyond the Standard Model. +Should this not be the case then PYTHIA will perform the decays of all +resonances it knows how to do, in the same way as for internal processes. +Note that you will be on slippery ground if you then restrict the decay of +these resonances to specific allowed channels since, if this is not what +was intended, you will obtain the wrong cross section and potentially the +wrong mix of different event types. (Since the original intention is +unknown, the cross section will not be corrected for the fraction of +open channels, i.e. the procedure used for internal processes is not +applied in this case.) + +

An interface to Les Houches Event Files

+ +The LHEF standard Alw06 specifies a format where a single file +packs initialization and event information. This has become the most +frequently used procedure to process external parton-level events in Pythia. +Therefore a special +pythia.init(fileName) +initialization option exists, where the LHEF name is provided as input. +Internally this name is then used to create an instance of the derived +class LHAupLHEF, which can do the job of reading an LHEF. + +

+An example how to generate events from an LHEF is found in +main12.cc. Note the use of +pythia.info.atEndOfFile() to find out when the whole +LHEF has been processed. + +

+To allow the sequential use of several event files the +init(...) method has an optional second argument: +pythia.init(fileName, bool skipInit = false). +If called with this argument true then there will be no +initialization, except that the existing LHAupLHEF class +instance will be deleted and replaced by ones pointing to the new file. +It is assumed (but never checked) that the initialization information is +identical, and that the new file simply contains further events of +exactly the same kind as the previous one. An example of this possibility, +and the option to mix with internal processes, is found in +main13.cc. + +

A runtime Fortran interface

+ +The runtime Fortran interface requires linking to an external Fortran +code. In order to avoid problems with unresolved external references +when this interface is not used, the code has been put in a separate +LHAFortran.h file, that is not included in any of the +other library files. Instead it should be included in the +user-supplied main program, together with the implementation of two +methods below that call the Fortran program to do its part of the job. + +

+The LHAupFortran class derives from LHAup. +It reads initialization and event information from the LHA standard +Fortran commonblocks, assuming these commonblocks behave like two +extern "C" struct named heprup_ and +hepeup_. (Note the final underscore, to match how the +gcc compiler internally names Fortran files.) + +

+The instantiation does not require any arguments. + +

+The user has to supply implementations of the fillHepRup() +and fillHepEup() methods, that is to do the actual calling +of the external Fortran routines that fill the HEPRUP and +HEPEUP commonblocks. The translation of this information to +the C++ structure is provided by the existing setInit() and +setEvent() code. + +

+See further +here for information how +PYTHIA 6.4 can be linked to make use of this facility. + +

Methods for LHEF output

+ +The main objective of the LHAup class is to feed information +from an external program into PYTHIA. It can be used to export information +as well, however. Specifically, there are four routines in the base class +that can be called to write a Les Houches Event File. These should be +called in sequence in order to build up the proper file structure. + + +Opens a file with the filename indicated, and writes a header plus a brief +comment with date and time information. + + + +Writes initialization information to the file above. Such information should +already have been set with the methods described in the "Initialization" +section above. + + + +Writes event information to the file above. Such information should +already have been set with the methods described in the "Event input" +section above. This call should be repeated once for each event to be +stored. + + + +Writes the closing tag and closes the file. Optionally, if +updateInit = true, this routine will reopen the file from +the beginning, rewrite the same header as openLHEF() did, +and then call initLHEF() again to overwrite the old +information. This is especially geared towards programs, such as PYTHIA +itself, where the cross section information is not available at the +beginning of the run, but only is obtained by Monte Carlo integration +in parallel with the event generation itself. Then the +setXSec( i, xSec), setXErr( i, xSec) and +setXMax( i, xSec) can be used to update the relevant +information before closeLHEF is called. +Warning: overwriting the beginning of a file without +upsetting anything is a delicate operation. It only works when the new +lines require exactly as much space as the old ones did. Thus, if you add +another process in between, the file will be corrupted. + + +

PYTHIA 8 output to an LHEF

+ +The above methods could be used by any program to write an LHEF. +For PYTHIA 8 to do this, a derived class already exists, +LHAupFromPYTHIA8. In order for it to do its job, +it must gain access to the information produced by PYTHIA, +specifically the process event record and the +generic information stored in info. Therefore, if you +are working with an instance pythia of the +Pythia class, you have to instantiate +LHAupFromPYTHIA8 with pointers to the +process and info objects of +pythia: +
LHAupFromPYTHIA8 myLHA(&pythia.process, &pythia.info); + +

+The method setInit() should be called to store the +pythia initialization information in the LHA object, +and setEvent() to store event information. +Furthermore, updateSigma() can be used at the end +of the run to update cross-section information, cf. +closeLHEF(true) above. An example how the +generation, translation and writing methods should be ordered is +found in main20.cc. + +

+Currently there are some limitations, that could be overcome if +necessary. Firstly, you may mix many processes in the same run, +but the cross-section information stored in info only +refers to the sum of them all, and therefore they are all classified +as a common process 9999. Secondly, you should generate your events +in the CM frame of the collision, since this is the assumed frame of +stored Les Houches events, and no boosts have been implemented +for the case that pythia.process is not in this frame. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/MainProgramSettings.xml b/PYTHIA8/pythia8130/xmldoc/MainProgramSettings.xml new file mode 100644 index 00000000000..7ebe63949c0 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/MainProgramSettings.xml @@ -0,0 +1,199 @@ + + +

Main-Program Settings

+ +

Introduction

+ +The main program is up to the user to write. However, +sample main programs +are provided. In one such class of programs, key settings of the run +are read in from a "cards file". These commands may be of two types
+(a) instructions directly to Pythia, like which +processes to generate, and
+(b) instructions to the main program for what it should do, +like how many events to generate, i.e. how many times +pythia.next() should be called.
+In principle these two kinds could be kept completely separate. +However, to make life simpler, a number of useful main-program +settings are defined on this page, so that they are recognized by +the Settings machinery. They can thus be put among +the other cards without distinction. It is up to you to decide which +ones, if any, you actually want to use when you write your main program. +For convenience, some in the second section below can also be interpreted +directly by Pythia, while the subsequent ones really have +to be used in your main program. + +

+Once you have used the pythia.readFile(fileName) method to +read in the cards file, you can interrogate the Settings +database to make the values available in your main program. A slight +complication is that you need to use a different Settings +method for each of the four possible return types that you want to +extract. To save some typing the same method names are found directly +in the Pythia class, and just send on to the +Settings ones to do the job, e.g. +

+  bool   showCS = pythia.flag("Main:showChangedSettings");
+  int    nEvent = pythia.mode("Main:numberOfEvents");
+  double spare1 = pythia.parm("Main:spareParm1");
+  string file   = pythia.word("Main:allSettingsFile"); 
+
+ +

Run settings

+ +Here settings related to how many events to generate and whether +to print some information on data used in run. These variables +can be set in an input "cards" file, and thereafter read out an used +in the user-written main program. Usage is purely optional, but may help +you reduce the need to recompile your main program. + + +The number of events to be generated. + + + +The number of events to list. + + + +Print the number of events generated so far, this many times, +i.e. once every numberOfEvents/numberToShow events. + + + +Allow this many times that pythia.next() returns false, +i.e. that an event is flawed, before aborting the run. + + + +Print a list of the changed flag/mode/parameter/word settings. + + + +Print a list of all flag/mode/parameter/word settings. +Warning: this will be a long list. + + + +Print particle and decay data for the particle with this particular +identity code. Default means that no particle is printed. + + + +Print a list of particle and decay data for those particles +that were changed (one way or another). + + + +In the previous listing also include the resonances that are +initialized at the beginning of a run and thus get new particle +data, even if these may well agree with the default ones. +Warning: this will be a rather long list. + + + +Print a list of all particle and decay data. +Warning: this will be a long list. + + + +Write a file with the changed flag/mode/parameter/word settings, in +a format appropriate to be read in at the beginning of a new +run, using the pythia.readFile(fileName) method. + + + +The name of the file to which the changed flag/mode/parameter/word +settings are written if Main:writeChangedSettings +is on. + + + +Write a file with all flag/mode/parameter/word settings, in +a format appropriate to be read in at the beginning of a new +run, using the pythia.readFile(fileName) method. + + + +The name of the file to which a flag/mode/parameter/word +settings are written if Main:writeAllSettings +is on. + + + +Print all available statistics or only the minimal set at the end +of the run. + + +

Subruns

+ +You can use subruns to carry out +several tasks in the same run. In that case you will need repeated +instances of the first setting below in your command file, and could +additionally use the second and third as well. + + +The number of the current subrun, a non-negative integer, put as +first line in a section of lines to be read for this particular subrun. + + + +If you read several Les Houches Event Files that you want to see +considered as one single combined event sample you can set this flag +on after the first subrun to skip (most of) the +(re-)initialization step. + + + +The number of subruns you intend to use in your current run. +Unlike the two settings above, Pythia itself will not +intepret this number, but you could e.g. have a loop in your main +program to loop over subruns from 0 through +numberOfSubruns - 1. + + +

Spares

+ +For currently unforeseen purposes, a few dummy settings are made +available here. The user can set the desired value in a "cards file" +and then use that value in the main program as desired. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/MasterSwitches.xml b/PYTHIA8/pythia8130/xmldoc/MasterSwitches.xml new file mode 100644 index 00000000000..80a74b073cc --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/MasterSwitches.xml @@ -0,0 +1,164 @@ + + +

Master Switches

+ +Sometimes it may be convenient to omit certain aspects of the event +generation chain. This cannot be motivated in a full-blown production +run, but can often be convenient for own understanding and for +debug purposes. The flags on this page allow just that. + +

+The event generation is subdivided into three levels: the process +level, the parton level and the hadron level, and flags are grouped +accordingly. + +

Process Level

+ +The ProcessLevel class administrates the initial step of +the event generation, wherein the basic process is selected. Currently +this is done either using some of the internal processes, or with +Les Houches Accord input. + +

+There could not be a complete event without an initial process, so +it would not be a normal action to switch off this step. Furthermore, +without a process set, it is also not possible to carry out the tasks +on the parton level. It is still possible, however, to hadronize +a parton-level configuration provided by some external program. + + +If off, do not attempt to carry out any generation at all on the +process or parton level. Do allow parton configurations stored in +the event record to hadronize and hadrons to decay, however, as set +by the HadronLevel switches. Further details are found +here. + + +

+For ProcessLevel:all = on one part of the event generation +on this level may be switched off individually: + + +Master switch to allow resonance decays; on/off = true/false. +Normal hadrons and leptons do not count as resonances, so this is +aimed specifically towards Z^0, W^+-, t, h^0 and similar +objects beyond the Standard Model. Do not use this option if you +may produce coloured resonances and intend to allow hadronization, +since currently the program would not know how to handle this. + + +

+It is possible to stop the generation immediately after the basic +process has been selected, see PartonLevel:all below. + +

PartonLevel

+ +The PartonLevel class administrates the middle step of the +event generation, i.e. the evolution from an input (hard) process from +ProcessLevel, containing a few partons only, to a complete +parton-level configuration to be handed on to HadronLevel. +This step involves the application of initial- and final-state radiation, +multiple interactions and the structure of beam remnants. + + +If off then stop the generation after the hard process has been +generated, but before the parton-level and hadron-level steps. +The process record is filled, but the event +one is then not. + + +

+For PartonLevel:all = on some parts of the event generation +on this level may be switched off individually: + + +Master switch for multiple interactions; on/off = true/false. +Further options are found here. + + + +Master switch for initial-state radiation; on/off = true/false. +Further options are found here. + + + +Master switch for initial-state radiation; on/off = true/false. +Further options are found here. +If you leave this switch on, the following two switches allow +more detailed control to switch off only parts of the showers. + + + +Switch for final-state radiation in association with the hard process +itself; on/off = true/false. In addition PartonLevel:FSR +must be on for these emissions to occur. + + + +Master switch for final-state radiation in any resonance decays +subsequent to the hard process itself; on/off = true/false. In addition +PartonLevel:FSR must be on for these emissions to occur. + + +

+Switching off all the above MI/ISR/FSR switches is not equivalent +to setting PartonLevel:all = off. In the former case a +minimal skeleton of parton-level operations are carried out, such as +tying together the scattered partons with the beam remnants into colour +singlets, and storing this information in the event record. +It is therefore possible to go on and hadronize the event, if desired. +In the latter case no operations at all are carried out on the +parton level, and therefore it is also not possible to go on to the +hadron level. + +

+It is possible to stop the generation immediately after the parton level +has been set up, see HadronLevel:all below. + +

HadronLevel

+ +The HadronLevel class administrates the final step of the +event generation, wherein the partonic configuration from +PartonLevel is hadronized, including string fragmentation +and secondary decays. + +

+Most of the code in this class itself deals with subdividing the partonic +content of the event into separate colour singlets, that can be +treated individually by the string fragmentation machinery. When a +junction and an antijunction are directly connected, it also breaks +the string between the two, so that the topology can be reduced back +to two separate one-junction systems, while still preserving the +expected particle flow in the junction-junction string region(s). + + +If off then stop the generation after the hard process and +parton-level activity has been generated, but before the +hadron-level steps. + + +

+For HadronLevel:all = on some parts of the event generation +on this level may be switched off individually: + + +Master switch for hadronization; on/off = true/false. +Further options are found here. + + + +Master switch for decays; on/off = true/false. +Further options are found here. + + + +Master switch for the simulation of Bose-Einstein effects; +on/off = true/false. Further options are found +here. + + + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/MultipleInteractions.xml b/PYTHIA8/pythia8130/xmldoc/MultipleInteractions.xml new file mode 100644 index 00000000000..893ce68296c --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/MultipleInteractions.xml @@ -0,0 +1,392 @@ + + +

Multiple Interactions

+ +The starting point for the multiple interactions physics scenario in +PYTHIA is provided by Sjo87. Recent developments have +included a more careful study of flavour and colour correlations, +junction topologies and the relationship to beam remnants +Sjo04, and interleaving with initial-state radiation +Sjo05, making use of transverse-momentum-ordered +initial- and final-state showers. + +

+A big unsolved issue is how the colour of all these subsystems is +correlated. For sure there is a correlation coming from the colour +singlet nature of the incoming beams, but in addition final-state +colour rearrangements may change the picture. Indeed such extra +effects appear necessary to describe data, e.g. on +<pT>(n_ch). A simple implementation of colour +rearrangement is found as part of the +beam remnants description. + +

Main variables

+ +The maximum pT to be allowed for multiple interactions is +related to the nature of the hard process itself. It involves a +delicate balance between not doublecounting and not leaving any +gaps in the coverage. The best procedure may depend on information +only the user has: how the events were generated and mixed (e.g. with +Les Houches Accord external input), and how they are intended to be +used. Therefore a few options are available, with a sensible default +behaviour. + +Way in which the maximum scale for multiple interactions is set +to match the scale of the hard process itself. + + + + + +

+The rate of interactions is determined by + +The value of alpha_strong at m_Z. Default value is +picked equal to the one used in CTEQ 5L. + + +

+The actual value is then regulated by the running to the scale +pT^2, at which it is evaluated + +The order at which alpha_strong runs at scales away from +m_Z. + + + + + +

+QED interactions are regulated by the alpha_electromagnetic +value at the pT^2 scale of an interaction. + + +The running of alpha_em used in hard processes. + + + + + +

+Note that the choices of alpha_strong and alpha_em +made here override the ones implemented in the normal process machinery, +but only for the interactions generated by the +MultipleInteractions class. + +

+In addition there is the possibility of a global rescaling of +cross sections (which could not easily be accommodated by a +changed alpha_strong, since alpha_strong runs) + +Multiply all cross sections by this fix factor. + + +

+There are two complementary ways of regularizing the small-pT +divergence, a sharp cutoff and a smooth dampening. These can be +combined as desired, but it makes sense to coordinate with how the +same issue is handled in spacelike +showers. Actually, by default, the parameters defined here are +used also for the spacelike showers, but this can be overridden. + +

+Regularization of the divergence of the QCD cross section for +pT -> 0 is obtained by a factor pT^4 / (pT0^2 + pT^2)^2, +and by using an alpha_s(pT0^2 + pT^2). An energy dependence +of the pT0 choice is introduced by two further parameters, +so that pT0Ref is the pT0 value for the reference +cm energy, pT0Ref = pT0(ecmRef). +Warning: if a large pT0 is picked for multiple +interactions, such that the integrated interaction cross section is +below the nondiffractive inelastic one, this pT0 will +automatically be scaled down to cope. + +

+The actual pT0 parameter used at a given cm energy scale, ecmNow, +is obtained as + + pT0 = pT0(ecmNow) = pT0Ref * (ecmNow / ecmRef)^ecmPow + +where pT0Ref, ecmRef and ecmPow are the +three parameters below. + + +The pT0Ref scale in the above formula. +Note: pT0Ref is one of the key parameters in a +complete PYTHIA tune. Its value is intimately tied to a number of other +choices, such as that of colour flow description, so unfortunately it is +difficult to give an independent meaning to pT0Ref. + + + +The ecmRef reference energy scale introduced above. + + + +The ecmPow energy rescaling pace introduced above. + + +

+Alternatively, or in combination, a sharp cut can be used. + +Lower cutoff in pT, below which no further interactions +are allowed. Normally pT0 above would be used to provide +the main regularization of the cross section for pT -> 0, +in which case pTmin is used mainly for technical reasons. +It is possible, however, to set pT0Ref = 0 and use +pTmin to provide a step-function regularization, or to +combine them in intermediate approaches. Currently pTmin +is taken to be energy-independent. + + +

+The choice of impact-parameter dependence is regulated by several +parameters. + + +Choice of impact parameter profile for the incoming hadron beams. + + + + + + + +When assuming a double Gaussian matter profile, bProfile = 2, +the inner core is assumed to have a radius that is a factor +coreRadius smaller than the rest. + + + +When assuming a double Gaussian matter profile, bProfile = 2, +the inner core is assumed to have a fraction coreFraction +of the matter content of the hadron. + + + +When bProfile = 3 it gives the power of the assumed overlap +shape exp(- b^expPow). Default corresponds to a simple +exponential drop, which is not too dissimilar from the overlap +obtained with the standard double Gaussian parameters. For +expPow = 2 we reduce to the simple Gaussian, bProfile = 1, +and for expPow -> infinity to no impact parameter dependence +at all, bProfile = 0. For small expPow the program +becomes slow and unstable, so the min limit must be respected. + + +

+It is possible to regulate the set of processes that are included in the +multiple-interactions framework. + + +Set of processes included in the machinery. + + + + + + +

Further variables

+ +These should normally not be touched. Their only function is for +cross-checks. + + +Number of allowed incoming quark flavours in the beams; a change +to 4 would thus exclude b and bbar as incoming +partons, etc. + + + +The allowed pT range is split (unevenly) into 100 bins, +and in each of these the interaction cross section is evaluated in +nSample random phase space points. The full integral is used +at initialization, and the differential one during the run as a +"Sudakov form factor" for the choice of the hardest interaction. +A larger number implies increased accuracy of the calculations. + + +

The process library

+ +The processes used to generate multiple interactions form a subset +of the standard library of hard processes. The input is slightly +different from the standard hard-process machinery, however, +since incoming flavours, the alpha_strong value and most +of the kinematics are aready fixed when the process is called. + +

Technical notes

+ +Relative to the articles mentioned above, not much has happened. +The main news is a technical one, that the phase space of the +2 -> 2 (massless) QCD processes is now sampled in +dy_3 dy_4 dpT^2, where y_3 and y_4 are +the rapidities of the two produced partons. One can show that + + (dx_1 / x_1) * (dx_2 / x_2) * d(tHat) = dy_3 * dy_4 * dpT^2 + +Furthermore, since cross sections are dominated by the "Rutherford" +one of t-channel gluon exchange, which is enhanced by a +factor of 9/4 for each incoming gluon, effective structure functions +are defined as + + F(x, pT2) = (9/4) * xg(x, pT2) + sum_i xq_i(x, pT2) + +With this technical shift of factors 9/4 from cross sections to parton +densities, a common upper estimate of + + d(sigmaHat)/d(pT2) < pi * alpha_strong^2 / pT^4 + +is obtained. + +

+In fact this estimate can be reduced by a factor of 1/2 for the +following reason: for any configuration (y_3, y_4, pT2) also +one with (y_4, y_3, pT2) lies in the phase space. Not both +of those can enjoy being enhanced by the tHat -> 0 +singularity of + + d(sigmaHat) propto 1/tHat^2. + +Or if they are, which is possible with identical partons like +q q -> q q and g g -> g g, each singularity comes +with half the strength. So, when integrating/averaging over the two +configurations, the estimated d(sigmaHat)/d(pT2) drops. +Actually, it drops even further, since the naive estimate above is +based on + + (4 /9) * (1 + (uHat/sHat)^2) < 8/9 < 1 + +The 8/9 value would be approached for tHat -> 0, which +implies sHat >> pT2 and thus a heavy parton-distribution +penalty, while parton distributions are largest for +tHat = uHat = -sHat/2, where the above expression +evaluates to 5/9. A fudge factor is therefore introduced to go the +final step, so it can easily be modifed when further non-Rutherford +processes are added, or should parton distributions change significantly. + +

+At initialization, it is assumed that + + d(sigma)/d(pT2) < d(sigmaHat)/d(pT2) * F(x_T, pT2) * F(x_T, pT2) + * (2 y_max(pT))^2 + +where the first factor is the upper estimate as above, the second two +the parton density sum evaluated at y_3 = y_ 4 = 0 so that +x_1 = x_2 = x_T = 2 pT / E_cm, where the product is expected +to be maximal, and the final is the phase space for +-y_max < y_{3,4} < y_max. +The right-hand side expression is scanned logarithmically in y, +and a N is determined such that it always is below +N/pT^4. + +

+To describe the dampening of the cross section at pT -> 0 by +colour screening, the actual cross section is multiplied by a +regularization factor (pT^2 / (pT^2 + pT0^2))^2, and the +alpha_s is evaluated at a scale pT^2 + pT0^2, +where pT0 is a free parameter of the order of 2 - 4 GeV. +Since pT0 can be energy-dependent, an ansatz + + pT0(ecm) = pT0Ref * (ecm/ecmRef)^ecmPow + +is used, where ecm is the current cm frame energy, +ecmRef is an arbitrary reference energy where pT0Ref +is defined, and ecmPow gives the energy rescaling pace. For +technical reasons, also an absolute lower pT scale pTmin, +by default 0.2 GeV, is introduced. In principle, it is possible to +recover older scenarios with a sharp pT cutoff by setting +pT0 = 0 and letting pTmin be a larger number. + +

+The above scanning strategy is then slightly modified: instead of +an upper estimate N/pT^4 one of the form +N/(pT^2 + r * pT0^2)^2 is used. At first glance, r = 1 +would seem to be fixed by the form of the regularization procedure, +but this does not take into account the nontrivial dependence on +alpha_s, parton distributions and phase space. A better +Monte Carlo efficiency is obtained for r somewhat below unity, +and currently r = 0.25 is hardcoded. + +In the generation a trial pT2 is then selected according to + + d(Prob)/d(pT2) = (1/sigma_ND) * N/(pT^2 + r * pT0^2)^2 * ("Sudakov") + +For the trial pT2, a y_3 and a y_4 are then +selected, and incoming flavours according to the respective +F(x_i, pT2), and then the cross section is evaluated for this +flavour combination. The ratio of trial/upper estimate gives the +probability of survival. + +

+Actually, to profit from the factor 1/2 mentioned above, the cross +section for the combination with y_3 and y_4 +interchanged is also tried, which corresponds to exchanging tHat +and uHat, and the average formed, while the final kinematics +is given by the relative importance of the two. + +

+Furthermore, since large y values are disfavoured by dropping +PDF's, a factor + + WT_y = (1 - (y_3/y_max)^2) * (1 - (y_4/y_max)^2) + +is evaluated, and used as a survival probability before the more +time-consuming PDF+ME evaluation, with surviving events given a +compensating weight 1/WT_y. + +

+An impact-parameter dependencs is also allowed. Based on the hard +pT scale of the first interaction, and enhancement/depletion +factor is picked, which multiplies the rate of subsequent interactions. + +

+Parton densities are rescaled and modified to take into account the +energy-momentum and flavours kicked out by already-considered +interactions. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/NewGaugeBosonProcesses.xml b/PYTHIA8/pythia8130/xmldoc/NewGaugeBosonProcesses.xml new file mode 100644 index 00000000000..ed271d0bf9c --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/NewGaugeBosonProcesses.xml @@ -0,0 +1,344 @@ + + +

New-Gauge-Boson Processes

+ +This page contains the production of new Z'^0 and +W'^+- gauge bosons, e.g. within the context of a new +U(1) or SU(2) gauge group, and also a +(rather speculative) horizontal gauge boson R^0. +Left-right-symmetry scenarios also contain new gauge bosons, +but are described +separately. + +

Z'^0

+ +This group only contains one subprocess, with the full +gamma^*/Z^0/Z'^0 interference structure for couplings +to fermion pairs. It is possible to pick only a subset, e.g, only +the pure Z'^0 piece. No higher-order processes are +available explicitly, but the ISR showers contain automatic +matching to the Z'^0 + 1 jet matrix elements, as for +the corresponding gamma^*/Z^0 process. + + +Scattering f fbar ->Z'^0. +Code 3001. + + + +Choice of full gamma^*/Z^0/Z'^0 structure or not in +the above process. Note that, with the Z'^0 part switched +off, this process is reduced to what already exists among +electroweak processes, +so those options are here only for crosschecks. + + + + + + + +Note: irrespective of the option used, the particle produced +will always be assigned code 32 for Z'^0, and open decay channels +is purely dictated by what is set for the Z'^0. + + +

+The couplings of the Z'^0 to quarks and leptons can +either be assumed universal, i.e. generation-independent, or not. +In the former case eight numbers parametrize the vector and axial +couplings of down-type quarks, up-type quarks, leptons and neutrinos, +respectively. Depending on your assumed neutrino nature you may +want to restrict your freedom in that sector, but no limitations +are enforced by the program. The default corresponds to the same +couplings as that of the Standard Model Z^0, with axial +couplings a_f = +-1 and vector couplings +v_f = a_f - 4 e_f sin^2(theta_W), with +sin^2(theta_W) = 0.23. Without universality +the same eight numbers have to be set separately also for the +second and the third generation. The choice of fixed axial and +vector couplings implies a resonance width that increases linearly +with the Z'^0 mass. + +

+By a suitable choice of the parameters, it is possible to simulate +just about any imaginable Z'^0 scenario, with full +interference effects in cross sections and decay angular +distributions and generation-dependent couplings; the default values +should mainly be viewed as placeholders. The conversion +from the coupling conventions in a set of different Z'^0 +models in the literature to those used in PYTHIA is described by +C. +Ciobanu et al. + + +If on then you need only set the first-generation couplings +below, and these are automatically also used for the second and +third generation. If off, then couplings can be chosen separately +for each generation. + + +

+Here are the couplings always valid for the first generation, +and normally also for the second and third by trivial analogy: + + +vector coupling of d quarks. + + + +axial coupling of d quarks. + + + +vector coupling of u quarks. + + + +axial coupling of u quarks. + + + +vector coupling of e leptons. + + + +axial coupling of e leptons. + + + +vector coupling of nu_e neutrinos. + + + +axial coupling of nu_e neutrinos. + + +

+Here are the further couplings that are specific for +a scenario with Zprime:universality swiched off: + + +vector coupling of s quarks. + + + +axial coupling of s quarks. + + + +vector coupling of c quarks. + + + +axial coupling of c quarks. + + + +vector coupling of mu leptons. + + + +axial coupling of mu leptons. + + + +vector coupling of nu_mu neutrinos. + + + +axial coupling of nu_mu neutrinos. + + + +vector coupling of b quarks. + + + +axial coupling of b quarks. + + + +vector coupling of t quarks. + + + +axial coupling of t quarks. + + + +vector coupling of tau leptons. + + + +axial coupling of tau leptons. + + + +vector coupling of nu_tau neutrinos. + + + +axial coupling of nu_tau neutrinos. + + +

+The coupling to the decay channel Z'^0 -> W^+ W^- is +more model-dependent. By default it is therefore off, but can be +switched on as follows. Furthermore, we have left some amount of +freedom in the choice of decay angular correlations in this +channel, but obviously alternative shapes could be imagined. + + +the coupling Z'^0 -> W^+ W^- is taken to be this number +times m_W^2 / m_Z'^2 times the Z^0 -> W^+ W^- +coupling. Thus a unit value corresponds to the +Z^0 -> W^+ W^- coupling, scaled down by a factor +m_W^2 / m_Z'^2, and gives a Z'^0 partial +width into this channel that again increases linearly. If you +cancel this behaviour, by letting Zprime:coup2WW be +proportional to m_Z'^2 / m_W^2, you instead obtain a +partial width that goes like the fifth power of the Z'^0 +mass. These two extremes correspond to the "extended gauge model" +and the "reference model", respectively, of Alt89. +Note that this channel only includes the pure Z' part, +while f fbar -> gamma^*/Z^*0 -> W^+ W^- is available +as a separate electroweak process. + + + +in the decay chain Z'^0 -> W^+ W^- ->f_1 fbar_2 f_3 fbar_4 +the decay angular distributions is taken to be a mixture of two +possible shapes. This parameter gives the fraction that is distributed +as in Higgs h^0 -> W^+ W^- (longitudinal bosons), +with the remainder (by default all) is taken to be the same as for +Z^0 -> W^+ W^- (a mixture of transverse and longitudinal +bosons). + + +

+A massive Z'^0 is also likely to decay into Higgses +and potentially into other now unknown particles. Such possibilities +clearly are quite model-dependent, and have not been included +for now. + +

W'^+-

+ +The W'^+- implementation is less ambitious than the +Z'^0. Specifically, while indirect detection of a +Z'^0 through its interference contribution is +a possible discovery channel in lepton colliders, there is no +equally compelling case for W^+-/W'^+- interference +effects being of importance for discovery, and such interference +has therefore not been implemented for now. Related to this, a +Z'^0 could appear on its own in a new U(1) group, +while W'^+- would have to sit in a SU(2) group +and thus have a Z'^0 partner that is likely to be found +first. Only one process is implemented but, like for the +W^+-, the ISR showers contain automatic matching to the +W'^+- + 1 jet matrix elements. + + +Scattering f fbar' -> W'^+-. +Code 3021. + + +

+The couplings of the W'^+- are here assumed universal, +i.e. the same for all generations. One may set vector and axial +couplings freely, separately for the q qbar' and the +l nu_l decay channels. The defaults correspond to the +V - A structure and normalization of the Standard Model +W^+-, but can be changed to simulate a wide selection +of models. One limitation is that, for simplicity, the same +Cabibbo--Kobayashi--Maskawa quark mixing matrix is assumed as for +the standard W^+-. Depending on your assumed neutrino +nature you may want to restrict your freedom in the lepton sector, +but no limitations are enforced by the program. + + +vector coupling of quarks. + + + +axial coupling of quarks. + + + +vector coupling of leptons. + + + +axial coupling of leptons. + + +

+The coupling to the decay channel W'^+- -> W^+- Z^0 is +more model-dependent, like for Z'^0 -> W^+ W^- described +above. By default it is therefore off, but can be +switched on as follows. Furthermore, we have left some amount of +freedom in the choice of decay angular correlations in this +channel, but obviously alternative shapes could be imagined. + + +the coupling W'^0 -> W^+- Z^0 is taken to be this number +times m_W^2 / m_W'^2 times the W^+- -> W^+- Z^0 +coupling. Thus a unit value corresponds to the +W^+- -> W^+- Z^0 coupling, scaled down by a factor +m_W^2 / m_W'^2, and gives a W'^+- partial +width into this channel that increases linearly with the +W'^+- mass. If you cancel this behaviour, by letting +Wprime:coup2WZ be proportional to m_W'^2 / m_W^2, +you instead obtain a partial width that goes like the fifth power +of the W'^+- mass. These two extremes correspond to the +"extended gauge model" and the "reference model", respectively, +of Alt89. + + + +in the decay chain W'^+- -> W^+- Z^0 ->f_1 fbar_2 f_3 fbar_4 +the decay angular distributions is taken to be a mixture of two +possible shapes. This parameter gives the fraction that is distributed +as in Higgs H^+- -> W^+- Z^0 (longitudinal bosons), +with the remainder (by default all) is taken to be the same as for +W^+- -> W^+- Z^0 (a mixture of transverse and longitudinal +bosons). + + +

+A massive W'^+- is also likely to decay into Higgses +and potentially into other now unknown particles. Such possibilities +clearly are quite model-dependent, and have not been included +for now. + +

R^0

+ +The R^0 boson (particle code 41) represents one possible +scenario for a horizontal gauge boson, i.e. a gauge boson +that couples between the generations, inducing processes like +s dbar -> R^0 -> mu^- e^+. Experimental limits on +flavour-changing neutral currents forces such a boson to be fairly +heavy. In spite of being neutral the antiparticle is distinct from +the particle: one carries a net positive generation number and +the other a negative one. This particular model has no new +parameters beyond the R^0 mass. Decays are assumed isotropic. +For further details see Ben85. + + +Scattering f_1 fbar_2 -> R^0 -> f_3 fbar_4, where +f_1 and fbar_2 are separated by +- one +generation and similarly for f_3 and fbar_4. +Thus possible final states are e.g. d sbar, u cbar +s bbar, c tbar, e- mu+ and +mu- tau+. +Code 3041. + + +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/OniaProcesses.xml b/PYTHIA8/pythia8130/xmldoc/OniaProcesses.xml new file mode 100644 index 00000000000..8c5c76f3908 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/OniaProcesses.xml @@ -0,0 +1,301 @@ + + +

Onia Processes

+ +Production of J/psi or Upsilon, directly and via chi states and the +colour-octet mechanism. +In each process the square-bracketed expression specifies the state +in spectroscopic notation, (2S+1) L J, followed by +(1) for colour-singlet states and (8) for +colour-octet ditto. + +

+The original Fortran code for these processes has been contributed +by Stefan Wolf [unpublished]. For the C++ version only the unpolarized +expressions are retained, since the theoretical predictions of the +colour-octet model anyway do not agree with the experimental +observations. Furthermore, the polarization effects are modest, +so isotropic decay is not a bad starting point. Such an event sample +can afterwards be reweighted at will by the user, to test various +assumptions. + +

+The description of +final-state radiation +is in this case based on some further model assumptions. + +

+Most of the processes below are divergent in the limit +pT -> 0, and therefore a pTmin scale should +be set. Comparisons with data indicate that this divergence +can be tamed the same way as for the normal QCD 2 -> 2 cross +sections, which makes sense, since they are all dominated by the +same kind of t-channel gluon exchange. It is therefore +possible to use the SuppressSmallPT +user hook to impose a reweighting that cancels the low-pT +divergence. + +

+An eikonalized description of these processes is included in the +multiple-interactions framework. Here the low-pT dampening +is automatic, and additionally the framework is more consistent +(e.g. with respect to energy-momentum constraints and the +impact-parameter description) for events where the onium production +is not the hardest subprocess, as would often be the case in the +low-pT limit. + +

Charmonium

+ + +Common switch for the group of charmonium production. + + + +g g -> ccbar[3S1(1)] g. +Code 401. + + + +g g -> ccbar[3P0(1)] g. +Code 402. + + + +g g -> ccbar[3P1(1)] g. +Code 403. + + + +g g -> ccbar[3P2(1)] g. +Code 404. + + + +q g -> ccbar[3P0(1)] q. +Code 405. + + + +q g -> ccbar[3P1(1)] q. +Code 406. + + + +q g -> ccbar[3P2(1)] q. +Code 407. + + + +q qbar -> ccbar[3P0(1)] g. +Code 408. + + + +q qbar -> ccbar[3P1(1)] g. +Code 409. + + + +q qbar -> ccbar[3P2(1)] g. +Code 410. + + + +g g -> ccbar[3S1(8)] g. +Code 411. + + + +g g -> ccbar[3S1(8)] g. +Code 412. + + + +g g -> ccbar[3S1(8)] g. +Code 413. + + + +q g -> ccbar[3S1(8)] q. +Code 414. + + + +q g -> ccbar[3S1(8)] q. +Code 415. + + + +q g -> ccbar[3S1(8)] q. +Code 416. + + + +q qbar -> ccbar[3S1(8)] g. +Code 417. + + + +q qbar -> ccbar[3S1(8)] g. +Code 418. + + + +q qbar -> ccbar[3S1(8)] g. +Code 419. + + +

Bottomonium

+ + +Common switch for the group of charmonium production. + + + +g g -> bbbar[3S1(1)] g. +Code 501. + + + +g g -> bbbar[3P0(1)] g. +Code 502. + + + +g g -> bbbar[3P1(1)] g. +Code 503. + + + +g g -> bbbar[3P2(1)] g. +Code 504. + + + +q g -> bbbar[3P0(1)] q. +Code 505. + + + +q g -> bbbar[3P1(1)] q. +Code 506. + + + +q g -> bbbar[3P2(1)] q. +Code 507. + + + +q qbar -> bbbar[3P0(1)] g. +Code 508. + + + +q qbar -> bbbar[3P1(1)] g. +Code 509. + + + +q qbar -> bbbar[3P2(1)] g. +Code 510. + + + +g g -> bbbar[3S1(8)] g. +Code 511. + + + +g g -> bbbar[3S1(8)] g. +Code 512. + + + +g g -> bbbar[3S1(8)] g. +Code 513. + + + +q g -> bbbar[3S1(8)] q. +Code 514. + + + +q g -> bbbar[3S1(8)] q. +Code 515. + + + +q g -> bbbar[3S1(8)] q. +Code 516. + + + +q qbar -> bbbar[3S1(8)] g. +Code 517. + + + +q qbar -> bbbar[3S1(8)] g. +Code 518. + + + +q qbar -> bbbar[3S1(8)] g. +Code 519. + + +

Onium matrix elements

+ +The implementation of charmonium and bottomonium production, including +the colour-octet production mechanism, requires information on NRQCD +matrix elements for the various wavefunctions involved. Default values +for these are encoded in the following ten variables. They +are taken from Nas00; see also Bar06. + + +<O(J/psi)[3S1(1)]>. + + + +<O(J/psi)[3S1(8)]>. + + + +<O(J/psi)[1S0(8)]>. + + + +<O(J/psi)[3P0(8)]>/m_c^2. + + + +<O(chi_c0)[3P0(8)]>/m_c^2. + + + +<O(Upsilon)[3S1(1)]>. + + + +<O(Upsilon)[3S1(8)]>. + + + +<O(Upsilon)[1S0(8)]>. + + + +<O(Upsilon)[3P0(8)]>/m_b^2. + + + +<O(chi_b0)[3P0(8)]>/m_b^2. + + + +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/PDFSelection.xml b/PYTHIA8/pythia8130/xmldoc/PDFSelection.xml new file mode 100644 index 00000000000..98f8bfc8a4e --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/PDFSelection.xml @@ -0,0 +1,219 @@ + + +

PDF Selection

+ +This page contains three subsections. The first deals with how to +pick the parton distribution set for protons, including from LHAPDF, +to be used for all proton and antiproton beams. The second is a special +option that allows a separate PDF set to be used for the hard process +only, while the first choice would still apply to everything else. +The third gives the possibility to switch off the lepton +"parton density". + +

Parton densities for protons

+ +The selection of parton densities is made once and then is propagated +through the program. It is essential to make an informed choice, +for several reasons: +Warning 1: the choice of PDF set affects a number of +properties of events. A change of PDF therefore requires a complete +retuning e.g. of the multiple-interactions model for minimum-bias and +underlying events. +Warning 2: People often underestimate the differences +between different sets on the market. The sets for the same order are +constructed to behave more or less similarly at large x and +Q^2, while the multiple interactions are dominated by the +behaviour in the region of small x and Q^2. A good +PDF parametrization ought to be sensible down to x = 10^-6 +(x = 10^-7) and Q^2 = 1 GeV^2 for Tevatron (LHC) +applications. Unfortunately there are distributions on the market that +completely derail in that region. The main41.cc and +main42.cc programs in the examples +subdirectory provide some examples of absolutely minimal sanity checks +before a new PDF set is put in production. +Warning 3: NLO and LO sets tend to have quite different +behaviours, e.g. NLO ones have less gluons at small x, which then is +compensated by positive corrections in the NLO matrix elements. +Therefore do not blindly assume that an NLO tune has to be better than +an LO one when combined with the LO matrix elements in PYTHIA. There are +explicit examples where such thinking can lead you down the wrong alley. + +

+The simplest option is to pick one +of the few distributions available internally: + + +Parton densities to be used for proton beams (and, by implication, +antiproton ones): + + + + +

+Obviously this choice is mainly intended to get going, and if you link to +the LHAPDF +library Wha05 you get access to a much wider selection. +Warning: owing to previous problems with the behaviour of PDF's +beyond the x and Q^2 boundaries of a set, you should +only use LHAPDF version 5.3.0 or later. + + +If off then the choice of proton PDF is based on pPDFset +above. If on then it is instead based on the choice of +LHAPDFset and LHAPDFmember below. +Note: in order for this option to work you must have +compiled PYTHIA appropriately and have set the LHAPATH +environment variable to provide the data-files directory of your local +LHAPDF installation. See the README file in the examples +directory for further instructions. + + + +Name of proton PDF set from LHAPDF to be used. You have to choose +from the + +list of available sets. Examples of some recent ones would be +cteq61.LHpdf, cteq61.LHgrid, cteq6l.LHpdf, cteq6ll.LHpdf, +MRST2004nlo.LHpdf, MRST2004nlo.LHgrid, MRST2004nnlo.LHgrid and +MRST2004FF3lo.LHgrid. If you pick a LHpdf set it will require some +calculation the first time it is called. +Technical note: if you provide a name beginning with a +slash (/) it is assumed you want to provide the full file path and then +initPDFsetM(name) is called, else the correct path is assumed +already set and initPDFsetByNameM(name) is called. + + + +Further choice of a specific member from the set picked above. Member 0 +should normally correspond to the central value, with higher values +corresponding to different error PDF's somewhat off in different +directions. You have to check from set to set which options are open. +Note: you can only use one member in a run, so if you +want to sweep over many members you either have to do many separate +runs or, as a simplification, save the +pdf weights at the hard scattering +and do an offline reweighting of events. + + + +Parton densities have a guaranteed range of validity in x +and Q^2, and what should be done beyond that range usually is +not explained by the authors of PDF sets. Nevertheless these boundaries +very often are exceeded, e.g. minimum-bias studies at LHC may sample +x values down to 10^-8, while many PDF sets stop +already at 10^-5. The default behaviour is then that the +PDF's are frozen at the boundary, i.e. xf(x,Q^2) is fixed at +its value at x_min for all values x < x_min, +and so on. This is a conservative approach. Alternatively, if you +switch on extrapolation, then parametrizations will be extended beyond +the boundaries, by some prescription. In some cases this will provide a +more realistic answer, in others complete rubbish. Another problem is +that some of the PDF-set codes will write a warning message anytime the +limits are exceeded, thus swamping your output file. Therefore you should +study a set seriously before you run it with this switch on. + + +

+If you want to use PDF's not found in LHAPDF, or you want to interface +LHAPDF another way, you have full freedom to use the more generic +interface options. + +

Parton densities for protons in the hard process

+ +The above options provides a PDF set that will be used everywhere: +for the hard process, the parton showers and the multiple interactions +alike. As already mentioned, therefore a change of PDF should be +accompanied by a complete retuning of the whole MI framework, +and maybe more. There are cases where one may want to explore +different PDF options for the hard process, but would not want to touch +the rest. If several different sets are to be compared, a simple +reweighting based on the originally +used flavour, x, Q^2 and PDF values may offer the +best route. The options in this section allow a choice of the PDF set +for the hard process alone, while the choice made in the previous section +would still be used for everything else. The hardest interaction +of the minimum-bias process is part of the multiple-interactions +framework and so does not count as a hard process here. + +

+Of course it is inconsistent to use different PDF's in different parts +of an event, but if the x and Q^2 ranges mainly accessed +by the components are rather different then the contradiction would not be +too glaring. Furthermore, since standard PDF's are one-particle-inclusive +we anyway have to 'invent' our own PDF modifications to handle configurations +where more than one parton is kicked out of the proton Sjo04. + +

+The PDF choices that can be made are the same as above, so we do not +repeat the detailed discussion. + + +If on then select a separate PDF set for the hard process, using the +variables below. If off then use the same PDF set for everything, +as already chosen above. + + + +Parton densities to be used for proton beams (and, by implication, +antiproton ones): + + + + + +If off then the choice of proton PDF is based on hardpPDFset +above. If on then it is instead based on the choice of +hardLHAPDFset and hardLHAPDFmember below. + + + +Name of proton PDF set from LHAPDF to be used. + + + +Further choice of a specific member from the set picked above. + + +

+Note that there is no separate equivalent of the +PDF:extrapolateLHAPDF flag specifically for the hard +PDF. Since LHAPDF only has one global flag for extrapolation or not, +the choice for the normal PDF's also applies to the hard ones. + +

Parton densities for leptons

+ +For electrons/leptons there is no need to choose between different +parametrizations, since only one implementation is available, and +should be rather uncontroversial (apart from some technical details). +However, insofar as e.g. e^+ e^- data often are corrected +back to a world without any initial-state photon radiation, it is +useful to have a corresponding option available here. + + +Use parton densities for lepton beams or not. If off the colliding +leptons carry the full beam energy, if on part of the energy is +radiated away by initial-state photons. In the latter case the +initial-state showers will generate the angles and energies of the +set of photons that go with the collision. In addition one collinear +photon per beam carries any leftover amount of energy not described +by shower emissions. If the initial-state showers are switched off +these collinear photons will carry the full radiated energy. + + +

Incoming parton selection

+ +There is one useful degree of freedom to restrict the set of incoming +quark flavours for hard processes. It does not change the PDF's as such, +only which quarks are allowed to contribute to the hard-process cross +sections. Note that separate but similarly named modes are available +for multiple interactions and spacelike showers. + + +Number of allowed incoming quark flavours in the beams; a change +to 4 would thus exclude b and bbar as incoming +partons, etc. + + +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/PYTHIA6TranslationTable.xml b/PYTHIA8/pythia8130/xmldoc/PYTHIA6TranslationTable.xml new file mode 100644 index 00000000000..9cd1f72a64b --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/PYTHIA6TranslationTable.xml @@ -0,0 +1,100 @@ + + +

PYTHIA 6 Translation Table

+ +For those more familiar with PYTHIA 6 than PYTHIA 8, here comes a table +that shows the approximate correspondence between some commonly used +variables in the two programs.The list can be expanded to meet explicit +needs (channel your suggestions via the Monte Carlo responsible of your +collaboration), but there is no question of ever providing anywhere near +a complete coverage. + +

Selecting properties of event generation

+ +For PYTHIA 8 you should use the pythia->readString("command") +to give in the commands listed below, assuming that you have access to a +pointer pythia to an instance of the Pythia class. + + + + + + + + + + + + + + + + + + + + + + + + +
PYTHIA 6 PYTHIA 8 Comment
MSEL = 1 SoftQCD:minBias = on soft and hard QCD events (for pp/pbarp)
MSEL = 2 SoftQCD:all = on as above, plus elastic and diffractive (for pp/pbarp)
MSTP(61) = 0 PartonLevel:ISR = off no initial-state radiation
MSTP(71) = 0 PartonLevel:FSR = off no final-state radiation
MSTP(81) = 0 PartonLevel:MI = off no multiple parton-parton interactions
MSTP(111) = 0 HadronLevel:all = off no hadronization and no decays
+ +

Information about generated event

+ +Several PYTHIA 6 variables are stored in two places, and then both are +given below. For PYTHIA 8 it is assumed that you have access to a pointer +pythia to an instance of the Pythia class. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PYTHIA 6 PYTHIA 8 Comment
msti(1), mint(1) pythia->info.code() process ID (but changed numbering)
pari(13), vint(43) pythia->info.mHat() invariant mass of the hard subprocess
pari(17), vint(47) pythia->info.pTHat() transverse momentum of the hard subprocess (2 -> 2)
pari(21), vint(51) pythia->info.QRen() renormalization scale Q of the hard subprocess (default definition changed)
vint(57) pythia->info.alphaEM() electromagnetic coupling constant in the hard subprocess
vint(58) pythia->info.alphaS() strong coupling constant in the hard subprocess
msti(15), mint(15) pythia->info.id1() ID of the first incoming parton
msti(16), mint(16) pythia->info.id2() ID of the second incoming parton
pari(33), vint(41) pythia->info.x1() momentum fraction x of the first incoming parton
pari(34), vint(42) pythia->info.x2() momentum fraction x of the second incoming parton
pari(23), vint(53) pythia->info.QFac() factorization scale Q of the hard subprocess (default definition changed)
pari(29), vint(39) pythia->info.pdf1() x1*f(x1) (PDF density 1)
pari(30), vint(40) pythia->info.pdf2() x2*f(x2) (PDF density 2)
pari(7), vint(97) pythia->info.weight() event weight (normally unity)
+ +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/ParticleData.xml b/PYTHIA8/pythia8130/xmldoc/ParticleData.xml new file mode 100644 index 00000000000..cd05640f544 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ParticleData.xml @@ -0,0 +1,7897 @@ + + +

Particle Data

+ +The structure and operation of the particle data table is described +here. That page +also describes how default data properties can be changed. The +current page provides the actual default values. + +

Main settings

+ +Apart from the data itself, the particle data table only contains +a few aspects that are available to change: + + +Selection of particle masses when the mass(id) is called +to provide a new mass: + + + + + +Note: this mode only applies to normal hadronic +resonances like the rho. The more massive states of the +isResonance() type, like Z^0 or top, are +considered separately. + + + +The modifications in options 2 and 4 above enhance the large-mass tail +of the Breit-Wigners (the mass spectrum develops a dm/m divergence). +However, we expect form factors to dampen this tail at masses some distance +above the nominal one, so cut off the rise by requiring the actual +Breit-Wigner weight not to be more than a factor maxEnhanceBW +above the one obtained with options 1 or 3, respectively. This also +opens up for a simpler technical handling of mass selection in options +2 and 4, by using standard hit-and-miss Monte Carlo. + + +

+Since running masses are only calculated for the six quark flavours, +e.g. to obtain couplings to the Higgs boson(s), there is not an entry +in the normal tables for each particles, but only the six MSbar mass +values below, used as starting point for the running. In addition you +can pick an alpha_s(M_Z), which is converted into a first-order +five-flavour Lambda that is used to determine the rate of the running. +(Without any match to four flavours below m_b; if desired, this +can be fixed by slightly shifted default mass values, since the routines +never should be called below the m_b scale anyway.) + + +the d quark MSbar mass at 2 GeV scale. + + +the u quark MSbar mass at 2 GeV scale. + + +the s quark MSbar mass at 2 GeV scale. + + +the c quark MSbar mass at the mass scale itself. + + +the b quark MSbar mass at the mass scale itself. + + +the t quark MSbar mass at the mass scale itself. + + +the alpha_s(M_Z) value used to define tha rate at which MSbar +masses run. + + +

Comments on the data

+ +The starting point for the current data is the 2006 Review of Particle +Physics Yao06. All known particle masses, widths and lifetimes +have been set accordingly, while not-yet-measured particles are kept at +their values from PYTHIA 6. Decay channels and their branching +ratios remain a major worry: many particles do not have one single solidly +measured branching ratio, and many further do not have known branching +ratios that add up to (the neighbourhood of) unity. + +

+Uncertainties are especially big for the scalar, pseudovector and tensor +L = 1 multiplets available in PYTHIA. We note that +some distributions become better described when these multiplets are +included in the generation, while others become worse. It is tempting to +associate this lackluster performance with the primitive knowledge. +Not even the multiplets themselves are particularly well known. +It used to be that the a_0(980) and f_0(980) +were considered to be members of the scalar multiplet. Nowadays they are +commonly assumed to be either four-quark states or of some other exotic +character. This means that the PYTHIA 8 PDG particle codes +have been changed for these particles, relative to what was used in +PYTHIA 6 based on previous PDG editions. Specifically their +numbers are now in the 9000000 series, and they have been replaced in the +scalar multiplet by a_0(1450) and f_0(1370). + +

+For charm and bottom mesons the jungle of partial measurements makes +it very difficult to construct fully consistent sets of decay channels. +This part of the program has not yet been brought up to date to the +2006 RPP. Instead the LHCb decay tables (for EvtGen, but without +using the EvtGen matrix-element machinery) and the DELPHI tune for +PYTHIA 6 is being used. (This also includes a few non-c/b +hadrons that only occur in the c/b decay tables.) This has the +advantage that many tests have been made for consistency, but the +disadvantage that it is not always in agreement with the latest +measurements of some specific decay channels. The decays based +on the LHCb tables (with some modifications) are 411, 421, 431, 441, +445, 511, 521, 531, 541, 3124, 4122, 4124, 5122, 10441, 10443, 13122, +14122, 20443, 23122, 30313, 30323, 30443, 33122, 100113, 100213, 100441, +100443, 100553, 9000111, 9000211. Correspondingly the decays based on +the DELPHI tables are 415, 425, 435, 515, 525, 535, 4132, 4232, 4332, +5132, 5232 and 5332. + +

The data itself

+ +Here comes the default particle data used in the program. Do not touch. +The meaning of the various properties and the format used are explained +here and the +meMode codes here. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/ParticleDataScheme.xml b/PYTHIA8/pythia8130/xmldoc/ParticleDataScheme.xml new file mode 100644 index 00000000000..10e6e23b4f9 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ParticleDataScheme.xml @@ -0,0 +1,625 @@ + + +

The Particle Data Scheme

+ +The particle data scheme may take somewhat longer to understand than +the settings one. In particular the set of methods to access information +is rather more varied, to allow better functionality for advanced usage. +However, PYTHIA does come with a sensible default set of particle +properties and decay tables. Thus there is no need to learn any of the +methods on this page to get going. Only when you perceive a specific need +does it make sense to learn the basics. + +

+The central section on this page is the Operation one. The preceding +sections are mainly there to introduce the basic structure and the set +of properties that can be accessed. + +

Databases

+ +The management of particle data is based on the four classes: +
    +
  • ParticleDataEntry, which stores the relevant information +on a particle species, and
  • +
  • ParticleDataTable, which is a map of PDG particle +id numbers Yao06 onto the relevant +ParticleDataEntry.
  • +
  • DecayChannel, which stores info on one particular decay +mode.
  • +
  • DecayTable, which is a vector of +DecayChannel's, containing all the decay modes of a +particle, and also methods for picking a decay mode.
  • +
+The objects of these classes together form a database that is +continuously being used as the program has to assign particle masses, +decay modes etc. + +

+The ParticleDataTable class is purely static, i.e. you +can interact with it directly by +ParticleDataTable::command(argument). +However, a particleData object of the +ParticleDataTable class is a public member of the +Pythia class, so an alternative +notation would be pythia.particleData.command(argument), +assuming that pythia is an instance of the +Pythia class. Further, for some of the most frequent user +tasks, Pythia methods have been defined, so that +pythia.command(argument) +would work, see further below. + +

+A fundamental difference between the ParticleData +classes and the Settings ones is that the former +are accessed regularly during the event generation process, as a new +particle is produced and its mass need to be set, e.g., while +Settings is mainly/only used at the initialization stage. +Nevertheless, it is not a good idea to change data in either of them +in mid-run, since this may lead to inconsistencies. + +

Stored properties for particles

+ +Currently the following particle properties are stored in the +ParticleDataTable for a given PDG particle identity code +id, here presented by the name used to access this property: + + +particle and antiparticle names are stored separately, the sign of +id determines which of the two is returned, with +void used to indicate the absence of an antiparticle. + + + +the spin type, of the form 2 s + 1, with special code 0 +for entries of unknown or indeterminate spin. + + + +three times the charge (to make it an integer), taking into account +the sign of id. + + + +the colour type, with 0 uncoloured, 1 triplet, -1 antitriplet and 2 +octet, taking into account the sign of id. + + + +the nominal mass m_0 (in GeV). + + + +the width Gamma of the Breit-Wigner distribution (in GeV). + + + +the lower and upper limit, respectively, of the allowed mass range +generated by the Breit-Wigner (in GeV). If mMax < mMin +then no upper limit is imposed. Have no meanings for particles +without width, and would typically be 0 there. + + + +the nominal proper lifetime tau_0 (in mm/c). + + + +a flag telling whether a particle species are considered as a resonance +or not. Here "resonance" +is used as shorthand for any massive particle +where the decay process should be counted as part of the hard process +itself, and thus be performed before showers and other event aspects +are added. Restrictions on allowed decay channels is also directly +reflected in the cross section of simulated processes, while those of +normal hadrons and other light particles are not. +In practice, it is reserved for states above the b bbar +bound systems in mass, i.e. for W, Z, t, Higgs states, +supersymmetric states and (most?) other states in any new theory. +All particles with m0 above 20 GeV are by default +initialized to be considered as resonances. + + + +a flag telling whether a particle species may decay or not, offering +the main user switch. Whether a given particle of this kind then actually +will decay also depends on it having allowed decay channels, and on +other flags for particle decays. +All particles with tau0 below 1000 mm are +by default initialized to allow decays. + + + +a flag telling whether a particle should be handled by an external +decay package or not, with the latter default. Can be manipulated as +described on this page, but should normally not be. Instead the +pythia.decayPtr +method should be provided with the list of relevant particles. + + + +a flag telling whether a particle species is to be considered as +visible in a detector or not, as used e.g. in analysis routines. +By default this includes neutrinos and a few BSM particles +(gravitino, sneutrinos, neutralinos) that have neither strong nor +electromagnetic charge, and are not made up of constituents that +have it. The value of this flag is only relevant if a particle is +long-lived enough actually to make it to a detector. + + + +a flag valid only for resonances where PYTHIA contains code to +calculate the width of the resonance from encoded matrix-element +expressions, i.e. the Z^0, W^+-, t, +h^0, and a few more. The normal behaviour (false) +is then that the width is calculated from the mass, but it is +possible to force the resonance +to retain the nominal width. Branching ratios and the running of the +total width are unaffected. + + +

+Similarly-named methods can also be used to set these properties. +We do not provide the details here, since other methods to be +introduced below are the ones likely to be used for such tasks. +(Normally the correspondence is obvious in the header file, but +for the name you either can use two methods to set name and +antiparticle name separately, or use one method that takes them +both as input.) + +

+There are some further methods for output only, i.e. properties +that cannot be set directly: + + +returns a pointer to the ParticleDataEntry object. + + + +bool whether a distinct antiparticle exists or not. Is true if an +antiparticle name has been set (and is different from +void). + + + +the electrical charge of a particle, as a double equal +to chargeType(id)/3. + + +returns a mass distributed according to a truncated Breit-Wigner, +with parameters as above (see also the +ParticleData:modeBreitWigner switch). Is equal to +m0(id) for particles without width. + + + +is the constituent mass for a quark, hardcoded as +m_u = m_d = 0.325, m_s = 0.50, m_c = 1.60 +and m_b = 5.0 GeV, for a diquark the sum of quark constituent +masses, and for everything else the same as the ordinary mass. + + + +similar to mMin() and mMax(), except that +for particles with no width the m0(id) value is returned. + + + +true for a lepton or an antilepton (including neutrinos). + + + +true for a quark or an antiquark. + + + +true for a gluon. + + + +true for a hadron (made up out of normal quarks and gluons, +i.e. not for R-hadrons and other exotic states). + + + +extracts the heaviest quark or antiquark, i.e. one with largest +id number, for a hadron. + + +

Stored properties for decays

+ +The following properties are stored for each decay channel: + + +0 if a channel is off,
+1 if on,
+2 if on for a particle but off for an antiparticle,
+3 if on for an antiparticle but off for a particle.
+If a particle is its own antiparticle then 2 is on and 3 off +but, of course, for such particles it is much simpler and safer +to use only 1 and 0.
+The 2 and 3 options can be used e.g. to encode CP violation in +B decays, or to let the W's in a q qbar -> W^+ W^- +process decay in different channels. +
+ + +the branching ratio. + + + +the mode of processing this channel, possibly with matrix elements +(see the particle decays description); + + + +the number of decay products in a channel, at most 8. +(Is not set as such, but obtained from the products list below.) + + + +a list of the decay products, 8 products 0 <= i < 8, +with trailing unused ones set to 0. + + +

+The decay table, a vector of decay channels, also defines a +few methods: + + +adds a decay channel with up to 8 products. + + + +gives the number of decay channels for a particle. + + + +rescale all branching ratios to the provided new sum, +by default unity. + + + +picks one decay channel according to their respective branching +ratios. + + + +intended for resonances specifically, this picks one decay channel +according to the respective partial widths for the specific mass +value of the resonance; assumes that the partial widths are input +beforehand, using a special dynamicBR() method. + + +

Operation

+ +The normal flow of the particle data operations is: + +
    + +
  1. +When a Pythia object pythia is created, the +ParticleDataTable member pythia.particleData +is asked to scan the ParticleData.xml file. + +

    +All lines beginning with <particle are scanned for +information on a particle species, and all lines beginning with +<channel are assumed to contain a decay channel of the +enclosing particle. In both cases XML syntax is used, with attributes +used to identify the stored properties, and with omitted properties +defaulting back to 0 where meaningful. The particle and channel +information may be split over several lines, up to the > endtoken. +The format of a <particle tag is: +

    +    <particle id="..." name="..." antiName="..." spinType="..." chargeType="..." colType="..." 
    +       m0="..." mWidth="..." mMin="..." mMax="..." tau0="...">
    +    </particle>
    +
    +where the fields are the properties already introduced above. +Note that isResonance, mayDecay, +doExternalDecay, isVisible and +doForceWidth are not set here, but are provided with +default values by the rules described above. Once initialized, also +these latter properties can be changed, see below.
    + +The format of a <channel> tag is: +
    +    <channel onMode="..." bRatio="..." meMode="..." products="..." />
    +
    +again see properties above. The products are given as a blank-separated +list of id codes. +Important: the values in the .xml file should not +be changed, except by the PYTHIA authors. Any changes should be done +with the help of the methods described below. +
  2. + +
  3. +Between the creation of the Pythia object and the +init call for it, you may use the methods of the +ParticleDataTable class to modify some of the default values. +Several different approaches can be chosen for this. + +

    +a) Inside your main program you can directly set values with +

    +    pythia.readString(string);
    +
    +where both the variable name and the value are contained inside +the character string, separated by blanks and/or a =, e.g. +
    +    pythia.readString("111:mayDecay = off"); 
    +
    +switches off the decays of the pi^0.
    + +The particle id (> 0) and the property to be changed must be given, +separated by a colon.
    + +The allowed properties are: name, antiName, +spinType, chargeType, colType, +m0, mWidth, mMin, +mMax, tau0, isResonance, +mayDecay, doExternalDecay, +isVisible and doForceWidth. All of these names +are case-insensitive. Names that do not match an existing variable +are ignored. A warning is printed, however, unless an optional +second argument false is used.
    +Strings beginning with a non-alphanumeric character, like # or !, +are assumed to be comments and are not processed at all. For +bool values, the following notation may be used +interchangeably: true = on = yes = ok = 1, while everything +else gives false (including but not limited to +false, off, no and 0). + +

    +Particle data often comes in sets of closely related information. +Therefore some properties expect the value to consist of several +numbers. These can then be separated by blanks (or by commas). +A simple example is names, which expects both the +name and antiname to be given. A more interesting one is the +all property, +

      
    +    id:all = name antiName spinType chargeType colType m0 mWidth mMin mMax tau0
    +
    +where all the current information on the particle itself is replaced, +but any decay channels are kept unchanged. Using new instead +of all also removes any previous decay channels. +If the string contains fewer fields than expected the trailing +properties are set to vanish ("void", 0 or 0.). Note that such a +truncated string should not be followed by a comment, since this +comment would then be read in as if it contained the missing properties. +The truncation can be done anywhere, specifically a string with only +id:new defines a new "empty" particle. +As before, isResonance, mayDecay, +doExternalDecay, isVisible and +doForceWidthare (re)set to their default values, and +would have to be changed separately if required. + +

    +A further command is rescaleBR, which rescales each of the +existing branching ratios with a common factor, such that their new +sum is the provided value. This may be a first step towards adding +new decay channels, see further below. + +

    +Alternatively the id code may be followed by another integer, +which then gives the decay channel number. This then has to be +followed by the property specific to this channel, either +onMode, bRatio, meMode or +products. In the latter case all the products of the channel +should be given: +

    +    id:channel:products =  product1 product2 ....  
    +
    +The line will be scanned until the end of the line, or until a +non-number word is encountered, or until the maximum allowed number +of eight products is encountered, whichever happens first. It is also +possible to replace all the properties of a channel in a similar way: +
    +    id:channel:all = onMode bRatio meMode product1 product2 ....  
    +
    +To add a new channel at the end, use +
    +    id:addChannel = onMode bRatio meMode product1 product2 ....
    +
    + +

    +It is currently not possible to remove a channel selectively, but +setting its branching ratio vanishing is as effective. If you want to +remove all existing channels and force decays into one new channel +you can use +

    +    id:oneChannel = onMode bRatio meMode product1 product2 ....
    +
    + A first oneChannel command could be followed by +several subsequent addChannel ones, to build +up a completely new decay table for an existing particle. + +

    +When adding new channels or changing branching ratios in general, +note that, once a particle is to be decayed, the sum of branching +ratios is always rescaled to unity. Beforehand, rescaleBR +may be used to rescale an existing branching ratio by the given factor. + +

    +There are a few commands that will study all the decay channels of the +given particle, to switch them on or off as desired. The +

    +    id:onMode = onMode
    +
    +will set the onMode property of all channels to the +desired value. The +
     
    +    id:offIfAny   = product1 product2 .... 
    +    id:onIfAny    = product1 product2 .... 
    +    id:onPosIfAny = product1 product2 .... 
    +    id:onNegIfAny = product1 product2 .... 
    +
    +will set the onMode 0, 1, 2 or 3, respectively, for all +channels which contain any of the enumerated products, where the matching +to these products is done without distinction of particles and +antiparticles. Note that "Pos" and "Neg" +are slightly misleading since it refers to the particle and antiparticle +of the id species rather than charge, but should still be +simpler to remember and understand than alternative notations. +Correspondingly +
     
    +    id:offIfAll   = product1 product2 .... 
    +    id:onIfAll    = product1 product2 .... 
    +    id:onPosIfAll = product1 product2 .... 
    +    id:onNegIfAll = product1 product2 .... 
    +
    +will set the onMode 0, 1, 2 or 3, respectively, for all +channels which contain all of the enumerated products, again without +distinction of particles and antiparticles. If the same product appears +twice in the list it must also appear twice in the decay channel, and +so on. The decay channel is allowed to contain further particles, +beyond the product list. By contrast, +
     
    +    id:offIfMatch   = product1 product2 .... 
    +    id:onIfMatch    = product1 product2 .... 
    +    id:onPosIfMatch = product1 product2 .... 
    +    id:onPosIfMatch = product1 product2 .... 
    +
    +requires the decay-channel multiplicity to agree with that of the product +list, but otherwise works as the onIfAll/offIfAll methods. + +

    +Note that the action of several of the commands depends on the order +in which they are executed, as one would logically expect. For instance, +id:oneChannel removes all decay channels of id +and thus all previous changes in this decay table, while subsequent +additions or changes would still take effect. Another example would be that +23:onMode = off followed by 23:onIfAny = 1 2 3 4 5 +would let the Z^0 decay to quarks, while no decays would be +allowed if the order were to be reversed. + +

    +b) The Pythia readString(string) method actually +does not do changes itself, but sends on the string either to the +ParticleData class or to the Settings one. +If desired, it is possible to communicate directly with the corresponding +ParticleData method: +

    +    pythia.particleData.readString("111:mayDecay = off"); 
    +    pythia.particleData.readString("15:2:products = 16 -211"); 
    +
    +In this case, changes intended for Settings would not be +understood. + +

    +c) Underlying this are commands for all the individual properties in +the ParticleDataTable class, one for each. Thus, an example +now reads +

    +    pythia.particleData.mayDecay(111, false);
    +
    +Boolean values should here be given as true or +false. + +

    +d) A simpler and more useful way is to collect all your changes +in a separate file, with one line per change, e.g. +

    +    111:mayDecay = off
    +
    +The file can be read by the +
    +    pythia.readFile(fileName); 
    +
    +method, where fileName is a string, e.g. +pythia.readFile("main.cmnd"). Each line is process as +described for the string in 2a). This file can freely mix commands to +the Settings and ParticleData classes. +
  4. + +
  5. +A routine reInit(fileName) is provided, and can be used to +zero the particle data table and reinitialize from scratch. Such a call +might be required if several Pythia objects are created in the +same run, and requested to have different values - by default the +init() call is only made the first time. Several +pythia with different values would have to run sequentially +and not in parallel, though; recall that there is only one instance of +the particle data table. +

  6. + +
  7. +You may at any time obtain a listing of all the particle data by calling +

    +    pythia.particleData.listAll();
    +
    +The listing is by increasing id number. It shows the basic +quantities introduced above. Some are abbreviated in the header to fit on +the lines: spn = spinType, chg = chargeType, +col = colType, res = isResonance, +dec = mayDecay && canDecay (the latter checks that decay +channels have been defined), ext = doExternalDecay, +vis = isVisible and wid = doForceWidth.
    + +To list only those particles that were changed (one way or another, the +listing will not tell what property or decay channel was changed), instead use +
    +    pythia.particleData.listChanged();
    +
    +(This info is based on a further hasChanged flag of a particle +or a channel, set true whenever any of the changing methods are +used. It is possible to manipulate this value, but this is not recommended.) +By default the internal initialization of the widths of resonances such as +gamma^*/Z^0, W^+-, t/tbar, H^0 do not count as changes; if you want +to list also those changes instead call listChanged(true). +
    + +To list only one particle, give its id code as argument to +the list(...) function.. To list a restricted set of particles, +give in their id codes to list(...) as a +vector<int>. +
  8. + +
  9. +For wholesale changes of particle properties all available data can be +written out, edited, and then read back in again. These methods are +mainly intended for expert users. You can choose between two alternative +syntaxes. + +

    +a) XML syntax, using the <particle and +<channel lines already described. You use the method +particleData.listXML(fileName) to produce such an XML +file and particleData.readXML(fileName) to read it back +in after editing. + +

    +b) Fixed/free format, using exactly the same information as illustrated +for the <particle and <channel lines +above, but now without any tags. This means that all information fields +must be provided (if there is no antiparticle then write +void), in the correct order (while the order is irrelevant +with XML syntax), and all on one line. Information is written out in +properly lined-up columns, but the reading is done using free format, +so fields need only be separated by at least one blank. Each new particle +is supposed to be separated by (at least) one blank line, whereas no +blank lines are allowed between the particle line and the subsequent +decay channel lines, if any. You use the method +particleData.listFF(fileName) to produce such a fixed/free +file and particleData.readFF(fileName) to read it back +in after editing. + +

    +As an alternative to the readXML and readFF +methods you can also use the +particleData.reInit(fileName, xmlFormat) method, where +xmlFormat = true (default) corresponds to reading an XML +file and xmlFormat = false to a fixed/free format one. + +

    +To check that the new particle and decay tables makes sense, you can use +the particleData.checkTable() method, either directly or by +switching it on among the standard +error checks. +

  10. + +
+ +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/ParticleDecays.xml b/PYTHIA8/pythia8130/xmldoc/ParticleDecays.xml new file mode 100644 index 00000000000..21214d6c862 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ParticleDecays.xml @@ -0,0 +1,255 @@ + + +

Particle Decays

+ +The ParticleDecays class performs the sequential decays of +all unstable hadrons produced in the string fragmentation stage, +i.e. up to and including b hadrons and their decay products, +such as the tau lepton. It is not to be used for the decay of +more massive resonances, such as top, +Z^0 or SUSY, where decays must be performed already at the +ProcessLevel of the event generation. + +

+The decay description essentially copies the one present in +PYTHIA since many years, but with some improvements, e.g. in the decay +tables and the number of decay models available. Some issues may need +further polishing. + +

Variables determining whether a particle decays

+ +Before a particle is actually decayed, a number of checks are made. + +

+(i) Decay modes must have been defined for the particle kind; +tested by the canDecay() method of Event +(and ParticleData). + +

+(ii) The main switch for allowing this particle kind to decay must +be on; tested by the mayDecay() method of Event +(and ParticleData). + +

+(iii) Particles may be requested to have a nominal proper lifetime +tau0 below a threshold. + + +When on, only particles with tau0 < tau0Max are decayed. + + + +The above tau0Max, expressed in mm/c. + + +

+(iv) Particles may be requested to have an actual proper lifetime +tau below a threshold. + + +When on, only particles with tau < tauMax are decayed. + + + +The above tauMax, expressed in mm/c.
+In order for this and the subsequent tests to work, a tau +is selected and stored for each particle, whether in the end it +decays or not. (If each test would use a different temporary +tau it would lead to inconsistencies.) +
+ +

+(v) Particles may be requested to decay within a given distance +of the origin. + + +When on, only particles with a decay within a radius r < rMax +are decayed. There is assumed to be no magnetic field or other +detector effects. + + + +The above rMax, expressed in mm/c. + + +

+(vi) Particles may be requested to decay within a given cylidrical +volume around the origin. + + +When on, only particles with a decay within a volume limited by +rho = sqrt(x^2 + y^2) < xyMax and |z| < zMax +are decayed. There is assumed to be no magnetic field or other +detector effects. + + + +The above xyMax, expressed in mm/c. + + + +The above zMax, expressed in mm/c. + + +

Mixing

+ + +Allow or not B^0 - B^0bar and B_s^0 - B_s^0bar mixing. + + + +The mixing parameter x_d = Delta(m_B^0)/Gamma_B^0 in the +B^0 - B^0bar system. (Default from RPP2006.) + + + +The mixing parameter x_s = Delta(m_B_s^0)/Gamma_B_s^0 in the +B_s^0 - B_s^0bar system. (Delta-m from CDF hep-ex-0609040, +Gamma from RPP2006.) + + +

Other variables

+ + +Minimum mass difference required between the decaying mother mass +and the sum of the daughter masses, kept as a safety margin to avoid +numerical problems in the decay generation. + + + +In semileptonic decays to more than one hadron, such as +B -> nu l D pi, decay products after the first three are +dampened in momentum by an explicit weight factor +exp(-p^2/sigmaSoft^2), where p is the +three-momentum in the rest frame of the decaying particle. +This takes into account that such further particles come from the +fragmentation of the spectator parton and thus should be soft. + + +

+When a decay mode is defined in terms of a partonic content, a random +multiplicity (and a random flavour set) of hadrons is to be picked, +especially for some charm and bottom decays. This is done according to +a Poissonian distribution, for n_p normal particles and +n_q quarks the average value is chosen as + + n_p/ 2 + n_q/4 + multIncrease * ln ( mDiff / multRefMass) + +with mDiff the difference between the decaying particle mass +and the sum of the normal-particle masses and the constituent quark masses. +For gluonic systems multGoffset offers and optional additional +term to the multiplicity. The lowest possible multiplicity is +n_p + n_q/2 (but at least 2) and the highest possible 10. +If the picked hadrons have a summed mass above that of the mother a +new try is made, including a new multiplicity. These constraints +imply that the actual average multiplicity does not quite agree with +the formula above. + + +The above multIncrease parameter. + + + +The above multRefMass parameter. + + + +The above multGoffset parameter. + + + +When a decay is given as a list of four partons to be turned into +hadrons (primarily for modes 41 - 80) it is assumed that they are +listed in pairs, as a first and a second colour singlet, which could +give rise to separate sets of hadrons. Here colRearrange is +the probability that this original assignment is not respected, and +default corresponds to no memory of this original colour topology. + + + +When a particle decays to q qbar, g g, g g g +or gamma g g, with meMode > 90, allow or not a +shower to develop from it, before the partonic system is hadronized. +(The typical example is Upsilon decay.) + + +In addition, some variables defined for string fragmentation and for +flavour production are used also here. + +

Modes for Matrix Element Processing

+ +Some decays can be treated better than what pure phase space allows, +by reweighting with appropriate matrix elements. In others a partonic +content has to be converted to a set of hadrons. The presence of such +corrections is signalled by a nonvanishing meMode() value +for a decay mode in the particle +data table. The list of allowed possibilities almost agrees with the +PYTHIA 6 ones, but several obsolete choices have been removed, +a few new introduced, and most have been moved for better consistency. +Here is the list of currently allowed meMode() codes: +
    +
  • 0 : pure phace space of produced particles ("default"); +input of partons is allowed and then the partonic content is +converted into the minimal number of hadrons (i.e. one per +parton pair, but at least two particles in total)
  • +
  • 1 : omega and phi -> pi+ pi- pi0
  • +
  • 2 : polarization in V -> PS + PS (V = vector, +PS = pseudoscalar), when V is produced by +PS -> PS + V or PS -> gamma + V
  • +
  • 11 : Dalitz decay into one particle, in addition to the +lepton pair (also allowed to specify a quark-antiquark pair that +should collapse to a single hadron)
  • +
  • 12 : Dalitz decay into two or more particles in addition +to the lepton pair
  • +
  • 13 : double Dalitz decay into two lepton pairs
  • +
  • 21 : decay to phase space, but weight up neutrino_tau spectrum +in tau decay
  • +
  • 22 : weak decay; if there is a quark spectator system it collapses to +one hadron; for leptonic/semileptonic decays the V-A matrix element +is used, for hadronic decays simple phase space
  • +
  • 23 : as 22, but require at least three particles in decay
  • +
  • 31 : decays of type B -> gamma X, very primitive simulation where +X is given in terms of its flavour content, the X multiplicity is picked +according to a geometrical distribution with average number 2, and +the photon energy spectrum is weighted up relative to pure phase space
  • +
  • 42 - 50 : turn partons into a random number of hadrons, picked according +to a Poissonian with average value as described above, but at least +code - 40 and at most 10, and then distribute then in pure +phase space; make a new try with another multiplicity if the sum of daughter +masses exceed the mother one
  • +
  • 52 - 60 : as 42 - 50, with multiplicity between code - 50 +and 10, but avoid already explicitly listed non-partonic channels
  • +
  • 62 - 70 : as 42 - 50, but fixed multiplicity code - 60
  • +
  • 72 - 80 : as 42 - 50, but fixed multiplicity code - 70, +and avoid already explicitly listed non-partonic channels
  • +
  • 91 : decay to q qbar or g g, which should shower +and hadronize
  • +
  • 92 : decay onium to g g g or g g gamma +(with matrix element), which should shower and hadronize
  • +
  • 100 - : reserved for the description of partial widths of +resonances
  • +
+ +Three special decay product identity codes are defined. +
    +
  • 81: remnant flavour. Used for weak decays of c and b hadrons, where the +c or b quark decays and the other quarks are considered as a spectator +remnant in this decay. In practice only used for baryons with multiple +c and b quarks, which presumably would never be used, but have simple +(copied) just-in-case decay tables. Assumed to be last decay product.
  • +
  • 82: random flavour, picked by the standard fragmentation flavour +machinery, used to start a sequence of hadrons, for matrix element +codes in 41 - 80. Assumed to be first decay product, with -82 as second +and last. Where multiplicity is free to be picked it is selected as for +normal quarkonic systems. Currently unused.
  • +
  • 83: as for 82, with matched pair 83, -83 of decay products. The +difference is that here the pair is supposed to come from a closed gluon +loop (e.g. eta_c -> g g) and so have a somewhat higher average +multiplicity than the simple string assumed for 82, see the +ParticleDecays:multGoffset parameter above.
  • +
+ +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/ParticleProperties.xml b/PYTHIA8/pythia8130/xmldoc/ParticleProperties.xml new file mode 100644 index 00000000000..413cb5eca88 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ParticleProperties.xml @@ -0,0 +1,485 @@ + + +

Particle Properties

+ +A Particle corresponds to one entry/slot in the +event record. Its properties therefore is a mix of ones belonging +to a particle-as-such, like its identity code or four-momentum, +and ones related to the event-as-a-whole, like which mother it has. + +

+What is stored for each particle is +

    +
  • the identity code,
  • +
  • the status code,
  • +
  • two mother indices,
  • +
  • two daughter indices,
  • +
  • a colour and an anticolour index,
  • +
  • the four-momentum and mass,
  • +
  • the production vertex and proper lifetime,
  • +
  • a pointer to the particle kind in the particle data tables.
  • +
+From these, a number of further quantities may be derived. + +

Basic methods

+ +The following member functions can be used to extract the information: + + +the identity of a particle, according to the PDG particle codes +Yao06. + + + +status code. The status code includes information on how a particle was +produced, i.e. where in the program execution it was inserted into the +event record, and why. It also tells whether the particle is still present +or not. It does not tell how a particle disappeared, whether by a decay, +a shower branching, a hadronization process, or whatever, but this is +implicit in the status code of its daughter(s). The basic scheme is: +
    +
  • status = +- (10 * i + j)
  • +
  • + : still remaining particles
  • +
  • - : decayed/branched/fragmented/... and not remaining
  • +
  • i = 1 - 9 : stage of event generation inside PYTHIA
  • +
  • i = 10 -19 : reserved for future expansion
  • +
  • i >= 20 : free for add-on programs
  • +
  • j = 1 - 9 : further specification
  • +
+In detail, the list of used or foreseen status codes is: +
    +
  • 11 - 19 : beam particles
  • +
      +
    • 11 : the event as a whole
    • +
    • 12 : incoming beam
    • +
    • 13 : incoming beam-inside-beam (e.g. gamma + inside e)
    • +
    • 14 : outgoing elastically scattered
    • +
    • 15 : outgoing diffractively scattered
    • +
    +
  • 21 - 29 : particles of the hardest subprocess
  • +
      +
    • 21 : incoming
    • +
    • 22 : intermediate (intended to have preserved mass)
    • +
    • 23 : outgoing
    • +
    +
  • 31 - 39 : particles of subsequent subprocesses
  • +
      +
    • 31 : incoming
    • +
    • 32 : intermediate (intended to have preserved mass)
    • +
    • 33 : outgoing
    • +
    +
  • 41 - 49 : particles produced by initial-state-showers
  • +
      +
    • 41 : incoming on spacelike main branch
    • +
    • 42 : incoming copy of recoiler
    • +
    • 43 : outgoing produced in timelike sidebranch of shower
    • +
    • 44 : outgoing shifted by the branching
    • +
    +
  • 51 - 59 : particles produced by final-state-showers
  • +
      +
    • 51 : outgoing produced by parton branching
    • +
    • 52 : outgoing copy of recoiler, with changed momentum
    • +
    • 53 : copy of recoiler when this is incoming parton, + with changed momentum
    • +
    +
  • 61 - 69 : particles produced by beam-remnant treatment
  • +
      +
    • 61 : incoming subprocess particle with primordial kT + included
    • +
    • 62 : outgoing subprocess particle with primordial kT + included
    • +
    • 63 : outgoing beam remnant
    • +
    +
  • 71 - 79 : partons in preparation of hadronization process
  • +
      +
    • 71 : copied partons to collect into contiguous colour singlet
    • +
    • 72 : copied recoiling singlet when ministring collapses to + one hadron and momentum has to be reshuffled
    • +
    • 73 : combination of very nearby partons into one
    • +
    • 74 : combination of two junction quarks (+ nearby gluons) + to a diquark
    • +
    • 75 : gluons split to decouple a junction-antijunction pair
    • +
    • 76 : partons with momentum shuffled to decouple a + junction-antijunction pair
    • +
    • 77 : temporary opposing parton when fragmenting first two + strings in to junction (should disappear again)
    • +
    • 78 : temporary combined diquark end when fragmenting last + string in to junction (should disappear again)
    • +
    +
  • 81 - 89 : primary hadrons produced by hadronization process
  • +
      +
    • 81 : from ministring into one hadron
    • +
    • 82 : from ministring into two hadrons
    • +
    • 83, 84 : from normal string (the difference between the two + is technical, whether fragmented off from the top of the + string system or from the bottom, useful for debug only)
    • +
    • 85, 86 : primary produced hadrons in junction frogmentation of + the first two string legs in to the junction, + in order of treatment
    • +
    +
  • 91 - 99 : particles produced in decay process, or by Bose-Einstein + effects
  • +
      +
    • 91 : normal decay products
    • +
    • 92 : decay products after oscillation B0 <-> B0bar or + B_s0 <-> B_s0bar
    • +
    • 93, 94 : decay handled by external program, normally + or with oscillation
    • +
    • 99 : particles with momenta shifted by Bose-Einstein effects + (not a proper decay, but bookkept as an 1 -> 1 such, + happening after decays of short-lived resonances but before + decays of longer-lived particles)
    • +
    +
  • 101 - 199 : reserved for future expansion
  • +
  • 201 - : free to be used by anybody
  • +
+
+ + +the indices in the event record where the first and last mothers are +stored, if any. There are five allowed combinations of mother1 +and mother2: +
    +
  1. mother1 = mother2 = 0: for lines 0 - 2, where line 0 +represents the event as a whole, and 1 and 2 the two incoming +beam particles;
  2. +
  3. mother1 = mother2 > 0: the particle is a "carbon copy" +of its mother, but with changed momentum as a "recoil" effect, +e.g. in a shower;
  4. +
  5. mother1 > 0, mother2 = 0: the "normal" mother case, where +it is meaningful to speak of one single mother to several products, +in a shower or decay;
  6. +
  7. mother1 < mother2, both > 0, for +abs(status) = 81 - 86: primary hadrons produced from the +fragmentation of a string spanning the range from mother1 +to mother2, so that all partons in this range should be +considered mothers;
  8. +
  9. mother1 < mother2, both > 0, except case 4: particles +with two truly different mothers, in particular the particles emerging +from a hard 2 -> n interaction.
  10. +
+Note 1: in backwards evolution of initial-state showers, +the mother may well appear below the daughter in the event record. +Note 2: the motherList(i) method of the +Event class returns a vector of all the mothers, +providing a uniform representation for all five cases. +
+ + +the indices in the event record where the first and last daughters +are stored, if any. There are five allowed combinations of +daughter1 and daughter2: +
    +
  1. daughter1 = daughter2 = 0: there are no daughters +(so far);
  2. +
  3. daughter1 = daughter2 > 0: the particle has a +"carbon copy" as its sole daughter, but with changed momentum +as a "recoil" effect, e.g. in a shower;
  4. +
  5. daughter1 > 0, daughter2 = 0: each of the incoming beams +has only (at most) one daughter, namely the initiator parton of the +hardest interaction; further, in a 2 -> 1 hard interaction, +like q qbar -> Z^0, or in a clustering of two nearby partons, +the initial partons only have this one daughter;
  6. +
  7. daughter1 < daughter2, both > 0: the particle has +a range of decay products from daughter1 to +daughter2;
  8. daughter2 < daughter1, +both > 0: the particle has two separately stored decay products (e.g. +in backwards evolution of initial-state showers).
  9. +
+Note 1: in backwards evolution of initial-state showers, the +daughters may well appear below the mother in the event record. +Note 2: the mother-daughter relation normally is reciprocal, +but not always. An example is hadron beams (indices 1 and 2), where each +beam remnant and the initiator of each multiple interaction has the +respective beam as mother, but the beam itself only has the initiator +of the hardest interaction as daughter. +Note 3: the daughterList(i) method of the +Event class returns a vector of all the daughters, +providing a uniform representation for all five cases. With this method, +also all the daughters of the beams are caught, with the initiators of +the basic process given first, while the rest are in no guaranteed order +(since they are found by a scanning of the event record for particles +with the beam as mother, with no further information). +
+ + +the colour and anticolour tags, Les Houches Accord Boo01 +style (starting from tag 101 by default, see below). + + + +the particle four-momentum components, alternatively extracted as a +Vec4 p(). + + + +the particle mass. + + + +the scale at which a parton was produced, which can be used to restrict +its radiation to lower scales in subsequent steps of the shower evolution. +Note that scale is linear in momenta, not quadratic (i.e. Q, +not Q^2). + + + +the production vertex coordinates, in mm or mm/c, alternatively extracted +as a Vec4 vProd(). The initial process is assumed to occur +at the origin. +Note:the Vec4 has components px(), py(), +pz() and e(), which of course should be reinterpreted as above. + + + +the proper lifetime, in mm/c; is assigned for all hadrons with +positive nominal tau, tau_0 > 0, even if not +decayed by PYTHIA (because of one veto or another). + + +

+The same method names are overloaded to take an argument, in which case +the corresponding property is set accordingly. + +

Further methods

+ + There are a few alternative methods for input: + + +sets the status sign positive or negative, without changing the absolute value. + + + +changes the absolute value but retains the original sign. + + + +sets both mothers in one go. + + + +sets both daughters in one go. + + + +sets both colour and anticolour in one go. + + + +sets the four-momentum in one go; +alternative input as a Vec4 object. + + + +sets the production vertex in one go; alternative input as a +Vec4 +object. + + +

+In addition, a number of derived quantities can easily be obtained +(but cannot be set), such as: + + +the absolute value of the particle identity code. + + + +the absolute value of the status code. + + + +true for a remaining particle, i.e. one with positive status code, +else false. Thus, after an event has been fully generated, it +separates the final-state particles from intermediate-stage ones. +(If used earlier in the generation process, a particle then +considered final may well decay later.) + + + +squared mass. + + + +(squared) mass calculated from the four-momentum; should agree +with m(), m2() up to roundoff. + + + +energy calculated from the mass and three-momentum; +should agree with e() up to roundoff. + + + +(squared) transverse momentum. + + + +(squared) transverse mass. + + + +(squared) three-momentum size. + + + +polar and azimuthal angle. + + + +angle in the (p_x, p_z) plane, between -pi and ++pi, with 0 along the +z axis + + + +E +- p_z. + + + +rapidity and pseudorapidity. + + + +the decay vertex coordinates, in mm or mm/c, alternatively extracted as +a Vec4 vDec(); this decay vertex is calculated from the +production vertex, the proper lifetime and the four-momentum assuming +no magnetic field or other detector interference; it can be used to +decide whether a decay should be performed or not, and thus is defined +also for particles which PYTHIA did not let decay. + + +

+Each Particle contains a pointer to the respective +ParticleDataEntry object in the +particle data tables. +This gives access to properties of the particle species as such. It is +there mainly for convenience, and should be thrown if an event is +written to disk, to avoid any problems of object persistency. Should +an event later be read back in, the pointer will be recreated from the +id code if the normal input methods are used. (Use the +Event::restorePtrs() method +if your persistency scheme bypasses the normal methods.) This pointer is +used by the following member functions: + + +the name of the particle, as a string. + + + +as above, but for negative-status particles the name is given in +brackets to emphasize that they are intermediaries. + + + +2 *spin + 1 when defined, else 0. + + + +charge, and three times it to make an integer. + + + +charge different from or equal to 0. + + + +0 for colour singlets, 1 for triplets, +-1 for antitriplets and 2 for octets. + + + +the nominal mass of the particle, according to the data tables. + + + +the width of the particle, and the minimum and maximum allowed mass value +for particles with a width, according to the data tables. + + + +the mass of the particle, picked according to a Breit-Wigner +distribution for particles with width, and thus different each +time called. + + + +will give the constituent masses for quarks and diquarks, +else the same masses as with m0(). + + + +particles where the decay is to be treated as part of the hard process, +typically with nominal mass above 20 GeV (W^+-, Z^0, t, ...). + + + +flag whether particle has been declared unstable or not, offering +the main user switch to select which particle species to decay. + + + +flag whether decay modes have been declared for a particle, +so that it could be decayed, should that be requested. + + + +particles that are decayed by an external program. + + + +particles with strong or electric charge, or composed of ones having it, +which thereby should be considered visible in a normal detector. + + + +resonances that have code to recalculate the width in mWidth +from the nominal mass value m0, but where nevertheless the +stored mWidth value is used. + + + +true for a lepton or an antilepton (including neutrinos). + + + +true for a quark or an antiquark. + + + +true for a gluon. + + + +true for a hadron (made up out of normal quarks and gluons, +i.e. not for R-hadrons and other exotic states). + + + +a reference to the ParticleDataEntry. + + +

+There are some further methods, inherited from Vec4, +to rotate and boost the four-momentum. + +

+Not part of the event class proper, but obviously tightly linked, +are the metods m(Particle, Particle) and +m2(Particle, Particle) to calculate the (squared) +invariant mass of two particles. + +

+The +Event +class also contains a few methods defined for individual particles, +but these may require some search in the event record and therefore +cannot be defined as a Particle method. + +

+Currently there is no information on polarization states. + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/PartonDistributions.xml b/PYTHIA8/pythia8130/xmldoc/PartonDistributions.xml new file mode 100644 index 00000000000..fdf81899f20 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/PartonDistributions.xml @@ -0,0 +1,102 @@ + + +

Parton Distributions

+ +The parton distributions file contains the PDF class. +PDF is the base class, from which specific PDF +classes are derived. + +

+The choice of which PDF to use is made by settings in the +Pythia class, see here. +These settings also allow to access all the proton PDF's available in the +LHAPDF library Wha05. Thus there is no need for a normal user +to study the PDF class. The structure must only be understood +when interfacing new PDF's, e.g. ones not yet found in LHAPDF. + +

The PDF base class

+ +PDF defines the interface that all PDF classes should respect. +The constructor requires the incoming beam species to be given: +even if used for a proton PDF, one needs to know whether the beam +is actually an antiproton. This is one of the reasons why Pythia +always defines two PDF objects in an event, one for each beam. + +

+Once a PDF object has been constructed, call it pdf, +the main method is pdf.xf( id, x, Q2), which returns +x*f_id(x, Q2), properly taking into account whether the beam +is an antiparticle or not. + +

+Whenever the xf member is called with a new flavour, x +or Q^2, the xfUpdate member is called to do the actual +updating. This routine may either update that particular flavour or all +flavours at this (x, Q^2) point. (In the latter case the saved +id value idSav should be set to 9.) The choice is +to be made by the producer of a given set, based on what he/she deems most +effective, given that sometimes only one flavour need be evaluated, and +about equally often all flavours are needed at the same x and +Q^2. Anyway, the latest value is always kept in memory. This is +the other reason why Pythia has one separate PDF +object for each beam, so that values at different x can be kept +in memory. + +

+Two further public methods are xfVal( id, x, Q2) and +xfSea( id, x, Q2). These are simple variants whereby +the quark distributions can be subdivided into a valence and a sea part. +If these are not directly accessible in the parametrization, onc can +make the simplified choices u_sea = ubar_sea, u_val = u_tot - u_sea, +and correspondingly for d. (Positivity will always be guaranteed +at output.) The xfUpdate method should also take care of +updating this information. + +

+A method setExtrapolate(bool) allows you to switch between +freezing parametrizations at the x and Q^2 boundaries +(false) or extrapolating them outside the boundaries +(true). This method is only implemented for the LHAPDF class +below. If you implement a new PDF you are free to use this method, but it +would be smarter to hardcode the desired limiting behaviour. + +

Derived classes

+ +There is only one pure virtual method, xfUpdate, that therefore +must be implemented in any derived class. Currently the list of such +classes is tiny: + +

+For protons: +

    +
  • GRV94L gives the GRV 94 L parametrization +Glu95.
  • +
  • CTEQ5L gives the CTEQ 5 L parametrization +Lai00.
  • +
  • LHAPDFinterface provides an interface to the +LHAPDF libraryWha05.
  • +
+The default is CTEQ 5L, which is the most recent of the two hardcoded sets. + +

+For charged leptons (e, mu, tau): +

    +
  • Lepton gives a QED parametrization Kle89. +In QED there are not so many ambiguities, so here one set should be +enough. On the other hand, there is the problem that the +lepton-inside-lepton pdf is integrably divergent for x -> 1, +which gives numerical problems. Like in PYTHIA 6, the pdf is therefore +made to vanish for x > 1 - 10^{-10}, and scaled up in the range +1 - 10^{-7} < x < 1 - 10^{-10} in such a way that the +total area under the pdf is preserved.
  • +
+ +There is another method, isSetup(), that returns the +base-class boolean variable isSet. This variable is +initially true, but could be set false if the +setup procedure of a PDF failed, e.g. if the user has chosen an unknown +PDF set. + +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/PhaseSpaceCuts.xml b/PYTHIA8/pythia8130/xmldoc/PhaseSpaceCuts.xml new file mode 100644 index 00000000000..424b22626d1 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/PhaseSpaceCuts.xml @@ -0,0 +1,120 @@ + + +

Phase Space Cuts

+ +PhaseSpace is base class for all hard-process phase-space +generators, either generic 2 -> 1 or 2 -> 2 ones, +or specialized ones like for elastic and diffractive scattering. + +

+In it, it is possible to constrain the kinematics of most processes. +(Exceptions are "soft physics", i.e. minimum bias, elastic and +diffractive processes. The Coulomb singularity for elastic scatterings, +if simulated, is handled separately.) +These constraints apply in the rest frame of the hard subprocess, and +topologies normally would be changed e.g. by subsequent showering +activity. The cross section of a process is adjusted to only +correspond to the allowed phase space. + +

+The more particles in the final state, the more cuts could be applied. +Here we have tried to remain with the useful minimum, however. More +generic possibilities could be handled by the +user hooks facility. + +

Cuts in all processes

+ + +The minimum invariant mass. + + + +The maximum invariant mass. +A value below mHatMin means there is no upper limit. + + +

Cuts in 2 -> 1 processes

+ +When a resonance id is produced, the +mMin(id)and +mMax(id) methods restrict the allowed mass range +of this resonance. Therefore the allowed range is chosen to be the +overlap of this range and the mHatMin to +mHatMax range above. Most resonances by default have no +upper mass limit, so effects mainly concern the lower limit. +Should there be no overlap between the two ranges then the process +will be switched off. + +

Cuts in 2 -> 2 processes

+ + +The minimum invariant pT. + + + +The maximum invariant pT. +A value below pTHatMin means there is no upper limit. + + + +Extra pT cut to avoid the divergences of some processes +in the limit pT -> 0. Specifically, if either or both +produced particles have a mass below pTHatMinDiverge +then pT is limited from below by the larger of +pTHatMin and pTHatMinDiverge. + + + +Allows masses to be selected according to Breit-Wigner shapes in +2 -> 2 processes, whenever particles have been declared +with a nonvanishing width above the threshold below. In those cases +also the limits below will be used for the mass selection. For +2 -> 1 processes the Breit-Wigner shape is part of the +cross section itself, and therefore always included. + + + +The minimum width a resonance must have for the mass to be dynamically +selected according to a Breit-Wigner shape, within the limits set below. +Only applies when useBreitWigners is on; else the nominal +mass value is always used. + + +

+For a particle with a Breit-Wigner shape selected, according to the +rules above and to the rules of the particle species itself, the +mMin(id) +and mMax(id) methods restrict the allowed mass range +of the particle, just like for the 2 -> 1 processes. + +

Cuts in 2 -> 3 processes

+ +Currently no further cuts have been introduced for 2 -> 3 +processes than those already available for 2 -> 2 ones. +A 2 -> 3 process in principle would allow to define a +separate pT range for each of the three particles (with some +correlations), but for now all three are restricted exactly the +same way by pTHatMin and pTHatMax. +As above, Breit-Wigner mass ranges can be restricted. + +

Documentation

+ + +Possibility to print information on the search for phase-space +coefficients that (in a multichannel approach) provides an analytical +upper envelope of the differential cross section, and the +corresponding upper estimate of the cross section. Of interest +for crosschecks by expert users only. + + + +Possibility to print information whenever the assumed maximum +differential cross section of a process is violated, i.e. when +the initial maximization procedure did not find the true maximum. +Also, should negative cross sections occur, print whenever a more +negative value is encountered. + + +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/ProcessSelection.xml b/PYTHIA8/pythia8130/xmldoc/ProcessSelection.xml new file mode 100644 index 00000000000..be82ba78330 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ProcessSelection.xml @@ -0,0 +1,130 @@ + + +

Process Selection

+ +There is no way PYTHIA could contain all processes of interest, +neither in terms of potential physics topics nor in terms of +high-multiplicity final states. What exists is a reasonably +complete setup of all 2 -> 1 and 2 -> 2 +processes within the Standard Model, plus some examples of +processes beyond that, again for low multiplicities. Combined with +the PYTHIA parton showers, this should be enough to get a flying +start in the study of many physics scenarios. +Other processes could be fed in via the +Les Houches Accord +or be implemented as a +Semi-Internal Process. +In the latter case the existing processes would act as obvious +templates. + +

+By default all processes are switched off. You should switch on +those you want to simulate. This may be done at two (occasionally +three) levels, either for each individual process or for a group of +processes. That is, a process is going to be generated either if its +own flag or its group flag is on. There is no built-in construction +to switch on a group and then switch off a few of its members. + +

+Each process is assigned an integer code. This code is not used in +the internal administration of events (so having the same code for +two completely different processes would not be a problem), but only +intended to allow a simpler user separation of different processes. +Also the process name is available, as a string. + +

+To ease navigation, the list of processes has been split into several +separate pages, by main topic. The classification is hopefully +intuitive, but by no means unambiguous. For instance, essentially +all processes involve QCD, so the "QCD processes" are the ones that +only involve QCD. (And also that is not completely true, once one +includes all that may happen in multiple interactions.) On these +separate pages also appear the settings that are completely local +to that particular process class, but not the ones that have a +broader usage. + +

QCD Processes

+ +QCD processes fall in two main categories: soft and hard. The soft ones +contain elastic, diffractive and "minimum-bias" events, together +covering the total cross section. Hard processea are the normal +2 -> 2 ones, including charm and bottom production. +
Reserved code range: 101 - 199. + +

Electroweak Processes

+ +Prompt-photon, gamma^*/Z^0 and W^+- production, +plus a few processes with t-channel boson exchange. +
Reserved code range: 201 - 299. + +

Onia Processes

+ +Colour singlet and octet production of charmonium and bottomonium. +
Reserved code range: 401 - 499 for charmonium and +501 - 599 for bottomonium. + +

Top Processes

+ +Top production, singly or doubly. +
Reserved code range: 601 - 699. + +

Fourth-Generation +Processes

+ +Production of hypothetical fourth-generation fermions. +
Reserved code range: 801 - 899. + +

Higgs Processes

+ +Higgs production, within or beyond the Standard Model. +See section on Left-Right-Symmetry processes for doubly charged Higgses. +
Reserved code range: 901 - 999 for a Standard Model Higgs +and 1001 - 1199 for MSSM Higgses. + +

SUSY Processes

+ +Production of supersymmetric particles, currently barely begun. +
Reserved code range: 1001 - 2999. (Whereof 1001 - 1199 +for Higgses; see above.) + +

New-Gauge-Boson +Processes

+ +Production of new gauge bosons such as Z' and W'. +
Reserved code range: 3001 - 3099. + +

Left-Right-Symmetry +Processes

+ +Production of righthanded Z_R and W_R bosons and of +doubly charged Higgses. +
Reserved code range: 3101 - 3199. + +

Leptoquark Processes

+ +Production of a simple scalar leptoquark state. +
Reserved code range: 3201 - 3299. + +

Compositeness Processes

+ +Production of excited fermion states and contact-interaction modification +to interactions between fermions (excluding technicolor; see below). +
Reserved code range: 4001 - 4099. + +

Technicolor Processes

+ +Production of technicolor particles and modifications of QCD processes +by technicolor interactions. Does not exist yet. +
Reserved code range: 4101 - 4199. + +

Extra-Dimensional +Processes

+ +A vast area, here represented by the production of a Randall-Sundrum +excited graviton state. +
Reserved code range: 5001 - 5099. + +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/ProgramFiles.xml b/PYTHIA8/pythia8130/xmldoc/ProgramFiles.xml new file mode 100644 index 00000000000..c2dcfb5566a --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ProgramFiles.xml @@ -0,0 +1,329 @@ + + +

Program Files

+ +The code is subdivided into a set of files, mainly by physics +task. Each file typically contains one main class, but often +with a few related helper classes that are not used elsewhere in +the program. Normally the files come in pairs. +
    +
  • A header file, .h in the include +subdirectory, where the public interface of the class is declared, +and inline methods are defined.
  • +
  • A source code file, .cc in the src +subdirectory, where most of the methods are implemented.
  • +
+During compilation, related dependency files, .d, and +compiled code, .o are created in the tmp +subdirectory. + +

+In part the .xml documentation files in the +xmldoc subdirectory have matching names, but the match +is broken by the desire to group topics more by user interaction than +internal operation. On these pages the function of the different code +files is summarized. Currently, each .xml file is also +translated into an .html one in the +htmldoc subdirectory, to allow easy viewing of the +contents in a web browser, and an .php one in +phpdoc, for more sophisticated interactivity +if that subdirectory is installed on a web server. + +

+Here is the current list of files, ordered alphabetically, with a brief +description of contents. + + +contains routines to analyze events. Currently it can do sphericity, +thrust, Lund/Jade/Durham jet clustering, and cone-jet finding. + + + +contains some basic facilities of general use: a random number +generator Rndm, a four-vector class Vec4, and a +histogram class Hist. + + + +contains information on all partons extracted from one of the two +beams. Defines modified parton distributions accordingly during the +showering and multiple interactions processing, thereby extending on +the one-particle-inclusive distributions defined by the previous class. +Finds the internal structure for a beam remnant. + + + +adds primordial kT to the set of hard subsystems, +and combines these subsystems with the two beam remnants to provide +the overall energy-momentum picture. Also ties together all the +colour lines into consistent singlets. + + + +provides a simple method to impose Bose-Einstein correlations on +pairs of identical mesons. + + + +contains the event record, which basically is a vector of particles. +This file also contains the Particle class, used by +Event. Pythia uses two Event +objects, one for the process-level record (process) and +one for the complete event (event). + + + +contains the classes for describing the fragmentation steps in +flavour and in longitudinal and transverse momentum. + + + +defines some containers of parton systems, for use in +the fragmentation routines. + + + +turns the parton-level event above into a set of outgoing particles, +by applying string fragmentation (with special treatment for low-mass +systems) and secondary decays, and optionally Bose-Einstein corrections. + + + +contains an interface to convert the PYTHIA 8 event record into the +HepMC format. The HepMCInterface.cc file is located in +the subdirectory hepmcinterface and is used to build a +separate libhepmcinterface library. + + + +is a simple container that gives access to some information on the +nature of the current process, such as Mandelstam variables. +Also contains a small database for errors and warnings encountered +during program execution. + + + +gives the possibility to feed in parton configurations for the +subsequent event generation. One base class is defined, with containers +for initialization and event information, that can be read from +Pythia. Derived classes allow for a few different cases. + + + +is a header file only, for a class derived from the above LesHouches +one, to be used for runtime interfacing to Fortran programs, such as +PYTHIA 6. + + + +is a header file only, with interfaces to the key LHAPDF routines, +as needed for a runtime interface. There is a file +lhapdfdummy/LHAPDFdummy.cc with matching dummy +implementations, however. This file is used to build a separate +liblhapdfdummy library, to be linked when the LHAPDF +library is not used, so as to avoid problems with undefined references. + + + +performs string fragmentation in cases where the colour singlet +subsystem mass is so small that one or at most two primary hadrons +should be produced from it. + + + +performs multiple parton-parton interactions. + + + +contains a database of all necessary particle data (masses, names, ..) +and decay channels. + + + +performs the decays of all normal unstable hadrons and leptons, i.e. +in mass up to and including b bbar systems. It is not +intended for decays of electroweak resonances, like Z^0. + + + +contains parton distribution functions for the proton and electron. +Currently very simple, with only two p parametrizations +and one e ditto available, but it is possible to link in +external sets. + + + +turns the (hard) process above into a complete set of partons, by +adding initial- and final-state radiation, multiple parton--parton +interactions, and beam remnants. + + + +selects a point in phase space for the hard-process generation, +optimized separately for each process to give improved Monte Carlo +efficiency. + + + +packages the information on a given subprocess, combining the +phase-space selection and cross-section evaluation machineries +with some statistics information. Also sets up the list of processes +to be studied in a run. + + + +handles the generation of the (hard) process that sets the character +of the event. This involves either using internally implemented +processes or linking to Les Houches information. The latter can +be by runtime interfaces or by reading in a file. This step also +includes resonance decays. + + + +is the main class, that administrates the whole event generation +process by making use of all the others classes. Objects of most +other classes reside (directly or indirectly) inside Pythia, +so only a Pythia object needs to be explicitly instantiated +and addressed by the user. + + + +is a header file only, with interfaces to the key PYTHIA 6 routines, +as needed for a runtime Les Houches interface to this program. + + + +is only a .h file, containing a typedef for +double precision complex numbers. + + + +is only a .h file, containing most of the Stdlib +headers used in PYTHIA 8, with using directives. It defines +M_PI if this is not already done. Also a few simple inline +methods: pow2(x), pow3(x), pow4(x) +and pow5(x) for small integer powers, and +sqrtpos(x) where a max(0., x) ensures that one +does not take the square root of a negative number. + + + +decays resonances as part of the hard-process stage, in many cases +(but not all) including angular correlations between the decay products. + + + +encodes some properties of resonances, in particular the dynamic +calculation of widths. + + + +contains a database of all flags, modes, parameters and words that +determine the performance of the generator. Initial values are obtained +from the contents of the .xml files, but these values can +then be changed by the user. + + + +contains the cross sections and matrix elements for production of +some particles in compositeness scenarios, specifically excited +fermions. + + + +contains the cross sections and matrix elements for electroweak +processes involving photons, Z^0's and W^+-'s. + + + +contains the cross sections and matrix elements for processes in +scenarios involving extra dimensions. + + + +contains the cross sections and matrix elements for Higgs production. + + + +contains the cross sections and matrix elements for particle production +in left-right-symmetry scenarios, specifically righthanded Z +and W bosons and doubly-charged Higgs bosons. + + + +contains the cross sections and matrix elements for leptoquark production. + + + +contains the cross sections and matrix elements for a Z'^0, +a W^+- and a horizontal gauge boson R^0. + + + +contains the cross sections and matrix elements for charmonium and +bottomonium production. + + + +contains the base class and derived classes for the evaluation of +different matrix elements. Also keeps track of allowed incoming +parton configurations and their cross sections, including parton +densities. In order to keep this file from becoming too big, actual +cross sections are found in several separate files of derived classes: +SigmaQCD, SigmaEW, SigmaOnia, +SigmaHiggs, SigmaSUSY, +SigmaNewGaugeBosons, SigmaLeftRightSym, +SigmaLeptoquark, SigmaCompositeness and +SigmaExtraDim. + + + +contains the cross sections and matrix elements for soft and hard +QCD processes. + + + +contains the cross sections and matrix elements for Supersymmetric +processes. + + + +contains parametrizations of total, elastic and diffractive hadronic +cross sections. + + + +performs spacelike initial-state transverse-momentum-ordered +shower evolution. + + + +contains the running alpha_strong, with Lambda +matching at flavour thresholds, the running alpha_em, +CKM mixing matrices, and a few other parameters such as +sin^2(theta_W). + + + +performs string fragmentation of a given set of partons. + + + +contains information on SUSY parameters and particle data as specified +by the SUSY Les Houches Accord. + + + +performs timelike final-state transverse-momentum-ordered +shower evolution. + + + +Provides a way for a user to study the event at a few intermediate +stages of evolution, to reject the event as a whole or to modify +its cross-section weight. + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/ProgramFlow.xml b/PYTHIA8/pythia8130/xmldoc/ProgramFlow.xml new file mode 100644 index 00000000000..72df478549e --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ProgramFlow.xml @@ -0,0 +1,492 @@ + + +

Program Flow

+ +Recall that, to first order, the event generation process can be +subdivided into three stages: +
    +
  1. Initialization.
  2. +
  3. The event loop.
  4. +
  5. Finishing.
  6. +
+This is reflected in how the top-level Pythia class should +be used in the user-supplied main program, further outlined in the +following. Since the nature of the run is defined at the initialization +stage, this is where most of the PYTHIA user code has to be written. +So as not to confuse the reader unduly, the description of initialization +options has been subdivided into what would normally be used and what is +intended for more special applications. + +

Initialization - normal usage

+ +
    + +
  1. +Already at the top of the main program file, you need to include the proper +header file +
    +    #include "Pythia.h"
    +
    +To simplify typing, it also makes sense to declare +
    +    using namespace Pythia8; 
    +
    +
  2. + +

    +

  3. +The first step is to create a generator object, +e.g. with +
    +     Pythia pythia;
    +
    +It is this object that we will use from now on. Normally a run +will only contain one Pythia object. (Hypothetically +you could use several Pythia objects sequentially, +but if done in parallel the static character of some +program elements is likely not to give the desired behaviour.)
    +By default all output from Pythia will be on the +cout stream, but the list methods below do +allow output to alternative streams or files (by an optional +last argument, a reference to an ostream, usually not +explicitly written out here). +
  4. + +

    +

  5. +You next want to set up the character of the run. +The pages under the "Setup Run Tasks" heading in the index +describe all the options available (with some very few exceptions, +found on the other pages). +The default values and your modifications are stored in two databases, +one for generic settings +and one for particle data. +Both of these are static classes, and are +initialized with their default values by the Pythia +constructor. The default values can then be changed, primarily +by one of the two ways below, or by a combination of them.
    + +

    +a) You can use the dedicated methods of each class to change the +database default values to fit the needs of your current run. However, +the +

    +    pythia.readString(string);
    +
    +method provides a covenient uniform interface to all of them. +The information in the string is case-insensitive, but upper- and +lowercase can be combined for clarity. The rules are that
    +(i) if the first nonblank character of the string is a letter +it is assumed to contain a setting, and is sent on to +pythia.settings.readString(string);
    +(ii) if instead the string begins with a digit it is assumed to +contain particle data updates, and so sent on to +pythia.particleData.readString(string);
    +(iii) if none of the above, the string is assumed to be a comment, +i.e. nothing will be done.
    +In the former two cases, a warning is issued whenever a string +cannot be recognized (maybe because of a spelling mistake), +unless an optional second argument false is used to +switch off warnings.
    +Some examples would be +
    +    pythia.readString("TimeShower:pTmin = 1.0");
    +    pythia.readString("111:mayDecay = false");
    +
    +The readString(string) method is intended primarily for +a few changes. It can also be useful if you want to construct a +parser of input files that contain commands to several different +libraries.
    + +

    +b) You can read in a file containing a list of those variables +you want to see changed, with a +

    +    pythia.readFile(fileName);
    +
    +Each line in this file with be processes by the +readString(string) method introduced above. You can thus +freely mix comment lines and lines handed on to Settings +or to ParticleDataTable. +Again, an optional second argument false allows +you to switch off warning messages for unknown variables.
    +This approach is better suited for more extensive changes than a direct +usage of readString(string), and can also avoid having to +recompile and relink your main program between runs. +
  6. + +

    +

  7. +Next comes the initialization stage, where all +remaining details of the generation are to be specified. The +init(...) method allows a few different input formats, +so you can pick the one convenient for you: + +

    +a) pythia.init( idA, idB, eCM);
    +lets you specify the identities and the CM energy of the two incoming +beam particles, with A (B) assumed moving in the +z (-z) +direction. + +

    +b) pythia.init( idA, idB, eA, eB);
    +is similar, but the two beam energies can be different, so the +collisions do not occur in the CM frame. If one of the beam energies +is below the particle mass you obtain a fixed-target topology. + +

    +c) pythia.init( idA, idB, pxA, pyA, pzA, pxB, pyB, pzB);
    +is similar, but here you provide the three-momenta +(p_x, p_y, p_z) of the two incoming particles, +to allow for arbitrary beam directions. + +

    +d) pythia.init(fileName);
    +assumes a file in the Les Houches +Event File format Alw06 is provided. + +

    +e) pythia.init();
    +with no arguments will read the beam parameters from the +Main +group of variables, which provides you with the same possibilities as +the above options a, b, c and d. If you don't change any of those you will +default to proton-proton collisions at 14 TeV, i.e. the nominal LHC +values. + +

    +f) pythia.init( LHAup*);
    +assumes Les Houches Accord +Boo01 initialization and event information is available +in an LHAup class object, and that a pointer to this object +is handed in. + +

    +

  8. +If you want to have a list of the generator and particle data used, +either only what has been changed or everything, you can use +
    +    pythia.settings.listChanged();
    +    pythia.settings.listAll();
    +    pythia.particleData.listChanged(); 
    +    pythia.particleData.listAll(); 
    +
    +
  9. + +
+ +

The event loop

+ +
    + +
  1. +Inside the event generation loop you generate the +next event using the next() method, +
    +    pythia.next();
    +
    +This method takes no arguments; everything has already been specified. +It does return a bool value, however, false when the +generation failed. This can be a "programmed death" when the +supply of input parton-level configurations on file is exhausted, +but also caused by a failure of Pythia to generate an event, +or that an event was generated but something strange was detected +in it. It makes sense to allow a few false +values before a run is aborted, so long as the related faulty +events are skipped. +
  2. + +

    +

  3. +The generated event is now stored in the event +object, of type Event, +which is a public member of pythia. You therefore have +access to all the tools described on the pages under the "Study Output" +header in the index. For instance, an event can be listed with +pythia.event.list(), the identity of the i'th +particle is given by +pythia.event[i].id(), and so on.
    +The hard process - roughly the information normally stored in the +Les Houches Accord event record - is available as a second object, +process, also of type Event.
    +A third public object is +info, which offers +a set of one-of-a kind pieces of information about the most recent +event. +
  4. + +
+ +

Finishing

+ +
    + +
  1. At the end of the generation process, you can call +
    +    pythia.statistics(); 
    +
    +to get some run statistics, on cross sections and the number of errors +and warnings encountered. With optional argument true +also further statistics is printed. Currently this means the number of +different subprocesses generated in the multiple-interactions +framework. +
  2. + +
+ +

Advanced usage, mainly for initialization

+ +A) Necessary data are automatically loaded when you use the +default PYTHIA installation directory structure and run the main +programs in the examples subdirectory. However, in the +general case, you must provide the path to the .xml files, +originally stored in the xmldoc directory, where default +settings and particle data are found. This can be done in two ways. + +
    + +
  1. +You can set the environment variable PYTHIA8DATA to +contain the location of the xmldoc directory. In the +csh and tcsh shells this could e.g. be +
    +     setenv PYTHIA8DATA /home/myname/pythia81xx/xmldoc
    +
    +while in other shells it could be +
    +     export PYTHIA8DATA=/home/myname/pythia81xx/xmldoc
    +
    +where xx is the subversion number.
    +Recall that environment variables set locally are only defined in the +current instance of the shell. The above lines should go into your +.cshrc and .bashrc files, respectively, +if you want a more permanant assignment. +
  2. + +

    +

  3. +You can provide the path as argument to the Pythia +constructor, e.g. +
    +     Pythia pythia("/home/myname/pythia81xx/xmldoc");
    +
    +
  4. +
+where again xx is the subversion number.
+When PYTHIA8DATA is set it takes precedence, else +the path in the constructor is used, else one defaults to the +../xmldoc directory. + +

+B) You can override the default behaviour of PYTHIA not only by the +settings and particle data, but also by replacing some of the +PYTHIA standard routines by ones of your own. Of course, this is only +possible if your routines fit into the general PYTHIA framework. +Therefore they must be coded according to the the rules relevant +in each case, as a derived class of a PYTHIA base class, and a pointer +to such an object must be handed in by one of the methods below. +These calls must be made before the pythia.init(...) call. + +

    + +
  1. +If you are not satisfied with the list of parton density functions that +are implemented internally or available via the LHAPDF interface +(see the PDF Selection page), you +can suppy your own by a call to the setPDFPtr(...) method +
    +      pythia.setPDFptr( pdfAPtr, pdfBPtr); 
    +
    +where pdfAPtr and pdfBPtr are pointers to +two Pythia PDF +objects. Note that pdfAPtr and pdfBPtr +cannot point to the same object; even if the PDF set is the same, +two copies are needed to keep track of two separate sets of x +and density values.
    +If you further wish to use separate PDF's for the hard process of an +event than the ones being used for everything else, the extended form +
    +      pythia.setPDFptr( pdfAPtr, pdfBPtr, pdfHardAPtr, pdfHardBPtr); 
    +
    +allows you to specify those separately, and then the first two sets +would only be used for the showers and for multiple interactions. +
  2. + +

    +

  3. +If you want to perform some particle decays with an +external generator, you can call the setDecayPtr(...) +method +
    +      pythia.setDecayPtr( decayHandlePtr, particles);
    +
    +where the decayHandlePtr derives from the +DecayHandler base +class and particles is a vector of particle codes to be +handled. +
  4. + +

    +

  5. +If you want to use an external random number generator, +you can call the setRndmEnginePtr(...) method +
    +      pythia.setRndmEnginePtr( rndmEnginePtr); 
    +
    +where rndmEnginePtr derives from the +RndmEngine base class. +The Pythia default random number generator is perfectly +good, so this is only intended for consistency in bigger frameworks. +
  6. + +

    +

  7. +If you want to interrupt the evolution at various stages, +to interrogate the event and possibly veto it, or you want to +reweight the cross section, you can use +
    +      pythia.setUserHooksPtr( userHooksPtr); 
    +
    +where userHooksPtr derives from the +UserHooks base class. +
  8. + +

    +

  9. +If you want to use your own parametrization of beam momentum spread and +interaction vertex, rather than the provided simple Gaussian +parametrization (off by default), you can call +
    +      pythia.setBeamShapePtr( beamShapePtr); 
    +
    +where beamShapePtr derives from the +BeamShape base class. +
  10. + +

    +

  11. +If you want to implement a cross section of your own, but still make use +of the built-in phase space selection machinery, you can use +
    +      pythia.setSigmaPtr( sigmaPtr);
    +
    +where sigmaPtr of type SigmaProcess* is an +instance of a class derived from one of the Sigma1Process, +Sigma2Process and Sigma3Process base classes +in their turn derived from +SigmaProcess. +This call can be used repeatedly to hand in several different processes. +
  12. + +

    +

  13. +If your cross section contains the production of a new resonance +with known analytical expression for all the relevant partial widths, +you can make this resonance available to the program with +
    +      pythia.setResonancePtr( resonancePtr);
    +
    +where resonancePtr of type ResonanceWidths* +is an instance of a class derived from the +ResonanceWidths +base class. In addition you need to add the particle to the normal +particle and decay database. +This procedure can be used repeatedly to hand in several different +resonances. +
  14. + +

    +

  15. +If you are a real expert and want to replace the PYTHIA initial- and +final-state showers, you can use +
    +      pythia.setShowerPtr( timesDecPtr, timesPtr, spacePtr);
    +
    +where timesDecPtr and timesPtr +derive from the TimeShower base class, and +spacePtr from SpaceShower +(further instructions). +
  16. + +
+ +

+C) Some comments on collecting several tasks in the same run. +

    + +
  1. +PYTHIA has not been written for threadsafe execution. As a rule, you +should not have more than one Pythia object in an executable +at any time. For multicore processors, if you want to use all cores, +the most efficient way presumably is to start correspondingly many jobs, +with different random number seeds, and add the statistics at the end. + +

    +In some cases it is possible to use more than one Pythia +object. The key example would be the simultaneous generation of signal +and pileup events, see main19.cc. Here all signal processes +must be switched on before the first initialization, and then switched +off and replaced by the background ones before the second initialization. +Also most other settings can be changed consistently in between the two +initializations, but in a few cases the last value will be used. Particle +data is always based on the latest information. As a rule, however, it is +safer to use two separate runs to store events on disk, in two separate +files, and mix afterwards. +

  2. + +

    +

  3. +When time is not an issue, it may be that you want to perform several +separate subruns sequentially inside a run, e.g. to combine results for +several kinematical regions or to compare results for some different +tunes of the underlying event. One way to go is to create and destroy a +pythia object once for each subrun, in which case they are +completely separate. You can also use the same pythia object, +only doing a new init(...) call for each subrun. In that +case, the settings and particle databases remain as they were in the +previous subrun, only affected by the specific changes you introduced in +the meantime. You can put those changes in the main program, with +pythia.readString(string), using your own logic to decide +which ones to execute in which subrun. A corresponding possibility +exists with pythia.readFile(fileName, subrun), which +as second argument can take a non-negative subrun number. (Or, +alternatively use the longer form +pythia.readFile(fileName, warn, subrun).) Then only those +sections of the file before any Main:subrun = ... line +or with matching subrun number will be read. That is, the +file could have a structure like +
    +    ( lines always read, i.e. "default values" always (re)set )
    +    Main:subrun = 1
    +    ( lines only read with readFile(fileName, 1) )
    +    Main:subrun = 2
    +    ( lines only read with readFile(fileName, 2) )
    +
    +Both of these possibilities are illustrated in main08.cc. +
  4. + +

    +

  5. +When working with Les Houches Event Files, it may well be that your +intended input event sample is spread over several files, that you all +want to turn into complete events in one and the same run. There is no +problem with looping over several subruns, where each new subrun +is initialized with a new file. However, in that case you will do +a complete re-initialization each time around. If you want to avoid +this, note that there is an optional second argument for LHEF +initialization: pythia.init(fileName, skipInit). +Alternatively, the tag Main:LHEFskipInit can be put +in a file of commands to obtain the same effect. +Here skipInit defaults to false, +but if set true then the new file will be simulated +with the same initialization data as already set in a previous +pythia.init(...) call. The burden rests on you to ensure +that this is indeed correct, e.g. that the two event samples have not +been generated for different beam energies. +
  6. + +
+ +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/QCDProcesses.xml b/PYTHIA8/pythia8130/xmldoc/QCDProcesses.xml new file mode 100644 index 00000000000..a55e21d1474 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/QCDProcesses.xml @@ -0,0 +1,164 @@ + + +

QCD Processes

+ +This section is subdivided into soft and hard QCD processes, with +open charm and bottom production set aside as a special part of the +latter. + +

Soft QCD processes

+ +As a rule, the processes in this class should not be mixed with +the simulation of other processes. All by themselves, they are +intended to represent the total cross section of hadron collisions, +with the exception of the "rare processes" that one wishes to study +separately. In particular, jet physics at all scales occurs as part +of the minimum-bias description. + +

+We here use the "minimum bias" expression as a shorthand for +inelastic, nondiffractive events. Strictly speaking, "minimum bias" +represents an experimental procedure of accepting "everything", with +some non-universal cuts to exclude elastic and diffractive topologies. +In practice, the experimental mimimum-bias sample may then contain +some contamination of what is in PYTHIA classified as diffractive, +especially (high-mass) double diffractive. + +

+Some options to modify these cross sections, and especially to include +Coulomb corrections to the elastic cross section, are found on the +Total Cross Sections page. + + +Common switch for the group of all soft QCD processes, +as listed separately in the following. + + + +Minimum-bias events, based on an eikonalized description of all the +hard QCD processes, so includes them in combinationation with +low-pT events. Code 101.
+Since the current description is handled by the multiple-interactions +machinery as part of the parton-level processing, no hard process at +all is defined at the process-level part of the event generation. +Fortunately, in this case a special +codeSub() +method provides information on the first, i.e. hardest, subprocess +selected by the multiple-interactions machinery. + +
+ + +Elastic scattering A B -> A B. +Code 102. + + + +Single diffractive scattering A B -> X B and +A B -> A X. +Codes 103 and 104. + + + +Double diffractive scattering A B -> X_1 X_2. +Code 105. + + +

Hard QCD processes

+ +This group contains the processes for QCD jet production above +some minimum pT threshold. The pT_min cut cannot be put +too low, or else unreasonably large jet cross sections will be obtained. +An eikonalized description, intended to be valid at all pT, +is included as part of the multiple-interactions framework, e.g. in +SoftQCD:minBias above. + + +Common switch for the group of all hard QCD processes, +as listed separately in the following. + + + +Scatterings g g -> g g. +Code 111. + + + +Scatterings g g -> q qbar, where q by default +is a light quark (u, d, s) (see below). +Code 112. + + + +Scatterings q g -> q g and qbar g -> qbar g. +Code 113. + + + +Scatterings q q' -> q q', q qbar' -> q qbar', +qbar qbar' -> qbar qbar', where q' and q +may agree, but the outgoing flavours equals the incoming ones +Code 114. + + + +Scatterings q qbar -> g g. +Code 115. + + + +Scatterings q qbar -> q' qbar', where q' +by default is a light quark (u, d, s) (see below). +Code 116. + + + +Number of allowed outgoing new quark flavours in the above +g g -> q qbar and q qbar -> q' qbar' processes, +where quarks are treated as massless in the matrix-element expressions +(but correctly in the phase space). It is thus assumed that c cbar +and b bbar are added separately with masses taken into account, +using the processes below. A change to 4 would also include c cbar +in the massless approximation, etc. In order to avoid doublecounting +the processes below should then not be used simultaneously. + + +

Hard QCD processes: heavy-flavour subset

+ +These processes form a natural part of the above class, but can +also be generated separately. Formally the heavy-quark mass makes +these matrix elements finite in the pT -> 0 limit, but at +high energies one may still question the validity of the expressions +at low pT values, like for the other hard-QCD processes. +Also as above, an eikonalized description, intended to be valid at all +pT, is included as part of the multiple-interactions framework. +
Note that the processes below only represent the "tip of the iceberg" +of charm and bottom production at high energies, where flavour excitation +and shower branchings provide major additional sources. All these sources +come together in the descriptions offered by SoftQCD:minBias +and HardQCD:all. + + +Scatterings g g -> c cbar. +Code 121. + + + +Scatterings q qbar -> c cbar. +Code 122. + + + +Scatterings g g -> b bbar. +Code 123. + + + +Scatterings q qbar -> b bbar. +Code 124. + + +
+ + + diff --git a/PYTHIA8/pythia8130/xmldoc/RandomNumberSeed.xml b/PYTHIA8/pythia8130/xmldoc/RandomNumberSeed.xml new file mode 100644 index 00000000000..eac5d0ff958 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/RandomNumberSeed.xml @@ -0,0 +1,30 @@ + + +

Random-Number Seed

+ +The seed of the random number generator can be set as follows: + + +Indicates whether a user-set seed should be used every time the +Pythia::init routine is called. If off, the random number +generator is initialized with its default seed at the beginning +of the run, and never again. If on, each new Pythia::init +call (should several be made in the same run) results in the random +number being re-initialized, thereby possibly starting over with the +same sequence, if you do not watch out. + + + +The seed to be used, if setSeed is on.
+A negative value gives the default seed,
+a value 0 gives a random seed based on the time, and
+a value between 1 and 900,000,000 a unique different random number +sequence. +
+ +

+For more on random numbers see here. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/RandomNumbers.xml b/PYTHIA8/pythia8130/xmldoc/RandomNumbers.xml new file mode 100644 index 00000000000..ff3af3d9f7d --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/RandomNumbers.xml @@ -0,0 +1,72 @@ + + +

Random Numbers

+ +This page describes the random-number generator in PYTHIA and +how it can be replaced by an external one. + +

Internal random numbers

+ +The Rndm class generates random numbers, using the +Marsaglia-Zaman-Tsang algorithm Mar90. It is purely static, +i.e. only exists in one copy, so that one cannot run several copies, +each with the same random number sequence, by mistake. + +

+Random numbers R uniformly distributed in +0 < R < 1 are obtained with +

+   Rndm::flat();
+
+There are also methods to generate according to an exponential, to +x * exp(-x), to a Gaussian, or picked among a set of +possibilites, which make use of flat(). + +

+If the random number generator is not initialized before, it will be +so the first time it is asked to generate a random number, and then +with the default seed, 19780503. You can initialize, or reinitialize, +with your own choice of seed with a +

+   Rndm::init(seed);
+
+Here values 0 < seed < 900 000 000 gives so many +different random number sequences, while seed = 0 will call +the Stdlib time(0) function to provide a "random" +seed, and seed < 0 will revert back to +the default seed. + +

+The Pythia class defines a +flag and a mode, that allows the seed to be set in +the Pythia::init call. That would be the standard way for a +user to pick the random number sequence in a run. + +

External random numbers

+ +RndmEngine is a base class for the external handling of +random-number generation. The user-written derived class is called +if a pointer to it has been handed in with the +pythia.rndmEnginePtr() method. Since the default +Marsaglia-Zaman-Tsang algorithm is quite good, chances are that any +replacement would be a step down, but this may still be required by +consistency with other program elements in big experimental frameworks. + +

+There is only one pure virtual method in RndmEngine, to +generate one random number flat in the range between 0 and 1: +

+  virtual double flat() = 0;
+
+Note that methods for initialization are not provided in the base +class, in part since input parameters may be specific to the generator +used, in part since initialization can as well be taken care of +externally to the Pythia code. + +

+An example illustrating how to run with an external random number +generator is provided in main24.cc. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/RandomNumbersAndChecks.xml b/PYTHIA8/pythia8130/xmldoc/RandomNumbersAndChecks.xml new file mode 100644 index 00000000000..1b662b1785d --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/RandomNumbersAndChecks.xml @@ -0,0 +1,30 @@ + + +

Random-Numbers Seed

+ +The seed of the random number generator can be set as follows: + + +Indicates whether a user-set seed should be used every time the +Pythia::init routine is called. If off, the random number +generator is initialized with its default seed at the beginning +of the run, and never again. If on, each new Pythia::init +call (should several be made in the same run) results in the random +number being re-initialized, thereby possibly starting over with the +same sequence, if you do not watch out. + + + +The seed to be used, if setSeed is on.
+A negative value gives the default seed,
+a value 0 gives a random seed based on the time, and
+a value between 1 and 900,000,000 a unique different random number +sequence. +
+ +

+See further here. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/ResonanceDecays.xml b/PYTHIA8/pythia8130/xmldoc/ResonanceDecays.xml new file mode 100644 index 00000000000..3906deff1e7 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/ResonanceDecays.xml @@ -0,0 +1,316 @@ + + +

Resonance Decays

+ +The ResonanceDecays class performs the sequential decays of +all resonances formed in the hard process. Note the important distinction +between "resonances" and other "particles" made in PYTHIA. +
    +
  • +The list of resonances contains gamma^*/Z^0, W^+-, top, +the Higgs, and essentially all new particles of Beyond-the-Standard-Model +physics: further Higgses, sfermions, gauginos, techniparticles, and so on. +The partial widths to different decay channels are perturbatively +calculable, given the parameters of the respective model, and branching +ratios may be allowed to vary across a (reasonably broad) resonance peak. +Usually resonances are short-lived, and therefore it makes sense to consider +their decays immediately after the primary hard process has been set up. +Furthermore, in several cases the decay angular distributions are encoded +as part of the specific process, e.g. the W decays differently in +f fbar -> W^+-, f fbar -> W^+ W^- and +h^0 -> W^+ W^- . All of these particles are (in PYTHIA) only +produced as part of the hard process itself, i.e. they are not produced +in showers or hadronization processes. Therefore the restriction to +specific decay channels can be consistently taken into account as a +corresponding reduction in the cross section of a process. Finally, note +that all of these resonances have an on-shell mass above 20 GeV, with the +exception of some hypothetical weakly interacting and stable particles +such as the gravitino. +
  • +
  • +The other particles include normal hadrons and the Standard-Model leptons, +including the tau^+-. These can be produced in the normal +hadronization and decay description, which involve unknown nonperturbative +parameters and multistep chains that cannot be predicted beforehand: +a hard process like g g -> g g can develop a shower with a +g -> b bbar branching, where the b hadronizes to a +B^0bar that oscillates to a B^0 that decays to a +tau^+. Therefore any change of branching ratios - most of which +are determined from data rather than from first principles anyway - +will not be taken into account in the cross section of a process. +Exceptions exist, but most particles in this class are made to decay +isotropically. Finally, note that all of these particles have a mass +below 20 GeV. +
  • +
+ +There is one ambiguous case in this classification, namely the photon. +The gamma^*/Z^0 combination contains a low-mass peak when +produced in a hard process. On the other hand, photons can participate +in shower evolution, and therefore a photon originally assumed +massless can be assigned an arbitrarily high mass when it is allowed +to branch into a fermion pair. In some cases this could lead to +doublecounting, e.g. between processes such as +f fbar -> (gamma^*/Z^0) (gamma^*/Z^0), +f fbar -> (gamma^*/Z^0) gamma and +f fbar -> gamma gamma. Here it make sense to limit the +lower mass allowed for the gamma^*/Z^0 combination, +in 23:mMin, to be the same as the upper limit allowed +for an off-shell photon in the shower evolution, in +TimeShower:mMaxGamma. By default this matching is done +at 10 GeV. + +

+In spite of the above-mentioned differences, the resonances and the +other particles are all stored in one common +particle data table, so as to offer a +uniform interface to setting and +getting properties such as name, mass, charge and decay modes, +also for the particle properties +in the event record. Some methods are specific to resonances, however, +in particular for the calculation of partial widths and thereby of +branching ratio. For resonances these can be calculated dynamically, +set up at initialization for the nominal mass and then updated to the +current mass when these are picked according to a Breit-Wigner resonance +shape. + +

Resonance Decays and Cross Sections

+ +As already hinted above, you have the possibility to set the allowed +decay channels of resonances, see +Particle Data Scheme description. +For instance, if you study the process q qbar -> H^0 Z^0 +you could specify that the Z^0 should decay only to +lepton pairs, the H^0 only to W^+ W^-, the +W^+ only to a muon and a neutrino, while the W^- +can decay to anything. Unfortunately there are limits to the +flexibility: you cannot set a resonance to have different properties +in different places of a process, e.g. if instead +H^0 -> Z^0 Z^0 in the above process then the three +Z^0's would all obey the same rules. + +

+The restrictions on the allowed final states of a process is directly +reflected in the cross section of it. That is, if some final states +are excluded then the cross section is reduced accordingly. Such +restrictions are built up recursively in cases of sequential decay +chains. The restrictions are also reflected in the compositions of +those events that actually do get to be generated. For instance, +the relative rates of H^0 -> W^+ W^- and +H^0 -> Z^0 Z^0 are shifted when the allowed sets of +W^+- and Z^0 decay channels are changed. + +

+We remind that only those particles that Pythia treat as resonances +enjoy this property, and only those that are considered as part of the +hard process and its assocaited resonance decays. + +

+There is one key restriction on resonances: + +Minimal allowed width of a resonance, in GeV. If the width falls below +this number the resonance is considered stable and will not be allowed +to decay. This is mainly intended as a technical parameter, to avoid +disasters in cases where no open decay channels exists at all. It could +be used for real-life decisions as well, however, but then typically +would have to be much bigger than the default value. Special caution +would be needed if coloured resonance particles were made stable, since +the program would not necessarily know how to hadronize them, and +therefore fail at that stage. + + +

Special properties and methods for resonances

+ +The method ParticleDataTable::isResonance(id) allows you to +query whether a given particle species is considered a resonance or not. +You can also change the default value of this flag in the normal way, +e.g. pythia.readString("id:isResonance = true"). + +

+An option with a forced width can be set with the +id:doForceWidth flag as above, and queried with +ParticleDataTable::doForceWidth(id). It is by default +off, and should normally so remain. If switched +on then the width stored in id:mWidth is +strictly used to describe the Breit-Wigner of the resonance. This is +unlike the normal behaviour of standard resonances such as the +Z^0, W^+-, t or h^0, which have +explicit decay-widths formulae encoded, in classes derived from the +ResonanceWidths +base class. These formulae are used, e.g., to derive all the Higgs partial +widths as a function of the Higgs mass you choose, and at initialization +overwrites the existing total width value. The reason for forcing the +width to another value specified by you would normally more have to do +with experimental issues than with physics ones, e.g. how sensitive your +detector would be to changes in the Higgs width by a factor of two. +A warning is that such a rescaling could modify the cross section of +a process correspondingly for some processes, while leaving it +(essentially) unchanged for others (as would seem most logical), +depending on how these were encoded. A further warning is that, +if you use this facility for Z^0 or Z'^0 with +gamma^*/Z^0 or gamma^*/Z^0/Z'^0 interference on, +then also the handling of this interference is questionable. +So, if you need to use the width-rescaling option, be extremely cautios. + +

+If a resonance does not have a class of its own, with hardcoded equations +for all relevant partial widths, then a simpler object will be created +at initialization. This object will take the total width and branching +ratios as is (with the optional variations explained in the next section), +and thus the rescaling approach brings no further freedom. + +

+Mainly for internal usage, the ParticleDataTable contain +some special methods that are only meaningful for resonances: +

    +
  • resInit(...) to initialize a resonance, possibly +including a recalculation of the nominal width to match the nominal +mass;
  • +
  • resWidth(...) to calculate the partial and total widths +at the currently selected mass;
  • +
  • resWidthOpen(...) to calculate the partial and total +widths of those channels left open by user switches, at the currently +selected mass;
  • +
  • resWidthStore(...) to calculate the partial and total +widths of those channels left open by user switches, at the currently +selected mass, and store those as input for a subsequent selection of +decay channel;
  • +
  • resOpenFrac(...) to return the fraction of the total +width that is open by the decay channel selection made by users (based on +the choice of onMode +for the various decay channels, recursively calculated for sequential +decays);
  • +
  • resWidthRescaleFactor(...) returns the factor by which +the internally calculated PYTHIA width has to be rescaled to give the +user-enforced width;
  • +
  • resWidthChan(...) to return the width for one particular +channel (currently only used for Higgs decays, to obtain instate coupling +from outstate width).
  • +
+These methods actually provide an interface to the classes derived from +the ResonanceWidths base class, to describe various +resonances. + +

Modes for Matrix Element Processing

+ +The meMode() value for a decay mode is used to specify +nonisotropic decays or the conversion of +a parton list into a set of hadrons in some channels of normal +particles. For resonances it can also take a third function, namely +to describe how the branching ratios and widths of a resonance should +be rescaled as a function of the current mass of the decaying resonance. +The rules are especially useful when new channels are added to an +existing particle, or a completely new resonance added. + +
    +
  • 0 : channels for which hardcoded partial-width expressions are +expected to exist in the derived class of the respective resonance. +Should no such code exist then the partial width defaults to zero. +
  • +
  • 1 - 99 : same as 0, but normally not used for resonances.
  • +
  • 100 : calculate the partial width of the channel from its stored +branching ratio times the stored total width. This value remains unchanged +when the resonance fluctuates in mass. Specifically there are no +threshold corrections. That is, if the resonance fluctuates down in +mass, to below the nominal threshold, it is assumed that one of the +daughters could also fluctuate down to keep the channel open. (If not, +there may be problems later on.) +
  • +
  • 101 : calculate the partial width of the channel from its stored +branching ratio times the stored total width. Multiply by a step threshold, +i.e. the channel is switched off when the sum of the daughter on-shell +masses is above the current mother mass.
  • +
  • 102 : calculate the partial width of the channel from its stored +branching ratio times the stored total width. Multiply by a smooth +threshold factor +beta = sqrt( (1 - m_1^2/m_2 - m_2^2/m^2)^2 - 4 m_1^2 m_2^2/m^4) +for two-body decays and sqrt(1 - Sum_i m_i / m) for multibody +ones. The former correctly encodes the size of the phase space but +misses out on any nontrivial matrix-element behaviour, while the latter +obviously is a very crude simplification of the correct phase-space +expression. Specifically, it is thereby assumed that the stored branching +ratio and total width did not take into account such a factor.
  • +
  • 103 : use the same kind of behaviour and threshold factor as for +102 above, but assume that such a threshold factor has been used when +the default branching ratio and total width were calculated, so that one +should additionally divide by the on-shell threshold factor. Specifically, +this will give back the stored branching ratios for on-shell mass, +unlike the 102 option. To avoid division by zero, or in general +unreasonably big rescaling factors, a lower limit +minThreshold (see below) on the value of the on-shell +threshold factor is imposed. (In cases where a big rescaling is +intentional, code 102 would be more appropriate.)
  • +
+ + +Used uniquely for meMode = 103 to set the minimal value +assumed for the threshold factor, +sqrt( (1 - m_1^2/m_2 - m_2^2/m^2)^2 - 4 m_1^2 m_2^2/m^4) +for two-body decays and sqrt(1 - Sum_i m_i / m) for multibody +ones. Thus the inverse of this number sets an upper limit for how +much the partial width of a channel can increase from the on-shell +value to the value for asymptotically large resonance masses. Is mainly +intended as a safety measure, to avoid unintentionally large rescalings. + + +

+All of these meMode's may coexist for the same resonance. +This would be the case e.g. if you want to add a few new channels to an +already existing resonance, where the old partial widths come hardcoded +while the new ones are read in from an external file. The typical example +would be an MSSM Higgs sector, where partial widths to SM particles are +already encoded, meMode = 0, while decay rates to sparticles +are read in from some external calculation and maybe would be best +approximated by using meMode = 103. Indeed the default +particle table in PYTHIA uses 103 for all channels that are expected +to be provided by external input. + +

+Some further clarification may be useful. At initialization the existing +total width and on-shell branching ratios will be updated. For channels +with meMode < 100 the originally stored branching ratios +are irrelevant, since the existing code will anyway be used to calculate +the partial widths from scratch. For channels with meMode = 100 +or bigger, instead the stored branching ratio is used together with the +originally stored total width to define the correct on-shell partial width. +The sum of partial widths then gives the new total width, and from there +new branching ratios are defined. + +

+In these operations the original sum of branching ratios need not be +normalized to unity. For instance, you may at input have a stored total +width of 1 GeV and a sum of branching ratios of 2. After initialization +the width will then have been changed to 2 GeV and the sum of branching +ratios rescaled to unity. This might happen e.g. if you add a few channels +to an existing resonance, without changing the branching ratios of the +existing channels or the total width of the resonance. + +

+In order to simulate the Breit-Wigner shape correctly, it is important +that all channels that contribute to the total width are included in the +above operations. This must be kept separate from the issue of which +channels you want to have switched on for a particular study, to be +considered next. + +

+ +In the event-generation process, when an off-shell resonance mass has been +selected, the width and branching ratios are re-evaluated for this new mass. +At this stage also the effects of restrictions on allowed decay modes are +taken into account, as set by the onMode switch for each +separate decay channel. Thus a channel may be on or off, with different +choices of open channels between the particle and its antiparticle. +In addition, even when a channel is on, the decay may be into another +resonance with its selection of allowed channels. It is these kinds of +restrictions that lead to the Gamma_out possibly being +smaller than Gamma_tot. As a reminder, the Breit-Wigner for +decays behaves like Gamma_out / ((s - m^2)^2 + s * Gamma_tot^2), +where the width in the numerator is only to those channels being studied, +but the one in the denominator to all channels of the particle. These +ever-changing numbers are not directly visible to the user, but are only +stored in a work area. + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/SUSYLesHouchesAccord.xml b/PYTHIA8/pythia8130/xmldoc/SUSYLesHouchesAccord.xml new file mode 100644 index 00000000000..95b1a88b26b --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/SUSYLesHouchesAccord.xml @@ -0,0 +1,29 @@ + + +

SUSY Les Houches Accord

+ +The PYTHIA 8 program does not contain an internal spectrum calculator +(a.k.a. RGE package) to provide supersymmetric couplings, mixing angles, +masses and branching ratios. Thus the SUSY Les Houches Accord (SLHA) +Ska04 is the only way of inputting SUSY models, and +SUSY processes cannot be run unless such an input has taken place. + + +Global switch for SUSY on or off. When on, the initialization step +(pythia.init) will read in the file below and set up +the information required for simulation of supersymmetric processes. + + + +Name of a SUSY Les Houches Accord (SLHA) spectrum file containing the +SUSY model definition, masses, and other parameters pertaining to +the desired SUSY model. Note that SLHA files can still be used +even if no supersymmetric processes are switched on, as an +alternative way of inputting particle masses, decay tables, etc. + + +
+ + + + diff --git a/PYTHIA8/pythia8130/xmldoc/SUSYProcesses.xml b/PYTHIA8/pythia8130/xmldoc/SUSYProcesses.xml new file mode 100644 index 00000000000..dbf10ee46ea --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/SUSYProcesses.xml @@ -0,0 +1,37 @@ + + +

SUSY Processes

+ +The implementation of SUSY processes is barely begun, so this page +is more a placeholder than a repository of useful processes. + +

+Here is collected processes involving supersymmetric particle +production, with the exception of the (extended) Higgs sector. +Since the number of separate but closely related processes is so big, +there will not be switches for each separate process but only for a +reasonable set of subgroups. + +
Important note: +In order to simulate SUSY processes it is required to read in the +couplings and masses relevant for the scenario to be studied. This +is done with the help of the SUSY Les Houches Accord (SLHA). The +reading of a relevant SLHA file must be set up, as described +on this page. + + +Common switch for production of supersymmetric particles, i.e. +particles with R-parity -1. + + + +Pair production of neutralinos by quark-antiquark annihilation. With +four neutralino species this gives ten separate processes, codes +1201 - 1210. Neutralino decays have not yet been implemented. + + + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/SampleMainPrograms.xml b/PYTHIA8/pythia8130/xmldoc/SampleMainPrograms.xml new file mode 100644 index 00000000000..b0a00d2ede2 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/SampleMainPrograms.xml @@ -0,0 +1,167 @@ + + +

Sample Main Programs

+ +To help exemplify what a main program could look like, a few simple +examples are provided in the examples subdirectory, +along with instructions how they should be run: +
    + +
  • main01.cc : a simple study of the charged multiplicity +for jet events at the LHC. (Brief example given in talks.)
  • + +
  • main02.cc : a simple study of the pT spectrum +of Z bosons at the Tevatron. (Brief example given in talks.)
  • + +
  • main03.cc : a simple single-particle analysis of jet +events, where input is set by main03.cmnd "cards file".
  • + +
  • main04.cc : a simple study of several different kinds +of events, with the choice to be made in the main04.cmnd +"cards file".
  • + +
  • main05.cc : generation of QCD jet events at the LHC, +with jet analysis using the CellJet cone-jet finder.
  • + +
  • main06.cc : tests of cross sections for elastic and +diffractive topologies, using main06.cmnd to pick process.
  • + +
  • main07.cc : tests of cross sections for minimum-bias +events, using main07.cmnd to pick options.
  • + +
  • main08.cc : generation of the QCD jet cross section +by splitting the run into subruns, each in its own pT bin, +and adding the results properly reweighted. Two options, with limits +set either in the main program or by subrun specification in the +main08.cmnd file.
  • + +
  • main09.cc : generation of LEP1 hadronic events, i.e. +e^+e^- -> gamma*/Z^0 -> q qbar, with charged multiplicity, +sphericity, thrust and jet analysis.
  • + +
  • main10.cc : illustration how userHooks can be used +interact directly with the event-generation process.
  • + +
  • main11.cc : generation of two predetermined hard +interactions in each event.
  • + +
  • main12.cc : a study of top events, fed in from the +Les Houches Event File ttbar.lhe, here generated by +main53.f. This file currently only contains 100 events +so as not to make the distributed PYTHIA package too big, and so serves +mainly as a demonstration of the principles involved.
  • + +
  • main13.cc : a more sophisticated variant of +main12.cc, where two Les Houches Event Files +(ttbar.lhe and ttbar2.lhe) successively +are used as input. Also illustrating some other aspects, like the +capability to mix in internally generated events.
  • + +
  • main14.cc : a systematic comparison of several +cross section values with their corresponding values in PYTHIA 6.4, +the latter available as a table in the code.
  • + +
  • main15.cc : loop over several tries, either to redo +B decays only or to redo the complete hadronization chain of an event. +Since much of the generation process is only made once this is a way +to increase efficiency.
  • + +
  • main16.cc : put all user analysis code into a class +of its own, separate from the main program; provide the "cards file" +name as a command-line argument.
  • + +
  • main17.cc : collect the Pythia calls in a wrapper class, +thereby simplifying the main program; provide the "cards file" name +as a command-line argument.
  • + +
  • main18.cc : shows how to write an event filter class, +where you keep a vector of pointers to the subset of particles you +want to study further. The event record itself remains unchanged.
  • + +
  • main19.cc : use several instances of Pythia, one for +signal events and others for a variable number of pileup and "beam-gas" +events, combined into one common event record.
  • + +
  • main20.cc : shows how PYTHIA 8 can write a Les Houches +Event File, using facilities potentially useful also for other programs +to write an LHEF.
  • + +
  • main21.cc : an example how parton-level configurations +can be input directly for hadronization, without being tied to the +full process-generation machinery, e.g. to study the hadronization of +junction topologies.
  • + +
  • main22.cc : tests of internally implemented cross sections +for Supersymmetric particle production, with SYSY spectrum defined in +main22.spc and settings in main22.cmnd.
  • + +
  • main23.cc : shows how an external decay handler can +be linked to handle the decays of some particles.
  • + +
  • main24.cc : shows how an external random number +generator can be linked to replace the internal one.
  • + +
  • main25.cc : shows how an external process can be +implemented as a new class derived from a PYTHIA base class, and then +handed in for generation as with a normal internal process.
  • + +
  • main26.cc : shows how an external resonance can be +implemented as a new class derived from a PYTHIA base class, and be +used in an external process, both of which are then handed in for +generation as with a normal internal resonance and process.
  • + +
  • main27.cc : shows how an external beam momentum spread +and vertex location generator can be implemented as a new class derived +from a PYTHIA base class, and then handed in for internal use.
  • + +
  • main31.cc : similar to main01, except that the +event record is output in the HepMC event record format. Requires +that HepMC is properly linked.
  • + +
  • main32.cc : a streamlined version for the generation +of events that are then stored in HepMC format, without any event +analysis. That is, all physics studies will have to be done afterwards. +The name of the input "cards file" (e.g. main32.cmnd) +and output HepMC event file are to be provided as command-line arguments. +Requires that HepMC is properly linked.
  • + +
  • main41.cc : a test of the shape of parton densities, +as a check prior to using a given PDF set in a generator. Requires +that LHAPDF is properly linked.
  • + +
  • main42.cc : compares the charged multiplicity +distribution, and a few other minimum-bias physics aspects, between +default PYTHIA PDF and another one. Requires that LHAPDF is properly +linked.
  • + +
  • main51.cc : a simple example how the Les Houches +Accord interface, plus a few more Fortran-to-C++ commands, allows +hard processes to be generated by PYTHIA 6.4 and then processed +further by PYTHIA 8. Requires that PYTHIA 6.4 is properly linked.
  • + +
  • main52.cc : a fairly extensive study of +event properties, with hard processes generated by PYTHIA 6.4. +It reads in a main52.fcmnd file with commands specfically +for the Fortran PYTHIA 6.4 program and another main52.ccmnd +file illustrating several of the settings listed on these pages. +Requires that PYTHIA 6.4 is properly linked.
  • + +
  • main53.f : a Fortran program (!) showing how +PYTHIA 6.4 can be used to generate a Les Houches Event File +ttbar.lhe with top events (which is used as input by +main12.cc). This program can easily be modified to +generate other files, bigger and/or for other processes. +Requires that PYTHIA 6.4 is properly linked.
  • + +
  • main54.cc : a final example where PYTHIA 6.4 is used +to generate hard processes, which are directly input to be generated +in full by the internal machinery, using the settings in +main54.cmnd, and the output consists of a file with +HepMC event records for further analysis. Requires that PYTHIA 6.4 +and HepMC are properly linked.
  • + +
+ +
+ + diff --git a/PYTHIA8/pythia8130/xmldoc/SaveSettings.xml b/PYTHIA8/pythia8130/xmldoc/SaveSettings.xml new file mode 100644 index 00000000000..af75688baf5 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/SaveSettings.xml @@ -0,0 +1,150 @@ + + +

Save Settings

+ +The information on this webpage is only valid if you access the PHP +dynamic webpages via a web browser, and does not apply to the static +HTML equivalents. With PHP, all of the settings in the PYTHIA program +are represented by radio buttons or fill-in boxes, that makes it easy +for you to construct a file with your desired changes. This file can +then be read into PYTHIA by your main program to steer the whole run. + +

Basic instructions

+ +The functionality of the PHP option is described in the following. + +

+
+ +
+ +

    + +

  • +To begin with, you must specify a (temporary) file name in the +box above. If the filename already exists on the server, you will be +requested to pick a new name.
  • + +

  • +Once you have Submitted your filename, you can browse through the +pages and make your selections. The values currently selected when you +load the page are the default values.
  • + +

  • +When you have finished making your changes to a particular page, +you must click on Save Settings at the bottom of +the page. This will write the changes to your temporary file. If you make +a mistake, just repeat the procedure for that category again.
    + +

  • +When you have finished all the changes you need, return to this page +and click Finish File.
  • + +

  • +You will then get up a link, that you are asked to right-click +with your mouse (or equivalent).
  • + +

  • +In the menu that appears, pick the option Save Link As +(or equivalent).
  • + +

  • +You will now get up a file browser, for you to pick and Save +the location and file name (the latter by default the same as the +temporary file name).
  • + +

  • +At any time, if you click the RESET button, your temporary +file will be erased and you can start anew.
  • + +

  • +Before you use a file, be sure to check it visually to confirm +that you saved what you intended to. Minor corrections are easily made +in a text editor. +
  • + +
+ +

+

Supplementary notes

+ + +The documentation files exist in three versions. +
    + +

  1. +As a set of .xml files, in the xmldoc/ +subdirectory. These are the master copies that no user ever should +touch, but that are used to generate the variants below.
  2. + +

  3. +As a set of .html files, in the htmldoc/ +subdirectory. You can open your own locally installed copy of the +Welcome.html file in your web browser and thereafter +navigate among all the pages. You can learn which parameters are free +to be changed, but not change anything, except by brute-force +cut-and-paste to a file of your own.
  4. + +

  5. +As a set of .php files, in the phpdoc/ +subdirectory. For these files to provide the functionality described +above they have to accessed via a webserver. The one where you have +your homepage should work fine. Alternatively you can use pages already +available on another server.
  6. + +
+ +

+A few further comments about the operation of the PHP option: +

    + +

  • +To set up the PHP files on your webserver, you have to install the whole +phpdoc/ subdirectory there. In addition to the +.php code this includes a few more files, plus a +subdirectory named files where the temporary files +are stored. This subdirectory must have public write access to work +(chmod a+w files if not).
  • + +

  • +The "temporary" files stored in files actually remain +unless the RESET button is used. The good news is that this makes +it possible to recover a file that otherwise might be lost. The bad +news is that the files directory may need to be cleaned +up from time to time. (But typically the files are pretty small, so +this should not be a major problem.)
  • + +

  • +When you click the Save Settings button on the bottom of a page +all changed settings are written on the temporary file in the format +
    +name-of-flag/mode/parameter/word = value
    +
    +with one variable per line. Thereafter all the settings on the page +are restored to their default values.
  • + +

  • +You can return to a page to do some further changes and save those. +If you change the same parameter twice, it is the last value that +counts. (Both values are stored in the file, with the more recent +lower down, and then PYTHIA does the changes sequentially.) However +remember that unchanged values are not stored, so if you want to +restore some default value it may be simpler to edit the file +afterwards.
  • + +

  • +The changeable flags/modes/parameters/words are mainly in the +"Setup Run Tasks" section of the index, but a few (less +frequently used ones) can also be found lower down, in the +"Study Output" and "Link to Other Programs" pages. + +

  • +It is not (yet) possible to modify particle data within the PHP-based +setup approach. This is a more difficult task, since e.g. the +modifications one may want to do in a decay table can be quite +interrelated. + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/SemiInternalProcesses.xml b/PYTHIA8/pythia8130/xmldoc/SemiInternalProcesses.xml new file mode 100644 index 00000000000..468e5d11c16 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/SemiInternalProcesses.xml @@ -0,0 +1,405 @@ + + +

    Semi-Internal Processes

    + +Normally users are expected to implement new processes via the +Les Houches Accord. Then +you do all flavour, colour and phase-space selection externally, +before your process-level events are input for further processing +by PYTHIA. However, it is also possible to implement a +new process in exactly the same way as the internal PYTHIA +ones, thus making use of the internal phase space selection machinery +to sample an externally provided cross-section expression. +This page gives a brief summary how to do that. If you additionally +want to introduce a new resonance species, with its own internal +width calculations, you will find further instructions +here. + +

    +Should you actually go ahead, it is strongly recommended to shop around +for a similar process that has already been implemented, and to use that +existing code as a template. Look for processes with the same combinations +of incoming flavours and colour flows, rather than the shape of the +cross section itself. With a reasonable such match the task should be +of medium difficulty, without it more demanding. + +

    +PYTHIA is rather good at handling the phase space of +2 -> 1 and 2 -> 2 processes, is more primitive for +2 -> 3 ones and does not at all address higher multiplicities. +This limits the set of processes that you can implement in this +framework. The produced particles may be resonances, however, so it is +possible to end up with bigger "final" multiplicities through sequential +decays, and to include further matrix-element weighting in those decays. + +

    +There are two steps involved in implementing a process: +
    1) writing a new class, where the matrix elements are implemented, +including information on incoming and outgoing flavours and colours, and +
    2) making the process available. +
    We consider these two aspects in turn. An example where it all comes +together is found in main25.cc. + +

    The Cross Section Class

    + +The matrix-element information has to be encoded in a new class. +The relevant code could either be put before the main program in the +same file, or be stored separately, e.g. in a matched pair +of .h and .cc files. The latter may be more +convenient, in particular if the cross sections are lengthy, or if you +intend to build up your own little process library, but of course +requires that these additional files are correctly compiled and linked. + +

    +The class has to be derived either from +Sigma1Process, for 2 -> 1 processes, from +Sigma2Process, for 2 -> 2 ones, or from +Sigma3Process, for 2 -> 3 ones. (The +Sigma0Process class is used for elastic, diffractive +and minimum-bias events, and is not recommended for use beyond that.) +These are in their turn derived from the SigmaProcess +base class. + +

    +The class can implement a number of methods. Some of these are +compulsory, others strongly recommended, and the rest are to be +used only when the need arises to override the default behaviour. +The methods are: + +

    +A constructor for the derived class obviously must be available. +Here you are quite free to allow a list of arguments, to set +the parameters of your model, or even to create a set of closely +related but distinct processes. For instance, g g -> Q Qbar, +Q = c or b, is only coded once, and then the +constructor takes the quark code (4 or 5) as argument, +to allow the proper amount of differentiation. + +

    +A destructor is only needed if you plan to delete the process +before the natural end of the run, and require some special behaviour +at that point. If you call such a destructor you will leave a pointer +dangling inside the Pythia object you gave it in to, +if that still exists. + + +is called once during initalization, and can then be used to set up +parameters, such as masses and couplings, and perform calculations +that need not be repeated for each new event, thereby saving time. +This method needs not be implemented, since in principle all +calculations can be done in sigmaHat below. + + +is called once a kinematical configuration has been determined, but +before the two incoming flavours are known. This routine can therefore +be used to perform calculations that otherwise might have to be repeated +over and over again in sigmaHat below. For instance +a flavour-independent cross section calculation for a q g +initial state would be repeated 20 times in sigmaHat, +five times for the five quark flavours allowed in the incoming beams, +times twice to include antiquarks, times twice since the (anti)quark +could be in either of the two beams. You could therefore calculate the +result once only and store it as a private data member of the class. +It is optional whether you want to use this method, however, or put +everything in sigmaHat. + + +is the key method for cross section calculations and returns a cross section +value, as further described below. It is called when also a preliminary set +of incoming flavours has been picked, in addition to the kinematical ones +already available for sigmaKin. Typically sigmaHat +is called inside a loop over all allowed incoming flavour combinations, +stored in id1 and id2, with fixed kinematics, +as already illustrated above. The sum over the different flavour combinations +provides the total cross section, while their relative size is used to make +a selection of a specific incomimg state. +
    For a 2 -> 1 process, the returned value should be +sigmaHat(sHat), where mH (= mHat), +sH (= sHat) and sH2 (= sHat^2) +are available to be used. +
    For a 2 -> 2 process, instead +d(sigmaHat)/d(tHat) should be returned, based on +provided mH, sH, sH2, tH, tH2, uH, uH2, m3, s3, m4, s4 and +pT2 values (s3 = m3*m3 etc.). +
    For a 2 -> 3 process, instead |M|^2 should be +returned, with normalization such that |M|^2 / (2 sHat) integrated +over the three-body phase space gives the cross section. Here no standard +set of variables exist. Instead the obvious ones, +mH, sH, m3, s3, m4, s4, m5, s5, are complemented by the +four-vectors p3cm, p4cm, p5cm, from which further invariants +may be calculated. The four-vectors are defined in the cm frame of the +subcollision, with incoming partons along the +-z axis. +
    In either case, alpha_s and alpha_em have already +been calculated, and are stored in alpS and alpEM. +Also other standard variables may be used, like +CoupEW::sin2thetaW(), and related flavour-dependent +vector and axial couplings in CoupEW and CKM combinations +in VCKM. +
    In case some of the final-state particles are resonances, their +squared masses have already been selected according to a Breit-Wigner +with a linearly running width Gamma(m) = Gamma(m_0) * m / m_0. +More precisely, the mass spectrum is weighted according to +w_BW(m^2) d(m^2), where + +w_BW(m^2) = (1/pi) * (m * Gamma(m)) / ( (m^2 - m_0^2)^2 + (m * Gamma(m))^2 ) . + +If you would like to have another expression, the above weights are stored +in runBW3, runBW4 and runBW5, +respectively. If you divide out one of these factors, you just remain with +a phase space selection d(m^2) for this particle, +and can multiply on your desired shape factor instead. Unfortunately, the +Monte Carlo efficiency will drop if your new mass distribution differs +dramatically from the input one. Therefore it does make sense to adjust the +database value of the width to be slightly (but not too much) broader +than the distribution you have in mind. Also note that, already by default, +the wings of the Breit-Wigner are oversampled (with a compensating lower +internal weight) by partly sampling like (a + b/m^2 + c/m^4) d(m^2), +where the last term is only used for gamma^*/Z^0. + + +is called only once an initial state and a kinematical configuration has +been picked. This routine must set the complete flavour information and +the colour flow of the process. This may involve further random choices, +between different possible final-state flavours or between possible +competing colour flows. Private data members of the class may be used to +retain some information from the previous steps above. +
    When this routine is called the two incoming flavours have already +been selected and are available in id1 and id2, +whereas the one, two or three outgoing ones either are fixed for a given +process or can be determined from the instate (e.g. whether a W^+ +or W^- was produced). There is also a standard method in +VCKM to pick a final flavour from an initial one with CKM +mixing. Once you have figured out the value of +id3 and, the case being, id4 and +id5, you store these values permanently by a call +setId( id1, id2, id3, id4, id5), where the last two may be +omitted if irrelevant. +
    Correspondingly, the colours are stored with +setColAcol( col1, acol1, col2, acol2, col3, acol3, col4, acol4, +col5, acol5), where the final ones may be omitted if irrelevant. +Les Houches style colour tags are used, but starting with number 1 +(and later shifted by the currently requested offset). The +input is grouped particle by particle, with the colour index before the +anticolour one. You may need to select colour flow dynamically, depending +on the kinematics, when several distinct possibilities exist. Trivial +operations, like swapping colours and anticolours, can be done with +existing methods. +
    When the id3Mass() and id4Mass() +methods have been used, the order of the outgoing particles may be +inconsistent with the way the tHat and uHat +variables have been defined. A typical example would be a process like +q g -> q' W with tHat defined between incoming and +outgoing quark, but where id3Mass() = 24 and so the +process is to be stored as q g -> W q'. One should then put +the variable swapTU = true in setIdColAcol() +for each event where the tHat and uHat variables +should be swapped before the event kinematics is reconstructed. This +variable is automatically restored to false for each new +event. + + +is called to allow a reweighting of the simultaneous flavour choices of +resonance decay products. Is currently only used for the +q qbar -> gamma*/Z^0 gamma*/Z^0 process, and will likely not +be of interest for you. + + +is called when the basic process has one or several resonances, after each +set of related resonances in process[i], +iResBeg <= i <= iResEnd, +has been allowed to decay. The calculated weight, to be normalized +to the range between 0 and 1, is used to decide whether to accept the +decay(s) or try for a new decay configuration. The base-class version of +this method returns unity, i.e. gives isotropic decays by default. +This method may be called repeatedly for a single event. For instance, in +q qbar -> H^0 Z^0 with H^0 -> W^+ W^-, a first call +would be made after the H^0 and Z^0 decays, and then +depend only on the Z^0 decay angles since the H^0 +decays isotropically. The second call would be after the W^+ W^- +decays and then involve correlations between the four daughter fermions. + + +returns the name of the process, as you want it to be shown in listings. + + +returns an integer identifier of the process. This has no internal function, +but is only intended as a service for the user to rapidly (and hopefully +uniquely) identify which process occured in a given event. Numbers below +10000 are reserved for internal PYTHIA use. + + +this string specifies the combinations of incoming partons that are +allowed for the process under consideration, and thereby which incoming +flavours id1 and id2 the sigmaHat() +calls will be looped over. It is always possible to pick a wider flavour +selection than strictly required and then put to zero cross sections in +the superfluous channels, but of course this may cost some extra execution +time. Currently allowed options are: +
    * gg: two gluons. +
    * qg: one (anti)quark and one gluon. +
    * qq: any combination of two quarks, two antiquarks or +a quark and an antiquark. +
    * qqbarSame: a quark and its antiquark; +this is a subset of the above qq option. +
    * ff: any combination of two fermions, two antifermions +or a fermion and an antifermion; is the same as qq for +hadron beams but also allows processes to work with lepton beams. +
    * ffbarSame: a fermion and its antifermion; is the +same as qqbarSame for hadron beams but also allows processes +to work with lepton beams. +
    * ffbarChg: a fermion and an antifermion that combine +to give charge +-1. +
    * fgm: a fermion and a photon (gamma). +
    * ggm: a gluon and a photon. +
    * gmgm: two photons. + + +it is assumed that cross sections normally come in dimensions such that +they, when integrated over the relevant phase space, obtain the dimension +GeV^-2, and therefore need to be converted to mb. If the cross section +is already encoded as mb then convert2mb() should be +overloaded to instead return false. + + +are the one, two or three final-state flavours, where masses are to be +selected before the matrix elements are evaluated. Only the absolute value +should be given. For massless particles, like gluons and photons, one need +not give anything, i.e. one defaults to 0. The same goes for normal light +quarks, where masses presumably are not implemented in the matrix elements. +Later on, these quarks can still (automatically) obtain constituent masses, +once a u, d or s flavour has been selected. + + +are the codes of up to two s-channel resonances contributing to +the matrix elements. These are used by the program to improve the phase-space +selection efficiency, by partly sampling according to the relevant +Breit-Wigners. Massless resonances (the gluon and photon) need not be +specified. + + +normally the choice of renormalization and factorization scales in +2 -> 2 and 2 -> 3 processes is based on the assumption +that t- and u-channel exchanges dominates the +cross section. In cases such as f fbar -> gamma* -> f' fbar' a +2 -> 2 process actually ought to be given scales as a +2 -> 1 one, in the sense that it proceeds entirely through +an s-channel resonance. This can be achieved if you override the +default false to return true. See further the +page on couplings and scales. + + +the 2 -> 3 phase space selection machinery is rather primitive, +as already mentioned. The efficiency can be improved in processes that +proceed though t-channel exchanges, such as +q qbar' -> H^0 q qbar' via Z^0 Z^0 fusion, if the identity +of the t-channel-exchanged particles on the two side of the +event are provided. Only the absolute value is of interest. + + +in the above kind of 2 -> 3 phase-space selection, the +sampling of pT^2 is done with one part flat, one part weighted +like 1 / (pT^2 + m_R^2) and one part like +1 / (pT^2 + m_R^2)^2. The above values provide the relative +amount put in the latter two channels, respectively, with the first +obtaining the rest. Thus the sum of tChanFracPow1() and +tChanFracPow2() must be below unity. The final results +should be independent of these numbers, but the Monte Carlo efficiency +may be quite low for a bad choice. Here m_R is the mass of the +exchanged resonance specified by idTchan1() or +idTchan2(). Note that the order of the final-state +listing is important in the above q qbar' -> H^0 q qbar' example, +i.e. the H^0 must be returned by id3Mass(), +since it is actually the pT^2 of the latter two that are +selected independently, with the first pT then fixed +by transverse-momentum conservation. + + +in 2 -> 3 processes the phase space selection used here +involves a twofold ambiguity basically corresponding to a flipping of +the positions of last two outgoing particles. These are assumed equally +likely by default, false, but for processes proceeding entirely +through t-channel exchange the Monte Carlo efficiency can be +improved by making a preselection based on the relative propagator +weights, true. + + +allows a possibility to override the global mode +WeakZ0:gmZmode +for a specific process. The global mode normally is used to switch off +parts of the gamma^*/Z^0 propagator for test purposes. The +above local mode is useful for processes where a Z^0 really is +that and nothing more, such as q qbar -> H^0 Z^0. The default +value -1 returned by gmZmode() ensures that the global +mode is used. + +

    Access to a process

    + +Once you have implemented a class, it is straightforward to make use of +it in a run. Assume you have written a new class MySigma, +which inherits from Sigma1Process, Sigma2Process +or Sigma3Process, which in their turn inherit from +SigmaProcess. You then create an instance of this class +and hand it in to a pythia object with +
    +      SigmaProcess* mySigma = new MySigma();
    +      pythia.setSigmaPtr( mySigma); 
    +
    +If you have several processes you can repeat the procedure any number +of times. When pythia.init(...) is called these processes +are initialized along with any internal processes you may have switched on, +and treated in exactly the same manner. The pythia.next() +will therefore generate a mix of the different kinds of processes without +distinction. See also the Program Flow +description. + +

    +If the code should be of good quality and general usefulness, it would +be simple to include it as a permanently available process in the +standard program distribution. The final step of that integration ought to +be left for the PYTHIA authors, but here is a description of what is +required. + +

    +A flag has to be defined, that allows the process to be switched on; +by default it should always be off. The name of the flag should be +chosen of the type model:process. Here the +model would be related to the general scenario considered, +e.g. Compositeness, while process would +specify instate and outstate, separated by a 2 (= to), e.g. +ug2u*g. +When several processes are implemented and "belong together" it is +also useful to define a model:all switch that affects +all the separate processes. + +

    +The flags should normally be stored in the ProcessSelection.xml +file or one of its daughters for a specific kind of processes. This is to +make them easily found by users. You could create and use your own +.xml file, so long as you then add that name to the +list of files in the Index.xml file. (If not, +the flags would never be created and the program would not work.) + +

    +In the ProcessContainer.c file, the +SetupContainers::init() method needs to be expanded to +create instances of the processes switched on. This code is fairly +repetitive, and should be easy to copy and modify from the code +already there. The basic structure is +
    (i) check whether a process is requested by the user and, if so, +
    (ii) create an instance of the matrix-element class, +
    (iii)create a container for the matrix element and its associated +phase-space handling, and +
    (iv) add the container to the existing process list. + +

    +Two minor variations are possible. One is that a set of related +processes are lumped inside the the same initial check, i.e. are +switched on all together. The second is that the matrix-element +constructor may take arguments, as specified by you (see above). +If so, the same basic matrix element may be recycled for a set of +related processes, e.g. one for a composite u and one for +a composite d. Obviously these variations may be combined. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/SemiInternalResonances.xml b/PYTHIA8/pythia8130/xmldoc/SemiInternalResonances.xml new file mode 100644 index 00000000000..e9fe7d1b68d --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/SemiInternalResonances.xml @@ -0,0 +1,204 @@ + + +

    Semi-Internal Resonances

    + +The introduction of a new +semi-internal process may also involve a new particle, +not currently implemented in PYTHIA. Often it is then enough to +use the standard machinery +to introduce a new particle (id:all = ...) and new +decay channels (id:addChannel = ...). By default this +only allows you to define a fixed total width and fixed branching +ratios. Using meMode +values 100 or bigger provides the possibility of a very +simple threshold behaviour. + +

    +If you want to have complete freedom, however, there are two +ways to go. One is that you make the resonance decay part of the +hard process itself, either using the +Les Houches interface or +a semi-internal process. The other is for you to create a new +ResonanceWidths object, where you write the code +needed for a calculation of the partial width of a particular +channel. + +

    +Here we will explain what is involved in setting up a resonance. +Should you actually go ahead with this, it is strongly recommended +to use an existing resonance as a template, to get the correct +structure. There also exists a sample main program, +main26.cc, that illustrates how you could combine +a new process and a new resonance. + +

    +There are three steps involved in implementing a new resonance: +
    1) providing the standard particle information, as already +outlined above (id:all = ..., +id:addChannel = ...), except that now branching +ratios need not be specified, since they anyway will be overwritten +by the dynamically calculated values. +
    2) writing the class that calculates the partial widths. +
    3) handing in a pointer to an instance of this class to PYTHIA. +
    We consider the latter two aspects in turn. + +

    The ResonanceWidths Class

    + +The resonance-width calculation has to be encoded in a new class. +The relevant code could either be put before the main program in the +same file, or be stored separately, e.g. in a matched pair +of .h and .cc files. The latter may be more +convenient, in particular if the calculations are lengthy, or +likely to be used in many different runs, but of course requires +that these additional files are correctly compiled and linked. + +

    +The class has to be derived from the ResonanceWidths +base class. It can implement a number of methods. The constructor +and the calcWidth ones are always needed, while others +are for convenience. Much of the administrativ machinery is handled +by methods in the base class. + +

    Thus, in particular, you must implement expressions for all +possible final states, whether switched on in the current run or not, +since all contribute to the total width needed in the denominator of +the Breit-Wigner expression. Then the methods in the base class take +care of selecting only allowed channels where that is required, and +also of including effects of closed channels in secondary decays. +These methods can be accessed indirectly via the +res... +methods of the normal particle database. + +

    +A constructor for the derived class obviously must be available. +Here you are quite free to allow a list of arguments, to set +the parameters of your model. The constructor must call the +base-class initBasic(idResIn) method, where the argument +idResIn is the PDG-style identity code you have chosen +for the new resonance. When you create several related resonances +as instances of the same class you would naturally make +idResIn an argument of the constructor; for the +PYTHIA classes this convention is used also in cases when it is +not needed. +
    The initBasic(...) method will +hook up the ResonanceWidths object with the corresponding +entry in the generic particle database, i.e. with the normal particle +information you set up in point 1) above. It will store, in base-class +member variables, a number of quantities that you later may find useful: +
    idRes : the identity code you provide; +
    hasAntiRes : whether there is an antiparticle; +
    mRes : resonance mass; +
    GammaRes resonance width; +
    m2Res : the squared mass; +
    GamMRat : the ratio of width to mass. + +

    +A destructor is only needed if you plan to delete the resonance +before the natural end of the run, and require some special behaviour +at that point. If you call such a destructor you will leave a pointer +dangling inside the Pythia object you gave it in to, +if that still exists. + + +is called once during initialization, and can then be used to set up +further parameters specific to this particle species, such as couplings, +and perform calculations that need not be repeated for each new event, +thereby saving time. This method needs not be implemented. + + +is called once a mass has been chosen for the resonance, but before +a specific final state is considered. This routine can therefore +be used to perform calculations that otherwise might have to be repeated +over and over again in calcWidth below. It is optional +whether you want to use this method, however, or put +everything in calcWidth(). +
    The optional argument will have the value true when +the resonance is initialized, and then be false throughout +the event generation, should you wish to make a distinction. +In PYTHIA such a distinction is made for gamma^*/Z^0 and +gamma^*/Z^0/Z'^0, owing to the necessity of a special +description of interference effects, but not for other resonances. +
    In addition to the base-class member variables already described +above, mHat contains the current mass of the resonance. +At initialization this agrees with the nominal mass mRes, +but during the run it will not (in general). + + +is the key method for width calculations and returns a partial width +value, as further described below. It is called for a specific +final state, typically in a loop over all allowed final states, +subsequent to the calcPreFac(...) call above. +Information on the final state is stored in a number of base-class +variables, for you to use in your calculations: +
    iChannel : the channel number in the list of +possible decay channels; +
    mult : the number of decay products; +
    id1, id2, id3 : the identity code of up to the first +three decay products, arranged in descending order of the absolute value +of the identity code; +
    id1Abs, id2Abs, id3Abs : the absolute value of the +above three identity codes; +
    mHat : the current resonance mass, which is the same +as in the latest calcPreFac(...) call; +
    mf1, mf2, mf3 : masses of the above decay products; +
    mr1, mr2, mr3 : squared ratio of the product masses +to the resonance mass; +
    ps : is only meaningful for two-body decays, where it +gives the phase-space factor +ps = sqrt( (1. - mr1 - mr2)^2 - 4. * mr1 * mr2 ); +
    In two-body decays the third slot is zero for the above properties. +Should there be more than three particles in the decay, you would have +to take care of the subsequent products yourself, e.g. using +
    particlePtr->decay[iChannel].product(j); +
    to extract the j'th decay products (with +j = 0 for the first, etc.). Currently we are not aware +of any such examples. +
    The base class also contains methods for alpha_em and +alpha_strong evaluation, and can access many standard-model +couplings; see the existing code for examples. +
    The result of your calculation should be stored in +
    widNow : the partial width of the current channel, +expressed in GeV. + + +is not normally used. In PYTHIA the only exception is Higgs decays, +where it is used to define the width (except for colour factors) +associated with a specific incoming state. It allows the results of +some loop expressions to be pretabulated. + + +

    Access to resonance widths

    + +Once you have implemented a class, it is straightforward to +make use of it in a run. Assume you have written a new class +MyResonance, which inherits from +ResonanceWidths. You then create an instance of +this class and hand it in to a pythia object with +
    +      ResonanceWidths* myResonance = new MyResonance();
    +      pythia.setResonancePtr( myResonance); 
    +
    +If you have several resonances you can repeat the procedure any number +of times. When pythia.init(...) is called these resonances +are initialized along with all the internal resonances, and treated in +exactly the same manner. See also the Program +Flow +description. + +

    +If the code should be of good quality and general usefulness, +it would be simple to include it as a permanently available process +in the standard program distribution. The final step of that integration +ought to be left for the PYTHIA authors, but basically all that is +needed is to add one line in +ParticleDataTable::initResonances, where one creates an +instance of the resonance in the same way as for the resonances already +there. In addition, the particle data and decay table for the new +resonance has to be added to the permanent +particle database, and the code itself +to include/ResonanceWidths.h and +src/ResonanceWidths.cc. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/SettingsScheme.xml b/PYTHIA8/pythia8130/xmldoc/SettingsScheme.xml new file mode 100644 index 00000000000..459ac8a1138 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/SettingsScheme.xml @@ -0,0 +1,266 @@ + + +

    The Settings Scheme

    + +The Settings class keeps track of all the flags, modes, +parameters and words in the program. As such, it serves the other program +elements from one central repository. Accessing it allows the user to +modify the behaviour of the program. The Settings class is +purely static, i.e. you can interact with it directly by +Settings::command(argument). +However, a settings object of the Settings class +is a public member of the Pythia class, so an alternative +notation would be pythia.settings.command(argument), +assuming that pythia is an instance of the Pythia +class. Further, for the most frequent user tasks, Pythia +methods have been defined, so that pythia.command(argument) +would work, see further below. + +

    Concepts

    + +We distinguish four kinds of user-modifiable variables, by the way +they have to be stored: +
      +
    1. Flags are on/off switches, and are stored as bool.
    2. +
    3. Modes corresponds to a finite enumeration of separate options, + and are stored as int.
    4. +
    5. Parameters take a continuum of values, and are stored as +double. The shorthand notation parm is used in the C++ +code and XML tags, so that all four kinds are represented by +four-letter type names.
    6. +
    7. Words are simple character strings and are stored as +string. No blanks or double quotation marks (") may +appear inside a word, the former to simplify parsing of an input file +and the latter not to cause conflicts with XML attribute delimiters. +Currently the main application is to store file names.
    8. +
    + +

    +In general, each variable stored in Settings is associated +with four kinds of information: +

      +
    • The variable name, of the form class:name +(or file:name, usually these agree), e.g. +TimeShower:pTmin. The class/file part usually identifies +the .xml file where the variable is defined, and the part of +the program where it is used, but such a connection cannot be strictly +upheld, since e.g. the same variable may be used in a few different +cases (even if most of them are not).
    • +
    • The default value, set in the original declaration, and intended +to represent a reasonable choice.
    • +
    • The current value, which differs from the default when the user so +requests.
    • +
    • An allowed range of values, represented by meaningful +minimum and maximum values. This has no sense for a flag +or a word (and is not used there), is usually rather +well-defined for a mode, but less so for a parm. +Often the allowed range exaggerates the degree of our current knowledge, +so as not to restrict too much what the user can do. One may choose +not to set the lower or upper limit, in which case the range is +open-ended.
    • +
    + +

    +Technically, the Settings class is implemented with the +help of four separate maps, one for each kind of variable, with the +variable name used as key. + +

    Operation

    + +The normal flow of setting values is: + +
      + +

    1. +When a Pythia object pythia is created, +the member pythia.settings is asked to scan the files +listed in the Index.xml file in the xmldoc +subdirectory. + +

      +In all of the files scanned, lines beginning with +<flag, <mode, <parm +or <word are identified, and the information on +such a line is used to define a new flag, mode, parameter or word. +To exemplify, consider a line +

      +<parm name="TimeShower:pTmin" default="0.5" min="0.1" max="2.0">
      +
      +which appears in the TimeShower.xml file, and there +defines a parameter TimeShower:pTmin with default value +0.5 GeV and allowed variation in the range 0.1 - 2.0 GeV. The min +and max values are optional. +Important: the values in the .xml files should +not be changed, except by the PYTHIA authors. Any changes should be +done with the help of the methods described below. +
    2. + +

    3. +Between the creation of the Pythia object and the +init call for it, you may use several alternative +methods to modify some of the default values. + +

      +a) Inside your main program you can directly set values with +

      +    pythia.readString(string) 
      +
      +where both the variable name and the value are contained inside +the character string, separated by blanks and/or a =, e.g. +
      +    pythia.readString("TimeShower:pTmin = 1.0"); 
      +
      +The match of the name to the database is case-insensitive. Names +that do not match an existing variable are ignored. A warning is +printed, however, unless an optional second argument false +is used. Strings beginning with a non-alphanumeric character, like +# or !, are assumed to be comments and are not processed at all. +Values below the minimum or above the maximum are set at +the respective border. For bool values, the following +notation may be used interchangeably: +true = on = yes = ok = 1, while everything else gives +false (including but not limited to +false, off, no and 0).
      + +

      +b) The Pythia readString(string) method +actually does not do changes itself, but sends on the string either +to the Settings class or to ParticleData. +If desired, it is possible to communicate +directly with the corresponding Settings method: +

      +    pythia.settings.readString("TimeShower:pTmin = 1.0"); 
      +
      +In this case, changes intended for ParticleData +would not be understood. + +

      +c) Underlying the settings.readString(string) method are +the settings-type-sensitive commands in the Settings, that +are split by names containing flag, mode, +parm or word. Thus, the example now reads +

      +    pythia.settings.parm("TimeShower:pTmin", 1.0); 
      +
      +Boolean values should here be given as true or +false i.e. there is less flexibility in the lower-level +methods. + +

      +At the same level, there are several different methods available. +We here show the ones for mode, but corresponding methods +exist for flag, parm and word, +with obvious restrictions where min and max +are not defined. Again name comparisons are case-insensitive. + +gives the current value, + + +sets the current value, + + +tells whether a mode has been defined or not, + + +defines a new mode, + + +sets the value, also when outside the recommended bounds (and it is +completely up to you to face the consequences), + + +resets the current value to the default one. + + +

      +Normally the user should have no need for these methods. The +main exception is when some of the variables defined on the +Main-Program Settings +page are used to set run-specific information +(like the CM energy or the number of events to generate) in an external +file (see 2d below) and these variables are to be read into the main +program. Then the flag(name), mode(name) +parm(name) and word(name) methods are to +be used, see e.g. the main programs in the examples +subdirectory to find out how it works. + +

      +d) A simpler and more useful way is to collect all your changes +in a separate file, with one line per change, e.g. +

      +    TimeShower:pTmin = 1.0
      +
      +Each line is read in as a string and processed with the methods already +introduced. + +The file can be read by the +
      +    pythia.readFile(fileName); 
      +
      +method. The file can freely mix commands to the Settings +and ParticleData classes, and so is preferable. Lines with +settings are handled by calls to the +pythia.settings.readString(string) method. Again, an optional +second argument false allows you to switch off warning +messages for unknown variables. +
    4. + +

    5. +In the Pythia init call, many of the various other program +elements are initialized, making use of the current values in the database. +Once initialized, the common Settings database is likely not +consulted again by these routines. It is therefore not productive to do +further changes in mid-run: at best nothing changes, at worst you may +set up inconsistencies. + +

      +A routine reInit(fileName) is provided, and can be used to +zero all the maps and reinitialize from scratch. Such a call might be +required if several Pythia objects are created in the same run, +and requested to have different values - by default the init() +call is only made the first time. However, a more economical solution +is then offered by resetAll(), which sets all variables to +their default values. +

    6. + +

    7. +You may at any time obtain a listing of all variables in the +database by calling +
      +    pythia.settings.listAll();
      +
      +The listing is strictly alphabetical, which at least means that names +from the same file are kept together, but otherwise may not be so +well-structured: important and unimportant ones will appear mixed. +A more relevant alternative is +
      +    pythia.settings.listChanged();
      +
      +where you will only get those variables that differ from their +defaults. Or you can use +
      +    pythia.settings.list("string");
      +
      +where only those variables with names that contain the string +(case-insensitive match) are listed. Thus, with a string +shower, the shower-related variables would be shown. +
    8. + +

    9. +The above listings are in a tabular form that cannot be read +back in. Assuming you want to save all changed settings (maybe because +you read in changes from several files), you can do that by calling +
      +    pythia.settings.writeFile(fileName);
      +
      +This file could then directly be read in by +readFile(fileName) in a subsequent (identical) run. +A second argument true would print all settings, not +only the changed ones. Further, the first argument can be replaced by +(a reference to) an ostream, by default cout. +
    10. +
    + +
    + + diff --git a/PYTHIA8/pythia8130/xmldoc/SpacelikeShowers.xml b/PYTHIA8/pythia8130/xmldoc/SpacelikeShowers.xml new file mode 100644 index 00000000000..14f72f3f2c2 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/SpacelikeShowers.xml @@ -0,0 +1,310 @@ + + +

    Spacelike Showers

    + +The PYTHIA algorithm for spacelike initial-state showers is +based on the recent article Sjo05, where a +transverse-momentum-ordered backwards evolution scheme is introduced. +This algorithm is a further development of the virtuality-ordered one +presented in Sj085, with matching to first-order matrix +element for Z^0, W^+- and Higgs (in the +m_t -> infinity limit) production as introduced in +Miu99. + +

    +The normal user is not expected to call SpaceShower +directly, but only have it called from Pythia, +via PartonLevel. Some of the parameters below, +in particular SpaceShower:alphaSvalue, +would be of interest for a tuning exercise, however. + +

    Main variables

    + +The maximum pT to be allowed in the shower evolution is +related to the nature of the hard process itself. It involves a +delicate balance between not doublecounting and not leaving any +gaps in the coverage. The best procedure may depend on information +only the user has: how the events were generated and mixed (e.g. with +Les Houches Accord external input), and how they are intended to be +used. Therefore a few options are available, with a sensible default +behaviour. + + +Way in which the maximum shower evolution scale is set to match the +scale of the hard process itself. + + + +Note 1: These options only apply to the hard interaction. +Emissions off subsequent multiple interactions are always constrainted +to be below the factorization scale of the process itself. +Note 2: Some processes contain matrix-element matching +to the first emission; this is the case notably for single +gamma^*/Z^0, W^+- and H^0 production. Then default +and option 2 give the correct result, while option 1 should never +be used. + + + +In cases where the above pTmaxMatch rules would imply +that pT_max = pT_factorization, pTmaxFudge +introduced a multiplicative factor f such that instead +pT_max = f * pT_factorization. Only applies to the hardest +interaction in an event. It is strongly suggested that f = 1, +but variations around this default can be useful to test this assumption. + + + +These options only take effect when a process is allowed to radiate up +to the kinematical limit by the above pTmaxMatch choice, +and no matrix-element corrections are available. Then, in many processes, +the fall-off in pT will be too slow by one factor of pT^2. +That is, while showers have an approximate dpT^2/pT^2 shape, often +it should become more like dpT^2/pT^4 at pT values above +the scale of the hard process. Whether this actually is the case +depends on the particular process studied, e.g. if t-channel +gluon exchange is likely to dominate. If so, the options below could +provide a reasonable high-pT behaviour without requiring +higher-order calculations. + + + +Note: These options only apply to the hard interaction. +Emissions off subsequent multiple interactions are always constrainted +to be below the factorization scale of the process itself. + + + +In cases 1 and 2 above, where a dampening is imposed at around the +factorization or renormalization scale, respectively, this allows the +pT scale of dampening of radiation by a half to be shifted +by this factor relative to the default Q_fac or Q_ren. +This number ought to be in the neighbourhood of unity, but variations +away from this value could do better in some processes. + + +

    +The amount of QCD radiation in the shower is determined by + +The alpha_strong value at scale M_Z^2. +Default value is picked equal to the one used in CTEQ 5L. + + +

    +The actual value is then regulated by the running to the scale +pT^2, at which it is evaluated + +Order at which alpha_strong runs, + + + + + +

    +QED radiation is regulated by the alpha_electromagnetic +value at the pT^2 scale of a branching. + + +The running of alpha_em. + + + + + +

    +There are two complementary ways of regularizing the small-pT +divergence, a sharp cutoff and a smooth dampening. These can be +combined as desired but it makes sense to coordinate with how the +same issue is handled in multiple interactions. + + +Regularize the pT -> 0 divergence using the same sharp cutoff +and smooth dampening parameters as used to describe multiple interactions. +That is, the MultipleInteractions:pT0Ref, +MultipleInteractions:ecmRef, +MultipleInteractions:ecmPow and +MultipleInteractions:pTmin parameters are used to regularize +all ISR QCD radiation, rather than the corresponding parameters below. +This is a sensible physics ansatz, based on the assumption that colour +screening effects influence both MI and ISR in the same way. Photon +radiation is regularized separately in either case. +Warning: if a large pT0 is picked for multiple +interactions, such that the integrated interaction cross section is +below the nondiffractive inelastic one, this pT0 will +automatically be scaled down to cope. Information on such a rescaling +does NOT propagate to SpaceShower, however. + + +

    +The actual pT0 parameter used at a given cm energy scale, +ecmNow, is obtained as + + pT0 = pT0(ecmNow) = pT0Ref * (ecmNow / ecmRef)^ecmPow + +where pT0Ref, ecmRef and ecmPow are the +three parameters below. + + +Regularization of the divergence of the QCD emission probability for +pT -> 0 is obtained by a factor pT^2 / (pT0^2 + pT^2), +and by using an alpha_s(pT0^2 + pT^2). An energy dependence +of the pT0 choice is introduced by the next two parameters, +so that pT0Ref is the pT0 value for the reference +cm energy, pT0Ref = pT0(ecmRef). + + + +The ecmRef reference energy scale introduced above. + + + +The ecmPow energy rescaling pace introduced above. + + + +Lower cutoff in pT, below which no further ISR branchings +are allowed. Normally the pT0 above would be used to +provide the main regularization of the branching rate for +pT -> 0, in which case pTmin is used mainly for +technical reasons. It is possible, however, to set pT0Ref = 0 +and use pTmin to provide a step-function regularization, +or to combine them in intermediate approaches. Currently pTmin +is taken to be energy-independent. + + + +Parton shower cut-off pT for photon coupling to a coloured +particle. + + + +Parton shower cut-off mass for pure QED branchings. +Assumed smaller than (or equal to) pTminChgQ. + + + +Force emissions, after the first, to be ordered in rapidity, +i.e. in terms of decreasing angles in a backwards-evolution sense. +Could be used to probe sensitivity to unordered emissions. +Only affects QCD emissions. + + +

    Further variables

    + +These should normally not be touched. Their only function is for +cross-checks. + +

    +There are three flags you can use to switch on or off selected +branchings in the shower: + + +Allow a QCD shower; on/off = true/false. + + + +Allow quarks to radiate photons; on/off = true/false. + + + +Allow leptons to radiate photons; on/off = true/false. + + +

    +There are three further possibilities to simplify the shower: + + +Use of matrix element corrections; on/off = true/false. + + + +Azimuthal asymmetry induced by gluon polarization; on/off = true/false. +Not yet implemented. + + + +Number of allowed quark flavours in g -> q qbar branchings, +when kinematically allowed, and thereby also in incoming beams. +Changing it to 4 would forbid g -> b bbar, etc. + + +

    Technical notes

    + +Almost everything is equivalent to the algorithm in [1]. Minor changes +are as follows. +
      +
    • +It is now possible to have a second-order running alpha_s, +in addition to fixed or first-order running. +
    • +
    • +The description of heavy flavour production in the threshold region +has been modified, so as to be more forgiving about mismatches +between the c/b masses used in Pythia relative to those +used in a respective PDF parametrization. The basic idea is that, +in the threshold region of a heavy quark Q, Q = c/b, +the effect of subsequent Q -> Q g branchings is negligible. +If so, then + + f_Q(x, pT2) = integral_mQ2^pT2 dpT'2/pT'2 * alpha_s(pT'2)/2pi + * integral P(z) g(x', pT'2) delta(x - z x') + +so use this to select the pT2 of the g -> Q Qbar +branching. In the old formalism the same kind of behaviour should +be obtained, but by a cancellation of a 1/f_Q that diverges +at the theshold and a Sudakov that vanishes. +
      +The strategy therefore is that, once pT2 < f * mQ2, with +f a parameter of the order of 2, a pT2 is chosen +like dpT2/pT2 between mQ2 and f * mQ2, a +nd a z flat in the allowed range. Thereafter acceptance +is based on the product of three factors, representing the running +of alpha_strong, the splitting kernel (including the mass term) +and the gluon density weight. At failure, a new pT2 is chosen +in the same range, i.e. is not required to be lower since no Sudakov +is involved. +
    • +
    + +
    + + + diff --git a/PYTHIA8/pythia8130/xmldoc/StandardModelParameters.xml b/PYTHIA8/pythia8130/xmldoc/StandardModelParameters.xml new file mode 100644 index 00000000000..c7c9da7e4a0 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/StandardModelParameters.xml @@ -0,0 +1,191 @@ + + +

    Standard-Model Parameters

    + +

    The strong coupling

    + +The AlphaStrong class is used to provide a first- or +second-order running alpha_strong (or, trivially, a +zeroth-order fixed one). Formulae are the standard ones found in +Yao06. The second-order expression used, eq. (9.5), +may be somewhat different in other approaches (with differences +formally of higher order), so do not necessarily expect perfect +agreement, especially not at small Q^2 scales. The starting +alpha_strong value is defined at the M_Z mass scale. +The Lambda values are matched at the b and c +flavour thresholds, such that alpha_strong is continuous. +For second-order matching an approximate iterative method is used. + +

    +Since we allow alpha_strong to vary separately for +hard processes, timelike showers, spacelike showers and multiple +interactions, the relevant values can be set in each of these classes. +The default behaviour is everywhere first-order running. + +

    +The alpha_strong calculation is initialized by +init( value, order), where value +is the alpha_strong value at M_Z and order +is the order of the running, 0, 1 or 2. Thereafter the value can be +calculated by alphaS(scale2), where +scale2 is the Q^2 scale in GeV^2. + +

    +For applications inside shower programs, a second-order alpha_s +value can be obtained as the product of the two functions +alphaS1Ord(scale2) and alphaS2OrdCorr(scale2), +where the first gives a simple first-order running (but with the +second-order Lambda) and the second the correction factor, +below unity, for the second-order terms. This allows a compact handling +of evolution equations. + +

    The electromagnetic coupling

    + +

    +The AlphaEM class is used to generate a running +alpha_em. The input StandardModel:alphaEMmZ +value at the M_Z mass is matched to a low-energy behaviour +with running starting at the electron mass threshold. The matching +is done by fitting an effective running coefficient in the region +betweeen the light-quark treshold and the charm/tau threshold. This +procedure is approximate, but good enough for our purposes. + +

    +Since we allow alpha_em to vary separately for +hard processes, timelike showers, spacelike showers and multiple +interactions, the choice between using a fixed or a running +alpha_em can be made in each of these classes. +The default behaviour is everywhere first-order running. +The actual values assumed at zero momentum transfer and +at M_Z are only set here, however. + + +The alpha_em value at vanishing momentum transfer +(and also below m_e). + + + +The alpha_em value at the M_Z mass scale. +Default is taken from Yao06. + + +

    +The alpha_em calculation is initialized by +init(order), where order is the order of +the running, 0 or 1, with -1 a special option to use the fix value +provided at M_Z. Thereafter the value can be +calculated by alphaEM(scale2), where +scale2 is the Q^2 scale in GeV^2. + +

    The electroweak couplings

    + +There are two degrees of freedom that can be set, related to the +electroweak mixing angle: + + +The weak mixing angle, as used in all Z^0 and W^+- +masses and couplings, except for the vector couplings of fermions +to the Z^0, see below. Default is the MSbar value from +Yao06. + + + +The weak mixing angle, as used to derive the vector couplings of fermions +to the Z^0, in the relation +v_f = a_f - 4 e_f sin^2(theta_W)bar. Default is the +effective-angle value from Yao06. + + +

    +These and various couplings can be read out from the static +CoupEW class:
    +CoupEW::sin2thetaW() gives the weak mixing angle set above.
    +CoupEW::cos2thetaW() gives 1 minus it.
    +CoupEW::sin2thetaWbar() gives the weak mixing angle as used +in fermion couplings.
    +CoupEW::ef(idAbs) gives the electrical charge. Note that this +and subsequent routines should be called with a positive +idAbs.
    +CoupEW::vf(idAbs) gives the vector coupling to +Z^0.
    +CoupEW::af(idAbs) gives the axial vector coupling.
    +CoupEW::t3f(idAbs) gives the weak isospin of lefthanded quarks, +i.e. a_f/2.
    +CoupEW::lf(idAbs) gives the lefthanded coupling, i.e. +(v_f + a_f/2)/2 (other definitions may differ by a factor +of 2).
    +CoupEW::rf(idAbs) gives the righthanded coupling, i.e. +(v_f - a_f/2)/2 (with comment as above).
    +CoupEW::ef2(idAbs) gives e_f^2.
    +CoupEW::vf2(idAbs) gives v_f^2.
    +CoupEW::af2(idAbs) gives a_f^2. + +

    The quark weak-mixing matrix

    + +The absolute values of the Cabibbo-Kobayashi-Maskawa matrix elements are +set by the following nine real values taken from Yao06 - +currently the CP-violating phase is not taken into account in this +parametrization. It is up to the user to pick a consistent unitary +set of new values whenever changes are made. + + +The V_ud CKM matrix element. + + + +The V_us CKM matrix element. + + + +The V_ub CKM matrix element. + + + +The V_cd CKM matrix element. + + + +The V_cs CKM matrix element. + + + +The V_cb CKM matrix element. + + + +The V_td CKM matrix element. + + + +The V_ts CKM matrix element. + + + +The V_tb CKM matrix element. + + +

    +These couplings can be read back out in a few alternative forms:
    +VCKM::Vgen(genU, genD) gives the CKM mixing element for +up-type generation index genU (1, 2 or 3) and +down-type generation index genD.
    +VCKM::V2gen(genU, genD) gives the square of the above.
    +VCKM::Vid(id1, id2) gives the CKM mixing element between +two quark flavours id1 and id2. The sign of +the flavours is irrelevant, since the process may be either of the type +q qbar' -> W or q g -> W q'. Flavour combinations +with no CKM mixing (e.g. u u) are given a vanishing value.
    +VCKM::V2id(id1, id2) gives the square of the above.
    +VCKM::V2sum(id) gives the sum of squares that a given +flavour can couple to, excluding the top quark. Is close to unity +for the first two generations.
    +VCKM::V2pick(id) picks a CKM partner quark (with the same +sign as id) according to the respective squared elements, +again excluding the top quark from the list of possibilities. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/TimelikeShowers.xml b/PYTHIA8/pythia8130/xmldoc/TimelikeShowers.xml new file mode 100644 index 00000000000..76f04f5f391 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/TimelikeShowers.xml @@ -0,0 +1,326 @@ + + +

    Timelike Showers

    + +The PYTHIA algorithm for timelike final-state showers is based on +the recent article Sjo05, where a transverse-momentum-ordered +evolution scheme is introduced. This algorithm is influenced by +the previous mass-ordered algorithm in PYTHIA Ben87 and by +the dipole-emission formulation in Ariadne Gus86. From the +mass-ordered algorithm it inherits a merging procedure for first-order +gluon-emission matrix elements in essentially all two-body decays +in the standard model and its minimal supersymmetric extension +Nor01. + +

    +The normal user is not expected to call TimeShower directly, +but only have it called from Pythia. Some of the parameters +below, in particular TimeShower:alphaSvalue, would be of +interest for a tuning exercise, however. + +

    Main variables

    + +Often the maximum scale of the FSR shower evolution is understood from the +context. For instance, in a resonace decay half the resonance mass sets an +absolute upper limit. For a hard process in a hadronic collision the choice +is not as unique. Here the factorization scale has been chosen as the +maximum evolution scale. This would be the pT for a +2 -> 2 process, supplemented by mass terms for massive outgoing +particles. Some small amount of freedom is offered by + +While the above rules would imply that pT_max = pT_factorization, +pTmaxFudge introduced a multiplicative factor f such +that instead pT_max = f * pT_factorization. Only applies to the +hardest interaction in an event. It is strongly suggested that +f = 1, but variations around this default can be useful to test +this assumption. + + +

    +The amount of QCD radiation in the shower is determined by + +The alpha_strong value at scale M_Z^2. The default +value corresponds to a crude tuning to LEP data, to be improved. + + +

    +The actual value is then regulated by the running to the scale +pT^2, at which the shower evaluates alpha_strong + + +Order at which alpha_strong runs, + + + + + +

    +QED radiation is regulated by the alpha_electromagnetic +value at the pT^2 scale of a branching. + + +The running of alpha_em. + + + + + +

    +The rate of radiation if divergent in the pT -> 0 limit. Here, +however, perturbation theory is expected to break down. Therefore an +effective pT_min cutoff parameter is introduced, below which +no emissions are allowed. The cutoff may be different for QCD and QED +radiation off quarks, and is mainly a technical parameter for QED +radiation off leptons. + + +Parton shower cut-off pT for QCD emissions. + + + +Parton shower cut-off pT for photon coupling to coloured particle. + + + +Parton shower cut-off pT for pure QED branchings. +Assumed smaller than (or equal to) pTminChgQ. + + +

    +Shower branchings gamma -> f fbar, where f is a +quark or lepton, in part compete with the hard processes involving +gamma^*/Z^0 production. In order to avoid overlap it makes +sense to correlate the maximum gamma mass allowed in showers +with the minumum gamma^*/Z^0 mass allowed in hard processes. +In addition, the shower contribution only contains the pure +gamma^* contribution, i.e. not the Z^0 part, so +the mass spectrum above 50 GeV or so would not be well described. + + +Maximum invariant mass allowed for the created fermion pair in a +gamma -> f fbar branching in the shower. + + +

    Interleaved evolution

    + +Multiple interactions (MI) and initial-state showers (ISR) are +always interleaved, as follows. Starting from the hard interaction, +the complete event is constructed by a set of steps. In each step +the pT scale of the previous step is used as starting scale +for a downwards evolution. The MI and ISR components each make +their respective Monte Carlo choices for the next lower pT +value. The one with larger pT is allowed to carry out its +proposed action, thereby modifying the conditions for the next steps. +This is relevant since the two components compete for the energy +contained in the beam remnants: both an interaction and an emission +take avay some of the energy, leaving less for the future. The end +result is a combined chain of decreasing pT values, where +ones associated with new interactions and ones with new emissions +are interleaved. + +

    +There is no corresponding requirement for final-state radiation (FSR) +to be interleaved. Such an FSR emission does not compete directly for +beam energy (but see below), and also can be viewed as occuring after +the other two components in some kind of time sense. Interleaving is +allowed, however, since it can be argued that a high-pT FSR +occurs on shorter time scales than a low-pT MI, say. +Backwards evolution of ISR is also an example that physical time +is not the only possible ordering principle, but that one can work +with conditional probabilities: given the partonic picture at a +specific pT resolution scale, what possibilities are open +for a modified picture at a slightly lower pT scale, either +by MI, ISR or FSR? Complete interleaving of the three components also +offers advantages if one aims at matching to higher-order matrix +elements above some given scale. + + +If on, final-state emissions are interleaved in the same +decreasing-pT chain as multiple interactions and initial-state +emissions. If off, final-state emissions are only addressed after the +multiple interactions and initial-state radiation have been considered. + + +

    +As an aside, it should be noted that such interleaving does not affect +showering in resonance decays, such as a Z^0. These decays are +only introduced after the production process has been considered in full, +and the subsequent FSR is carried out inside the resonance, with +preserved resonance mass. + +

    +One aspect of FSR for a hard process in hadron collisions is that often +colour diples are formed between a scattered parton and a beam remnant, +or rather the hole left behind by an incoming partons. If such holes +are allowed as dipole ends and take the recoil when the scattered parton +undergoes a branching then this translates into the need to take some +amount of remnant energy also in the case of FSR, i.e. the roles of +ISR and FSR are not completely decoupled. The energy taken away is +bokkept by increasing the x value assigned to the incoming +scattering parton, and a reweighting factor +x_new f(x_new, pT^2) / x_old f(x_old, pT^2) +in the emission probability ensures that not unphysically large +x_new values are reached. Usually such x changes are +small, and they can be viewed as a higher-order effect beyond the +accuracy of the leading-log initial-state showers. + +

    +This choice is not unique, however. As an alternative, if nothing else +useful for cross-checks, one could imagine that the FSR is completely +decoupled from the ISR and beam remnants. + + +If on, the final-state shower is allowed to borrow energy from +the beam remnants as described above, thereby changing the mass of the +scattering subsystem. If off, the partons in the scattering subsystem +are constrained to borrow energy from each other, such that the total +four-momentum of the system is preserved. This flag has no effect +on resonance decays, where the shower always preserves the resonance +mass, cf. the comment above about showers for resonances never being +interleaved. + + + +

    Radiation off octet onium states

    + +In the current implementation, charmonium and bottomonium production +can proceed either through colour singlet or colour octet mechanisms, +both of them implemented in terms of 2 -> 2 hard processes +such as g g -> (onium) g. +In the former case the state does not radiate and the onium therefore +is produced in isolation, up to normal underlying-event activity. In +the latter case the situation is not so clear, but it is sensible to +assume that a shower can evolve. (Assuming, of course, that the +transverse momentum of the onium state is sufficiently high that +radiation is of relevance.) + +

    +There could be two parts to such a shower. Firstly a gluon (or even a +quark, though less likely) produced in a hard 2 -> 2 process +can undergo showering into many gluons, whereof one branches into the +heavy-quark pair. Secondly, once the pair has been produced, each quark +can radiate further gluons. This latter kind of emission could easily +break up a semibound quark pair, but might also create a new semibound +state where before an unbound pair existed, and to some approximation +these two effects should balance in the onium production rate. +The showering "off an onium state" as implemented here therefore should +not be viewed as an accurate description of the emission history +step by step, but rather as an effective approach to ensure that the +octet onium produced "in the hard process" is embedded in a realistic +amount of jet activity. +Of course both the isolated singlet and embedded octet are likely to +be extremes, but hopefully the mix of the two will strike a reasonable +balance. However, it is possible that some part of the octet production +occurs in channels where it should not be accompanied by (hard) radiation. +Therefore reducing the fraction of octet onium states allowed to radiate +is a valid variation to explore uncertainties. + +

    +If an octet onium state is chosen to radiate, the simulation of branchings +is based on the assumption that the full radiation is provided by an +incoherent sum of radiation off the quark and off the antiquark of the +onium state. Thus the splitting kernel is taken to be the normal +q -> q g one, multiplied by a factor of two. Obviously this is +a simplification of a more complex picture, averaging over factors pulling +in different directions. Firstly, radiation off a gluon ought +to be enhanced by a factor 9/4 relative to a quark rather than the 2 +now used, but this is a minor difference. Secondly, our use of the +q -> q g branching kernel is roughly equivalent to always +following the harder gluon in a g -> g g branching. This could +give us a bias towards producing too hard onia. A soft gluon would have +little phase space to branch into a heavy-quark pair however, so the +bias may not be as big as it would seem at first glance. Thirdly, +once the gluon has branched into a quark pair, each quark carries roughly +only half of the onium energy. The maximum energy per emitted gluon should +then be roughly half the onium energy rather than the full, as it is now. +Thereby the energy of radiated gluons is exaggerated, i.e. onia become too +soft. So the second and the third points tend to cancel each other. + +

    +Finally, note that the lower cutoff scale of the shower evolution depends +on the onium mass rather than on the quark mass, as it should be. Gluons +below the octet-onium scale should only be part of the octet-to-singlet +transition. + + +Allow colour-octet charmonium and bottomonium states to radiate gluons. +0 means that no octet-onium states radiate, 1 that all do, with possibility +to interpolate between these two extremes. + + + +The colour factor used used in the splitting kernel for those octet onium +states that are allowed to radiate, normalized to the q -> q g +splitting kernel. Thus the default corresponds to twice the radiation +off a quark. The physically preferred range would be between 1 and 9/4. + + +

    Further variables

    + +There are several possibilities you can use to switch on or off selected +branching types in the shower, or in other respects simplify the shower. +These should normally not be touched. Their main function is for +cross-checks. + + +Allow a QCD shower, i.e. branchings q -> q g, g -> g g +and g -> q qbar; on/off = true/false. + + + +Number of allowed quark flavours in g -> q qbar branchings +(phase space permitting). A change to 4 would exclude +g -> b bbar, etc. + + + +Allow quarks to radiate photons, i.e. branchings q -> q gamma; +on/off = true/false. + + + +Allow leptons to radiate photons, i.e. branchings l -> l gamma; +on/off = true/false. + + + +Allow photons to branch into lepton or quark pairs, i.e. branchings +gamma -> l+ l- and gamma -> q qbar; +on/off = true/false. + + + +Number of allowed quark flavours in gamma -> q qbar branchings +(phase space permitting). A change to 4 would exclude +g -> b bbar, etc. + + + +Number of allowed lepton flavours in gamma -> l+ l- branchings +(phase space permitting). A change to 2 would exclude +gamma -> tau+ tau-, and a change to 1 also +gamma -> mu+ mu-. + + + +Use of matrix element corrections where available; on/off = true/false. + + + +Azimuthal asymmetry induced by gluon polarization; on/off = true/false. + + +
    + + diff --git a/PYTHIA8/pythia8130/xmldoc/TopProcesses.xml b/PYTHIA8/pythia8130/xmldoc/TopProcesses.xml new file mode 100644 index 00000000000..4167a944472 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/TopProcesses.xml @@ -0,0 +1,43 @@ + + +

    Top Processes

    + +Different ways to produce top quarks, singly or in pairs. + + +Common switch for the group of top production. + + + +Scatterings g g -> t tbar. +Code 601. + + + +Scatterings q qbar -> t tbar by gluon exchange. +Code 602. + + + +Scatterings q q' -> t q'' by t-channel exchange +of a W^+- boson. +Code 603. + + + +Scatterings f fbar -> t tbar by s-channel exchange +of a gamma^*/Z^0 boson. +Code 604. + + + +Scatterings f fbar' -> t q'' by s-channel exchange +of a W^+- boson. +Code 605. + + + +
    + + + diff --git a/PYTHIA8/pythia8130/xmldoc/TotalCrossSections.xml b/PYTHIA8/pythia8130/xmldoc/TotalCrossSections.xml new file mode 100644 index 00000000000..0c06db166f4 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/TotalCrossSections.xml @@ -0,0 +1,115 @@ + + +

    Total Cross Sections

    + +The SigmaTotal class returns the total, elastic, diffractive +and nondiffractive cross sections in hadronic collisions, and also the +slopes of the d(sigma)/dt distributions. The parametrizations +used are from Sch97 which borrows some of the total cross +sections from Don92. + +

    +The allowed combinations of incoming particles are p + p, +pbar + p, pi+ + p, pi- + p, +pi0/rho0 + p, phi + p, J/psi + p, +rho + rho, rho + phi, rho + J/psi, +phi + phi, phi + J/psi, J/psi + J/psi. +The strong emphasis on vector mesons is related to the description +of gamma + p and gamma + gamma interactions in a +Vector Dominance Model framework (which will not be available for some +time to come, so this is a bit of overkill). + +

    Variables

    + +If the internally implemented cross section parametrizations are not +satisfactory, it is possible to override the cross section values +with + + +Allow a user to set own cross sections by hand; yes/no = true/false. + + +

    +When SigmaTotal:setOwn = yes, the user is expected to set +values for the corresponding cross sections: + + +Total cross section in mb. + + + +Elastic cross section in mb. + + + +Single Diffractive cross section A + B -> X + B in mb. + + + +Single Diffractive cross section A + B -> A + X in mb. + + + +Double Diffractive cross section A + B -> X_1 + X_2 in mb. + + +

    +Note that the total cross section subtracted by the elastic and various +diffractive ones gives the inelastic nondiffractive cross section, +which therefore is not set separately. If this cross section evaluates +to be negative the internal parametrizations are used instead of the +ones here. However, since the nondiffractive inelastic cross section +is what makes up the minimum-bias event class, and plays a major role +in the description of multiple interactions, it is important that a +consistent set is used. + +

    +In the above option the t slopes are based on the internal +parametrizations. In addition there is no Coulomb-term contribution +to the elastic (or total) cross section, which of course becomes +infinite if this contribution is included. If you have switched on +SigmaTotal:setOwn you can further switch on a machinery +to include the Coulomb term, including interference with the conventional +strong-interaction Pomeron one Ber87. Then the elastic cross +section is no longer taken from SigmaTotal:sigmaEl but +derived from the parameters below and SigmaTotal:sigmaTot, +using the optical theorem. The machinery is only intended to be used for +p p and pbar p collisions. The description of +diffractive events, and especially their slopes, remains unchanged. + + +Allow a user to set parameters for the normalization and shape of the +elastic cross section the by hand; yes/no = true/false. + + + +the slope b of the strong-interaction term exp(bt), +in units of GeV^-2. + + + +the ratio of the real to the imaginary parts of the nuclear scattering +amplitude. + + + +the main parameter of the electric form factor +G(t) = lambda^2 / (lambda + |t|)^2, in units of GeV^2. + + + +since the Coulomb contribution is infinite a lower limit on +|t| must be set to regularize the divergence, +in units of GeV^2. + + + +The Coulomb term is taken to contain a phase factor +exp(+- i alpha phi(t)), with + for p p and - for +pbar p, where phi(t) = - phaseConst - ln(-B t/2). +This constant is model dependent Cah82. + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/Tunes.xml b/PYTHIA8/pythia8130/xmldoc/Tunes.xml new file mode 100644 index 00000000000..c84c5046e1e --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/Tunes.xml @@ -0,0 +1,96 @@ + + +

    Tunes

    + +Since some physics aspects cannot be derived from first principles, +this program contains many parameters that represent a true +uncertainty in our understanding of nature. Particularly afflicted +are the areas of hadronization and multiple interactions, which both +involve nonperturbative QCD physics. + +

    +Technically, PYTHIA parameters can be varied independently of each +other, but the physical requirement of a sensible description of a set +of data leads to correlations and anticorrelations between the +parameters. Hence the need to produce tunes, not of one parameter at +a time, but simultaneously for a group of them. A well-known such +example is parton densities, where combined tunes to a wide range of data +have been produced, that can then be obtained prepackaged. + +

    +Given the many PYTHIA parameters to be tuned, it is convenient to +divide the task into subtasks. Firstly, if we assume jet universality, +hadronization and final-state parton showers should be tuned to +e^+e^- annihilation data, notably from LEP1, since this +offers the cleanest environment. Secondly, with such parameters fixed, +hadron collider data should be studied to pin down multiple interactions +and other further aspects, such as initial-state radiation. (Thirdly +would come anything else, such as physics with photon beams, which +involve further parameters, but that is beyond the current scope.) + +

    +Sadly PYTHIA 8 did not yet take many steps along this long road. +While the default values in PYTHIA 8 have been chosen "sensibly", +so far there has not been a complete, consistent tuning of the program. +For hadronization we can partly benefit from the LEP experience with +PYTHIA 6, since the basic hadronization scheme did not change. +However, there never was a combined LEP tune, since each of the four +LEP collaborations produced their own tunes to their own data. The +situation is worse for multiple interactions, where PYTHIA 8 is more +different from PYTHIA 6. Nevertheless, the PYTHIA 6 tunes to CDF data, +performed by R.D. Field, have been used as a rough guide in picking +reasonable default values. + +

    +In the future we hope to see PYTHIA 8 tunes appear. Like with parton +distributions, there is likely to be several tunes, because different +sets of data will pull in different directions, by imperfections +in the model or in the data, and by differences in the chosen +tuning strategies. We therefore propose to collect some of these tunes +here, in a prepackaged form. Of course, in all cases it is a matter +of setting values for parameters already defined elsewhere, so the +tunes offer no new functionality, only a more convenient setup. + +

    +If you set either the Tune:ee and Tune:pp +modes below non-zero then all parameters used in the respective tune +will be set accordingly when pythia.init(...) is called. +You can check this by calling pythia.settings.listChanged() +before and after initialization; before only the tune modes are +nondefault, afterwards all the non-default-valued parameters in the +tune appear. Therefore, for better or worse, you cannot combine a tune +option with your own choices for some of the parameters used in the tune, +since the values you set before pythia.init(...) would be +overwritten at that point. + + +Choice of tune to e^+e^- data, mainly for the hadronization +and timelike-showering aspects of PYTHIA. + + + + + +Choice of tune to pp / ppbar data, mainly for the +multiple-interactions and initial-state-radiation aspects of PYTHIA. +Note: Currently this is only a placeholder, since no +tunes alternative to the default values exist. + + + + + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/UpdateHistory.xml b/PYTHIA8/pythia8130/xmldoc/UpdateHistory.xml new file mode 100644 index 00000000000..7806eaadf80 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/UpdateHistory.xml @@ -0,0 +1,180 @@ + + +

    Update History

    + +These update notes describe major updates relative to the baseline +PYTHIA 8.100 version. However, they are less extensive than the +corresponding update notes for PYTHIA 6. There are three main +reasons for this: +
      +
    • The manual contained on these html/php pages is kept up to date. + (However, the "Brief Introduction" may not always be.) +
    • +
    • 8.1 is a quite new code, so there are many minor changes that, + if all were to be documented, would hide the key ones. +
    • +
    • 8.1 is not yet used for "mission critical" applications, + so there is less need to trace changed behaviour. +
    • +
    + +

    Main news by version

    + +
      +
    • 8.101: 10 November 2007 +
        +
      • New option to initialize with arbitrary beam directions
        +pythia.init( idA, idB, pxA, pyA, pzA, pxB, pyB, pzB) +
      • +
      • The LHAevnt and LHAinit classes have been +joined into a new LHAup one, with new options that allow +the writing of a Les Houches Event File. +
      • +
      +
    • + +
    • 8.102: 6 December 2007 +
        +
      • Limited capability to use two different Pythia instances +for signal + pileup event generation, see main19.cc for an +example. +
      • +
      • Added capability to set beam energy spread +and beam vertex. +
        +Warning: as a consequence, some settings names have been changed, +see below. +
      • +
      +
    • + +
    • 8.103: 22 January 2008 +
        +
      • Updated HepMC conversion routine. +
      • +
      • In the Event class the = and +=+ methods have been overloaded to allow the copying +or appending of event records. Illustrated in main19.cc. +
      • +
      +
    • + +
    • 8.104: 14 February 2008 +
        +
      • Updated configure scripts. +
      • +
      • The SusyLesHouches class updated to handle +SLHA version 2. +
      • +
      • The forceHadronLevel() method introduced for standalone +hadronization. +
      • +
      • main15.cc illustrated how either full hadronization or +only decays of some particles can be looped over for the rest of the +event retained. +
      • +
      • The html and php page formatting improved with +cascading style sheets. +
      • +
      • The static ErrorMsg class has been removed and +its functionality moved into the non-static Info class, +in the renamed Info file. +
      • +
      +
    • + +
    • 8.105: 24 February 2008 +
        +
      • Further reduction of the use of static, with related code changes. +This should allow to have several almost independent Pythia +instances. Some static classes still remain, however, notably for +random number generation and particle properties. +
      • +
      • Several minor improvements and new options. +
      • +
      +
    • + +
    • 8.106: 11 March 2008 +
        +
      • Improved handling of the Higgs width, relevant for massive and thereby +broad resonance shapes. +
      • +
      +
    • + +
    • 8.107: 17 March 2008 +
        +
      • Correction in the event record, so that the beam particles in line +1 and 2 do not have any mother according to the motherList +method. Previously the "system" entry in line 0 was counted as their +mother, which gave rise to an unexpected extra vertex in the conversion +to the HepMC format. +
      • +
      +
    • + +
    • 8.108: 1 May 2008 +
        +
      • Support for HepMC version 1 is removed, to simplify the code and +reflect the evolution of the field. +
      • +
      • Status codes are stored in HepMC only as 1 for existing and 2 for +decayed or fragmented particles (whereas previously the original PYTHIA +codes were used for the latter). +
      • +
      • Parton densities are stored in HepMC as xf(x,Q^2) +rather than the f(x,Q^2) used in (some) previous versions. +
      • +
      • The SusyLesHouches class has ben updated so that reading is fully +compatible with the SLHA2 standard. +
      • +
      • The matrix elements for neutralino pair production have now been +completed and checked. +
      • +
      • A new compilation option -Wshadow is introduced and +code is rewritten at all places where this option gave warnings. +
      • +
      • Minor library correction to allow compilation with gcc 4.3.0.
      • +
      • Ensure that alpha_strong does not blow up, by introducing +a minimal scale somewhat above Lambda_3 (roughly where +alpha_strong = 10). +
      • +
      • New methods isValence1() and isValence2() +in the Info class. +
      • +
      +
    • + +
    + +

    Changes among settings names

    + +New capabilities are still being added, meaning new settings names. +It then may become preferable to rename existing settings to form +new logical groups. Here is a list of thise changes that have been +made since be 8.100 baseline version. +
      +
    • A '*' is used as wildcard. +
    • +
    • Names within brackets denotes also new/changed functionality. +
    • +
    + + + + + + + + + + + +
    8.100 setting has been moved to
    Beams:* BeamRemnants:*
    Main:idA Beams:idA
    Main:idB Beams:idB
    Main:inCMframe (Beams:frameType)
    Main:eCM Beams:eCM
    Main:eA Beams:eA
    Main:eB Beams:eB
    Main:LHEF Beams:LHEF
    + + + +
    + + diff --git a/PYTHIA8/pythia8130/xmldoc/UserHooks.xml b/PYTHIA8/pythia8130/xmldoc/UserHooks.xml new file mode 100644 index 00000000000..aab7ef6e199 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/UserHooks.xml @@ -0,0 +1,292 @@ + + +

    User Hooks

    + +Sometimes it may be convenient to step in during the generation +process: to modify the built-in cross sections, to veto undesirable +events or simply to collect statistics at various stages of the +evolution. There is a base class UserHooks that gives +you this access at a few selected places. This class in itself does +nothing; the idea is that you should write your own derived class +for your task. A few very simple derived classes come with the +program, mainly as illustration. + +

    +For a derived class to be called during the execution, a pointer to +an object of this class should be handed in with the +
    + +pythia.setUserHooksPtr( UserHooks*) method. + +

    +There are four distinct sets of routines. Ordered by increasing +complexity, rather than by their appearance in the event-generation +sequence, they are: +
    (i) Ones that gives you access to the event record in between +the process-level and parton-level steps, or in between the +parton-level and hadron-level ones. You can study the event record +and decide whether to veto this event. +
    (ii) Ones that allow you to set a scale at with the combined +parton-level MI+ISR+FSR downwards evolution in pT is +temporarily interrupted, so the event can be studied and either +vetoed or allowed to continue the evolution. +
    (iii) Ones that allow you to to study the event after the first +few ISR/FSR emissions, so the event can be vetoed or allowed to +continue the evolution. +
    (iv) Ones that gives you access to the properties of the trial +hard process, so that you can modify the internal Pythia cross section +by your own correction factors. +
    They are described further in the following. + +

    Interrupt between the main generation levels

    + +If your derived class redefines the +
    bool canVetoProcessLevel() +
    method to return true, then the method +
    bool doVetoProcessLevel(const Event& process) +
    will be called immediately after a hard process has been selected and +stored in the process event record. You can study, but not +modify, this record. Based on that you can decide whether to veto the +event or let it continue to evolve. If you veto, then this event is not +counted among the accepted ones, and do not contribute to the estimated +cross section. The pytha.next() method will begin a +completely new event, so the vetoed event will not appear in the +output of pythia.next(). + +

    +Note that this is different from setting the flag +PartonLevel:all = off. +Also in this case the event +generation will stop after the process level, but an event generated +up to this point is considered perfectly acceptable, and cross sections +are not affected. That is, this option is intended for simple studies of +hard processes, where one can save time by not generating the rest of the +story. By contrast, the doVetoProcessLevel() allows you to +throw away uninteresting events at an early stage to save time that way, +but those events that do survive the veto are allowed to develop into +complete final states (unless flags have been set otherwise). + +

    +The +
    bool canVetoPartonLevel() +
    and +
    bool doVetoPartonLevel(const Event& event) +
    are exact analogues to the above two methods, except that these +ones are called after the parton level, i.e. when showers, multiple +interactions and beam remnants have been set up, but hadronization and +decays have not yet been performed. Information is now made available in +the event event record. The difference relative to the +HadronLevel:all = off +flag setting follows the same pattern as above. + +

    +The effect of the vetoes can be studied in the output of the +pythia.statistics() method. The "Selected" column represents +the number of events that were found acceptable by the internal Pythia +machinery, whereas the "Accepted" one are the events that also survived +the user cuts. + +

    Interrupt during the parton-level evolution, at a pT scale

    + +During the parton-level evolution, multiple interactions (MI), +initial-state radiation (ISR) and final-state radiation (FSR) +are normally evolved downwards in +one interleaved evolution sequence of decreasing pT values. +For some applications, e.g matrix-element-matching approaches, it +may be convenient to stop the evolution temporarily when the "hard" +emissions have been considered, but before continuing with the more +time-consuming soft activity. Based on these hard partons one can make +a decision whether the event at all falls in the intended event class, +e.g. has the "right" number of parton-level jets. If yes then, as for +the methods above, the evolution will continue all the way up to a +complete event. Also as above, if no, then the event will not be +considered in the final cross section. + +

    +In this subsection we outline the possibility to interrupt at a given +pT scale, in the next to interrupt after a given number of +emissions. + +

    +To use this possibility you need to redefine +
    bool canVetoPT() +
    to return true and +
    double scaleVetoPT() +
    to return the pT scale at which you want to study the event. + +

    +The key routine, where you decide whether the event should be vetoed +(return true) or not (false), is +
    bool doVetoPT(int iPos, const Event& event) +
    Here +
    iPos is the position/status when the routine is +called: +
    = 0 when no MI, ISR or FSR occured above the veto scale; +
    = 1 when inside the interleaved MI + ISR + FSR evolution, +after an MI process; +
    = 2 when inside the interleaved MI + ISR + FSR evolution, +after an ISR emission; +
    = 3 when inside the interleaved MI + ISR + FSR evolution, +after an FSR emission; +
    = 4 for the optional case where FSR is deferred from the interleaved +evolution and only considered separately afterward (then alternative 3 +would never occur); +
    = 5 is for subsequent resonance decays, and is called once +for each decay in a chain such as t -> b W, W -> u dbar. + +

    +The event record contains a list of all partons generated so far, also +including intermediate ones not part of the "current final state", +and also those from further multiple interactions. This may not be +desirable for comparisons with matrix-element calculations. The method +
    void subEvent(const Event& event, bool isHardest = true) +
    offers a simple recipe to extract a list of only the current +partons from the hardest interaction, as relevant for iPos +codes 0 - 4. With isHardest = false instead the latest +"subprocess" is extracted, as relevant when iPos is 5, +where it corresponds to the partons in the currently considered decay. + +

    +The result is stored in the class member Event workEvent. +The daughter1() and daughter2() both return +the position in the original event record (process or +event), so you can trace the full history, if of interest. +The workEvent can e.g. be sent on to a +jet clustering algorithm. +You are free to edit workEvent as you desire, e.g. boost +to its rest frame before analysis, or remove particles that should +not be analyzed. + +

    Interrupt during the parton-level evolution, after a step

    + +This option is closely related to the one above, so we do not repeat +the introduction, nor the possibilities to study the event record, +also by using subEvent(...). +What is different is that this method gives access to the event as +it looks like after each of the first few steps in the downwards +evolution, irrespectively of the pT scales of these branchings. +Furthermore, it is here assumed that the focus is on the hardest +subprocess, so that ISR/FSR emissions associated with additional MI's +are not considered. + +

    +To use the possibility to study the event after the first steps you need +to redefine +
    bool canVetoStep() +
    to return true and +
    int numberVetoStep() +
    to return up to how many steps each of ISR and FSR (for the hardest +interaction) that you want to be able to study. The number of steps +defaults to the first one only. + +

    +The key routine, where you decide whether the event should be vetoed +(return true) or not (false), is +
    bool doVetoStep( int iPos, int nISR, int nFSR, +const Event& event) +
    Here +
    iPos is the position from where the routine has been +called, options 2 - 5 of the doVetoPT(...) routine +above, while options 0 and 1 are not relevant here; +
    nISR is the number of ISR emissions in the hardest +process so far; and +
    nFSR is the number of FSR emissions in the hardest +process so far. +
    For resonance decays, iPos = 5, the nISR +is set 0 and nFSR refers to the number of emissions in +the currently studied system. + +

    Modify cross-sections

    + +If you want to modify a cross section you need to redefine +
    bool canModifySigma() +
    to return true and +
    double multiplySigmaBy(const SigmaProcess* sigmaProcessPtr, +const PhaseSpace* phaseSpacePtr, bool inEvent) +
    to provide the factor by +which you want to see the cross section modified. If you return unity +then the normal cross section is obtained. Note that, unlike the +methods above, these modifications do not lead to a difference between +the number of "selected" events and the number of "accepted" ones, +since the modifications occur already before the "selected" level. +The integrated cross section of a process is modified, of course. + +

    +What makes the multiplySigmaBy(...) routine somewhat +tricky to write is that the hard-process event has not yet been +constructed, so one is restricted to use the information available +in the phase-space and cross-section objects currently being accessed. +Which of their methods are applicable depends on the process, +in particular the number of final-state particles. The +UserHooks code contains explicit instructions about +which methods provide meaningful information. + +

    +The inEvent flag is true when this method is +called from within the event-generation machinery and false +when it is called at the initialization stage of the run, when the +cross section is explored to find a maximum for later Monte Carlo usage. +Cross-section modifications should be independent of this flag, +for consistency, but if multiplySigmaBy(...) is used to +collect statistics on the original kinematics distributions before cuts, +then it is important to be able to exclude the initialization stage +from comparisons. + +

    +Note that the cross section is only modifiable for normal hard processes. +It does not affect the cross section in further multiple interactions, +nor in elastic/diffractive/minimum-bias events. + +

    +One derived class is supplied as an example how this facility can be used +to reweight cross sections in the same spirit as is done with QCD cross +sections for the minimum-bias/underlying-event description: + +suppress small-pT production for 2 -> 2 processes +only, while leaving other processes unaffected. The basic suppression +factor is pT^4 / ((k*pT0)^2 + pT^2)^2, where pT +refers to the current hard subprocess and pT0 is the same +energy-dependent dampening scale as used for +multiple interactions. +The optional arguments provide further variability. + +corresponds to the additional factor k in the above formula. +It is by default equal to 1 but can be used to explore deviations from +the expected value. + + +if this number n is bigger than the default 0, the +corresponding number of alpha_strong factors is also +reweighted from the normal renormalization scale to a modified one, +i.e. a further suppression factor +( alpha_s((k*pT0)^2 + Q^2_ren) / alpha_s(Q^2_ren) )^n +is introduced. + + +regulates which kind of new alpha_strong value is evaluated +for the numerator in the above expression. It is by default the same +as set for multiple interactions (i.e. same starting value at +M_Z and same order of running), but if false +instead the one for hard subprocesses. The denominator +alpha_s(Q^2_ren) is always the value used for the "original", +unweighted cross section. + + + +

    Final comments

    + +All the possibilities above can be combined freely and also be combined +with the standard flags. An event would then survive only if it survived +each of the possible veto methods. There are no hidden interdependencies +in this game, but of course some combinations may not be particularly +meaningful. For instance, if you set PartonLevel:all = off +then the doVetoPT(...) and doVetoPartonLevel(...) +locations in the code are not even reached, so they would never be called. + +

    +An example how the above methods can be used for toy studies is found in +main10.cc. + + + + diff --git a/PYTHIA8/pythia8130/xmldoc/Version.xml b/PYTHIA8/pythia8130/xmldoc/Version.xml new file mode 100644 index 00000000000..2045c1aeb1b --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/Version.xml @@ -0,0 +1,19 @@ + + +

    Version

    + +The settings on this page should not be changed by the ordinary user, +but appear here for documentation purposes, and so that they can +form part of the standard databases and be queried accordingly. + + +Version and subversion number, with three significant decimals. + + + +Last date of change of current (sub)version, in format yyyymmdd. + + +
    + + diff --git a/PYTHIA8/pythia8130/xmldoc/Welcome.xml b/PYTHIA8/pythia8130/xmldoc/Welcome.xml new file mode 100644 index 00000000000..d44c0af0d72 --- /dev/null +++ b/PYTHIA8/pythia8130/xmldoc/Welcome.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + -- 2.39.3