@@ -193,6 +193,9 @@ struct OnTheFlyTracker {
193193
194194 ConfigurableAxis axisRadius{" axisRadius" , {2500 , 0 .0f , +250 .0f }, " R (cm)" };
195195 ConfigurableAxis axisZ{" axisZ" , {100 , -250 .0f , +250 .0f }, " Z (cm)" };
196+
197+ ConfigurableAxis axisNphotons{" axisNphotons" , {10 , 0 .5f , 10 .5f }, " N_{#gamma}" };
198+ ConfigurableAxis axisBRenergyLoss{" axisBRenergyLoss" , {500 , 0 .0f , 1 .0f }, " #Delta p / p" };
196199 } axes;
197200
198201 // for topo var QA
@@ -246,6 +249,15 @@ struct OnTheFlyTracker {
246249 Configurable<bool > useWeightedFinalPCA{" useWeightedFinalPCA" , false , " Recalculate vertex position using track covariances, effective only if useAbsDCA is true" };
247250 } cfgFitter;
248251
252+ struct : ConfigurableGroup {
253+ std::string prefix = " cfgBR" ; // configuration for bremsstrahlung
254+ Configurable<bool > radiateBR{" radiateBR" , false , " simulate bremsstrahlung" };
255+ Configurable<bool > doBRQA{" doBRQA" , false , " Do QA for bremsstrahlung" };
256+ Configurable<float > minBREnergyFraction{" minEnergyFraction" , 0 .001f , " Minimum energy fraction a bremsstrahlung photon can carry" };
257+ Configurable<float > maxBREnergyFraction{" maxEnergyFraction" , 0 .95f , " Maximum energy fraction a bremsstrahlung photon can carry" };
258+ Configurable<float > radiationStrength{" radiationStrength" , 1e-6f , " Strenght of the bremsstrahlung radiation" };
259+ } brSettings;
260+
249261 using PVertex = o2::dataformats::PrimaryVertex;
250262
251263 // for secondary vertex finding
@@ -568,6 +580,14 @@ struct OnTheFlyTracker {
568580 insertHist (histPath + " h2dDCAz" , " h2dDCAz;p_{T};DCA_{z}" , {kTH2D , {{axes.axisMomentum , axes.axisDCA }}});
569581 }
570582
583+ if (brSettings.doBRQA ) {
584+ insertHist (histPath + " h1dNBRPhotons" , " h1dNBRPhotons;N_{#gamma};Counts" , {kTH1D , {{axes.axisNphotons }}});
585+ insertHist (histPath + " h1dBREnergyLoss" , " h1dBREnergyLoss;#Delta p / p;Counts" , {kTH1D , {{axes.axisBRenergyLoss }}});
586+
587+ insertHist (histPath + " h2dBRPtRes" , " h2dPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}" , {kTH2D , {{axes.axisMomentum , axes.axisPtRes }}});
588+ insertHist (histPath + " h2dBRPtResAbs" , " h2dPtResAbs;Gen p_{T};#Delta p_{T}" , {kTH2D , {{axes.axisMomentum , axes.axisPtRes }}});
589+ }
590+
571591 } // end config loop
572592
573593 // Basic QA
@@ -1749,6 +1769,67 @@ struct OnTheFlyTracker {
17491769 }
17501770 }
17511771
1772+ // / Function to compute the bremsstrahlung loss of charged-particles for each layer of the current configuration
1773+ // / \param icfg index of the current configuration
1774+ // / \param mcParticle true MC particle to identify particle and get the energy
1775+ // / \param trackParCov track of the particle to compute bremsstrahlung for
1776+ void computeBremsstrahlungLoss (const int icfg, const auto & mcParticle, o2::track::TrackParCov& trackParCov)
1777+ {
1778+ if (brSettings.radiateBR ) {
1779+ const o2::fastsim::GeometryEntry geoEntry = mGeoContainer .getEntry (icfg);
1780+
1781+ for (auto const & layerName : geoEntry.getLayerNames ()) {
1782+ if (layerName.find (" global" ) != std::string::npos) { // Layers with global tag are skipped
1783+ continue ;
1784+ }
1785+
1786+ float mass = o2::constants::physics::MassElectron;
1787+
1788+ switch (std::abs (mcParticle.pdgCode ())) {
1789+ case kElectron :
1790+ mass = o2::constants::physics::MassElectron;
1791+ break ;
1792+ case kMuonMinus :
1793+ mass = o2::constants::physics::MassMuon;
1794+ break ;
1795+ case kPiPlus :
1796+ mass = o2::constants::physics::MassPionCharged;
1797+ break ;
1798+ case kKPlus :
1799+ mass = o2::constants::physics::MassKaonCharged;
1800+ break ;
1801+ case kProton :
1802+ mass = o2::constants::physics::MassProton;
1803+ break ;
1804+ default :
1805+ break ;
1806+ }
1807+
1808+ float lambda = brSettings.radiationStrength * mcParticle.e () * geoEntry.getFloatValue (layerName, " x0" ) / (mass * mass);
1809+ ULong64_t nPhotons = gRandom ->Poisson (lambda);
1810+
1811+ double initialMomentum = trackParCov.getP ();
1812+
1813+ for (ULong64_t photon = 0 ; photon < nPhotons; ++photon) {
1814+ float radiativeLoss = 1 .0f - brSettings.minBREnergyFraction * std::pow (brSettings.maxBREnergyFraction / brSettings.minBREnergyFraction , gRandom ->Rndm ());
1815+ trackParCov.setQ2Pt (trackParCov.getQ2Pt () / radiativeLoss);
1816+ }
1817+
1818+ double afterRadiationMomentum = trackParCov.getP ();
1819+
1820+ if (brSettings.doBRQA ) {
1821+ const std::string histPath = " Configuration_" + std::to_string (icfg) + " /" ;
1822+
1823+ getHist (TH1, histPath + " h1dNBRPhotons" )->Fill (static_cast <double >(nPhotons));
1824+ getHist (TH1, histPath + " h1dBREnergyLoss" )->Fill ((initialMomentum - afterRadiationMomentum) / afterRadiationMomentum);
1825+
1826+ getHist (TH2, histPath + " h2dBRPtRes" )->Fill (trackParCov.getPt (), (trackParCov.getPt () - mcParticle.pt ()) / trackParCov.getPt ());
1827+ getHist (TH2, histPath + " h2dBRPtResAbs" )->Fill (trackParCov.getPt (), trackParCov.getPt () - mcParticle.pt ());
1828+ }
1829+ }
1830+ }
1831+ }
1832+
17521833 void processWithLUTs (aod::McCollision const & mcCollision, aod::McParticles const & mcParticles, const int icfg)
17531834 {
17541835 const std::string histPath = " Configuration_" + std::to_string (icfg) + " /" ;
@@ -1811,12 +1892,14 @@ struct OnTheFlyTracker {
18111892 o2::track::TrackParCov perfectTrackParCov;
18121893 o2::upgrade::convertMCParticleToO2Track (mcParticle, perfectTrackParCov, pdgDB);
18131894 perfectTrackParCov.setPID (pdgCodeToPID (mcParticle.pdgCode ()));
1895+ computeBremsstrahlungLoss (icfg, mcParticle, perfectTrackParCov);
18141896 nTrkHits = fastTracker[icfg]->FastTrack (perfectTrackParCov, trackParCov, dNdEta);
18151897 if (nTrkHits < fastPrimaryTrackerSettings.minSiliconHits ) {
18161898 reconstructed = false ;
18171899 }
18181900 } else {
18191901 o2::upgrade::convertMCParticleToO2Track (mcParticle, trackParCov, pdgDB);
1902+ computeBremsstrahlungLoss (icfg, mcParticle, trackParCov);
18201903 reconstructed = mSmearer [icfg]->smearTrack (trackParCov, mcParticle.pdgCode (), dNdEta);
18211904 nTrkHits = fastTrackerSettings.minSiliconHits ;
18221905 }
@@ -2002,11 +2085,13 @@ struct OnTheFlyTracker {
20022085 int nTrkHits = 0 ;
20032086 if (enablePrimarySmearing && mcParticle.isPrimary ()) {
20042087 o2::upgrade::convertMCParticleToO2Track (mcParticle, trackParCov, pdgDB);
2088+ computeBremsstrahlungLoss (icfg, mcParticle, trackParCov);
20052089 reconstructed = mSmearer [icfg]->smearTrack (trackParCov, mcParticle.pdgCode (), dNdEta);
20062090 nTrkHits = fastTrackerSettings.minSiliconHits ;
20072091 } else if (enableSecondarySmearing) {
20082092 o2::track::TrackParCov perfectTrackParCov;
20092093 o2::upgrade::convertMCParticleToO2Track (mcParticle, perfectTrackParCov, pdgDB);
2094+ computeBremsstrahlungLoss (icfg, mcParticle, perfectTrackParCov);
20102095 perfectTrackParCov.setPID (pdgCodeToPID (mcParticle.pdgCode ()));
20112096 nTrkHits = fastTracker[icfg]->FastTrack (perfectTrackParCov, trackParCov, dNdEta);
20122097 if (nTrkHits < fastTrackerSettings.minSiliconHits ) {
0 commit comments