@@ -307,6 +307,7 @@ struct StrangenessInJets {
307307 }
308308 }
309309
310+ /*
310311 // Calculation of perpendicular axes
311312 void getPerpendicularAxis(TVector3 p, TVector3& u, double sign)
312313 {
@@ -370,6 +371,96 @@ struct StrangenessInJets {
370371
371372 return deltaPhi;
372373 }
374+ */
375+
376+ // Check if particle is a physical primary or a decay product of a heavy-flavor hadron
377+ bool isPhysicalPrimaryOrFromHF (aod::McParticle const & particle, aod::McParticles const & mcParticles)
378+ {
379+ // Keep only pi, K, p, e, mu
380+ int pdg = std::abs (particle.pdgCode ());
381+ if (!(pdg == PDG_t::kPiPlus || pdg == PDG_t::kKPlus || pdg == PDG_t::kProton || pdg == PDG_t::kElectron || pdg == PDG_t::kMuonMinus ))
382+ return false ;
383+
384+ // Constants for identifying heavy-flavor (charm and bottom) content from PDG codes
385+ static constexpr int kCharmQuark = 4 ;
386+ static constexpr int kBottomQuark = 5 ;
387+ static constexpr int hundreds = 100 ;
388+ static constexpr int thousands = 1000 ;
389+
390+ // Check if particle is from heavy-flavor decay
391+ bool fromHF = false ;
392+ if (particle.has_mothers ()) {
393+ auto mother = mcParticles.iteratorAt (particle.mothersIds ()[0 ]);
394+ int motherPdg = std::abs (mother.pdgCode ());
395+ fromHF = (motherPdg / hundreds == kCharmQuark || motherPdg / hundreds == kBottomQuark || motherPdg / thousands == kCharmQuark || motherPdg / thousands == kBottomQuark );
396+ }
397+
398+ // Select only physical primary particles or from heavy-flavor
399+ return (particle.isPhysicalPrimary () || fromHF);
400+ }
401+
402+ // Compute two transverse directions orthogonal to vector p
403+ void getPerpendicularDirections (const TVector3& p, TVector3& u1, TVector3& u2)
404+ {
405+ // Get momentum components
406+ double px = p.X ();
407+ double py = p.Y ();
408+ double pz = p.Z ();
409+
410+ // Precompute squared terms
411+ double px2 = px * px;
412+ double py2 = py * py;
413+ double pz2 = pz * pz;
414+ double pz4 = pz2 * pz2;
415+
416+ // Case 1: vector along z-axis -> undefined perpendiculars
417+ if (px == 0 && py == 0 ) {
418+ u1.SetXYZ (0 , 0 , 0 );
419+ u2.SetXYZ (0 , 0 , 0 );
420+ return ;
421+ }
422+
423+ // Case 2: px = 0 -> avoid division by zero
424+ if (px == 0 && py != 0 ) {
425+ double ux = std::sqrt (py2 - pz4 / py2);
426+ double uy = -pz2 / py;
427+ u1.SetXYZ (ux, uy, pz);
428+ u2.SetXYZ (-ux, uy, pz);
429+ return ;
430+ }
431+
432+ // Case 3: py = 0 -> avoid division by zero
433+ if (py == 0 && px != 0 ) {
434+ double ux = -pz2 / px;
435+ double uy = std::sqrt (px2 - pz4 / px2);
436+ u1.SetXYZ (ux, uy, pz);
437+ u2.SetXYZ (ux, -uy, pz);
438+ return ;
439+ }
440+
441+ // General case: solve quadratic for perpendicular vectors
442+ double a = px2 + py2;
443+ double b = 2.0 * px * pz2;
444+ double c = pz4 - py2 * py2 - px2 * py2;
445+ double delta = b * b - 4.0 * a * c;
446+
447+ // Invalid or degenerate solutions
448+ if (delta < 0 || a == 0 ) {
449+ u1.SetXYZ (0 , 0 , 0 );
450+ u2.SetXYZ (0 , 0 , 0 );
451+ return ;
452+ }
453+
454+ // Solution 1
455+ double u1x = (-b + std::sqrt (delta)) / (2.0 * a);
456+ double u1y = (-pz2 - px * u1x) / py;
457+ u1.SetXYZ (u1x, u1y, pz);
458+
459+ // Solution 2
460+ double u2x = (-b - std::sqrt (delta)) / (2.0 * a);
461+ double u2y = (-pz2 - px * u2x) / py;
462+ u2.SetXYZ (u2x, u2y, pz);
463+ }
373464
374465 // Find ITS hit
375466 template <typename TrackIts>
@@ -879,10 +970,11 @@ struct StrangenessInJets {
879970
880971 // Calculation of perpendicular cones
881972 TVector3 jetAxis (jet.px (), jet.py (), jet.pz ());
882- TVector3 ueAxis1 (0 , 0 , 0 );
883- TVector3 ueAxis2 (0 , 0 , 0 );
884- getPerpendicularAxis (jetAxis, ueAxis1, +1 );
885- getPerpendicularAxis (jetAxis, ueAxis2, -1 );
973+ TVector3 ueAxis1 (0 , 0 , 0 ), ueAxis2 (0 , 0 , 0 );
974+ getPerpendicularDirections (jetAxis, ueAxis1, ueAxis2);
975+ if (ueAxis1.Mag () == 0 || ueAxis2.Mag () == 0 ) {
976+ continue ;
977+ }
886978
887979 // Store jet and UE axes
888980 selectedJet.emplace_back (jetAxis);
@@ -1058,6 +1150,7 @@ struct StrangenessInJets {
10581150 }
10591151 PROCESS_SWITCH (StrangenessInJets, processData, " Process data" , true );
10601152
1153+ // Define per-collision preslices for V0s, cascades, MC particles, and daughter tracks
10611154 Preslice<aod::V0Datas> perCollisionV0 = o2::aod::v0data::collisionId;
10621155 Preslice<aod::CascDataExt> perCollisionCasc = o2::aod::cascade::collisionId;
10631156 Preslice<aod::McParticles> perMCCollision = o2::aod::mcparticle::mcCollisionId;
@@ -1066,9 +1159,23 @@ struct StrangenessInJets {
10661159 // Generated MC events
10671160 void processMCgenerated (aod::McCollisions const & collisions, aod::McParticles const & mcParticles)
10681161 {
1162+ // Define per-event particle containers
1163+ std::vector<fastjet::PseudoJet> fjParticles;
1164+ std::vector<TVector3> strHadronMomentum;
1165+ std::vector<int > pdg;
1166+
1167+ // Jet and area definitions
1168+ fastjet::JetDefinition jetDef (fastjet::antikt_algorithm, rJet);
1169+ fastjet::AreaDefinition areaDef (fastjet::active_area, fastjet::GhostedAreaSpec (1.0 ));
1170+
10691171 // Loop over all simulated collision events
10701172 for (const auto & collision : collisions) {
10711173
1174+ // Clear containers at the start of the event loop
1175+ fjParticles.clear ();
1176+ strHadronMomentum.clear ();
1177+ pdg.clear ();
1178+
10721179 // Fill event counter before any selection
10731180 registryMC.fill (HIST (" number_of_events_mc_gen" ), 0.5 );
10741181
@@ -1088,15 +1195,13 @@ struct StrangenessInJets {
10881195 // MC particles per collision
10891196 auto mcParticlesPerColl = mcParticles.sliceBy (perMCCollision, collision.globalIndex ());
10901197
1091- // Store strange hadron pdg code and momentum
1092- std::vector<int > pdg;
1093- std::vector<TVector3> strHadronMomentum;
1094-
10951198 // Loop over all MC particles and select physical primaries within acceptance
1096- std::vector<fastjet::PseudoJet> fjParticles;
10971199 for (const auto & particle : mcParticlesPerColl) {
1098- if (!particle.isPhysicalPrimary ())
1200+
1201+ // Select physical primary particles or HF decay products
1202+ if (!isPhysicalPrimaryOrFromHF (particle, mcParticles))
10991203 continue ;
1204+
11001205 double minPtParticle = 0.1 ;
11011206 if (particle.eta () < etaMin || particle.eta () > etaMax || particle.pt () < minPtParticle)
11021207 continue ;
@@ -1122,8 +1227,6 @@ struct StrangenessInJets {
11221227 registryMC.fill (HIST (" number_of_events_mc_gen" ), 3.5 );
11231228
11241229 // Cluster MC particles into jets using anti-kt algorithm
1125- fastjet::JetDefinition jetDef (fastjet::antikt_algorithm, rJet);
1126- fastjet::AreaDefinition areaDef (fastjet::active_area, fastjet::GhostedAreaSpec (1.0 ));
11271230 fastjet::ClusterSequenceArea cs (fjParticles, jetDef, areaDef);
11281231 std::vector<fastjet::PseudoJet> jets = fastjet::sorted_by_pt (cs.inclusive_jets ());
11291232
@@ -1150,8 +1253,10 @@ struct StrangenessInJets {
11501253 TVector3 jetAxis (jet.px (), jet.py (), jet.pz ());
11511254 double coneRadius = std::sqrt (jet.area () / PI);
11521255 TVector3 ueAxis1 (0 , 0 , 0 ), ueAxis2 (0 , 0 , 0 );
1153- getPerpendicularAxis (jetAxis, ueAxis1, +1 );
1154- getPerpendicularAxis (jetAxis, ueAxis2, -1 );
1256+ getPerpendicularDirections (jetAxis, ueAxis1, ueAxis2);
1257+ if (ueAxis1.Mag () == 0 || ueAxis2.Mag () == 0 ) {
1258+ continue ;
1259+ }
11551260
11561261 // Loop over strange hadrons
11571262 int index = -1 ;
@@ -1327,8 +1432,25 @@ struct StrangenessInJets {
13271432 aod::V0Datas const & fullV0s, aod::CascDataExt const & Cascades,
13281433 const aod::McParticles&)
13291434 {
1435+ // Define per-event containers
1436+ std::vector<fastjet::PseudoJet> fjParticles;
1437+ std::vector<TVector3> selectedJet;
1438+ std::vector<TVector3> ue1;
1439+ std::vector<TVector3> ue2;
1440+
1441+ // Jet and area definitions
1442+ fastjet::JetDefinition jetDef (fastjet::antikt_algorithm, rJet);
1443+ fastjet::AreaDefinition areaDef (fastjet::active_area, fastjet::GhostedAreaSpec (1.0 ));
1444+
1445+ // Loop over reconstructed collisions
13301446 for (const auto & collision : collisions) {
13311447
1448+ // Clear containers at the start of the event loop
1449+ fjParticles.clear ();
1450+ selectedJet.clear ();
1451+ ue1.clear ();
1452+ ue2.clear ();
1453+
13321454 // Fill event counter before any selection
13331455 registryMC.fill (HIST (" number_of_events_mc_rec" ), 0.5 );
13341456 if (!collision.sel8 ())
@@ -1351,7 +1473,6 @@ struct StrangenessInJets {
13511473 auto tracksPerColl = mcTracks.sliceBy (perCollisionTrk, collision.globalIndex ());
13521474
13531475 // Loop over reconstructed tracks
1354- std::vector<fastjet::PseudoJet> fjParticles;
13551476 for (auto const & track : tracksPerColl) {
13561477 if (!passedTrackSelectionForJetReconstruction (track))
13571478 continue ;
@@ -1367,17 +1488,12 @@ struct StrangenessInJets {
13671488 registryMC.fill (HIST (" number_of_events_mc_rec" ), 3.5 );
13681489
13691490 // Cluster particles using the anti-kt algorithm
1370- fastjet::JetDefinition jetDef (fastjet::antikt_algorithm, rJet);
1371- fastjet::AreaDefinition areaDef (fastjet::active_area, fastjet::GhostedAreaSpec (1.0 ));
13721491 fastjet::ClusterSequenceArea cs (fjParticles, jetDef, areaDef);
13731492 std::vector<fastjet::PseudoJet> jets = fastjet::sorted_by_pt (cs.inclusive_jets ());
13741493 auto [rhoPerp, rhoMPerp] = backgroundSub.estimateRhoPerpCone (fjParticles, jets);
13751494
13761495 // Jet selection
13771496 bool isAtLeastOneJetSelected = false ;
1378- std::vector<TVector3> selectedJet;
1379- std::vector<TVector3> ue1;
1380- std::vector<TVector3> ue2;
13811497
13821498 // Loop over clustered jets
13831499 for (const auto & jet : jets) {
@@ -1396,8 +1512,10 @@ struct StrangenessInJets {
13961512 // Perpendicular cones
13971513 TVector3 jetAxis (jet.px (), jet.py (), jet.pz ());
13981514 TVector3 ueAxis1 (0 , 0 , 0 ), ueAxis2 (0 , 0 , 0 );
1399- getPerpendicularAxis (jetAxis, ueAxis1, +1 );
1400- getPerpendicularAxis (jetAxis, ueAxis2, -1 );
1515+ getPerpendicularDirections (jetAxis, ueAxis1, ueAxis2);
1516+ if (ueAxis1.Mag () == 0 || ueAxis2.Mag () == 0 ) {
1517+ continue ;
1518+ }
14011519
14021520 // Store selected jet and UE cone axes
14031521 selectedJet.emplace_back (jetAxis);
0 commit comments