Skip to content

Commit 6542824

Browse files
authored
Better pruning of events from Pythia8 and enable in HepMC (#12275)
Fixes the pruning of events in GeneratorPythia8. The old implementation had a number of problems - Beam particles (HepMC status = 4) was not kept - The event structure was not preserved. That meant that the event would be split into many disjoint trees. Thus, subsequent passes over the event would not be able to tie things together. This was especially a problem when converting the event to HepMC (via AOD) since the events would not be complete. Added the option to prune events read in via GeneratorHepMC. The configuration key HepMC.prune=true will enable this mode (off by default). By pruning, I mean that all particles that are not - beam particles (HepMC status = 4), - decayed (HepMC status = 2), nor - final state (HepMC status = 1) are removed from the event. When we do that, it is extremely important to connect up particles so that we have a consistent event structure. For example, we may remove a gluon from the tree. In that case, we must take care to move all child particles to the proper node in the tree, or the children will be disjoint from the rest of the event. This patch also adds Doxygen documentation to GeneratorPythia8, as well as a new run/SimExamples/Pythia8/README.md file.
1 parent d002f26 commit 6542824

8 files changed

Lines changed: 965 additions & 190 deletions

File tree

Generators/include/Generators/GeneratorHepMC.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace HepMC3
3131
class Reader;
3232
class GenEvent;
3333
class FourVector;
34+
class GenParticle;
3435
} // namespace HepMC3
3536
#endif
3637

@@ -101,12 +102,22 @@ class GeneratorHepMC : public Generator, public GeneratorFileOrCmd
101102
/** Make our reader */
102103
bool makeReader();
103104

105+
/** Type of function to select particles to keep when pruning
106+
* events */
107+
typedef bool (*Select)(std::shared_ptr<const HepMC3::GenParticle>);
108+
/** Prune event of particles that are not selected by passed
109+
* function. The event structure is preserved. */
110+
void pruneEvent(Select select);
111+
104112
/** HepMC interface **/
105113
uint64_t mEventsToSkip = 0;
114+
/** HepMC event record version to expected. Deprecated. */
106115
int mVersion = 0;
107116
std::shared_ptr<HepMC3::Reader> mReader;
108117
/** Event structure */
109118
HepMC3::GenEvent* mEvent = nullptr;
119+
/** Option whether to prune event */
120+
bool mPrune; //!
110121

111122
ClassDefOverride(GeneratorHepMC, 1);
112123

Generators/include/Generators/GeneratorHepMCParam.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,27 @@ namespace eventgen
3030
**/
3131

3232
struct GeneratorHepMCParam : public o2::conf::ConfigurableParamHelper<GeneratorHepMCParam> {
33+
/** Version number of event structure to decode. Note, when reading
34+
* from a file, this key is ignored. The interface will figure out
35+
* the version automatically. When reading from a pipe, and the
36+
* command line writes HepMC version 2 format, then this parameter
37+
* should be set to 2 */
3338
int version = 0;
39+
/** Number of events to skip at the start of the input */
3440
uint64_t eventsToSkip = 0;
41+
/** Deprecated. Set the name of the file to read from. Use
42+
* GeneratorFileOrCmd.fileNames instead. */
3543
std::string fileName = "";
44+
/** Wether to prune the event tree. If true, then only particles that are
45+
*
46+
* - beam particles (status == 4)
47+
* - decayed (status == 2), or
48+
* - final state (status == 1)
49+
*
50+
* are kept. This reduces the event size. How much depends on the
51+
* event generator producing the event. Use with caution, as it may
52+
* corrupt the event record. */
53+
bool prune = false;
3654
O2ParamDef(GeneratorHepMCParam, "HepMC");
3755
};
3856

Generators/include/Generators/GeneratorPythia8.h

Lines changed: 176 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,63 @@ namespace eventgen
2424

2525
/*****************************************************************/
2626
/*****************************************************************/
27-
27+
/** Interface to the Pythia8 event generator. This generator is
28+
* configured by configuration files (e.g.,
29+
* `Generators/share/egconfig/pythia8_inel.cfg` for the type of
30+
* events to generate.
31+
*
32+
* The above file, for example, contains
33+
*
34+
* @verbatim
35+
* ### Beams, proton-proton collisions at sqrt(s)=14TeV
36+
* Beams:idA 2212 # proton
37+
* Beams:idB 2212 # proton
38+
* Beams:eCM 14000. # GeV
39+
*
40+
* ### Processes, min-bias inelastic events
41+
* SoftQCD:inelastic on # all inelastic processes
42+
*
43+
* ### Decays. Only decay until 1cm/c - corresponding to (physical) primaries
44+
* ParticleDecays:limitTau0 on
45+
* ParticleDecays:tau0Max 10.
46+
* @endverbatim
47+
*
48+
* The configuration file to read is initially set in
49+
* `GeneratorFactory`, but an additional configuration file can be
50+
* specified with the configuration key `GeneratorPythia8::config`.
51+
*
52+
* If the configuration key `GeneratorPythia8::includePartonEvent` is
53+
* set to false (default), then the event is pruned. That is, all
54+
* particles that are not
55+
*
56+
* - beam particles (HepMC status = 4),
57+
* - decayed particles (HepMC status = 2), nor
58+
* - final state partcles (HepMC status = 1)
59+
*
60+
* are removed from the event before passing on to the simulation.
61+
* The event structure is kept, so that we have a well-formed event
62+
* structure. This reduces the event size by roughly 30%.
63+
*
64+
* If the configuration key `GeneratorPythia8::includePartonEvent` is
65+
* true, then the full event is kept, including intermediate partons
66+
* such as gluons, pomerons, diffractive hadrons, and so on.
67+
*
68+
* In the future, the way to prune events may become more flexible.
69+
* For example, we could have the configuration keys
70+
*
71+
* - GeneratorPythia8::onlyStatus a list of HepMC status codes to accept
72+
* - GeneratorPythia8::onlyPDGs a list of PDG particle codes to accept
73+
*
74+
* The configuration key `GeneratorPythia8::hooksFileName` allows the
75+
* definition of a Pythia8 user hook. See for example
76+
* `Generators/share/egconfig/pythia8_userhooks_charm.C`. The file
77+
* specified is interpreted via ROOT (i.e., a ROOT script), and the
78+
* function name set via the configuration key
79+
* `GeneratorPythia8::hooksFuncName` (default `pythia8_user_hooks`) is
80+
* executed. That function must return a pointer to a
81+
* `Pythia8::UserHooks` object (see the Pythia8 manual for more on
82+
* this).
83+
*/
2884
class GeneratorPythia8 : public Generator
2985
{
3086

@@ -36,47 +92,69 @@ class GeneratorPythia8 : public Generator
3692
/** destructor **/
3793
~GeneratorPythia8() override = default;
3894

95+
/** @{
96+
@name methods to override **/
3997
/** Initialize the generator if needed **/
4098
Bool_t Init() override;
41-
42-
/** methods to override **/
99+
/** Generate a single event */
43100
Bool_t generateEvent() override;
101+
/** Import particles from Pythia onto the simulation event stack */
44102
Bool_t importParticles() override { return importParticles(mPythia.event); };
103+
/** @} */
45104

46-
/** setters **/
105+
/** @{
106+
* @name setters **/
107+
/** Set Pythia8 configuration file to read */
47108
void setConfig(std::string val) { mConfig = val; };
109+
/**
110+
* Set the ROOT script file name that defines a Pythia8::UserHooks
111+
* object */
48112
void setHooksFileName(std::string val) { mHooksFileName = val; };
113+
/** Function in ROOT script that returns a pointer to a
114+
* Pythia8::UserHooks object */
49115
void setHooksFuncName(std::string val) { mHooksFuncName = val; };
50-
void setUserHooks(Pythia8::UserHooks* hooks)
51-
{
52-
#if PYTHIA_VERSION_INTEGER < 8300
53-
mPythia.setUserHooksPtr(hooks);
54-
#else
55-
mPythia.setUserHooksPtr(std::shared_ptr<Pythia8::UserHooks>(hooks));
56-
#endif
57-
}
58-
59-
/** methods **/
116+
/** Set the user hooks (defined in a Pythia8::UserHooks object) for
117+
* the event generator. */
118+
void setUserHooks(Pythia8::UserHooks* hooks);
119+
/** @} */
120+
121+
/** @{
122+
* @name Configuration methods **/
123+
/** Read a Pythia8 configuration string */
60124
bool readString(std::string val) { return mPythia.readString(val, true); };
125+
/** Read a Pythia8 configuration file */
61126
bool readFile(std::string val) { return mPythia.readFile(val, true); };
127+
/** @} */
62128

63-
/** utilities **/
129+
/** @{
130+
* @name Utilities **/
131+
/** Get number of binary collisions. Note that this method deviates
132+
* from how the Pythia authors count number of binary collisions */
64133
void getNcoll(int& nColl)
65134
{
66135
getNcoll(mPythia.info, nColl);
67136
};
137+
/** Get number of participants. Note that this method deviates
138+
* from how the Pythia authors count number of participants */
68139
void getNpart(int& nPart)
69140
{
70141
getNpart(mPythia.info, nPart);
71142
};
143+
/** Get number of participants, split by nucleon type and origin.
144+
* Note that this method deviates from how the Pythia authors count
145+
* number of participants */
72146
void getNpart(int& nProtonProj, int& nNeutronProj, int& nProtonTarg, int& nNeutronTarg)
73147
{
74148
getNpart(mPythia.info, nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg);
75149
};
150+
/** Get number of nuclei remnants, split by nucleon type and origin. */
76151
void getNremn(int& nProtonProj, int& nNeutronProj, int& nProtonTarg, int& nNeutronTarg)
77152
{
78153
getNremn(mPythia.event, nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg);
79154
};
155+
/** Get number of spectators, split by nucleon type and origin.
156+
* Note that this method deviates from how the Pythia authors count
157+
* number of spectators */
80158
void getNfreeSpec(int& nFreenProj, int& nFreepProj, int& nFreenTarg, int& nFreepTarg)
81159
{
82160
getNfreeSpec(mPythia.info, nFreenProj, nFreepProj, nFreenTarg, nFreepTarg);
@@ -88,27 +166,101 @@ class GeneratorPythia8 : public Generator
88166
/** operator= **/
89167
GeneratorPythia8& operator=(const GeneratorPythia8&);
90168

91-
/** methods that can be overridded **/
92-
void updateHeader(o2::dataformats::MCEventHeader* eventHeader) override;
169+
/** @{
170+
* @name Some function definitions
171+
*/
172+
/** Select particles when pruning event */
173+
typedef bool (*Select)(const Pythia8::Particle& particle);
174+
/** Get relatives (mothers or daughters) of a particle */
175+
typedef std::vector<int> (*GetRelatives)(const Pythia8::Particle&);
176+
/** Set relatives (mothers or daughters) of a particle */
177+
typedef void (*SetRelatives)(Pythia8::Particle&, int, int);
178+
/** Get range of relatives (mothers or daughters) of a particle */
179+
typedef std::pair<int, int> (*FirstLastRelative)(const Pythia8::Particle&);
180+
/** @} */
93181

94-
/** internal methods **/
95-
Bool_t importParticles(Pythia8::Event const& event);
182+
/** @{
183+
* @name Methods that can be overridded **/
184+
/** Update the event header. This propagates all sorts of
185+
* information from Pythia8 to the simulation event header,
186+
* including parton distribution function parameters, event weight,
187+
* cross-section information, heavy-ion collision information, and
188+
* so on. */
189+
void updateHeader(o2::dataformats::MCEventHeader* eventHeader) override;
190+
/** @} */
96191

97-
/** utilities **/
192+
/** @{
193+
* @name Internal methods **/
194+
/** Import particles from Pythia onto the simulation stack */
195+
Bool_t importParticles(Pythia8::Event& event);
196+
/** Prune an event. Only particles for which the function select
197+
* returns true are kept in the event record. The structure of the
198+
* event is preserved, meaning that particles will point back to
199+
* their ultimate (selected) mothers and, if select preserves the
200+
* beam particles, the ultimate collision interaction. */
201+
void pruneEvent(Pythia8::Event& event, Select select);
202+
/** Investigate relatives (mothers or daughters) for particles to
203+
* keep when pruning an event. This checks the current particle,
204+
* identified by index, if any of its relatives (either mothers or
205+
* daughters) are to be kept. If a relative is to be kept, then
206+
* that is added to an internal list. If a relative is _not_ to be
207+
* kept, then that relatives relatives are queried (recursive call).
208+
* The result of the recursive call is a list of relatives to the
209+
* current particle which are to be kept. These are then also added
210+
* to the internal list. The relatives that are found to be kept
211+
* are then set to be relatives of the current particle. Note that
212+
* this member function modifies the relatives of the passed
213+
* particle, and thus modifies the passed event structure.
214+
* Calculations are cached. */
215+
void investigateRelatives(Pythia8::Event& event, // Event
216+
const std::vector<int>& old2New, // Map from old to new idx
217+
size_t index, // Current particle
218+
std::vector<bool>& done, // cache flag
219+
GetRelatives getter, // get relatives
220+
SetRelatives setter, // set relatives
221+
FirstLastRelative firstLast, // get first and last relative
222+
const std::string& what, // what are we looking for
223+
const std::string& ind = ""); // logging indent
224+
/** @{
225+
* @name utilities **/
226+
/** Select from ancestor. Fills the output event with all particles
227+
* related to an ancestor of the input event
228+
*
229+
* Starting from ancestor, select all daughters (and their daughters
230+
* recursively), and store them in the output event.
231+
**/
98232
void selectFromAncestor(int ancestor, Pythia8::Event& inputEvent, Pythia8::Event& outputEvent);
233+
/** Get number of binary collisions. Note that this method deviates
234+
* from how the Pythia authors count number of binary collisions */
99235
void getNcoll(const Pythia8::Info& info, int& nColl);
236+
/** Get number of participants. Note that this method deviates
237+
* from how the Pythia authors count number of participants */
100238
void getNpart(const Pythia8::Info& info, int& nPart);
239+
/** Get number of participants, split by nucleon type and origin.
240+
* Note that this method deviates from how the Pythia authors count
241+
* number of participants */
101242
void getNpart(const Pythia8::Info& info, int& nProtonProj, int& nNeutronProj, int& nProtonTarg, int& nNeutronTarg);
243+
/** Get number of nuclei remnants, split by nucleon type and origin. */
102244
void getNremn(const Pythia8::Event& event, int& nProtonProj, int& nNeutronProj, int& nProtonTarg, int& nNeutronTarg);
245+
/** Get number of spectators, split by nucleon type and origin.
246+
* Note that this method deviates from how the Pythia authors count
247+
* number of spectators */
103248
void getNfreeSpec(const Pythia8::Info& info, int& nFreenProj, int& nFreepProj, int& nFreenTarg, int& nFreepTarg);
249+
/** @} */
104250

105251
/** Pythia8 **/
106252
Pythia8::Pythia mPythia; //!
107253

108-
/** configuration **/
254+
/** @{
255+
* @name Configurations */
256+
/** configuration file to read **/
109257
std::string mConfig;
258+
/** ROOT script defining a Pythia8::UserHooks object */
110259
std::string mHooksFileName;
260+
/** Function in `mHooksFileName` to execute to return pointer to
261+
* Pythia8::UserHooks object */
111262
std::string mHooksFuncName;
263+
/** @} */
112264

113265
ClassDefOverride(GeneratorPythia8, 1);
114266

@@ -121,3 +273,6 @@ class GeneratorPythia8 : public Generator
121273
} // namespace o2
122274

123275
#endif /* ALICEO2_EVENTGEN_GENERATORPYTHIA8_H_ */
276+
//
277+
// EOF
278+
//

0 commit comments

Comments
 (0)