@@ -121,12 +121,112 @@ bool generateEvent() override
121121 return true;
122122}
123123
124+ /// @brief Main function to find out whether the particle comes charm or beauty quark
125+ /// @param partId is the index of the particle under study
126+ /// @param particles are the particles of the full event
127+ bool isFromCharmOrBeauty (const int partId , std ::vector < TParticle > const & particles ) {
128+
129+ // Let's check wheter this is already a c or b quark?
130+ const TParticle & part = particles .at (partId );
131+ const int pdgAbs = std ::abs (part .GetPdgCode ());
132+ if (pdgAbs == 4 || pdgAbs == 5 ) {
133+ return true;
134+ }
135+
136+ // Let's check the mother particles of the hadron at all stages
137+ // and look for the charm or beauty quark
138+ std ::vector < std ::vector < int64_t >> arrayIds {};
139+ std ::vector < int64_t > initVec {partId };
140+ arrayIds .push_back (initVec ); // the first vector contains the index of the original particle
141+ int stage = 0 ;
142+ while (arrayIds [- stage ].size () > 0 ) {
143+
144+ //LOG(info) << "### stage " << stage << ", arrayIds[-stage].size() = " << arrayIds[-stage].size();
145+
146+ std ::vector < int64_t > arrayIdsStage {};
147+
148+ for (auto& iPart : arrayIds [- stage ]) { // check all the particles that were the mothers at the previous stage
149+ const TParticle & partStage = particles .at (iPart );
150+
151+ // check the first mother
152+ const int firstMotherId = partStage .GetFirstMother ();
153+ if ( firstMotherId >= 0 ) {
154+ const TParticle & firstMother = particles .at (firstMotherId );
155+ const int pdgAbsFirstMother = std ::abs (firstMother .GetPdgCode ());
156+ if (pdgAbsFirstMother == 4 || pdgAbsFirstMother == 5 ) {
157+ return true;
158+ }
159+ // the first mother is not a charm or beauty quark
160+ arrayIdsStage .push_back (firstMotherId );
161+ }
162+
163+ // let's check all other mothers, if any
164+ const int lastMotherId = partStage .GetSecondMother ();
165+ if (lastMotherId >=0 && lastMotherId != firstMotherId ) {
166+ for (int motherId = firstMotherId + 1 /*first mother already considered*/ ; motherId <= lastMotherId ; motherId ++ ) {
167+ const TParticle & mother = particles .at (motherId );
168+ const int pdgAbsMother = std ::abs (mother .GetPdgCode ());
169+ if (pdgAbsMother == 4 || pdgAbsMother == 5 ) {
170+ return true;
171+ }
172+ // this mother is not a charm or beauty quark
173+ arrayIdsStage .push_back (motherId );
174+ }
175+ }
176+
177+ }
178+
179+ /*
180+ All light-flavour mothers are not considered with this approach
181+ eg: D+ coming from c and uBar --> uBar lost
182+ --> TODO: check if the current particle has a charm or beauty hadron as daughter. If yes, keep it
183+ >>> 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
184+ */
185+
186+ // none of the particle mothers is a charm or beauty quark, let's consider their indices for the next stage
187+ arrayIds .push_back (arrayIdsStage );
188+ stage -- ; // ready to go to next stage
189+
190+ } /// end while(arrayIds[-stage].size() > 0)
191+
192+ return false;
193+ }
194+
195+
196+ void printParticleVector (std ::vector < TParticle > v ) {
197+ for (int id = 0 ; id < v .size (); id ++ ) {
198+ const int pdgCode = v .at (id ).GetPdgCode ();
199+ const int idFirstMother = v .at (id ).GetFirstMother ();
200+ const int idLastMother = v .at (id ).GetSecondMother ();
201+ const int idFirstDaughter = v .at (id ).GetFirstDaughter ();
202+ const int idLastDaughter = v .at (id ).GetLastDaughter ();
203+ LOG (info ) << " id = " << id << ", pdgCode = " << pdgCode << " --> idFirstMother=" << idFirstMother << ", idLastMother=" << idLastMother << ", idFirstDaughter=" << idFirstDaughter << ", idLastDaughter=" << idLastDaughter ;
204+ }
205+ }
206+
207+
208+ int findKey (const std ::map < int , int /*index*/ > & m , int value ) {
209+ for (std ::pair < int , int > p : m ) {
210+ if (p .second /*index*/ == value ) {
211+ return p .first ; // key --> it becomes the new index
212+ }
213+ }
214+ return -1 ;
215+ }
216+
217+
124218/// @brief Main function to copy the generated particles in mPythia.event into the stack (this.mParticles)
125219Bool_t importParticles () override
126220{
127221 /// Import particles from generated event
128222 /// This should not do anything now, since we override generateEvent
129223 GeneratorPythia8 ::importParticles ();
224+
225+ LOG (info ) << "" ;
226+ LOG (info ) << "*************************************************************" ;
227+ LOG (info ) << "************** New signal event considered **************" ;
228+ LOG (info ) << "*************************************************************" ;
229+ LOG (info ) << "" ;
130230
131231 /// Generate mNumSigEvs HF events to be merged in one
132232 int nEvsHF = 0 ;
@@ -138,22 +238,126 @@ Bool_t importParticles() override
138238 genOk = (mGeneratorEvHF -> generateEvent () && mGeneratorEvHF -> importParticles () /*copy particles from mGeneratorEvHF.mPythia.event to mGeneratorEvHF.mParticles*/ );
139239 }
140240
241+ int originalSize = mParticles .size (); // stack of this event generator
242+
243+ // for debug
244+ // LOG(info) << "";
245+ // LOG(info) << "============ Before HF event " << nEvsHF;
246+ // LOG(info) << "Full stack (size " << originalSize << "):";
247+ // printParticleVector(mParticles);
248+
141249 /// copy the particles from the HF event in the particle stack
142250 auto particlesHfEvent = mGeneratorEvHF -> getParticles ();
143- int originalSize = mParticles .size (); // stack of this event generator
251+ std ::map < int , int /*particle id in HF event stack*/ > mapHfParticles = {};
252+ int counterHfParticles = 0 ;
253+
254+ // for debug
255+ // LOG(info) << "-----------------------------------------------";
256+ // LOG(info) << ">>> HF event " << nEvsHF;
257+ // LOG(info) << " HF event stack:";
258+ // printParticleVector(particlesHfEvent);
259+
144260 for (int iPart = 0 ; iPart < particlesHfEvent .size (); iPart ++ ) {
145261 auto particle = particlesHfEvent .at (iPart );
146262
263+ /// Establish if this particle comes from charm or beauty
264+ /// If not, ignore this particle and increase the number of discarded particles from the pp event
265+ if (!isFromCharmOrBeauty (iPart , particlesHfEvent )) {
266+ continue ;
267+ }
268+ /// if we arrive here, then the current particle is from charm or beauty, keep it!
269+ mapHfParticles [counterHfParticles ++ /*fill and update the counter*/ ] = iPart ;
270+ }
271+
272+ /// print the map (debug)
273+ // LOG(info) << " >>>";
274+ // LOG(info) << " >>> printing mapHfParticles:";
275+ // for(auto& p : mapHfParticles) {
276+ // const int pdgCodeFromMap = particlesHfEvent.at(p.second).GetPdgCode();
277+ // 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();
278+ // }
279+
280+
281+ // In the map we have only the particles from charm or beauty
282+ // Let's readapt the mother/daughter indices accordingly
283+ int offset = originalSize ;
284+ for (int iHfPart = 0 ; iHfPart < counterHfParticles ; iHfPart ++ ) {
285+ TParticle & particle = particlesHfEvent .at (mapHfParticles [iHfPart ]);
286+ int idFirstMother = particle .GetFirstMother (); // NB: indices from the HF event stack
287+ int idLastMother = particle .GetSecondMother (); // NB: indices from the HF event stack
288+ int idFirstDaughter = particle .GetFirstDaughter (); // NB: indices from the HF event stack
289+ int idLastDaughter = particle .GetLastDaughter (); // NB: indices from the HF event stack
290+ const int pdgCode = particle .GetPdgCode ();
291+
292+ /// fix mother indices
293+ bool isFirstMotherOk = false;
294+ const int idFirstMotherOrig = idFirstMother ; /// useful only if the 1st mother is not charm or beauty
295+ if (idFirstMother >= 0 ) {
296+ idFirstMother = findKey (mapHfParticles , idFirstMother );
297+ /// If idFirstMother>=0, the 1st mother is from charm or beauty, i.e. is not a light-flavoured parton
298+ /// Instead, if idFirstMother==-1 from findKey this means that the first mother was a light-flavoured parton --> not stored in the map
299+ if (idFirstMother >=0 ) {
300+ /// the 1st mother is from charm or beauty, i.e. is not a light-flavoured parton
301+ if (idLastMother != idFirstMotherOrig ) {
302+ if (idLastMother != -1 ) {
303+ /// idLastMother is >= 0
304+ }
305+ } else {
306+ /// idLastMother is equal to idFirstMother
307+ idLastMother = idFirstMother ;
308+ }
309+ isFirstMotherOk = true;
310+ }
311+ }
312+ if (!isFirstMotherOk ) {
313+ /// - If we are here, it means that the 1st mother was not from charm or beauty
314+ /// - No need to check whether idLastMother>=0,
315+ /// because this would mean that none of the mother is from charm or beauty and this was checked already in isFromCharmOrBeauty
316+ /// - Need to loop between 1st and last mother, to treat cases like these
317+ /// [11:52:13][INFO] id = 565, pdgCode = -2 --> idFirstMother=519, idLastMother=519
318+ /// [11:52:13][INFO] id = 566, pdgCode = -4 --> idFirstMother=520, idLastMother=520
319+ /// [11:52:13][INFO] id = 567, pdgCode = -1 --> idFirstMother=518, idLastMother=518
320+ /// [11:52:13][INFO] id = 568, pdgCode = -311 --> idFirstMother=565, idLastMother=567
321+ /// [11:52:13][INFO] id = 569, pdgCode = -4212 --> idFirstMother=565, idLastMother=567
322+ /// --> w/o loop between 1st and last mother, the mother Ids assigned to this Sc+ (4212) by findKey are -1, both first and last
323+ bool foundAnyMother = false;
324+ for (int idMotherOrig = (idFirstMotherOrig + 1 ); idMotherOrig <=idLastMother ; idMotherOrig ++ ) {
325+ const int idMother = findKey (mapHfParticles , idMotherOrig );
326+ if (idMother >= 0 ) {
327+ /// this should mean that the mother is from HF, i.e. that we found the correct one
328+ idFirstMother = idMother ;
329+ idLastMother = idFirstMother ;
330+ foundAnyMother = true;
331+ break ;
332+ }
333+ }
334+ // set last mother to -1 if no mother has been found so far
335+ if (!foundAnyMother ) {
336+ idLastMother = -1 ;
337+ }
338+ }
339+
340+ /// fix daughter indices
341+ idFirstDaughter = findKey (mapHfParticles , idFirstDaughter );
342+ idLastDaughter = findKey (mapHfParticles , idLastDaughter );
343+
147344 /// adjust the particle mother and daughter indices
148- if ( particle .GetFirstMother () >= 0 ) particle . SetFirstMother ( particle . GetFirstMother () + originalSize );
149- if ( particle .GetSecondMother () >= 0 ) particle . SetLastMother ( particle . GetSecondMother () + originalSize );
150- if ( particle .GetFirstDaughter () >= 0 ) particle . SetFirstDaughter ( particle . GetFirstDaughter () + originalSize );
151- if ( particle .GetLastDaughter () >= 0 ) particle . SetLastDaughter ( particle . GetLastDaughter () + originalSize );
345+ particle .SetFirstMother (( idFirstMother >= 0 ) ? idFirstMother + offset : idFirstMother );
346+ particle .SetLastMother (( idLastMother >= 0 ) ? idLastMother + offset : idLastMother );
347+ particle .SetFirstDaughter (( idFirstDaughter >= 0 ) ? idFirstDaughter + offset : idFirstDaughter );
348+ particle .SetLastDaughter (( idLastDaughter >= 0 ) ? idLastDaughter + offset : idLastDaughter );
152349
153350 /// copy inside this.mParticles from mGeneratorEvHF.mParticles, i.e. the particles generated in mGeneratorEvHF
154351 mParticles .push_back (particle );
352+
155353 }
156354
355+ // for debug
356+ // LOG(info) << "-----------------------------------------------";
357+ // LOG(info) << "============ After HF event " << nEvsHF;
358+ // LOG(info) << "Full stack:";
359+ // printParticleVector(mParticles);
360+
157361 /// one more event generated, let's update the counter and clear it, to allow the next generation
158362 nEvsHF ++ ;
159363 //mGeneratedEvents++;
0 commit comments