Skip to content

Commit 8c07c8d

Browse files
authored
[PWGJE,EMCAL-689] Add DeltaEta and DeltaPhi values to `EMCALMatchedTr… (#12244)
1 parent ba284ce commit 8c07c8d

File tree

6 files changed

+387
-276
lines changed

6 files changed

+387
-276
lines changed

PWGJE/Core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ o2physics_target_root_dictionary(PWGJECore
2525
JetBkgSubUtils.h
2626
JetDerivedDataUtilities.h
2727
emcalCrossTalkEmulation.h
28+
utilsTrackMatchingEMC.h
2829
LINKDEF PWGJECoreLinkDef.h)
2930
endif()

PWGJE/Core/JetUtilities.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,6 @@ std::tuple<std::vector<std::vector<int>>, std::vector<std::vector<int>>> MatchCl
7676
throw std::invalid_argument("track collection eta and phi sizes don't match. Check the inputs.");
7777
}
7878

79-
// for (std::size_t iTrack = 0; iTrack < nTracks; iTrack++) {
80-
// if (trackEta[iTrack] == 0)
81-
// LOG(warning) << "Track eta is 0!";
82-
// }
83-
8479
// Build the KD-trees using vectors
8580
// We build two trees:
8681
// treeBase, which contains the base collection.

PWGJE/Core/utilsTrackMatchingEMC.h

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
/// \file utilsTrackMatchingEMC.h
13+
/// \brief EMCal track matching related utils
14+
/// \author Marvin Hemmer <marvin.hemmer@cern.ch>
15+
16+
#ifndef PWGJE_CORE_UTILSTRACKMATCHINGEMC_H_
17+
#define PWGJE_CORE_UTILSTRACKMATCHINGEMC_H_
18+
19+
#include <TKDTree.h>
20+
21+
#include <algorithm>
22+
#include <cmath>
23+
#include <cstddef>
24+
#include <limits>
25+
#include <span>
26+
#include <stdexcept>
27+
#include <vector>
28+
29+
namespace tmemcutilities
30+
{
31+
32+
struct MatchResult {
33+
std::vector<std::vector<int>> matchIndexTrack;
34+
std::vector<std::vector<float>> matchDeltaPhi;
35+
std::vector<std::vector<float>> matchDeltaEta;
36+
};
37+
38+
/**
39+
* Match clusters and tracks.
40+
*
41+
* Match cluster with tracks, where maxNumberMatches are considered in dR=maxMatchingDistance.
42+
* If no unique match was found for a jet, an index of -1 is stored.
43+
* The same map is created for clusters matched to tracks e.g. for electron analyses.
44+
*
45+
* @param clusterPhi cluster collection phi.
46+
* @param clusterEta cluster collection eta.
47+
* @param trackPhi track collection phi.
48+
* @param trackEta track collection eta.
49+
* @param maxMatchingDistance Maximum matching distance.
50+
* @param maxNumberMatches Maximum number of matches (e.g. 5 closest).
51+
*
52+
* @returns (cluster to track index map, track to cluster index map)
53+
*/
54+
MatchResult matchTracksToCluster(
55+
std::span<float> clusterPhi,
56+
std::span<float> clusterEta,
57+
std::span<float> trackPhi,
58+
std::span<float> trackEta,
59+
double maxMatchingDistance,
60+
int maxNumberMatches)
61+
{
62+
const std::size_t nClusters = clusterEta.size();
63+
const std::size_t nTracks = trackEta.size();
64+
MatchResult result;
65+
66+
result.matchIndexTrack.resize(nClusters);
67+
result.matchDeltaPhi.resize(nClusters);
68+
result.matchDeltaEta.resize(nClusters);
69+
70+
if (nClusters == 0 || nTracks == 0) {
71+
// There are no jets, so nothing to be done.
72+
return result;
73+
}
74+
// Input sizes must match
75+
if (clusterPhi.size() != clusterEta.size()) {
76+
throw std::invalid_argument("cluster collection eta and phi sizes don't match. Check the inputs.");
77+
}
78+
if (trackPhi.size() != trackEta.size()) {
79+
throw std::invalid_argument("track collection eta and phi sizes don't match. Check the inputs.");
80+
}
81+
82+
// Build the KD-trees using vectors
83+
// We build two trees:
84+
// treeBase, which contains the base collection.
85+
// treeTag, which contains the tag collection.
86+
// The trees are built to match in two dimensions (eta, phi)
87+
TKDTree<int, float> treeTrack(trackEta.size(), 2, 1);
88+
treeTrack.SetData(0, trackEta.data());
89+
treeTrack.SetData(1, trackPhi.data());
90+
treeTrack.Build();
91+
92+
// Find the track closest to each cluster.
93+
for (std::size_t iCluster = 0; iCluster < nClusters; iCluster++) {
94+
float point[2] = {clusterEta[iCluster], clusterPhi[iCluster]};
95+
int index[50]; // size 50 for safety
96+
float distance[50]; // size 50 for safery
97+
std::fill_n(index, 50, -1);
98+
std::fill_n(distance, 50, std::numeric_limits<float>::max());
99+
treeTrack.FindNearestNeighbors(point, maxNumberMatches, index, distance);
100+
101+
// allocate enough memory
102+
result.matchIndexTrack[iCluster].reserve(maxNumberMatches);
103+
result.matchDeltaPhi[iCluster].reserve(maxNumberMatches);
104+
result.matchDeltaEta[iCluster].reserve(maxNumberMatches);
105+
106+
// test whether indices are matching:
107+
for (int m = 0; m < maxNumberMatches; m++) {
108+
if (index[m] >= 0 && distance[m] < maxMatchingDistance) {
109+
result.matchIndexTrack[iCluster].push_back(index[m]);
110+
result.matchDeltaPhi[iCluster].push_back(trackPhi[index[m]] - clusterPhi[iCluster]);
111+
result.matchDeltaEta[iCluster].push_back(trackEta[index[m]] - clusterEta[iCluster]);
112+
}
113+
}
114+
}
115+
return result;
116+
}
117+
}; // namespace tmemcutilities
118+
119+
#endif // PWGJE_CORE_UTILSTRACKMATCHINGEMC_H_

PWGJE/DataModel/EMCALClusters.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,13 @@ using EMCALClusterCell = EMCALClusterCells::iterator;
162162
using EMCALAmbiguousClusterCell = EMCALAmbiguousClusterCells::iterator;
163163
namespace emcalmatchedtrack
164164
{
165-
DECLARE_SOA_INDEX_COLUMN(Track, track); //! linked to Track table only for tracks that were matched
165+
DECLARE_SOA_INDEX_COLUMN(Track, track); //! linked to Track table only for tracks that were matched
166+
DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! difference between matched track and cluster azimuthal angle
167+
DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); //! difference between matched track and cluster pseudorapidity
166168
} // namespace emcalmatchedtrack
167-
DECLARE_SOA_TABLE(EMCALMatchedTracks, "AOD", "EMCMATCHTRACKS", //!
168-
o2::soa::Index<>, emcalclustercell::EMCALClusterId, emcalmatchedtrack::TrackId); //!
169+
DECLARE_SOA_TABLE(EMCALMatchedTracks, "AOD", "EMCMATCHTRACKS", //!
170+
o2::soa::Index<>, emcalclustercell::EMCALClusterId, emcalmatchedtrack::TrackId,
171+
emcalmatchedtrack::DeltaPhi, emcalmatchedtrack::DeltaEta); //!
169172
using EMCALMatchedTrack = EMCALMatchedTracks::iterator;
170173
} // namespace o2::aod
171174
#endif // PWGJE_DATAMODEL_EMCALCLUSTERS_H_

0 commit comments

Comments
 (0)