@@ -107,12 +107,112 @@ bool generateEvent() override
107107 return true;
108108}
109109
110+ /// @brief Main function to find out whether the particle comes charm or beauty quark
111+ /// @param partId is the index of the particle under study
112+ /// @param particles are the particles of the full event
113+ bool isFromCharmOrBeauty (const int partId , std ::vector < TParticle > const & particles ) {
114+
115+ // Let's check wheter this is already a c or b quark?
116+ const TParticle & part = particles .at (partId );
117+ const int pdgAbs = std ::abs (part .GetPdgCode ());
118+ if (pdgAbs == 4 || pdgAbs == 5 ) {
119+ return true;
120+ }
121+
122+ // Let's check the mother particles of the hadron at all stages
123+ // and look for the charm or beauty quark
124+ std ::vector < std ::vector < int64_t >> arrayIds {};
125+ std ::vector < int64_t > initVec {partId };
126+ arrayIds .push_back (initVec ); // the first vector contains the index of the original particle
127+ int stage = 0 ;
128+ while (arrayIds [- stage ].size () > 0 ) {
129+
130+ //LOG(info) << "### stage " << stage << ", arrayIds[-stage].size() = " << arrayIds[-stage].size();
131+
132+ std ::vector < int64_t > arrayIdsStage {};
133+
134+ for (auto& iPart : arrayIds [- stage ]) { // check all the particles that were the mothers at the previous stage
135+ const TParticle & partStage = particles .at (iPart );
136+
137+ // check the first mother
138+ const int firstMotherId = partStage .GetFirstMother ();
139+ if ( firstMotherId >= 0 ) {
140+ const TParticle & firstMother = particles .at (firstMotherId );
141+ const int pdgAbsFirstMother = std ::abs (firstMother .GetPdgCode ());
142+ if (pdgAbsFirstMother == 4 || pdgAbsFirstMother == 5 ) {
143+ return true;
144+ }
145+ // the first mother is not a charm or beauty quark
146+ arrayIdsStage .push_back (firstMotherId );
147+ }
148+
149+ // let's check all other mothers, if any
150+ const int lastMotherId = partStage .GetSecondMother ();
151+ if (lastMotherId >=0 && lastMotherId != firstMotherId ) {
152+ for (int motherId = firstMotherId + 1 /*first mother already considered*/ ; motherId <= lastMotherId ; motherId ++ ) {
153+ const TParticle & mother = particles .at (motherId );
154+ const int pdgAbsMother = std ::abs (mother .GetPdgCode ());
155+ if (pdgAbsMother == 4 || pdgAbsMother == 5 ) {
156+ return true;
157+ }
158+ // this mother is not a charm or beauty quark
159+ arrayIdsStage .push_back (motherId );
160+ }
161+ }
162+
163+ }
164+
165+ /*
166+ All light-flavour mothers are not considered with this approach
167+ eg: D+ coming from c and uBar --> uBar lost
168+ --> TODO: check if the current particle has a charm or beauty hadron as daughter. If yes, keep it
169+ >>> we can ignore it! This might be useful only for jet analyses, however this approach of embedding N pp events into a Pb-Pb one might be not ideal for them
170+ */
171+
172+ // none of the particle mothers is a charm or beauty quark, let's consider their indices for the next stage
173+ arrayIds .push_back (arrayIdsStage );
174+ stage -- ; // ready to go to next stage
175+
176+ } /// end while(arrayIds[-stage].size() > 0)
177+
178+ return false;
179+ }
180+
181+
182+ void printParticleVector (std ::vector < TParticle > v ) {
183+ for (int id = 0 ; id < v .size (); id ++ ) {
184+ const int pdgCode = v .at (id ).GetPdgCode ();
185+ const int idFirstMother = v .at (id ).GetFirstMother ();
186+ const int idLastMother = v .at (id ).GetSecondMother ();
187+ const int idFirstDaughter = v .at (id ).GetFirstDaughter ();
188+ const int idLastDaughter = v .at (id ).GetLastDaughter ();
189+ LOG (info ) << " id = " << id << ", pdgCode = " << pdgCode << " --> idFirstMother=" << idFirstMother << ", idLastMother=" << idLastMother << ", idFirstDaughter=" << idFirstDaughter << ", idLastDaughter=" << idLastDaughter ;
190+ }
191+ }
192+
193+
194+ int findKey (const std ::map < int , int /*index*/ > & m , int value ) {
195+ for (std ::pair < int , int > p : m ) {
196+ if (p .second /*index*/ == value ) {
197+ return p .first ; // key --> it becomes the new index
198+ }
199+ }
200+ return -1 ;
201+ }
202+
203+
110204/// @brief Main function to copy the generated particles in mPythia.event into the stack (this.mParticles)
111205Bool_t importParticles () override
112206{
113207 /// Import particles from generated event
114208 /// This should not do anything now, since we override generateEvent
115209 GeneratorPythia8 ::importParticles ();
210+
211+ LOG (info ) << "" ;
212+ LOG (info ) << "*************************************************************" ;
213+ LOG (info ) << "************** New signal event considered **************" ;
214+ LOG (info ) << "*************************************************************" ;
215+ LOG (info ) << "" ;
116216
117217 /// Generate mNumSigEvs HF events to be merged in one
118218 int nEvsHF = 0 ;
@@ -124,22 +224,126 @@ Bool_t importParticles() override
124224 genOk = (mGeneratorEvHF -> generateEvent () && mGeneratorEvHF -> importParticles () /*copy particles from mGeneratorEvHF.mPythia.event to mGeneratorEvHF.mParticles*/ );
125225 }
126226
227+ int originalSize = mParticles .size (); // stack of this event generator
228+
229+ // for debug
230+ // LOG(info) << "";
231+ // LOG(info) << "============ Before HF event " << nEvsHF;
232+ // LOG(info) << "Full stack (size " << originalSize << "):";
233+ // printParticleVector(mParticles);
234+
127235 /// copy the particles from the HF event in the particle stack
128236 auto particlesHfEvent = mGeneratorEvHF -> getParticles ();
129- int originalSize = mParticles .size (); // stack of this event generator
237+ std ::map < int , int /*particle id in HF event stack*/ > mapHfParticles = {};
238+ int counterHfParticles = 0 ;
239+
240+ // for debug
241+ // LOG(info) << "-----------------------------------------------";
242+ // LOG(info) << ">>> HF event " << nEvsHF;
243+ // LOG(info) << " HF event stack:";
244+ // printParticleVector(particlesHfEvent);
245+
130246 for (int iPart = 0 ; iPart < particlesHfEvent .size (); iPart ++ ) {
131247 auto particle = particlesHfEvent .at (iPart );
132248
249+ /// Establish if this particle comes from charm or beauty
250+ /// If not, ignore this particle and increase the number of discarded particles from the pp event
251+ if (!isFromCharmOrBeauty (iPart , particlesHfEvent )) {
252+ continue ;
253+ }
254+ /// if we arrive here, then the current particle is from charm or beauty, keep it!
255+ mapHfParticles [counterHfParticles ++ /*fill and update the counter*/ ] = iPart ;
256+ }
257+
258+ /// print the map (debug)
259+ // LOG(info) << " >>>";
260+ // LOG(info) << " >>> printing mapHfParticles:";
261+ // for(auto& p : mapHfParticles) {
262+ // const int pdgCodeFromMap = particlesHfEvent.at(p.second).GetPdgCode();
263+ // LOG(info) << " >>> entry " << p.first << ", original id = " << p.second << ", pdgCode=" << pdgCodeFromMap << " --> firstMotherId=" << particlesHfEvent.at(p.second).GetFirstMother() << ", lastMotherId=" << particlesHfEvent.at(p.second).GetSecondMother() << ", firstDaughterId=" << particlesHfEvent.at(p.second).GetFirstDaughter() << ", lastDaughterId=" << particlesHfEvent.at(p.second).GetLastDaughter();
264+ // }
265+
266+
267+ // In the map we have only the particles from charm or beauty
268+ // Let's readapt the mother/daughter indices accordingly
269+ int offset = originalSize ;
270+ for (int iHfPart = 0 ; iHfPart < counterHfParticles ; iHfPart ++ ) {
271+ TParticle & particle = particlesHfEvent .at (mapHfParticles [iHfPart ]);
272+ int idFirstMother = particle .GetFirstMother (); // NB: indices from the HF event stack
273+ int idLastMother = particle .GetSecondMother (); // NB: indices from the HF event stack
274+ int idFirstDaughter = particle .GetFirstDaughter (); // NB: indices from the HF event stack
275+ int idLastDaughter = particle .GetLastDaughter (); // NB: indices from the HF event stack
276+ const int pdgCode = particle .GetPdgCode ();
277+
278+ /// fix mother indices
279+ bool isFirstMotherOk = false;
280+ const int idFirstMotherOrig = idFirstMother ; /// useful only if the 1st mother is not charm or beauty
281+ if (idFirstMother >= 0 ) {
282+ idFirstMother = findKey (mapHfParticles , idFirstMother );
283+ /// If idFirstMother>=0, the 1st mother is from charm or beauty, i.e. is not a light-flavoured parton
284+ /// Instead, if idFirstMother==-1 from findKey this means that the first mother was a light-flavoured parton --> not stored in the map
285+ if (idFirstMother >=0 ) {
286+ /// the 1st mother is from charm or beauty, i.e. is not a light-flavoured parton
287+ if (idLastMother != idFirstMotherOrig ) {
288+ if (idLastMother != -1 ) {
289+ /// idLastMother is >= 0
290+ }
291+ } else {
292+ /// idLastMother is equal to idFirstMother
293+ idLastMother = idFirstMother ;
294+ }
295+ isFirstMotherOk = true;
296+ }
297+ }
298+ if (!isFirstMotherOk ) {
299+ /// - If we are here, it means that the 1st mother was not from charm or beauty
300+ /// - No need to check whether idLastMother>=0,
301+ /// because this would mean that none of the mother is from charm or beauty and this was checked already in isFromCharmOrBeauty
302+ /// - Need to loop between 1st and last mother, to treat cases like these
303+ /// [11:52:13][INFO] id = 565, pdgCode = -2 --> idFirstMother=519, idLastMother=519
304+ /// [11:52:13][INFO] id = 566, pdgCode = -4 --> idFirstMother=520, idLastMother=520
305+ /// [11:52:13][INFO] id = 567, pdgCode = -1 --> idFirstMother=518, idLastMother=518
306+ /// [11:52:13][INFO] id = 568, pdgCode = -311 --> idFirstMother=565, idLastMother=567
307+ /// [11:52:13][INFO] id = 569, pdgCode = -4212 --> idFirstMother=565, idLastMother=567
308+ /// --> w/o loop between 1st and last mother, the mother Ids assigned to this Sc+ (4212) by findKey are -1, both first and last
309+ bool foundAnyMother = false;
310+ for (int idMotherOrig = (idFirstMotherOrig + 1 ); idMotherOrig <=idLastMother ; idMotherOrig ++ ) {
311+ const int idMother = findKey (mapHfParticles , idMotherOrig );
312+ if (idMother >= 0 ) {
313+ /// this should mean that the mother is from HF, i.e. that we found the correct one
314+ idFirstMother = idMother ;
315+ idLastMother = idFirstMother ;
316+ foundAnyMother = true;
317+ break ;
318+ }
319+ }
320+ // set last mother to -1 if no mother has been found so far
321+ if (!foundAnyMother ) {
322+ idLastMother = -1 ;
323+ }
324+ }
325+
326+ /// fix daughter indices
327+ idFirstDaughter = findKey (mapHfParticles , idFirstDaughter );
328+ idLastDaughter = findKey (mapHfParticles , idLastDaughter );
329+
133330 /// adjust the particle mother and daughter indices
134- if ( particle .GetFirstMother () >= 0 ) particle . SetFirstMother ( particle . GetFirstMother () + originalSize );
135- if ( particle .GetSecondMother () >= 0 ) particle . SetLastMother ( particle . GetSecondMother () + originalSize );
136- if ( particle .GetFirstDaughter () >= 0 ) particle . SetFirstDaughter ( particle . GetFirstDaughter () + originalSize );
137- if ( particle .GetLastDaughter () >= 0 ) particle . SetLastDaughter ( particle . GetLastDaughter () + originalSize );
331+ particle .SetFirstMother (( idFirstMother >= 0 ) ? idFirstMother + offset : idFirstMother );
332+ particle .SetLastMother (( idLastMother >= 0 ) ? idLastMother + offset : idLastMother );
333+ particle .SetFirstDaughter (( idFirstDaughter >= 0 ) ? idFirstDaughter + offset : idFirstDaughter );
334+ particle .SetLastDaughter (( idLastDaughter >= 0 ) ? idLastDaughter + offset : idLastDaughter );
138335
139336 /// copy inside this.mParticles from mGeneratorEvHF.mParticles, i.e. the particles generated in mGeneratorEvHF
140337 mParticles .push_back (particle );
338+
141339 }
142340
341+ // for debug
342+ // LOG(info) << "-----------------------------------------------";
343+ // LOG(info) << "============ After HF event " << nEvsHF;
344+ // LOG(info) << "Full stack:";
345+ // printParticleVector(mParticles);
346+
143347 /// one more event generated, let's update the counter and clear it, to allow the next generation
144348 nEvsHF ++ ;
145349 //mGeneratedEvents++;
0 commit comments