@@ -93,6 +93,12 @@ struct OnTheFlyTofPid {
9393 Configurable<bool > considerEventTime{" considerEventTime" , true , " flag to consider event time" };
9494 Configurable<float > innerTOFRadius{" innerTOFRadius" , 20 , " barrel inner TOF radius (cm)" };
9595 Configurable<float > outerTOFRadius{" outerTOFRadius" , 80 , " barrel outer TOF radius (cm)" };
96+ Configurable<float > innerTOFLength{" innerTOFLength" , 124 , " barrel inner TOF length (cm)" };
97+ Configurable<float > outerTOFLength{" outerTOFLength" , 250 , " barrel outer TOF length (cm)" };
98+ Configurable<std::array<float , 2 >> innerTOFPixelDimension{" innerTOFPixelDimension" , {0.1 , 0.1 }, " barrel inner TOF pixel dimension in Z and RPhi (cm)" };
99+ Configurable<float > innerTOFFractionOfInactiveArea{" innerTOFFractionOfInactiveArea" , 0 .f , " barrel inner TOF fraction of inactive area" };
100+ Configurable<std::array<float , 2 >> outerTOFPixelDimension{" outerTOFPixelDimension" , {0.1 , 0.1 }, " barrel outer TOF pixel dimension in Z and RPhi (cm)" };
101+ Configurable<float > outerTOFFractionOfInactiveArea{" outerTOFFractionOfInactiveArea" , 0 .f , " barrel outer TOF fraction of inactive area" };
96102 Configurable<float > innerTOFTimeReso{" innerTOFTimeReso" , 20 , " barrel inner TOF time error (ps)" };
97103 Configurable<float > outerTOFTimeReso{" outerTOFTimeReso" , 20 , " barrel outer TOF time error (ps)" };
98104 Configurable<int > nStepsLIntegrator{" nStepsLIntegrator" , 200 , " number of steps in length integrator" };
@@ -196,12 +202,14 @@ struct OnTheFlyTofPid {
196202 histos.add (" iTOF/h2dTrackLengthInnerVsPt" , " h2dTrackLengthInnerVsPt" , kTH2F , {axisMomentumSmall, axisTrackLengthInner});
197203 histos.add (" iTOF/h2dTrackLengthInnerRecoVsPt" , " h2dTrackLengthInnerRecoVsPt" , kTH2F , {axisMomentumSmall, axisTrackLengthInner});
198204 histos.add (" iTOF/h2dDeltaTrackLengthInnerVsPt" , " h2dDeltaTrackLengthInnerVsPt" , kTH2F , {axisMomentumSmall, axisTrackDeltaLength});
205+ histos.add (" iTOF/h2HitMap" , " h2HitMap" , kTH2F , {{1000 , -simConfig.innerTOFLength / 2 , simConfig.innerTOFLength / 2 }, {1000 , 0 , simConfig.innerTOFRadius * 2 * M_PI}});
199206
200207 histos.add (" oTOF/h2dVelocityVsMomentumOuter" , " h2dVelocityVsMomentumOuter" , kTH2F , {axisMomentum, axisVelocity});
201208 histos.add (" oTOF/h2dVelocityVsRigidityOuter" , " h2dVelocityVsRigidityOuter" , kTH2F , {axisRigidity, axisVelocity});
202209 histos.add (" oTOF/h2dTrackLengthOuterVsPt" , " h2dTrackLengthOuterVsPt" , kTH2F , {axisMomentumSmall, axisTrackLengthOuter});
203210 histos.add (" oTOF/h2dTrackLengthOuterRecoVsPt" , " h2dTrackLengthOuterRecoVsPt" , kTH2F , {axisMomentumSmall, axisTrackLengthOuter});
204211 histos.add (" oTOF/h2dDeltaTrackLengthOuterVsPt" , " h2dDeltaTrackLengthOuterVsPt" , kTH2F , {axisMomentumSmall, axisTrackDeltaLength});
212+ histos.add (" oTOF/h2HitMap" , " h2HitMap" , kTH2F , {{1000 , -simConfig.outerTOFLength / 2 , simConfig.outerTOFLength / 2 }, {1000 , 0 , simConfig.outerTOFRadius * 2 * M_PI}});
205213
206214 const AxisSpec axisPt{static_cast <int >(plotsConfig.nBinsP ), 0 .0f , +4 .0f , " #it{p}_{T} (GeV/#it{c})" };
207215 const AxisSpec axisEta{static_cast <int >(plotsConfig.nBinsEta ), -2 .0f , +2 .0f , " #eta" };
@@ -244,11 +252,172 @@ struct OnTheFlyTofPid {
244252 }
245253 }
246254
255+ struct TOFLayerEfficiency {
256+ private:
257+ const float layerRadius;
258+ const float layerLength;
259+ const float pixelDimensionZ;
260+ const float pixelDimensionRPhi;
261+ const float fractionInactive;
262+ const float magField;
263+
264+ TAxis* axisZ = nullptr ;
265+ TAxis* axisRPhi = nullptr ;
266+ TAxis* axisInPixelZ = nullptr ;
267+ TAxis* axisInPixelRPhi = nullptr ;
268+
269+ TH2F* hHitMapInPixel = nullptr ;
270+ TH2F* hHitMapInPixelBefore = nullptr ;
271+ TH2F* hHitMap = nullptr ;
272+
273+ public:
274+ ~TOFLayerEfficiency ()
275+ {
276+ hHitMap->SaveAs (Form (" /tmp/%s.png" , hHitMap->GetName ()));
277+ hHitMapInPixel->SaveAs (Form (" /tmp/%s.png" , hHitMapInPixel->GetName ()));
278+ hHitMapInPixelBefore->SaveAs (Form (" /tmp/%s.png" , hHitMapInPixelBefore->GetName ()));
279+
280+ delete axisZ;
281+ delete axisRPhi;
282+ delete axisInPixelZ;
283+ delete axisInPixelRPhi;
284+ delete hHitMap;
285+ delete hHitMapInPixel;
286+ delete hHitMapInPixelBefore;
287+ }
288+
289+ TOFLayerEfficiency (float r, float l, std::array<float , 2 > pDimensions, float fIA , float m)
290+ : layerRadius(r), layerLength(l), pixelDimensionZ(pDimensions[0 ]), pixelDimensionRPhi(pDimensions[1 ]), fractionInactive(fIA ), magField(m)
291+ {
292+ // Assuming square pixels for simplicity
293+ const float circumference = 2 .0f * M_PI * layerRadius;
294+ axisZ = new TAxis (static_cast <int >(layerLength / pixelDimensionZ), -layerLength / 2 , layerLength);
295+ axisRPhi = new TAxis (static_cast <int >(circumference / pixelDimensionRPhi), 0 .f , circumference);
296+
297+ const float inactiveBorderRPhi = pixelDimensionRPhi * std::sqrt (fractionInactive) / 2 ;
298+ const float inactiveBorderZ = pixelDimensionZ * std::sqrt (fractionInactive) / 2 ;
299+ const double arrayRPhi[4 ] = {-pixelDimensionRPhi / 2 , -pixelDimensionRPhi / 2 + inactiveBorderRPhi, pixelDimensionRPhi / 2 - inactiveBorderRPhi, pixelDimensionRPhi / 2 };
300+ for (int i = 0 ; i < 4 ; i++) {
301+ LOG (info) << " arrayRPhi[" << i << " ] = " << arrayRPhi[i];
302+ }
303+ axisInPixelRPhi = new TAxis (3 , arrayRPhi);
304+ const double arrayZ[4 ] = {-pixelDimensionZ / 2 , -pixelDimensionZ / 2 + inactiveBorderZ, pixelDimensionZ / 2 - inactiveBorderZ, pixelDimensionZ / 2 };
305+ for (int i = 0 ; i < 4 ; i++) {
306+ LOG (info) << " arrayZ[" << i << " ] = " << arrayZ[i];
307+ }
308+ axisInPixelZ = new TAxis (3 , arrayZ);
309+
310+ hHitMap = new TH2F (Form (" hHitMap_R%.0f" , layerRadius), " HitMap;z (cm); r#phi (cm)" , 1000 , -1000 , 1000 , 1000 , -1000 , 1000 );
311+ hHitMapInPixel = new TH2F (Form (" hHitMapInPixel_R%.0f" , layerRadius), " HitMapInPixel;z (cm); r#phi (cm)" , 1000 , -10 , 10 , 1000 , -10 , 10 );
312+ hHitMapInPixelBefore = new TH2F (Form (" hHitMapInPixelBefore_R%.0f" , layerRadius), " HitMapInPixel;z (cm); r#phi (cm)" , 1000 , -10 , 10 , 1000 , -10 , 10 );
313+ }
314+
315+ bool isInTOFActiveArea (std::array<float , 3 > hitPosition)
316+ {
317+ if (fractionInactive <= 0 .0f ) {
318+ return true ;
319+ }
320+ if (fractionInactive >= 1 .0f ) {
321+ return false ;
322+ }
323+
324+ // Convert 3D position to cylindrical coordinates for area calculation
325+ const float phi = std::atan2 (hitPosition[1 ], hitPosition[0 ]);
326+ const float rphi = phi * layerRadius;
327+ const float z = hitPosition[2 ];
328+ const float r = std::sqrt (hitPosition[0 ] * hitPosition[0 ] + hitPosition[1 ] * hitPosition[1 ]);
329+
330+ // Check if hit is within layer geometric acceptance
331+ if (std::abs (layerRadius - r) > 10 .f ) {
332+ LOG (debug) << " Hit out of TOF layer acceptance: r=" << r << " cm with respect to the layer radius " << layerRadius;
333+ return false ;
334+ }
335+ if (std::abs (z) > layerLength / 2 .0f ) {
336+ LOG (debug) << " Hit out of TOF layer acceptance: z=" << z << " cm with respect to the layer length " << layerLength;
337+ return false ;
338+ }
339+
340+ const int pixelIndexPhi = axisRPhi->FindBin (rphi);
341+ const int pixelIndexZ = axisZ->FindBin (z);
342+
343+ // LOG(info) << "Hit pixel " << pixelIndexPhi << "/" << nPixelsRPhi << " and " << pixelIndexZ << "/" << nPixelsZ;
344+
345+ if (pixelIndexPhi <= 0 || pixelIndexPhi > axisRPhi->GetNbins () || pixelIndexZ <= 0 || pixelIndexZ > axisZ->GetNbins ()) {
346+ // LOG(info) << "Hit out of TOF layer pixel range: pixelIndexPhi=" << pixelIndexPhi << ", pixelIndexZ=" << pixelIndexZ;
347+ return false ;
348+ }
349+ // Calculate local position within the pixel
350+ const float localRPhi = (rphi - axisRPhi->GetBinCenter (pixelIndexPhi));
351+ const float localZ = (z - axisZ->GetBinCenter (pixelIndexZ));
352+
353+ // The difference between the hit and the pixel position cannot be greater than the size of the pixel
354+ if (std::abs (localRPhi - axisRPhi->GetBinCenter (pixelIndexPhi)) > axisRPhi->GetBinWidth (pixelIndexPhi)) {
355+ // LOG(warning) << "Local hit difference in phi is bigger than the pixel size";
356+ }
357+ if (std::abs (localZ - axisZ->GetBinCenter (pixelIndexZ)) > axisZ->GetBinWidth (pixelIndexZ)) {
358+ // LOG(warning) << "Local hit difference in z is bigger than the pixel size";
359+ }
360+ hHitMapInPixelBefore->Fill (localZ, localRPhi);
361+ switch (axisInPixelRPhi->FindBin (localRPhi)) {
362+ case 0 :
363+ case 1 :
364+ case 3 :
365+ case 4 :
366+ return false ;
367+ }
368+ switch (axisInPixelZ->FindBin (localZ)) {
369+ case 0 :
370+ case 1 :
371+ case 3 :
372+ case 4 :
373+ return false ;
374+ }
375+ hHitMapInPixel->Fill (localZ, localRPhi);
376+ hHitMap->Fill (z, rphi);
377+ return true ;
378+ }
379+
380+ // / Check if a track hits the active area (convenience function)
381+ // / \param track the track parameters for automatic hit position calculation
382+ // / \return true if the hit is in the active area
383+ bool isTrackInActiveArea (const o2::track::TrackParCov& track)
384+ {
385+ if (fractionInactive <= 0 .f ) {
386+ return true ;
387+ }
388+ float x, y, z;
389+ if (!track.getXatLabR (layerRadius, x, magField)) {
390+ LOG (debug) << " Could not propagate track to TOF layer at radius " << layerRadius << " cm" ;
391+ return false ;
392+ }
393+ bool b;
394+ ROOT::Math::PositionVector3D hit = track.getXYZGloAt (x, magField, b);
395+ if (!b) {
396+ LOG (debug) << " Could not get hit position at radius " << layerRadius << " cm" ;
397+ return false ;
398+ }
399+ hit.GetCoordinates (x, y, z);
400+ return isInTOFActiveArea (std::array<float , 3 >{x, y, z});
401+ }
402+ };
403+
404+ bool isInInnerTOFActiveArea (const o2::track::TrackParCov& track)
405+ {
406+ static TOFLayerEfficiency innerTOFLayer (simConfig.innerTOFRadius , simConfig.innerTOFLength , simConfig.innerTOFPixelDimension , simConfig.innerTOFFractionOfInactiveArea , simConfig.magneticField );
407+ return innerTOFLayer.isTrackInActiveArea (track);
408+ }
409+
410+ bool isInOuterTOFActiveArea (const o2::track::TrackParCov& track)
411+ {
412+ static TOFLayerEfficiency outerTOFLayer (simConfig.outerTOFRadius , simConfig.outerTOFLength , simConfig.outerTOFPixelDimension , simConfig.outerTOFFractionOfInactiveArea , simConfig.magneticField );
413+ return outerTOFLayer.isTrackInActiveArea (track);
414+ }
415+
247416 // / function to calculate track length of this track up to a certain radius
248417 // / \param track the input track
249418 // / \param radius the radius of the layer you're calculating the length to
250419 // / \param magneticField the magnetic field to use when propagating
251- float computeTrackLength (o2::track::TrackParCov track, float radius, float magneticField)
420+ static float computeTrackLength (o2::track::TrackParCov track, float radius, float magneticField)
252421 {
253422 // don't make use of the track parametrization
254423 float length = -100 ;
@@ -496,6 +665,25 @@ struct OnTheFlyTofPid {
496665 trackLengthOuterTOF = computeTrackLength (o2track, simConfig.outerTOFRadius , simConfig.magneticField );
497666 }
498667
668+ // Check if the track hit a sensitive area of the TOF
669+ const bool activeInnerTOF = isInInnerTOFActiveArea (o2track);
670+ if (!activeInnerTOF) {
671+ trackLengthInnerTOF = -999 .f ;
672+ } else {
673+ float x = 0 .f ;
674+ o2track.getXatLabR (simConfig.innerTOFRadius , x, simConfig.magneticField );
675+ histos.fill (HIST (" iTOF/h2HitMap" ), o2track.getZAt (x, simConfig.magneticField ), simConfig.innerTOFRadius * o2track.getPhiAt (x, simConfig.magneticField ));
676+ }
677+
678+ const bool activeOuterTOF = isInOuterTOFActiveArea (o2track);
679+ if (!activeOuterTOF) {
680+ trackLengthOuterTOF = -999 .f ;
681+ } else {
682+ float x = 0 .f ;
683+ o2track.getXatLabR (simConfig.outerTOFRadius , x, simConfig.magneticField );
684+ histos.fill (HIST (" oTOF/h2HitMap" ), o2track.getZAt (x, simConfig.magneticField ), simConfig.outerTOFRadius * o2track.getPhiAt (x, simConfig.magneticField ));
685+ }
686+
499687 // get mass to calculate velocity
500688 auto pdgInfo = pdg->GetParticle (mcParticle.pdgCode ());
501689 if (pdgInfo == nullptr ) {
@@ -504,8 +692,8 @@ struct OnTheFlyTofPid {
504692 continue ;
505693 }
506694 const float v = computeParticleVelocity (o2track.getP (), pdgInfo->Mass ());
507- const float expectedTimeInnerTOF = trackLengthInnerTOF / v + eventCollisionTimePS; // arrival time to the Inner TOF in ps
508- const float expectedTimeOuterTOF = trackLengthOuterTOF / v + eventCollisionTimePS; // arrival time to the Outer TOF in ps
695+ const float expectedTimeInnerTOF = trackLengthInnerTOF > 0 ? trackLengthInnerTOF / v + eventCollisionTimePS : - 999 . f ; // arrival time to the Inner TOF in ps
696+ const float expectedTimeOuterTOF = trackLengthOuterTOF > 0 ? trackLengthOuterTOF / v + eventCollisionTimePS : - 999 . f ; // arrival time to the Outer TOF in ps
509697 upgradeTofMC (expectedTimeInnerTOF, trackLengthInnerTOF, expectedTimeOuterTOF, trackLengthOuterTOF);
510698
511699 // Smear with expected resolutions
0 commit comments