Skip to content

Commit 3242656

Browse files
authored
[EMCAL-734][EMCAL-689] implemented track matching and connection between cell and cluster (#1079)
* [EMCAL-734] adapted cluster definition * [EMCAL-689] added EMC cluster track matching and link of clusters to cells * [EMCAL-689] fixed trailing whitespace * [EMCAL-689] fixed tcomiler warnings
1 parent f369b12 commit 3242656

5 files changed

Lines changed: 274 additions & 28 deletions

File tree

PWGJE/Core/JetUtilities.h

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,111 @@ std::tuple<std::vector<int>, std::vector<int>> MatchJetsGeometrically(
278278
return std::make_tuple(baseToTagMap, tagToBaseMap);
279279
}
280280

281+
/**
282+
* Match clusters and tracks.
283+
*
284+
* Match cluster with tracks, where maxNumberMatches are considered in dR=maxMatchingDistance.
285+
* If no unique match was found for a jet, an index of -1 is stored.
286+
* The same map is created for clusters matched to tracks e.g. for electron analyses.
287+
*
288+
* @param clusterPhi cluster collection phi.
289+
* @param clusterEta cluster collection eta.
290+
* @param trackPhi track collection phi.
291+
* @param trackEta track collection eta.
292+
* @param maxMatchingDistance Maximum matching distance.
293+
* @param maxNumberMatches Maximum number of matches (e.g. 5 closest).
294+
*
295+
* @returns (cluster to track index map, track to cluster index map)
296+
*/
297+
template <typename T>
298+
std::tuple<std::vector<std::vector<int>>, std::vector<std::vector<int>>> MatchClustersAndTracks(
299+
std::vector<T>& clusterPhi,
300+
std::vector<T>& clusterEta,
301+
std::vector<T>& trackPhi,
302+
std::vector<T>& trackEta,
303+
double maxMatchingDistance,
304+
int maxNumberMatches)
305+
{
306+
// test
307+
// Validation
308+
const std::size_t nClusters = clusterEta.size();
309+
const std::size_t nTracks = trackEta.size();
310+
if (!(nClusters && nTracks)) {
311+
// There are no jets, so nothing to be done.
312+
return std::make_tuple(std::vector<std::vector<int>>(nClusters, std::vector<int>(maxNumberMatches, -1)), std::vector<std::vector<int>>(nTracks, std::vector<int>(maxNumberMatches, -1)));
313+
}
314+
// Input sizes must match
315+
if (clusterPhi.size() != clusterEta.size()) {
316+
throw std::invalid_argument("cluster collection eta and phi sizes don't match. Check the inputs.");
317+
}
318+
if (trackPhi.size() != trackEta.size()) {
319+
throw std::invalid_argument("track collection eta and phi sizes don't match. Check the inputs.");
320+
}
321+
322+
// for (std::size_t iTrack = 0; iTrack < nTracks; iTrack++) {
323+
// if (trackEta[iTrack] == 0)
324+
// LOG(warning) << "Track eta is 0!";
325+
// }
326+
327+
// Build the KD-trees using vectors
328+
// We build two trees:
329+
// treeBase, which contains the base collection.
330+
// treeTag, which contains the tag collection.
331+
// The trees are built to match in two dimensions (eta, phi)
332+
TKDTree<int, T> treeCluster(clusterEta.size(), 2, 1), treeTrack(trackEta.size(), 2, 1);
333+
// By utilizing SetData, we can avoid having to copy the data again.
334+
treeCluster.SetData(0, clusterEta.data());
335+
treeCluster.SetData(1, clusterPhi.data());
336+
treeCluster.Build();
337+
treeTrack.SetData(0, trackEta.data());
338+
treeTrack.SetData(1, trackPhi.data());
339+
treeTrack.Build();
340+
341+
// Storage for the cluster matching indices.
342+
std::vector<std::vector<int>> matchIndexTrack(nClusters, std::vector<int>(maxNumberMatches, -1));
343+
std::vector<std::vector<int>> matchIndexCluster(nTracks, std::vector<int>(maxNumberMatches, -1));
344+
345+
// Find the track closest to each cluster.
346+
for (std::size_t iCluster = 0; iCluster < nClusters; iCluster++) {
347+
T point[2] = {clusterEta[iCluster], clusterPhi[iCluster]};
348+
int index[50]; // size 50 for safety
349+
T distance[50]; // size 50 for safery
350+
std::fill_n(index, 50, -1);
351+
std::fill_n(distance, 50, std::numeric_limits<T>::max());
352+
treeTrack.FindNearestNeighbors(point, maxNumberMatches, index, distance);
353+
// test whether indices are matching:
354+
matchIndexTrack[iCluster] = std::vector<int>(maxNumberMatches);
355+
for (int m = 0; m < maxNumberMatches; m++) {
356+
if (index[m] >= 0 && distance[m] < maxMatchingDistance) {
357+
matchIndexTrack[iCluster][m] = index[m];
358+
} else {
359+
// no match or no more matches found, fill -1
360+
matchIndexTrack[iCluster][m] = -1;
361+
}
362+
}
363+
}
364+
365+
// Find the base jet closest to each tag jet
366+
for (std::size_t iTrack = 0; iTrack < nTracks; iTrack++) {
367+
T point[2] = {trackEta[iTrack], trackPhi[iTrack]};
368+
int index[50]; // size 50 for safety
369+
T distance[50]; // size 50 for safery
370+
std::fill_n(index, 50, -1);
371+
std::fill_n(distance, 50, std::numeric_limits<T>::max());
372+
treeCluster.FindNearestNeighbors(point, maxNumberMatches, index, distance);
373+
matchIndexCluster[iTrack] = std::vector<int>(maxNumberMatches);
374+
// loop over maxNumberMatches closest matches
375+
for (int m = 0; m < maxNumberMatches; m++) {
376+
if (index[m] >= 0 && distance[m] < maxMatchingDistance) {
377+
matchIndexCluster[iTrack][m] = index[m];
378+
} else {
379+
// no match jet or no more matches found, fill -1
380+
matchIndexCluster[iTrack][m] = -1;
381+
}
382+
}
383+
}
384+
return std::make_tuple(matchIndexTrack, matchIndexCluster);
385+
}
281386
}; // namespace JetUtilities
282387

283388
#endif

PWGJE/DataModel/EMCALClusterDefinition.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,13 @@ struct EMCALClusterDefinition {
3939
double minCellEnergy = 0.05; // minimum cell energy (GeV)
4040
double timeMin = -10000; // minimum time (ns)
4141
double timeMax = 10000; // maximum time (ns)
42-
double gradientCut = 0.03; // gradient cut
42+
bool doGradientCut = true; // apply gradient cut if true
43+
double gradientCut = -1; // gradient cut
4344

4445
// default constructor
4546
EMCALClusterDefinition() = default;
4647
// constructor
47-
EMCALClusterDefinition(ClusterAlgorithm_t pAlgorithm, int pStorageID, int pSelectedCellType, std::string pName, double pSeedEnergy, double pMinCellEnergy, double pTimeMin, double pTimeMax, double pGradientCut)
48+
EMCALClusterDefinition(ClusterAlgorithm_t pAlgorithm, int pStorageID, int pSelectedCellType, std::string pName, double pSeedEnergy, double pMinCellEnergy, double pTimeMin, double pTimeMax, bool pDoGradientCut, double pGradientCut)
4849
{
4950
algorithm = pAlgorithm;
5051
storageID = pStorageID;
@@ -54,13 +55,14 @@ struct EMCALClusterDefinition {
5455
minCellEnergy = pMinCellEnergy;
5556
timeMin = pTimeMin;
5657
timeMax = pTimeMax;
58+
doGradientCut = pDoGradientCut;
5759
gradientCut = pGradientCut;
5860
}
5961

6062
// implement comparison operators for int std::string and ClusterAlgorithm_t
6163
bool operator==(const EMCALClusterDefinition& rhs) const
6264
{
63-
return (algorithm == rhs.algorithm && storageID == rhs.storageID && name == rhs.name && seedEnergy == rhs.seedEnergy && minCellEnergy == rhs.minCellEnergy && timeMin == rhs.timeMin && timeMax == rhs.timeMax && gradientCut == rhs.gradientCut);
65+
return (algorithm == rhs.algorithm && storageID == rhs.storageID && name == rhs.name && seedEnergy == rhs.seedEnergy && minCellEnergy == rhs.minCellEnergy && timeMin == rhs.timeMin && timeMax == rhs.timeMax && gradientCut == rhs.gradientCut && doGradientCut == rhs.doGradientCut);
6466
}
6567
bool operator!=(const EMCALClusterDefinition& rhs) const
6668
{

PWGJE/DataModel/EMCALClusters.h

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ namespace emcalcluster
2727
// define global cluster definitions
2828
// the V1 algorithm is not yet implemented, but the V3 algorithm is
2929
// New definitions should be added here!
30-
const EMCALClusterDefinition kV1Default(ClusterAlgorithm_t::kV1, 0, 1, "kV1Default", 0.5, 0.1, -10000, 10000, 0.03);
31-
const EMCALClusterDefinition kV1Variation1(ClusterAlgorithm_t::kV3, 1, 1, "kV1Variation1", 0.3, 0.1, -10000, 10000, 0.03);
32-
const EMCALClusterDefinition kV1Variation2(ClusterAlgorithm_t::kV3, 2, 1, "kV1Variation2", 0.2, 0.1, -10000, 10000, 0.03);
33-
const EMCALClusterDefinition kV3Default(ClusterAlgorithm_t::kV3, 10, 1, "kV3Default", 0.5, 0.1, -10000, 10000, 0.03);
34-
const EMCALClusterDefinition kV3Variation1(ClusterAlgorithm_t::kV3, 11, 1, "kV3Variation1", 0.3, 0.1, -10000, 10000, 0.03);
35-
const EMCALClusterDefinition kV3Variation2(ClusterAlgorithm_t::kV3, 12, 1, "kV3Variation2", 0.2, 0.1, -10000, 10000, 0.03);
30+
const EMCALClusterDefinition kV1Default(ClusterAlgorithm_t::kV1, 0, 1, "kV1Default", 0.5, 0.1, -10000, 10000, true, 0.03); //dummy
31+
const EMCALClusterDefinition kV1Variation1(ClusterAlgorithm_t::kV3, 1, 1, "kV1Variation1", 0.3, 0.1, -10000, 10000, true, 0.03); //dummy
32+
const EMCALClusterDefinition kV1Variation2(ClusterAlgorithm_t::kV3, 2, 1, "kV1Variation2", 0.2, 0.1, -10000, 10000, true, 0.03); //dummy
33+
const EMCALClusterDefinition kV3Default(ClusterAlgorithm_t::kV3, 10, 1, "kV3Default", 0.5, 0.1, -10000, 10000, true, 0.03);
34+
const EMCALClusterDefinition kV3Variation1(ClusterAlgorithm_t::kV3, 11, 1, "kV3Variation1", 0.5, 0.1, -10000, 10000, true, 0.);
35+
const EMCALClusterDefinition kV3Variation2(ClusterAlgorithm_t::kV3, 12, 1, "kV3Variation2", 0.5, 0.1, -10000, 10000, false, 0.);
3636

3737
/// \brief function returns EMCALClusterDefinition for the given name
3838
/// \param name name of the cluster definition
@@ -89,6 +89,27 @@ DECLARE_SOA_TABLE(EMCALAmbiguousClusters, "AOD", "EMCALAMBCLUS", //!
8989
using EMCALCluster = EMCALClusters::iterator;
9090
using EMCALAmbiguousCluster = EMCALAmbiguousClusters::iterator;
9191

92-
} // namespace o2::aod
92+
namespace emcalclustercell
93+
{
94+
// declare index column pointing to cluster table
95+
DECLARE_SOA_INDEX_COLUMN(EMCALCluster, emcalcluster); //! linked to EMCalClusters table
96+
DECLARE_SOA_INDEX_COLUMN(Calo, calo); //! linked to calo cells
9397

98+
// declare index column pointing to ambiguous cluster table
99+
DECLARE_SOA_INDEX_COLUMN(EMCALAmbiguousCluster, emcalambiguouscluster); //! linked to EMCalAmbiguousClusters table
100+
} // namespace emcalclustercell
101+
DECLARE_SOA_TABLE(EMCALClusterCells, "AOD", "EMCCLUSCELLS", //!
102+
o2::soa::Index<>, emcalclustercell::EMCALClusterId, emcalclustercell::CaloId); //!
103+
DECLARE_SOA_TABLE(EMCALAmbiguousClusterCells, "AOD", "EMCAMBBCLUSCLS", //!
104+
o2::soa::Index<>, emcalclustercell::EMCALAmbiguousClusterId, emcalclustercell::CaloId); //!
105+
using EMCALClusterCell = EMCALClusterCells::iterator;
106+
using EMCALAmbiguousClusterCell = EMCALAmbiguousClusterCells::iterator;
107+
namespace emcalmatchedtrack
108+
{
109+
DECLARE_SOA_INDEX_COLUMN(Track, track); //! linked to Track table only for tracks that were matched
110+
} // namespace emcalmatchedtrack
111+
DECLARE_SOA_TABLE(EMCALMatchedTracks, "AOD", "EMCMATCHTRACKS", //!
112+
o2::soa::Index<>, emcalclustercell::EMCALClusterId, emcalmatchedtrack::TrackId); //!
113+
using EMCALMatchedTrack = EMCALMatchedTracks::iterator;
114+
} // namespace o2::aod
94115
#endif

PWGJE/TableProducer/emcalCorrectionTask.cxx

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "EMCALBase/Geometry.h"
3333
#include "EMCALBase/ClusterFactory.h"
3434
#include "EMCALReconstruction/Clusterizer.h"
35+
#include "PWGJE/Core/JetUtilities.h"
3536
#include "TVector2.h"
3637

3738
using namespace o2;
@@ -41,11 +42,17 @@ using namespace o2::framework::expressions;
4142
struct EmcalCorrectionTask {
4243
Produces<o2::aod::EMCALClusters> clusters;
4344
Produces<o2::aod::EMCALAmbiguousClusters> clustersAmbiguous;
45+
Produces<o2::aod::EMCALClusterCells> clustercells; // cells belonging to given cluster
46+
Produces<o2::aod::EMCALAmbiguousClusterCells> clustercellsambiguous;
47+
Produces<o2::aod::EMCALMatchedTracks> matchedTracks;
4448

49+
Preslice<aod::Tracks> perCollision = aod::track::collisionId;
4550
// Options for the clusterization
4651
// 1 corresponds to EMCAL cells based on the Run2 definition.
4752
Configurable<int> selectedCellType{"selectedCellType", 1, "EMCAL Cell type"};
4853
Configurable<std::string> clusterDefinitions{"clusterDefinition", "kV3Default", "cluster definition to be selected, e.g. V3Default. Multiple definitions can be specified separated by comma"};
54+
Configurable<float> maxMatchingDistance{"maxMatchingDistance", 0.4f, "Max matching distance track-cluster"};
55+
4956
// CDB service (for geometry)
5057
Service<o2::ccdb::BasicCCDBManager> mCcdbManager;
5158

@@ -56,6 +63,8 @@ struct EmcalCorrectionTask {
5663
std::vector<std::unique_ptr<o2::emcal::ClusterFactory<o2::emcal::Cell>>> mClusterFactories;
5764
// Cells and clusters
5865
std::vector<o2::emcal::Cell> mEmcalCells;
66+
// map of cellId (local in BC) to global cell index in cell table in AO2D
67+
std::map<int, int64_t> mCellIdToCellGlobalIndex;
5968
std::vector<o2::emcal::AnalysisCluster> mAnalysisClusters;
6069

6170
std::vector<o2::aod::EMCALClusterDefinition> mClusterDefinitions;
@@ -100,14 +109,15 @@ struct EmcalCorrectionTask {
100109
}
101110
}
102111
for (auto& clusterDefinition : mClusterDefinitions) {
103-
mClusterizers.emplace_back(std::make_unique<o2::emcal::Clusterizer<o2::emcal::Cell>>(1, clusterDefinition.timeMin, clusterDefinition.timeMax, clusterDefinition.gradientCut, true, clusterDefinition.seedEnergy, clusterDefinition.minCellEnergy));
112+
mClusterizers.emplace_back(std::make_unique<o2::emcal::Clusterizer<o2::emcal::Cell>>(1E9, clusterDefinition.timeMin, clusterDefinition.timeMax, clusterDefinition.gradientCut, clusterDefinition.doGradientCut, clusterDefinition.seedEnergy, clusterDefinition.minCellEnergy));
104113
mClusterFactories.emplace_back(std::make_unique<o2::emcal::ClusterFactory<o2::emcal::Cell>>());
105114
LOG(info) << "Cluster definition initialized: " << clusterDefinition.toString();
106115
LOG(info) << "timeMin: " << clusterDefinition.timeMin;
107116
LOG(info) << "timeMax: " << clusterDefinition.timeMax;
108117
LOG(info) << "gradientCut: " << clusterDefinition.gradientCut;
109118
LOG(info) << "seedEnergy: " << clusterDefinition.seedEnergy;
110119
LOG(info) << "minCellEnergy: " << clusterDefinition.minCellEnergy;
120+
LOG(info) << "storageID" << clusterDefinition.storageID;
111121
}
112122
for (auto& clusterizer : mClusterizers) {
113123
clusterizer->setGeometry(geometry);
@@ -134,15 +144,17 @@ struct EmcalCorrectionTask {
134144
// void process(aod::BCs const& bcs, aod::Collision const& collision, aod::Calos const& cells)
135145

136146
// Appears to need the BC to be accessed to be available in the collision table...
137-
void process(aod::BC const& bc, aod::Collisions const& collisions, aod::Calos const& cells)
147+
void process(aod::BC const& bc, aod::Collisions const& collisions, aod::Tracks const& tracks, aod::Calos const& cells)
138148
{
139149
LOG(debug) << "Starting process.";
140150
// Convert aod::Calo to o2::emcal::Cell which can be used with the clusterizer.
141151
// In particular, we need to filter only EMCAL cells.
142152
mEmcalCells.clear();
153+
mCellIdToCellGlobalIndex.clear();
154+
int c = 0;
143155
for (auto& cell : cells) {
144156
if (cell.caloType() != selectedCellType) {
145-
// LOG(debug) << "Rejected";
157+
LOG(debug) << "Rejected";
146158
continue;
147159
}
148160
// LOG(debug) << "Cell E: " << cell.getEnergy();
@@ -152,7 +164,11 @@ struct EmcalCorrectionTask {
152164
cell.amplitude(),
153165
cell.time(),
154166
o2::emcal::intToChannelType(cell.cellType())));
167+
mCellIdToCellGlobalIndex.insert(std::make_pair(c, cell.globalIndex()));
168+
LOG(debug) << "Creating map " << c << " -> " << cell.globalIndex();
169+
c++;
155170
}
171+
LOG(debug) << "Number of cells (CF): " << mEmcalCells.size();
156172

157173
// Cell QA
158174
// For convenience, use the clusterizer stored geometry to get the eta-phi
@@ -197,6 +213,7 @@ struct EmcalCorrectionTask {
197213
for (int icl = 0; icl < mClusterFactories.at(i)->getNumberOfClusters(); icl++) {
198214
auto analysisCluster = mClusterFactories.at(i)->buildCluster(icl);
199215
mAnalysisClusters.emplace_back(analysisCluster);
216+
LOG(debug) << "Cluster " << icl << ": E: " << analysisCluster.E() << ", NCells " << analysisCluster.getNCells();
200217
}
201218
LOG(debug) << "Converted to analysis clusters.";
202219

@@ -212,8 +229,40 @@ struct EmcalCorrectionTask {
212229
vz = col.posZ();
213230
hasCollision = true;
214231

232+
// store positions of all tracks of collision
233+
auto groupedTracks = tracks.sliceBy(perCollision, col.globalIndex());
234+
235+
std::vector<double> trackPhi;
236+
std::vector<double> trackEta;
237+
std::vector<int64_t> trackGlobalIndex;
238+
for (auto& track : groupedTracks) {
239+
// TODO this actually needs to use the eta phi
240+
// of track propagated to EMC surface! Will be provided centrally according to Ruben
241+
// TODO only consider tracks in current emcal/dcal acceptanc
242+
trackPhi.emplace_back(TVector2::Phi_0_2pi(track.phi()));
243+
trackEta.emplace_back(track.eta());
244+
trackGlobalIndex.emplace_back(track.globalIndex());
245+
}
246+
247+
std::vector<double> clusterPhi;
248+
std::vector<double> clusterEta;
249+
250+
// TODO one loop that could in principle be combined with the other loop to improve performance
251+
for (const auto& cluster : mAnalysisClusters) {
252+
// Determine the cluster eta, phi, correcting for the vertex position.
253+
auto pos = cluster.getGlobalPosition();
254+
pos = pos - math_utils::Point3D<float>{vx, vy, vz};
255+
// Normalize the vector and rescale by energy.
256+
pos *= (cluster.E() / std::sqrt(pos.Mag2()));
257+
clusterPhi.emplace_back(TVector2::Phi_0_2pi(pos.Phi()));
258+
clusterEta.emplace_back(pos.Eta());
259+
}
260+
auto&& [clusterToTrackIndexMap, trackToClusterIndexMap] = JetUtilities::MatchClustersAndTracks(clusterPhi, clusterEta, trackPhi, trackEta, maxMatchingDistance, 5);
215261
// we found a collision, put the clusters into the none ambiguous table
216262
clusters.reserve(mAnalysisClusters.size());
263+
int cellindex = -1;
264+
265+
unsigned int k = 0;
217266
for (const auto& cluster : mAnalysisClusters) {
218267

219268
// Determine the cluster eta, phi, correcting for the vertex position.
@@ -228,9 +277,23 @@ struct EmcalCorrectionTask {
228277
cluster.getM02(), cluster.getM20(), cluster.getNCells(), cluster.getClusterTime(),
229278
cluster.getIsExotic(), cluster.getDistanceToBadChannel(), cluster.getNExMax(), static_cast<int>(mClusterDefinitions.at(i)));
230279

280+
clustercells.reserve(cluster.getNCells());
281+
// loop over cells in cluster and save to table
282+
for (int ncell = 0; ncell < cluster.getNCells(); ncell++) {
283+
cellindex = cluster.getCellIndex(ncell);
284+
LOG(debug) << "trying to find cell index " << cellindex << " in map";
285+
clustercells(clusters.lastIndex(), mCellIdToCellGlobalIndex.at(cellindex));
286+
}
231287
// fill histograms
232288
hClusterE->Fill(cluster.E());
233289
hClusterEtaPhi->Fill(pos.Eta(), TVector2::Phi_0_2pi(pos.Phi()));
290+
for (unsigned int iTrack = 0; iTrack < clusterToTrackIndexMap[k].size(); iTrack++) {
291+
if (clusterToTrackIndexMap[k][iTrack] >= 0) {
292+
LOG(debug) << "Found track " << trackGlobalIndex[clusterToTrackIndexMap[k][iTrack]] << " in cluster " << cluster.getID();
293+
matchedTracks(clusters.lastIndex(), trackGlobalIndex[clusterToTrackIndexMap[k][iTrack]]);
294+
}
295+
}
296+
k++;
234297
} // end of cluster loop
235298
} // end of collision loop
236299
}
@@ -241,6 +304,7 @@ struct EmcalCorrectionTask {
241304
// Store the clusters in the table where a mathcing collision could
242305
// be identified.
243306
if (!hasCollision) { // ambiguous
307+
int cellindex = -1;
244308
clustersAmbiguous.reserve(mAnalysisClusters.size());
245309
for (const auto& cluster : mAnalysisClusters) {
246310
auto pos = cluster.getGlobalPosition();
@@ -254,6 +318,11 @@ struct EmcalCorrectionTask {
254318
clustersAmbiguous(bc, cluster.getID(), cluster.E(), cluster.getCoreEnergy(), pos.Eta(), TVector2::Phi_0_2pi(pos.Phi()),
255319
cluster.getM02(), cluster.getM20(), cluster.getNCells(), cluster.getClusterTime(),
256320
cluster.getIsExotic(), cluster.getDistanceToBadChannel(), cluster.getNExMax(), static_cast<int>(mClusterDefinitions.at(i)));
321+
clustercellsambiguous.reserve(cluster.getNCells());
322+
for (int ncell = 0; ncell < cluster.getNCells(); ncell++) {
323+
cellindex = cluster.getCellIndex(ncell);
324+
clustercellsambiguous(clustersAmbiguous.lastIndex(), mCellIdToCellGlobalIndex.at(cellindex));
325+
}
257326
}
258327
}
259328
LOG(debug) << "Cluster loop done for clusterizer " << i;

0 commit comments

Comments
 (0)