Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-09 08:25:44

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2024, Sebouh Paul
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}; //mm
0040   cfg.diffLayerDistXY      = {1.0 * dd4hep::mm, 1.0 * dd4hep::mm}; //mm
0041   cfg.minClusterEdep       = 9 * dd4hep::MeV;
0042   // minimum number of hits (to save this cluster)
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}}), // std::uint64_t cellID,
0056           5.0,                                                      // float energy,
0057           0.0,                                                      // float energyError,
0058           0.0,                                                      // float time,
0059           0.0,                                                      // float timeError,
0060           edm4hep::Vector3f(0.0, 0.0, 0.0),                         // edm4hep::Vector3f position,
0061           edm4hep::Vector3f(0.0, 0.0, 0.0),                         // edm4hep::Vector3f dimension,
0062           0,                                                        // std::int32_t sector,
0063           0,                                                        // std::int32_t layer,
0064           edm4hep::Vector3f(0.0, 0.0, 0.0)                          // edm4hep::Vector3f local
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}}), // std::uint64_t cellID,
0079           5.0,                                                      // float energy,
0080           0.0,                                                      // float energyError,
0081           0.0,                                                      // float time,
0082           0.0,                                                      // float timeError,
0083           edm4hep::Vector3f(0.0, 0.0, 0.0),                         // edm4hep::Vector3f position,
0084           edm4hep::Vector3f(1.0, 1.0, 0.0),                         // edm4hep::Vector3f dimension,
0085           0,                                                        // std::int32_t sector,
0086           0,                                                        // std::int32_t layer,
0087           edm4hep::Vector3f(0.0, 0.0, 0.0)                          // edm4hep::Vector3f local
0088       );
0089       hits_coll.create(
0090           id_desc.encode(
0091               {{"system", 255}, {"x", 2}, {"y", 2}, {"layer", 0}}), // std::uint64_t cellID,
0092           6.0,                                                      // float energy,
0093           0.0,                                                      // float energyError,
0094           0.0,                                                      // float time,
0095           0.0,                                                      // float timeError,
0096           edm4hep::Vector3f(1.1, 1.1, 0.0),                         // edm4hep::Vector3f position,
0097           edm4hep::Vector3f(1.0, 1.0, 0.0),                         // edm4hep::Vector3f dimension,
0098           0,                                                        // std::int32_t sector,
0099           0,                                                        // std::int32_t layer,
0100           edm4hep::Vector3f(1.1 /* mm */, 1.1 /* mm */, 0.0)        // edm4hep::Vector3f local
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}}), // std::uint64_t cellID,
0116           5.0,                                                   // float energy,
0117           0.0,                                                   // float energyError,
0118           0.0,                                                   // float time,
0119           0.0,                                                   // float timeError,
0120           edm4hep::Vector3f(0.0, 0.0, 0.0),                      // edm4hep::Vector3f position,
0121           edm4hep::Vector3f(1.0, 1.0, 0.0),                      // edm4hep::Vector3f dimension,
0122           0,                                                     // std::int32_t sector,
0123           0,                                                     // std::int32_t layer,
0124           edm4hep::Vector3f(0.0, 0.0, 0.0)                       // edm4hep::Vector3f local
0125       );
0126       hits_coll.create(
0127           id_desc.encode({{"system", 255}, {"x", 1}, {"y", 0}}), // std::uint64_t cellID,
0128           6.0,                                                   // float energy,
0129           0.0,                                                   // float energyError,
0130           0.0,                                                   // float time,
0131           0.0,                                                   // float timeError,
0132           edm4hep::Vector3f(0.9, 0.9, 0.0),                      // edm4hep::Vector3f position,
0133           edm4hep::Vector3f(1.0, 1.0, 0.0),                      // edm4hep::Vector3f dimension,
0134           0,                                                     // std::int32_t sector,
0135           0,                                                     // std::int32_t layer,
0136           edm4hep::Vector3f(0.9 /* mm */, 0.9 /* mm */, 0.0)     // edm4hep::Vector3f local
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) // local
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 /* mm */, 0.9 /* mm */, 0.9 /* mm */) // local
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) // local
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 /* mm */, 1.1 /* mm */, 1.1 /* mm */) // local
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), // global position
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), // global position within diffLayerDistXYZ
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}}), // std::uint64_t cellID,
0222         5.0,                                                      // float energy,
0223         0.0,                                                      // float energyError,
0224         0.0,                                                      // float time,
0225         0.0,                                                      // float timeError,
0226         edm4hep::Vector3f(0.0, 0.0, 0.0),                         // edm4hep::Vector3f position,
0227         edm4hep::Vector3f(1.0, 1.0, 0.0),                         // edm4hep::Vector3f dimension,
0228         0,                                                        // std::int32_t sector,
0229         0,                                                        // std::int32_t layer,
0230         edm4hep::Vector3f(0.0, 0.0, 0.0)                          // edm4hep::Vector3f local
0231     );
0232     hits_coll.create(
0233         id_desc.encode(
0234             {{"system", 255}, {"x", 1}, {"y", 0}, {"layer", 1}}), // std::uint64_t cellID,
0235         1.0,                                                      // float energy,
0236         0.0,                                                      // float energyError,
0237         0.0,                                                      // float time,
0238         0.0,                                                      // float timeError,
0239         edm4hep::Vector3f(0.9, 0.9, 0.0),                         // edm4hep::Vector3f position,
0240         edm4hep::Vector3f(1.0, 1.0, 0.0),                         // edm4hep::Vector3f dimension,
0241         0,                                                        // std::int32_t sector,
0242         1,                                                        // std::int32_t layer,
0243         edm4hep::Vector3f(0.9 /* mm */, 0.9 /* mm */, 0.0)        // edm4hep::Vector3f local
0244     );
0245     hits_coll.create(
0246         id_desc.encode(
0247             {{"system", 255}, {"x", 2}, {"y", 0}, {"layer", 0}}), // std::uint64_t cellID,
0248         6.0,                                                      // float energy,
0249         0.0,                                                      // float energyError,
0250         0.0,                                                      // float time,
0251         0.0,                                                      // float timeError,
0252         edm4hep::Vector3f(1.8, 1.8, 0.0),                         // edm4hep::Vector3f position,
0253         edm4hep::Vector3f(1.0, 1.0, 0.0),                         // edm4hep::Vector3f dimension,
0254         0,                                                        // std::int32_t sector,
0255         0,                                                        // std::int32_t layer,
0256         edm4hep::Vector3f(1.8 /* mm */, 1.8 /* mm */, 0.0)        // edm4hep::Vector3f local
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 }