ATLAS Offline Software
Loading...
Searching...
No Matches
Clustering.h
Go to the documentation of this file.
1
14
15#ifndef CLUSTERINGHELPER_H
16#define CLUSTERINGHELPER_H
17
18
19#include <algorithm>
20#include <iostream>
21#include <cmath>
22#include <memory>
23#include <stdexcept>
24#include <utility>
25#include <vector>
26#include <ranges>
27
28namespace HGTD {
29
30template <typename T> class Cluster {
31
32public:
33 Cluster();
34
35 Cluster(const std::vector<double> &v, const std::vector<double> &v_sigma);
36
37 Cluster(const std::vector<double> &v, const std::vector<double> &v_sigma,
38 const T &entry);
39
46 void addEntry(const T &entry);
47
56 void addEntryVector(const std::vector<T> &entry_vector);
57
61 const std::vector<T>& getEntries() const;
62
72 void setClusterValue(const std::vector<double> &v,
73 const std::vector<double> &v_sigma);
74
78 std::vector<double> getValues() const;
79
83 const std::vector<double>& getSigmas() const;
84
88 int getNEntries() const;
89
93 bool mergeStatus() const;
94
95 void setMergeStatus(bool status);
96
97 int getMergeIteration() const;
98
99 void setMergeIteration(int iteration);
100
101 bool containsUnknowns() const;
102
103 void setUnknownStatus(bool status);
104
105private:
106 int m_debug_level = 0; // TODO set this dynamically
107 std::vector<T> m_entries { }; // Stores raw objects that are part of this Cluster
110 std::vector<double> m_combined_value_vector { };
111 std::vector<double> m_combined_sigma_vector { };
112 bool m_was_merged = false;
115};
116
118
120
122
123template <typename T> class ClusterCollection {
124public:
125 void addCluster(const Cluster<T> & vx);
126 void doClustering(ClusterAlgo algo);
127
128private:
129 double getDistanceBetweenClusters(const Cluster<T> &a, const Cluster<T> &b);
130
139
141
142 std::pair<Cluster<T>, int> largestClusterInfo();
143
144public:
147 const std::vector<Cluster<T>>& getClusters() const;
148 int getNClusters() const;
156 void updateDistanceCut(double cut_value);
157 void setDebugLevel(int debug_level) { m_debug_level = debug_level; }
158
159private:
161 double m_distance_cut = 3.0;
162 std::vector<Cluster<T>> m_clusters;
163};
164
170
171template <class T>
174
175template <typename T>
177 const std::vector<double> &v, const std::vector<double> &v_sigma)
179 m_contains_unknowns(std::ranges::any_of(v_sigma, [](double s){return s < 0;})){
180 //
181}
182
183template <typename T>
185 const std::vector<double> &v, const std::vector<double> &v_sigma, const T &entry)
187 m_contains_unknowns(std::ranges::any_of(v_sigma, [](double s){return s < 0;})){
188 //
189}
190
191template <class T> int Cluster<T>::getNEntries() const {
192 return m_entries.size();
193}
194
195template <class T> void Cluster<T>::addEntry(const T &entry) {
196 m_entries.push_back(entry);
197}
198
199template <class T> const std::vector<T>& Cluster<T>::getEntries() const {
200 return m_entries;
201}
202
203template <class T>
204void Cluster<T>::addEntryVector(const std::vector<T> &entry_vector) {
205 if (not entry_vector.empty()) {
206 m_entries.insert(m_entries.end(), entry_vector.begin(), entry_vector.end());
207 }
208}
209
210template <class T>
211void Cluster<T>::setClusterValue(const std::vector<double> &v,
212 const std::vector<double> &v_sigma) {
214 m_combined_sigma_vector = v_sigma;
215}
216
217template <class T> std::vector<double> Cluster<T>::getValues() const {
218 // return a warning when this value is a default value
219 if (m_combined_value_vector.size() == 0) {
220 if (m_debug_level > 0) {
221 std::cout
222 << "Cluster::getTime: ATTENTION, combi values are not initialized!"
223 << std::endl;
224 }
225 }
227}
228
229template <class T> const std::vector<double>& Cluster<T>::getSigmas() const {
231}
232
233template <class T> void Cluster<T>::setMergeStatus(bool status) {
234 m_was_merged = status;
235}
236
237template <class T> bool Cluster<T>::mergeStatus() const { return m_was_merged; }
238
239template <class T> int Cluster<T>::getMergeIteration() const {
240 return m_merge_iteration;
241}
242
243template <class T> void Cluster<T>::setMergeIteration(int iteration) {
244 m_merge_iteration = iteration;
245}
246
247template <class T> bool Cluster<T>::containsUnknowns() const {
248 return m_contains_unknowns;
249}
250
251template <class T> void Cluster<T>::setUnknownStatus(bool status) {
252 m_contains_unknowns = status;
253}
254
257
258template <class T>
260 m_distance_cut = cut_value;
261}
262
263template <typename T> void ClusterCollection<T>::addCluster(const Cluster<T> & vx) {
264 m_clusters.push_back(vx);
265}
266
267template <typename T>
269 const Cluster<T> &b) {
270 std::vector<double> a_values = a.getValues();
271 std::vector<double> b_values = b.getValues();
272 std::vector<double> a_sigmas = a.getSigmas();
273 std::vector<double> b_sigmas = b.getSigmas();
274
275 std::vector<double> distances(a_values.size());
276 for (size_t i = 0; i < a_values.size(); i++) {
277 double distance_i = 0;
278 if (a_sigmas.at(i) >= 0.0 && b_sigmas.at(i) >= 0.0) {
279 distance_i = std::abs(a_values.at(i) - b_values.at(i)) /
280 std::hypot(a_sigmas.at(i), b_sigmas.at(i));
281 }
282 distances.at(i) = distance_i;
283 }
284 double distance2 = 0.;
285 for (double d : distances) {
286 distance2 += d * d;
287 }
288 return std::sqrt(distance2);
289}
290
291template <class T>
293 const Cluster<T> &b) {
294 Cluster<T> merged_cluster;
295 merged_cluster.addEntryVector(a.getEntries());
296 merged_cluster.addEntryVector(b.getEntries());
297
298 std::vector<double> a_values = a.getValues();
299 std::vector<double> b_values = b.getValues();
300 std::vector<double> a_sigmas = a.getSigmas();
301 std::vector<double> b_sigmas = b.getSigmas();
302
303 std::vector<double> new_cluster_values(a_values.size());
304 std::vector<double> new_cluster_sigmas(a_values.size());
305
306 for (size_t i = 0; i < a_values.size(); i++) {
307 double value1 = a_values.at(i);
308 double value2 = b_values.at(i);
309 double var1 = std::pow(a_sigmas.at(i), 2.0);
310 double var2 = std::pow(b_sigmas.at(i), 2.0);
311 double new_cluster_value =
312 (value1 / var1 + value2 / var2) / (1.0 / var1 + 1.0 / var2);
313 double new_cluster_sigma = std::sqrt(var1 * var2 / (var1 + var2));
314 new_cluster_values.at(i) = new_cluster_value;
315 new_cluster_sigmas.at(i) = new_cluster_sigma;
316 }
317 int new_merge_iteration = a.getMergeIteration() + b.getMergeIteration() + 1;
318 merged_cluster.setClusterValue(new_cluster_values, new_cluster_sigmas);
319 merged_cluster.setMergeStatus(true);
320 merged_cluster.setMergeIteration(new_merge_iteration);
321 return merged_cluster;
322}
323
324template <class T>
326 const Cluster<T> &b) {
327 Cluster<T> merged_cluster;
328 merged_cluster.addEntryVector(a.getEntries());
329 merged_cluster.addEntryVector(b.getEntries());
330
331 std::vector<double> a_values = a.getValues();
332 std::vector<double> b_values = b.getValues();
333 std::vector<double> a_sigmas = a.getSigmas();
334 std::vector<double> b_sigmas = b.getSigmas();
335
336 std::vector<double> new_cluster_values(a_values.size());
337 std::vector<double> new_cluster_sigmas(a_values.size());
338
339 for (size_t i = 0; i < a_values.size(); i++) {
340 double value1 = a_values.at(i);
341 double value2 = b_values.at(i);
342 double sigma1 = a_sigmas.at(i);
343 double sigma2 = b_sigmas.at(i);
344 double new_cluster_value = (value1 + value2) / 2.;
345 double new_cluster_sigma = std::hypot(sigma1, sigma2);
346 new_cluster_values.at(i) = new_cluster_value;
347 new_cluster_sigmas.at(i) = new_cluster_sigma;
348 }
349 int new_merge_iteration = a.getMergeIteration() + b.getMergeIteration() + 1;
350 merged_cluster.setClusterValue(new_cluster_values, new_cluster_sigmas);
351 merged_cluster.setMergeStatus(true);
352 merged_cluster.setMergeIteration(new_merge_iteration);
353 return merged_cluster;
354}
355
356template <typename T>
358 if (algo == ClusterAlgo::Eager) {
359 for (const auto &clust : m_clusters) {
360 if (clust.containsUnknowns()) {
361 throw std::invalid_argument(
362 "[ClusterCollection::doClustering] ERROR "
363 "- eager clustering does not allow for unknown values");
364 }
365 }
366 }
367
368 // TODO case where I have 2 vertices in my collection
369 if (m_debug_level > 0) {
370 std::cout << "ClusterCollection::doTimeClustering" << std::endl;
371 }
372 double distance = 1.e30; // initial distance value, "far away"
373
374 while (m_clusters.size() > 1) {
375 int i0 = 0;
376 int j0 = 0;
377 if (m_debug_level > 0) {
378 std::cout << "using " << m_clusters.size() << " vertices" << std::endl;
379 }
380 // find the two vertices that are closest to each other
381 distance = getDistanceBetweenClusters(m_clusters.at(0), m_clusters.at(1));
382 for (size_t i = 0; i < m_clusters.size(); i++) {
383 for (size_t j = i + 1; j < m_clusters.size(); j++) {
384
385 if (algo == ClusterAlgo::Simultaneous ||
387
388 if (m_clusters.at(i).mergeStatus() or m_clusters.at(j).mergeStatus()) {
389 continue;
390 }
391 }
392
393 double current_distance =
395 if (current_distance <= distance) {
396 distance = current_distance;
397 i0 = i;
398 j0 = j;
399 }
400 } // loop over j
401 } // loop over i
402 if (m_debug_level > 0) {
403 std::cout << "using vertex " << i0 << " and " << j0 << std::endl;
404 }
405 // now the closest two vertices are found and will be fused if cut passes
406 if (distance < m_distance_cut && i0 != j0) {
407
408 Cluster<T> new_cluster { };
409
410 if (algo == ClusterAlgo::SimultaneousMean) {
411 new_cluster = mergeClustersMean(m_clusters.at(i0), m_clusters.at(j0));
412 } else {
413 new_cluster = mergeClusters(m_clusters.at(i0), m_clusters.at(j0));
414 }
415
416 if (m_debug_level > 0) {
417 std::cout << "starting to erase" << std::endl;
418 }
419 m_clusters.erase(m_clusters.begin() + j0);
420 if (i0 < j0) {
421 m_clusters.erase(m_clusters.begin() + i0);
422 } else {
423 m_clusters.erase(m_clusters.begin() + (i0 - 1));
424 }
425 if (m_debug_level > 0) {
426 std::cout << "erase done" << std::endl;
427 }
428 m_clusters.push_back(std::move(new_cluster));
429 if (m_debug_level > 0) {
430 std::cout << "new cluster stored" << std::endl;
431 }
432 } else {
433 if (algo == ClusterAlgo::Eager) {
434 break;
435 }
436 // if there is a cluster that was merged
437 if (std::find_if(m_clusters.begin(), m_clusters.end(),
438 [](const Cluster<T> &c) { return c.mergeStatus(); }) !=
439 m_clusters.end()) {
440 // reset each status to false
441 std::for_each(m_clusters.begin(), m_clusters.end(), [](Cluster<T> &c) {
442 c.setMergeStatus(false);
443 });
444 } else {
445 // if not, this is the end of the clustering
446 break;
447 }
448 }
449 } // while loop
450}
451
452template <typename T>
453std::pair<Cluster<T>, int> ClusterCollection<T>::largestClusterInfo() {
454
455 int max_n_hits = 0;
456 int count = 0;
457 Cluster<T> max_n_vertex { };
458
459 for (const auto& vx : m_clusters) {
460 int current_n = vx.getNEntries();
461
462 if (current_n > max_n_hits) {
463 max_n_hits = current_n;
464 max_n_vertex = vx;
465 count = 1;
466 }
467 else if (current_n == max_n_hits) {
468 count++;
469 }
470 }
471
472 return std::make_pair(max_n_vertex, count);
473}
474
476
477 const auto [max_cluster, nMaxClusters] = largestClusterInfo();
478 // If two or more clusters have the same maximum number of entries, I can't
479 // decide, so return default
480 if (nMaxClusters > 1) {
481 return Cluster<T> { };
482 }
483 return max_cluster;
484}
485
487 // find the vertex with a maximum amount of hits clustered in it
488 // and return thisn umber
489 const auto [max_cluster, nMaxClusters] = largestClusterInfo();
490
491 return max_cluster.getNEntries();
492}
493
494template <typename T>
495const std::vector<Cluster<T>>& ClusterCollection<T>::getClusters() const {
496 return m_clusters;
497}
498
499template <typename T> int ClusterCollection<T>::getNClusters() const {
500 return static_cast<int>(m_clusters.size());
501}
502
503} // namespace HGTD
504
505#endif // CLUSTERINGHELPER_H
static Double_t a
Cluster< T > mergeClustersMean(const Cluster< T > &a, const Cluster< T > &b)
Definition Clustering.h:325
double getDistanceBetweenClusters(const Cluster< T > &a, const Cluster< T > &b)
Definition Clustering.h:268
std::vector< Cluster< T > > m_clusters
Definition Clustering.h:162
std::pair< Cluster< T >, int > largestClusterInfo()
Definition Clustering.h:453
void setDebugLevel(int debug_level)
Definition Clustering.h:157
Cluster< T > getMaxEntriesCluster()
Definition Clustering.h:475
void doClustering(ClusterAlgo algo)
Definition Clustering.h:357
void updateDistanceCut(double cut_value)
Set the distance cut.
Definition Clustering.h:259
Cluster< T > mergeClusters(const Cluster< T > &a, const Cluster< T > &b)
Creates a new Cluster object that is a fusion of the two clusters given in the arguments.
Definition Clustering.h:292
void addCluster(const Cluster< T > &vx)
Definition Clustering.h:263
const std::vector< Cluster< T > > & getClusters() const
Definition Clustering.h:495
std::vector< T > m_entries
Definition Clustering.h:107
int getNEntries() const
Return the number of objects stored in the Cluster.
Definition Clustering.h:191
void setClusterValue(const std::vector< double > &v, const std::vector< double > &v_sigma)
The value of a vertex has to be set manually.
Definition Clustering.h:211
void setMergeStatus(bool status)
Definition Clustering.h:233
std::vector< double > m_combined_sigma_vector
Definition Clustering.h:111
bool containsUnknowns() const
Definition Clustering.h:247
bool mergeStatus() const
Return true if the Cluster is the result of a merge.
Definition Clustering.h:237
void setUnknownStatus(bool status)
Definition Clustering.h:251
void setMergeIteration(int iteration)
Definition Clustering.h:243
std::vector< double > getValues() const
Return the N-dimensional value of the Cluster.
Definition Clustering.h:217
int getMergeIteration() const
Definition Clustering.h:239
int m_merge_iteration
Definition Clustering.h:113
const std::vector< double > & getSigmas() const
Return the N-dimensional resolution of the Cluster.
Definition Clustering.h:229
double m_combined_value
Definition Clustering.h:108
const std::vector< T > & getEntries() const
Return the objects that are part of the Cluster.
Definition Clustering.h:199
void addEntry(const T &entry)
Add an object of type T to the Cluster.
Definition Clustering.h:195
double m_combined_sigma
Definition Clustering.h:109
std::vector< double > m_combined_value_vector
Definition Clustering.h:110
bool m_contains_unknowns
Definition Clustering.h:114
void addEntryVector(const std::vector< T > &entry_vector)
This can be used to combine the subsets stored in two vertices all in once while merging.
Definition Clustering.h:204
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:148
Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration.
ClusterAlgo
Definition Clustering.h:119
STL namespace.