File indexing completed on 2025-10-21 08:07:33
0001
0002
0003
0004 #include <DD4hep/Detector.h>
0005 #include <DD4hep/IDDescriptor.h>
0006 #include <DD4hep/Readout.h>
0007 #include <Evaluator/DD4hepUnits.h>
0008 #include <algorithms/geo.h>
0009 #include <catch2/catch_test_macros.hpp>
0010 #include <catch2/generators/catch_generators.hpp>
0011 #include <catch2/matchers/catch_matchers.hpp>
0012 #include <catch2/matchers/catch_matchers_floating_point.hpp>
0013 #include <edm4eic/CalorimeterHitCollection.h>
0014 #include <edm4eic/ProtoClusterCollection.h>
0015 #include <edm4hep/Vector3f.h>
0016 #include <podio/RelationRange.h>
0017 #include <spdlog/common.h>
0018 #include <spdlog/logger.h>
0019 #include <spdlog/spdlog.h>
0020 #include <gsl/pointers>
0021 #include <limits>
0022 #include <memory>
0023 #include <string>
0024 #include <utility>
0025 #include <variant>
0026 #include <vector>
0027
0028 #include "algorithms/calorimetry/CalorimeterIslandCluster.h"
0029 #include "algorithms/calorimetry/CalorimeterIslandClusterConfig.h"
0030
0031 using eicrecon::CalorimeterIslandCluster;
0032 using eicrecon::CalorimeterIslandClusterConfig;
0033
0034 TEST_CASE("the clustering algorithm runs", "[CalorimeterIslandCluster]") {
0035 CalorimeterIslandCluster algo("CalorimeterIslandCluster");
0036
0037 std::shared_ptr<spdlog::logger> logger =
0038 spdlog::default_logger()->clone("CalorimeterIslandCluster");
0039 logger->set_level(spdlog::level::trace);
0040
0041 CalorimeterIslandClusterConfig cfg;
0042 cfg.minClusterHitEdep = 0. * dd4hep::GeV;
0043 cfg.minClusterCenterEdep = 0. * dd4hep::GeV;
0044
0045 auto detector = algorithms::GeoSvc::instance().detector();
0046 auto id_desc = detector->readout("MockCalorimeterHits").idSpec();
0047
0048 SECTION("without splitting") {
0049 bool use_adjacencyMatrix = GENERATE(false, true);
0050 cfg.splitCluster = false;
0051 if (use_adjacencyMatrix) {
0052 cfg.adjacencyMatrix = "abs(x_1 - x_2) + abs(y_1 - y_2) == 1";
0053 cfg.readout = "MockCalorimeterHits";
0054 } else {
0055 cfg.localDistXY = {1 * dd4hep::mm, 1 * dd4hep::mm};
0056 }
0057 algo.applyConfig(cfg);
0058 algo.init();
0059
0060 SECTION("on a single cell") {
0061 edm4eic::CalorimeterHitCollection hits_coll;
0062 hits_coll.create(
0063 id_desc.encode({{"system", 255}, {"x", 0}, {"y", 0}}),
0064 5.0,
0065 0.0,
0066 0.0,
0067 0.0,
0068 edm4hep::Vector3f(0.0, 0.0, 0.0),
0069 edm4hep::Vector3f(0.0, 0.0, 0.0),
0070 0,
0071 0,
0072 edm4hep::Vector3f(0.0, 0.0, 0.0)
0073 );
0074 auto protoclust_coll = std::make_unique<edm4eic::ProtoClusterCollection>();
0075 algo.process({&hits_coll}, {protoclust_coll.get()});
0076
0077 REQUIRE((*protoclust_coll).size() == 1);
0078 REQUIRE((*protoclust_coll)[0].hits_size() == 1);
0079 REQUIRE((*protoclust_coll)[0].weights_size() == 1);
0080 }
0081
0082 SECTION("on two separated cells") {
0083 edm4eic::CalorimeterHitCollection hits_coll;
0084 hits_coll.create(0,
0085 5.0,
0086 0.0,
0087 0.0,
0088 0.0,
0089 edm4hep::Vector3f(0.0, 0.0, 0.0),
0090 edm4hep::Vector3f(1.0, 1.0, 0.0),
0091 0,
0092 0,
0093 edm4hep::Vector3f(0.0, 0.0, 0.0)
0094 );
0095 hits_coll.create(1,
0096 6.0,
0097 0.0,
0098 0.0,
0099 0.0,
0100 edm4hep::Vector3f(0.0, 0.0, 0.0),
0101 edm4hep::Vector3f(1.0, 1.0, 0.0),
0102 0,
0103 0,
0104 edm4hep::Vector3f(1.1 , 1.1 , 0.0)
0105 );
0106 auto protoclust_coll = std::make_unique<edm4eic::ProtoClusterCollection>();
0107 algo.process({&hits_coll}, {protoclust_coll.get()});
0108
0109 REQUIRE((*protoclust_coll).size() == 2);
0110 REQUIRE((*protoclust_coll)[0].hits_size() == 1);
0111 REQUIRE((*protoclust_coll)[0].weights_size() == 1);
0112 REQUIRE((*protoclust_coll)[1].hits_size() == 1);
0113 REQUIRE((*protoclust_coll)[1].weights_size() == 1);
0114 }
0115
0116 SECTION("on two adjacent cells") {
0117 edm4eic::CalorimeterHitCollection hits_coll;
0118 hits_coll.create(
0119 id_desc.encode({{"system", 255}, {"x", 0}, {"y", 0}}),
0120 5.0,
0121 0.0,
0122 0.0,
0123 0.0,
0124 edm4hep::Vector3f(0.0, 0.0, 0.0),
0125 edm4hep::Vector3f(1.0, 1.0, 0.0),
0126 0,
0127 0,
0128 edm4hep::Vector3f(0.0, 0.0, 0.0)
0129 );
0130 hits_coll.create(
0131 id_desc.encode({{"system", 255}, {"x", 1}, {"y", 0}}),
0132 6.0,
0133 0.0,
0134 0.0,
0135 0.0,
0136 edm4hep::Vector3f(0.0, 0.0, 0.0),
0137 edm4hep::Vector3f(1.0, 1.0, 0.0),
0138 0,
0139 0,
0140 edm4hep::Vector3f(0.9 , 0.9 , 0.0)
0141 );
0142 auto protoclust_coll = std::make_unique<edm4eic::ProtoClusterCollection>();
0143 algo.process({&hits_coll}, {protoclust_coll.get()});
0144
0145 REQUIRE((*protoclust_coll).size() == 1);
0146 REQUIRE((*protoclust_coll)[0].hits_size() == 2);
0147 REQUIRE((*protoclust_coll)[0].weights_size() == 2);
0148 }
0149 }
0150
0151 SECTION("run on three adjacent cells") {
0152 bool use_adjacencyMatrix = GENERATE(false, true);
0153 if (use_adjacencyMatrix) {
0154 cfg.adjacencyMatrix = "abs(x_1 - x_2) + abs(y_1 - y_2) == 1";
0155 } else {
0156 cfg.localDistXY = {1 * dd4hep::mm, 1 * dd4hep::mm};
0157 }
0158 bool disalow_diagonal_peaks = GENERATE(false, true);
0159 if (disalow_diagonal_peaks) {
0160 cfg.peakNeighbourhoodMatrix = "max(abs(x_1 - x_2), abs(y_1 - y_2)) == 1";
0161 } else {
0162 cfg.peakNeighbourhoodMatrix = "abs(x_1 - x_2) + abs(y_1 - y_2) == 1";
0163 }
0164 cfg.readout = "MockCalorimeterHits";
0165
0166 cfg.splitCluster = GENERATE(false, true);
0167 if (cfg.splitCluster) {
0168 cfg.transverseEnergyProfileMetric = "localDistXY";
0169 cfg.transverseEnergyProfileScale =
0170 std::numeric_limits<decltype(cfg.transverseEnergyProfileScale)>::infinity();
0171 }
0172 cfg.localDistXY = {1 * dd4hep::mm, 1 * dd4hep::mm};
0173 algo.applyConfig(cfg);
0174 algo.init();
0175
0176 edm4eic::CalorimeterHitCollection hits_coll;
0177 hits_coll.create(id_desc.encode({{"system", 255}, {"x", 0}, {"y", 0}}),
0178 5.0,
0179 0.0,
0180 0.0,
0181 0.0,
0182 edm4hep::Vector3f(0.0, 0.0, 0.0),
0183 edm4hep::Vector3f(1.0, 1.0, 0.0),
0184 0,
0185 0,
0186 edm4hep::Vector3f(0.0, 0.0, 0.0)
0187 );
0188 hits_coll.create(id_desc.encode({{"system", 255}, {"x", 1}, {"y", 0}}),
0189 1.0,
0190 0.0,
0191 0.0,
0192 0.0,
0193 edm4hep::Vector3f(0.0, 0.0, 0.0),
0194 edm4hep::Vector3f(1.0, 1.0, 0.0),
0195 0,
0196 0,
0197 edm4hep::Vector3f(0.9 , 0.9 , 0.0)
0198 );
0199
0200 bool test_diagonal_cluster = GENERATE(false, true);
0201
0202
0203
0204
0205
0206
0207
0208 hits_coll.create(
0209 id_desc.encode({{"system", 255},
0210 {"x", test_diagonal_cluster ? 1 : 2},
0211 {"y", test_diagonal_cluster ? 1 : 0}}),
0212 6.0,
0213 0.0,
0214 0.0,
0215 0.0,
0216 edm4hep::Vector3f(0.0, 0.0, 0.0),
0217 edm4hep::Vector3f(1.0, 1.0, 0.0),
0218 0,
0219 0,
0220 edm4hep::Vector3f(1.8 , 1.8 , 0.0)
0221 );
0222 auto protoclust_coll = std::make_unique<edm4eic::ProtoClusterCollection>();
0223 algo.process({&hits_coll}, {protoclust_coll.get()});
0224
0225 bool expect_two_peaks = cfg.splitCluster;
0226 if (cfg.splitCluster && disalow_diagonal_peaks) {
0227 expect_two_peaks = not test_diagonal_cluster;
0228 }
0229 if (expect_two_peaks) {
0230 REQUIRE((*protoclust_coll).size() == 2);
0231 REQUIRE((*protoclust_coll)[0].hits_size() == 3);
0232 REQUIRE((*protoclust_coll)[0].weights_size() == 3);
0233 for (double weight : (*protoclust_coll)[0].getWeights()) {
0234 double energy_fraction =
0235 hits_coll[0].getEnergy() / (hits_coll[0].getEnergy() + hits_coll[2].getEnergy());
0236 REQUIRE_THAT(weight, Catch::Matchers::WithinAbs(energy_fraction, 1e-5));
0237 }
0238 REQUIRE((*protoclust_coll)[1].hits_size() == 3);
0239 REQUIRE((*protoclust_coll)[1].weights_size() == 3);
0240 for (double weight : (*protoclust_coll)[1].getWeights()) {
0241 double energy_fraction =
0242 hits_coll[2].getEnergy() / (hits_coll[0].getEnergy() + hits_coll[2].getEnergy());
0243 REQUIRE_THAT(weight, Catch::Matchers::WithinAbs(energy_fraction, 1e-5));
0244 }
0245 } else {
0246 REQUIRE((*protoclust_coll).size() == 1);
0247 REQUIRE((*protoclust_coll)[0].hits_size() == 3);
0248 REQUIRE((*protoclust_coll)[0].weights_size() == 3);
0249 }
0250 }
0251 }