File indexing completed on 2026-08-09 08:25:44
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 <edm4eic/CalorimeterHitCollection.h>
0011 #include <edm4eic/ProtoClusterCollection.h>
0012 #include <edm4hep/Vector3f.h>
0013 #include <spdlog/common.h>
0014 #include <spdlog/logger.h>
0015 #include <spdlog/spdlog.h>
0016 #include <gsl/pointers>
0017 #include <memory>
0018 #include <string>
0019 #include <utility>
0020 #include <variant>
0021 #include <vector>
0022
0023 #include "algorithms/calorimetry/ImagingTopoCluster.h"
0024 #include "algorithms/calorimetry/ImagingTopoClusterConfig.h"
0025
0026 using eicrecon::ImagingTopoCluster;
0027 using eicrecon::ImagingTopoClusterConfig;
0028
0029 TEST_CASE("the clustering algorithm runs", "[ImagingTopoCluster]") {
0030 ImagingTopoCluster algo("ImagingTopoCluster");
0031
0032 std::shared_ptr<spdlog::logger> logger = spdlog::default_logger()->clone("ImagingTopoCluster");
0033 logger->set_level(spdlog::level::trace);
0034
0035 ImagingTopoClusterConfig cfg;
0036 cfg.sameLayerMode = eicrecon::ImagingTopoClusterConfig::ELayerMode::xy;
0037 cfg.minClusterHitEdep = 0. * dd4hep::GeV;
0038 cfg.minClusterCenterEdep = 0. * dd4hep::GeV;
0039 cfg.sameLayerDistXY = {1.0 * dd4hep::mm, 1.0 * dd4hep::mm};
0040 cfg.diffLayerDistXY = {1.0 * dd4hep::mm, 1.0 * dd4hep::mm};
0041 cfg.minClusterEdep = 9 * dd4hep::MeV;
0042
0043 cfg.minClusterNhits = 1;
0044 auto detector = algorithms::GeoSvc::instance().detector();
0045 auto id_desc = detector->readout("MockCalorimeterHits").idSpec();
0046
0047 SECTION("without splitting") {
0048 algo.applyConfig(cfg);
0049 algo.init();
0050
0051 SECTION("on a single cell") {
0052 edm4eic::CalorimeterHitCollection hits_coll;
0053 hits_coll.create(
0054 id_desc.encode(
0055 {{"system", 255}, {"x", 0}, {"y", 0}, {"layer", 0}}),
0056 5.0,
0057 0.0,
0058 0.0,
0059 0.0,
0060 edm4hep::Vector3f(0.0, 0.0, 0.0),
0061 edm4hep::Vector3f(0.0, 0.0, 0.0),
0062 0,
0063 0,
0064 edm4hep::Vector3f(0.0, 0.0, 0.0)
0065 );
0066 auto protoclust_coll = std::make_unique<edm4eic::ProtoClusterCollection>();
0067 algo.process({&hits_coll}, {protoclust_coll.get()});
0068
0069 REQUIRE((*protoclust_coll).size() == 1);
0070 REQUIRE((*protoclust_coll)[0].hits_size() == 1);
0071 REQUIRE((*protoclust_coll)[0].weights_size() == 1);
0072 }
0073
0074 SECTION("on two separated cells") {
0075 edm4eic::CalorimeterHitCollection hits_coll;
0076 hits_coll.create(
0077 id_desc.encode(
0078 {{"system", 255}, {"x", 0}, {"y", 0}, {"layer", 0}}),
0079 5.0,
0080 0.0,
0081 0.0,
0082 0.0,
0083 edm4hep::Vector3f(0.0, 0.0, 0.0),
0084 edm4hep::Vector3f(1.0, 1.0, 0.0),
0085 0,
0086 0,
0087 edm4hep::Vector3f(0.0, 0.0, 0.0)
0088 );
0089 hits_coll.create(
0090 id_desc.encode(
0091 {{"system", 255}, {"x", 2}, {"y", 2}, {"layer", 0}}),
0092 6.0,
0093 0.0,
0094 0.0,
0095 0.0,
0096 edm4hep::Vector3f(1.1, 1.1, 0.0),
0097 edm4hep::Vector3f(1.0, 1.0, 0.0),
0098 0,
0099 0,
0100 edm4hep::Vector3f(1.1 , 1.1 , 0.0)
0101 );
0102 auto protoclust_coll = std::make_unique<edm4eic::ProtoClusterCollection>();
0103 algo.process({&hits_coll}, {protoclust_coll.get()});
0104
0105 REQUIRE((*protoclust_coll).size() == 2);
0106 REQUIRE((*protoclust_coll)[0].hits_size() == 1);
0107 REQUIRE((*protoclust_coll)[0].weights_size() == 1);
0108 REQUIRE((*protoclust_coll)[1].hits_size() == 1);
0109 REQUIRE((*protoclust_coll)[1].weights_size() == 1);
0110 }
0111
0112 SECTION("on two adjacent cells (same layer)") {
0113 edm4eic::CalorimeterHitCollection hits_coll;
0114 hits_coll.create(
0115 id_desc.encode({{"system", 255}, {"x", 0}, {"y", 0}}),
0116 5.0,
0117 0.0,
0118 0.0,
0119 0.0,
0120 edm4hep::Vector3f(0.0, 0.0, 0.0),
0121 edm4hep::Vector3f(1.0, 1.0, 0.0),
0122 0,
0123 0,
0124 edm4hep::Vector3f(0.0, 0.0, 0.0)
0125 );
0126 hits_coll.create(
0127 id_desc.encode({{"system", 255}, {"x", 1}, {"y", 0}}),
0128 6.0,
0129 0.0,
0130 0.0,
0131 0.0,
0132 edm4hep::Vector3f(0.9, 0.9, 0.0),
0133 edm4hep::Vector3f(1.0, 1.0, 0.0),
0134 0,
0135 0,
0136 edm4hep::Vector3f(0.9 , 0.9 , 0.0)
0137 );
0138 auto protoclust_coll = std::make_unique<edm4eic::ProtoClusterCollection>();
0139 algo.process({&hits_coll}, {protoclust_coll.get()});
0140
0141 REQUIRE((*protoclust_coll).size() == 1);
0142 REQUIRE((*protoclust_coll)[0].hits_size() == 2);
0143 REQUIRE((*protoclust_coll)[0].weights_size() == 2);
0144 }
0145 }
0146
0147 SECTION("xyz mode: two adjacent cells on the same layer (local xyz within threshold)") {
0148 cfg.sameLayerMode = eicrecon::ImagingTopoClusterConfig::ELayerMode::xyz;
0149 cfg.sameLayerDistXYZ = {1.0 * dd4hep::mm, 1.0 * dd4hep::mm, 1.0 * dd4hep::mm};
0150 algo.applyConfig(cfg);
0151 algo.init();
0152
0153 edm4eic::CalorimeterHitCollection hits_coll;
0154 hits_coll.create(id_desc.encode({{"system", 255}, {"x", 0}, {"y", 0}, {"layer", 0}}), 5.0, 0.0,
0155 0.0, 0.0, edm4hep::Vector3f(0.0, 0.0, 0.0), edm4hep::Vector3f(1.0, 1.0, 1.0),
0156 0, 0, edm4hep::Vector3f(0.0, 0.0, 0.0)
0157 );
0158 hits_coll.create(id_desc.encode({{"system", 255}, {"x", 1}, {"y", 0}, {"layer", 0}}), 6.0, 0.0,
0159 0.0, 0.0, edm4hep::Vector3f(0.9, 0.9, 0.9), edm4hep::Vector3f(1.0, 1.0, 1.0),
0160 0, 0, edm4hep::Vector3f(0.9 , 0.9 , 0.9 )
0161 );
0162 auto protoclust_coll = std::make_unique<edm4eic::ProtoClusterCollection>();
0163 algo.process({&hits_coll}, {protoclust_coll.get()});
0164
0165 REQUIRE((*protoclust_coll).size() == 1);
0166 REQUIRE((*protoclust_coll)[0].hits_size() == 2);
0167 }
0168
0169 SECTION("xyz mode: two separated cells on the same layer (local xyz beyond threshold)") {
0170 cfg.sameLayerMode = eicrecon::ImagingTopoClusterConfig::ELayerMode::xyz;
0171 cfg.sameLayerDistXYZ = {1.0 * dd4hep::mm, 1.0 * dd4hep::mm, 1.0 * dd4hep::mm};
0172 algo.applyConfig(cfg);
0173 algo.init();
0174
0175 edm4eic::CalorimeterHitCollection hits_coll;
0176 hits_coll.create(id_desc.encode({{"system", 255}, {"x", 0}, {"y", 0}, {"layer", 0}}), 5.0, 0.0,
0177 0.0, 0.0, edm4hep::Vector3f(0.0, 0.0, 0.0), edm4hep::Vector3f(1.0, 1.0, 1.0),
0178 0, 0, edm4hep::Vector3f(0.0, 0.0, 0.0)
0179 );
0180 hits_coll.create(id_desc.encode({{"system", 255}, {"x", 2}, {"y", 2}, {"layer", 0}}), 6.0, 0.0,
0181 0.0, 0.0, edm4hep::Vector3f(1.1, 1.1, 1.1), edm4hep::Vector3f(1.0, 1.0, 1.0),
0182 0, 0, edm4hep::Vector3f(1.1 , 1.1 , 1.1 )
0183 );
0184 auto protoclust_coll = std::make_unique<edm4eic::ProtoClusterCollection>();
0185 algo.process({&hits_coll}, {protoclust_coll.get()});
0186
0187 REQUIRE((*protoclust_coll).size() == 2);
0188 }
0189
0190 SECTION("xyz mode: two adjacent cells on different layers (global xyz within threshold)") {
0191 cfg.diffLayerMode = eicrecon::ImagingTopoClusterConfig::ELayerMode::xyz;
0192 cfg.diffLayerDistXYZ = {1.0 * dd4hep::mm, 1.0 * dd4hep::mm, 1.0 * dd4hep::mm};
0193 algo.applyConfig(cfg);
0194 algo.init();
0195
0196 edm4eic::CalorimeterHitCollection hits_coll;
0197 hits_coll.create(id_desc.encode({{"system", 255}, {"x", 0}, {"y", 0}, {"layer", 0}}), 5.0, 0.0,
0198 0.0, 0.0, edm4hep::Vector3f(0.0, 0.0, 0.0),
0199 edm4hep::Vector3f(1.0, 1.0, 1.0), 0, 0, edm4hep::Vector3f(0.0, 0.0, 0.0));
0200 hits_coll.create(id_desc.encode({{"system", 255}, {"x", 1}, {"y", 0}, {"layer", 1}}), 6.0, 0.0,
0201 0.0, 0.0,
0202 edm4hep::Vector3f(0.9, 0.9, 0.9),
0203 edm4hep::Vector3f(1.0, 1.0, 1.0), 0, 1, edm4hep::Vector3f(0.9, 0.9, 0.9));
0204 auto protoclust_coll = std::make_unique<edm4eic::ProtoClusterCollection>();
0205 algo.process({&hits_coll}, {protoclust_coll.get()});
0206
0207 REQUIRE((*protoclust_coll).size() == 1);
0208 REQUIRE((*protoclust_coll)[0].hits_size() == 2);
0209 }
0210
0211 SECTION("run on three cells, two of which are on the same layer, and there is a third one on "
0212 "another layer acting as a bridge between them") {
0213
0214 cfg.sameLayerDistXY = {1 * dd4hep::mm, 1 * dd4hep::mm};
0215 algo.applyConfig(cfg);
0216 algo.init();
0217
0218 edm4eic::CalorimeterHitCollection hits_coll;
0219 hits_coll.create(
0220 id_desc.encode(
0221 {{"system", 255}, {"x", 0}, {"y", 0}, {"layer", 0}}),
0222 5.0,
0223 0.0,
0224 0.0,
0225 0.0,
0226 edm4hep::Vector3f(0.0, 0.0, 0.0),
0227 edm4hep::Vector3f(1.0, 1.0, 0.0),
0228 0,
0229 0,
0230 edm4hep::Vector3f(0.0, 0.0, 0.0)
0231 );
0232 hits_coll.create(
0233 id_desc.encode(
0234 {{"system", 255}, {"x", 1}, {"y", 0}, {"layer", 1}}),
0235 1.0,
0236 0.0,
0237 0.0,
0238 0.0,
0239 edm4hep::Vector3f(0.9, 0.9, 0.0),
0240 edm4hep::Vector3f(1.0, 1.0, 0.0),
0241 0,
0242 1,
0243 edm4hep::Vector3f(0.9 , 0.9 , 0.0)
0244 );
0245 hits_coll.create(
0246 id_desc.encode(
0247 {{"system", 255}, {"x", 2}, {"y", 0}, {"layer", 0}}),
0248 6.0,
0249 0.0,
0250 0.0,
0251 0.0,
0252 edm4hep::Vector3f(1.8, 1.8, 0.0),
0253 edm4hep::Vector3f(1.0, 1.0, 0.0),
0254 0,
0255 0,
0256 edm4hep::Vector3f(1.8 , 1.8 , 0.0)
0257 );
0258 auto protoclust_coll = std::make_unique<edm4eic::ProtoClusterCollection>();
0259 algo.process({&hits_coll}, {protoclust_coll.get()});
0260
0261 REQUIRE((*protoclust_coll).size() == 1);
0262 REQUIRE((*protoclust_coll)[0].hits_size() == 3);
0263 REQUIRE((*protoclust_coll)[0].weights_size() == 3);
0264 }
0265 }