Belle II Software development
FragmentationModule.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <generators/modules/fragmentation/FragmentationModule.h>
10
11#include <generators/evtgen/EvtGenInterface.h>
12#include <generators/utilities/GeneratorConst.h>
13
14#include <framework/gearbox/Unit.h>
15#include <framework/gearbox/Const.h>
16#include <framework/particledb/EvtGenDatabasePDG.h>
17#include <framework/utilities/FileSystem.h>
18
19#include <TRandom3.h>
20
21#include <mdst/dataobjects/MCParticleGraph.h>
22
23#include <framework/logging/Logger.h>
24#include <framework/utilities/IOIntercept.h>
25
26#include <string>
27
28using namespace std;
29using namespace Belle2;
30using namespace Pythia8;
31
32//-----------------------------------------------------------------
33// Register the Module
34//-----------------------------------------------------------------
35REG_MODULE(Fragmentation);
36
37//-----------------------------------------------------------------
38// Implementation
39//-----------------------------------------------------------------
41{
42 //Set module properties
43 setDescription("Fragmention of (u/d/s/c) quarks using PYTHIA8");
44
45 //Parameter definition
46 addParam("ParameterFile", m_parameterfile, "Input parameter file for PYTHIA",
47 FileSystem::findFile("generators/modules/fragmentation/data/pythia_belle2.dat"));
48 addParam("ListPYTHIAEvent", m_listEvent, "List event record of PYTHIA after hadronization", 0);
49 addParam("UseEvtGen", m_useEvtGen, "Use EvtGen for specific decays", 1);
50 addParam("DecFile", m_DecFile, "EvtGen decay file (DECAY.DEC)",
51 FileSystem::findFile("decfiles/dec/DECAY_BELLE2.DEC", true));
52 addParam("UserDecFile", m_UserDecFile, "User EvtGen decay file", std::string(""));
53 addParam("CoherentMixing", m_coherentMixing, "Decay the B0-B0bar coherently (should always be true)", true);
54 addParam("QuarkPairMotherParticle", m_quarkPairMotherParticle,
55 "PDG Code of the mother particle of the quark pair (default Z0 boson)", 23);
56 addParam("AdditionalPDGCodes", m_additionalPDGCodes, "Additional particles used by Pythia", {});
57
58 //initialize member variables
59 evtgen = 0;
60 nAdded = 0;
61 nQuarks = 0;
62 nVpho = 0;
63 nAll = 0;
64 nGood = 0;
65}
66
67
72
74{
75
76 // print internal pythia error statistics
78 statLogCapture.start();
79 m_Pythia->stat();
80 statLogCapture.finish();
81
82 if (nAll != nGood) {
83 double ratio = 0.; //ratio of good over all events
84 if (nAll) ratio = 100.0 * nGood / nAll;
85
86 B2WARNING("Not all events could be fragmented: " << nAll - nGood << " events failed.");
87 B2WARNING("Total number of events: " << nAll << ", of these fragmented: " << nGood << ", success-ratio (should be >97%): " << ratio
88 << "%");
89 B2WARNING("Please contact the generator librarian if the success ratio is below 97%.");
90 B2WARNING("Please treat the success-ratio as correction of the effective cross section due to unphysical events.");
91 }
92}
93
94//-----------------------------------------------------------------
95// Initialize
96//-----------------------------------------------------------------
98{
99 m_mcparticles.isRequired(m_particleList);
100
101 B2DEBUG(150, "Initialize PYTHIA8");
102
103 // Generator and the shorthand m_PythiaEvent = pythia->event are declared in .h file
104 // A simple way to collect all the changes is to store the parameter values in a separate file,
105 // with one line per change. This should be done between the creation of the Pythia object
106 // and the init call for it.
107
109 initLogCapture.start();
110
111 m_Pythia = new Pythia;
112 m_PythiaEvent = &m_Pythia->event;
113 (*m_PythiaEvent) = 0;
114
115 // Load EvtGen particle data.
118
119 // Switch off ProcessLevel
120 m_Pythia->readString("ProcessLevel:all = off");
121
122 // Read the PYTHIA input file, overrides parameters
123 if (!m_Pythia->readFile(m_parameterfile))
124 B2FATAL("Cannot read Pythia parameter file.");
125
126 // Set framework generator
127 // Switch between raw and smart pointers depending on the Pythia version
128#if PYTHIA_VERSION_INTEGER < 8301
129 FragmentationRndm* fragRndm = new FragmentationRndm();
130 m_Pythia->setRndmEnginePtr(fragRndm);
131#else
132 std::shared_ptr<FragmentationRndm> fragRndm = std::make_shared<FragmentationRndm>();
133 m_Pythia->setRndmEnginePtr(fragRndm);
134#endif
135
136 // Initialize PYTHIA
137 m_Pythia->init();
138
139 // Set EvtGen (after m_Pythia->init())
140 evtgen = 0;
141
142 if (m_useEvtGen) {
143 B2INFO("Using PYTHIA EvtGen Interface");
144 const std::string defaultDecFile = FileSystem::findFile("decfiles/dec/DECAY_BELLE2.DEC", true);
145 if (m_DecFile.empty()) {
146 B2ERROR("No global decay file defined, please make sure the parameter 'DecFile' is set correctly");
147 return;
148 }
149 if (defaultDecFile.empty()) {
150 B2WARNING("Cannot find default decay file");
151 } else if (defaultDecFile != m_DecFile) {
152 B2INFO("Using non-standard DECAY file \"" << m_DecFile << "\"");
153 }
154 evtgen = new EvtGenDecays(m_Pythia, evtGen);
155 // Set signal particle suffix.
156 // Signal particle names must end in "sig" in user decay file.
157 evtgen->signalSuffix = "sig";
158 // Read the user decay file.
159 evtgen->readDecayFile(m_UserDecFile);
160 // Workaround for Pythia bug. It is the only way to call
161 // EvtGenDecays::updateData(true) to disable particle decays
162 // for all particles from EvtGen decay table. Thus, EvtGen generation
163 // has to be called before generation of the first Pythia event.
164 // Since Pythia event is currently empty, it actually only updates
165 // the particle properties (exactly what is necessary).
166 evtgen->decay();
167 }
168
169 // List variable(s) that differ from their defaults
170 m_Pythia->settings.listChanged();
171
172 initLogCapture.finish();
173}
174
175//-----------------------------------------------------------------
176// Event
177//-----------------------------------------------------------------
179{
180 // Reset the indices of the graph
181 mcParticleGraph.clear();
183
184 // Reset PYTHIA event record to allow for new event
185 IOIntercept::OutputToLogMessages resetLogCapture("EvtGen", LogConfig::c_Debug, LogConfig::c_Error, 100, 100);
186 resetLogCapture.start();
187 m_PythiaEvent->reset();
188 resetLogCapture.finish();
189
190 // Reset counter for added quarks and vphos
191 nAdded = 0;
192 nQuarks = 0;
193 nVpho = 0;
194
195 // Store which MCParticle index belongs to which Pythia index
196 std::map<int, int> indexPYTHIA;
197
198 // Store which Pythia index belongs to which MCParticle index
199 std::map<int, int> indexMCGraph;
200
201 // Store position of the quark (mother of hadronized final state)
202 int quarkPosition = 0;
203
204 // Loop over all particles to find the quark pair
205 int nPart = m_mcparticles.getEntries();
206 for (int iPart = 0; iPart < nPart; iPart++) {
207 MCParticle* currParticle = m_mcparticles[iPart];
208
209 //returns quark id if it finds a quark, zero otherwise
210 //increments a counter for the number of found quarks
211 int pythiaIndex = addParticleToPYTHIA(*currParticle);
212
213 if (pythiaIndex != 0) {
214 indexPYTHIA[nAdded] = iPart;
215 if (pythiaIndex > 0) quarkPosition = iPart;
216 }
217 }
218
219 // Check needed if virtual exchange boson and two quarks are present
220 if (nQuarks != 2) {
221 B2FATAL("Invalid number of quarks: " << nQuarks << " (should be 2)!");
222 }
223
224 if (nVpho != 1) {
225 B2WARNING("No virtual exchange particle given, no PYTHIA FSR in Decays");
226 } else {
227 // Adding QCD and QED FSR
228 m_Pythia->forceTimeShower(2, 3, 20.00);
229 }
230
231 // Check needed if event is energetically possible
232 // ...
233
234 // Do the fragmentation using PYTHIA
235 setReturnValue(1); //return value is 1...
236 nAll = nAll + 1;
237
239 eventLogCapture.start();
240 int success = m_Pythia->next();
241 eventLogCapture.finish();
242
243 if (!success) {
245 listLogCapture.start();
246 m_PythiaEvent->list();
247 listLogCapture.finish();
248
249 setReturnValue(-1); //return value becomes -1 if trials were not successful
250 } else {
251 nGood = nGood + 1;
252 }
253
254 // use evtgen to perform the decay
255 if (m_useEvtGen) {
257 decayLogCapture.start();
258 evtgen->decay();
259 decayLogCapture.finish();
260 }
261
262 // Loop over the PYTHIA list and assign the mother-daughter relation
263 // Might not work if the mother appear below the daughter in the event record
264 for (int iPythiaPart = 0; iPythiaPart < m_Pythia->event.size(); ++iPythiaPart) {
265 auto oldindex = indexPYTHIA.find(iPythiaPart);
266
267 //skip "system" particle generated by PYTHIA
268 if (m_Pythia->event[iPythiaPart].id() == 90) continue;
269
270 if (oldindex == end(indexPYTHIA)) {
271 // --> new particle
272
273 // Add to particle grapg
274 int position = mcParticleGraph.size();
275 mcParticleGraph.addParticle();
276 indexMCGraph[iPythiaPart] = position;
277
279
280 // from PYTHIA manual: "<1: an empty entry, with no meaningful information and
281 // therefore to be skipped unconditionally (should not occur in PYTHIA)"
282 if (m_Pythia->event[iPythiaPart].statusHepMC() < 1) continue;
283
284 // Set PDG code
285 p->setPDG(m_Pythia->event[iPythiaPart].id());
286
287 // Set four vector
288 ROOT::Math::PxPyPzEVector p4(m_Pythia->event[iPythiaPart].px(), m_Pythia->event[iPythiaPart].py(),
289 m_Pythia->event[iPythiaPart].pz(),
290 m_Pythia->event[iPythiaPart].e());
291 p->set4Vector(p4);
292 p->setMass(m_Pythia->event[iPythiaPart].m());
293
294 // Set vertex
295 p->setProductionVertex(m_Pythia->event[iPythiaPart].xProd() * Unit::mm, m_Pythia->event[iPythiaPart].yProd() * Unit::mm,
296 m_Pythia->event[iPythiaPart].zProd() * Unit::mm);
297 p->setProductionTime(m_Pythia->event[iPythiaPart].tProd() * Unit::mm / Const::speedOfLight);
298 p->setValidVertex(true);
299
300 // Set all(!) particles from the generator to primary
302
303 // Set FSR flag from PYTHIA TimeShower:QEDshowerByQ
304 if (m_Pythia->event[iPythiaPart].status() == 51 && m_Pythia->event[iPythiaPart].id() == 22) {
306 }
307
308 // Set PHOTOS flag from PYTHIA-EvtGen
309 if (m_Pythia->event[iPythiaPart].status() == GeneratorConst::FSR_STATUS_CODE && m_Pythia->event[iPythiaPart].id() == 22) {
311 }
312
313 // Set stable at generator level
314 if (m_Pythia->event[iPythiaPart].statusHepMC() == 1) {
316 }
317
318 //set mother
319 const int motherid = m_Pythia->event[iPythiaPart].mother1();
320
321 //check if mother exists in indexMCGraph
322 auto motherindex = indexMCGraph.find(motherid);
323
324 if (motherindex != end(indexMCGraph)) {
325 int motheridingraph = indexMCGraph[motherid];
326 MCParticleGraph::GraphParticle* q = &mcParticleGraph[motheridingraph];
327 p->comesFrom(*q);
328 } else {
329 // Particle has no mother from PYTHIA, add quark as mother
331 p->comesFrom(*q);
332 }
333
334 } else {
335 // particle is already in the graph
336 // modify here if needed
337 // ...
338 }
339 }
340
341 // Print original PYTHIA list
342 if (m_listEvent) m_PythiaEvent->list();
343
344 // Create new ParticleGraph
345 mcParticleGraph.generateList(m_particleList,
347
348}
349
350//-----------------------------------------------------------------
351// addParticleToPYTHIA
352//-----------------------------------------------------------------
354{
355 //get PDG code
356 const int id = mcParticle.getPDG();
357
358 //check that this particle is a quark or a virtual photon(-like)
359 bool isVPho = false;
360 bool isQuark = false;
361 if (abs(id) >= 1 && abs(id) <= 5) isQuark = true;
362 if (id == m_quarkPairMotherParticle) isVPho = true;
363
364 if (!(isVPho || isQuark)) return 0;
365
366 //check that there is no daughter for the quarks
367 if (isQuark && mcParticle.getDaughters().size()) {
368 B2WARNING("Quark already has a daughter!");
369 return 0;
370 }
371
372 //get some basic kinematics
373 const double mass = mcParticle.getMass();
374 const ROOT::Math::XYZVector& p = mcParticle.getMomentum();
375 const double energy = sqrt(mass * mass + p.Mag2());
376
377 //add this (anti)quark to the m_PythiaEvent
378 if (id == m_quarkPairMotherParticle) {
379 m_PythiaEvent->append(m_quarkPairMotherParticle, -22, 0, 0, 2, 3, 0, 0, p.X(), p.Y(), p.Z(), energy, mass);
380 nVpho++;
381 } else if (id > 0) {
382 m_PythiaEvent->append(id, 23, 1, 0, 0, 0, 101, 0, p.X(), p.Y(), p.Z(), energy, mass, 20.0);
383 nQuarks++;
384 } else if (id < 0) {
385 m_PythiaEvent->append(id, 23, 1, 0, 0, 0, 0, 101, p.X(), p.Y(), p.Z(), energy, mass, 20.0);
386 nQuarks++;
387 }
388
389 nAdded++;
390
391 return id;
392}
393
395{
396 Pythia8::ParticleData* particleData = &pythia->particleData;
397 int nParticles = EvtPDL::entries();
398 for (int i = 0; i < nParticles; ++i) {
399 EvtId evtgenParticle = EvtPDL::getEntry(i);
400 /*
401 * Pythia uses absolute value of the PDG code, thus, only positive codes
402 * are necessary. Only leptons (11 <= pdg <= 20) and hadrons (pdg > 100)
403 * are updated.
404 */
405 int pdg = EvtPDL::getStdHep(evtgenParticle);
406 if (pdg <= 10 || (pdg > 20 && pdg <= 100))
407 continue;
408 EvtId evtgenAntiParticle = EvtPDL::chargeConj(evtgenParticle);
409 if (particleData->isParticle(pdg)) {
410 particleData->setAll(pdg,
411 EvtPDL::name(evtgenParticle),
412 EvtPDL::name(evtgenAntiParticle),
413 EvtPDL::getSpinType(evtgenParticle),
414 EvtPDL::chg3(evtgenParticle),
415 // colType == 0 for uncolored particles.
416 0,
417 EvtPDL::getMeanMass(evtgenParticle),
418 EvtPDL::getWidth(evtgenParticle),
419 EvtPDL::getMinMass(evtgenParticle),
420 EvtPDL::getMaxMass(evtgenParticle),
421 EvtPDL::getctau(evtgenParticle));
422 } else if (std::find(m_additionalPDGCodes.begin(), m_additionalPDGCodes.end(), pdg) != m_additionalPDGCodes.end()) {
423 particleData->addParticle(
424 pdg,
425 EvtPDL::name(evtgenParticle),
426 EvtPDL::name(evtgenAntiParticle),
427 EvtPDL::getSpinType(evtgenParticle),
428 EvtPDL::chg3(evtgenParticle),
429 // colType == 0 for uncolored particles.
430 0,
431 EvtPDL::getMeanMass(evtgenParticle),
432 EvtPDL::getWidth(evtgenParticle),
433 EvtPDL::getMinMass(evtgenParticle),
434 EvtPDL::getMaxMass(evtgenParticle),
435 EvtPDL::getctau(evtgenParticle));
436 }
437 }
438}
439
440//-----------------------------------------------------------------
441// random generator for PYTHIA
442//-----------------------------------------------------------------
443FragmentationRndm::FragmentationRndm() : Pythia8::RndmEngine()
444{
445
446}
447
449{
450 double value = gRandom->Rndm();
451 return value;
452}
static const double speedOfLight
[cm/ns]
Definition Const.h:695
static EvtGen * createEvtGen(const std::string &decayFileName, bool coherentMixing)
Create and initialize an EvtGen instance:
static std::string findFile(const std::string &path, bool silent=false)
Search for given file or directory in local or central release directory, and return absolute path if...
EvtGenDecays * evtgen
EvtGen decay engine inside PYTHIA8.
int nGood
number of events with successful fragmentation.
void loadEvtGenParticleData(Pythia8::Pythia *pythia)
Load EvtGen particle data.
bool m_coherentMixing
decay the B0-B0bar coherently.
int nVpho
number of virtual exchange particles.
virtual void initialize() override
Initialize the module.
virtual void event() override
Event method (process events)
Pythia8::Pythia * m_Pythia
Pythia generator.
StoreArray< MCParticle > m_mcparticles
store array for the MCParticles
virtual ~FragmentationModule()
Destructor.
virtual void terminate() override
terminate the module
Pythia8::Event * m_PythiaEvent
Pythia event.
int addParticleToPYTHIA(const MCParticle &mcParticle)
Add particle to Pythia event.
std::string m_DecFile
EvtGen decay file.
int m_useEvtGen
use EvtGen for some decays.
int nAll
number of events created.
std::string m_UserDecFile
User EvtGen decay file.
std::string m_particleList
The name of the MCParticle collection.
MCParticleGraph mcParticleGraph
An instance of the MCParticle graph.
std::string m_parameterfile
Module parameters.
std::vector< int > m_additionalPDGCodes
Additional particles used in Pythia.
int nAdded
number of added particles.
int m_quarkPairMotherParticle
PDG Code of the mother particle of the quark pair.
int m_listEvent
list event generated by PYTHIA.
Minimal class for external random generator to be used in PYTHIA.
double flat()
flat random generator.
bool start()
Start intercepting the output.
Capture stdout and stderr and convert into log messages.
bool finish()
Finish the capture and emit the message if output has appeard on stdout or stderr.
@ c_Error
Error: for things that went wrong and have to be fixed.
Definition LogConfig.h:30
@ c_Debug
Debug: for code development.
Definition LogConfig.h:26
@ c_Warning
Warning: for potential problems that the user should pay attention to.
Definition LogConfig.h:29
Class to represent Particle data in graph.
@ c_checkCyclic
Check for cyclic dependencies.
@ c_clearParticles
Clear the particle list before adding the graph.
@ c_setDecayInfo
Set decay time and vertex.
A Class to store the Monte Carlo particle information.
Definition MCParticle.h:32
@ c_IsFSRPhoton
bit 7: Particle is from final state radiation
Definition MCParticle.h:61
@ c_IsPHOTOSPhoton
bit 8: Particle is an radiative photon from PHOTOS
Definition MCParticle.h:63
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Definition MCParticle.h:47
@ c_StableInGenerator
bit 1: Particle is stable, i.e., not decaying in the generator.
Definition MCParticle.h:49
std::vector< Belle2::MCParticle * > getDaughters() const
Get vector of all daughter particles, empty vector if none.
Definition MCParticle.cc:52
float getMass() const
Return the particle mass in GeV.
Definition MCParticle.h:124
int getPDG() const
Return PDG code of particle.
Definition MCParticle.h:101
ROOT::Math::XYZVector getMomentum() const
Return momentum.
Definition MCParticle.h:187
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
Module()
Constructor.
Definition Module.cc:30
void setReturnValue(int value)
Sets the return value for this module as integer.
Definition Module.cc:220
static const double mm
[millimeters]
Definition Unit.h:70
A class to perform decays via the external EvtGen decay program, see http://evtgen....
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
Abstract base class for different kinds of events.
STL namespace.