Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-04 08:02:27

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2024, Chun Yuen Tsang, Prithwish Tribedy
0003 
0004 #include <DD4hep/Detector.h>
0005 #include <DD4hep/IDDescriptor.h>
0006 #include <DD4hep/Readout.h>
0007 #include <Evaluator/DD4hepUnits.h>
0008 #include <TMath.h>
0009 #include <algorithms/geo.h>
0010 #include <catch2/catch_test_macros.hpp> // for AssertionHandler, operator""_catch_sr, StringRef, REQUIRE, operator<, operator==, operator>, TEST_CASE
0011 #include <edm4eic/RawTrackerHitCollection.h>
0012 #include <edm4hep/RawTimeSeriesCollection.h>
0013 #include <spdlog/common.h> // for level_enum
0014 #include <spdlog/logger.h> // for logger
0015 #include <spdlog/spdlog.h> // for default_logger
0016 #include <cmath>
0017 #include <gsl/pointers>
0018 #include <memory> // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access
0019 #include <tuple>
0020 #include <utility>
0021 
0022 #include "algorithms/digi/LGADPulseDigitization.h"
0023 #include "algorithms/digi/LGADPulseDigitizationConfig.h"
0024 
0025 TEST_CASE("the LGAD charge sharing algorithm runs", "[LGADPulseDigitization]") {
0026   const float EPSILON = 1e-5;
0027 
0028   eicrecon::LGADPulseDigitization algo("LGADPulseDigitization");
0029 
0030   std::shared_ptr<spdlog::logger> logger = spdlog::default_logger()->clone("LGADPulseDigitization");
0031   logger->set_level(spdlog::level::trace);
0032 
0033   eicrecon::LGADPulseDigitizationConfig cfg;
0034 
0035   auto detector = algorithms::GeoSvc::instance().detector();
0036   auto id_desc  = detector->readout("MockLGADHits").idSpec();
0037 
0038   cfg.tdc_bit      = 8;
0039   cfg.adc_bit      = 7;
0040   cfg.tMax         = 10 * dd4hep::ns;
0041   cfg.tdc_range    = pow(2, cfg.tdc_bit);
0042   cfg.adc_range    = pow(2, cfg.adc_bit);
0043   cfg.t_thres      = -cfg.adc_range * 0.1;
0044 
0045   // check if max pulse height is linearly proportional to the initial Edep
0046   algo.applyConfig(cfg);
0047   algo.init();
0048 
0049   SECTION("TDC vs analytic solution scan") {
0050     logger->info("Begin TDC vs analytic solution scan");
0051 
0052     for(double time = -cfg.tMax; time <= cfg.tMax; time += cfg.tMax) {
0053       if(time < 0) logger->info("Generation pulse at the negative time");
0054       else if(time == 0) logger->info("Generation pulse at the first EICROC cycle");
0055       else logger->info("Generation pulse at the second EICROC cycle");
0056 
0057       // test pulse with gaussian shape
0058       for (double tdc_frac = 0.4; tdc_frac < 1; tdc_frac += 0.1) {
0059         edm4hep::RawTimeSeriesCollection time_series_coll;
0060         auto rawhits_coll = std::make_unique<edm4eic::RawTrackerHitCollection>();
0061 
0062         auto pulse = time_series_coll.create();
0063         auto cellID =
0064             id_desc.encode({{"system", 0}, {"module", 0}, {"sensor", 1}, {"x", 1}, {"y", 1}});
0065 
0066         pulse.setCellID(cellID);
0067         pulse.setCharge(1.); // placeholder
0068         pulse.setTime(time);   // placeholder
0069         pulse.setInterval(1);
0070 
0071         int test_peak_TDC   = static_cast<int>(tdc_frac * cfg.tdc_range);
0072         int test_peak       = static_cast<int>(0.7 * cfg.adc_range);
0073         int test_peak_sigma = static_cast<int>(0.1 * cfg.tdc_range);
0074 
0075         for (int i = 0; i < cfg.tdc_range; ++i) {
0076           int ADC =
0077               -test_peak *
0078               TMath::Exp(-0.5 * pow((i - test_peak_TDC) / static_cast<double>(test_peak_sigma), 2));
0079           pulse.addToAdcCounts(ADC);
0080         }
0081 
0082         // calculate analytically when the pulse passes t_thres
0083         // ADC = amp*exp(-(TDC - mean)^2/(2sigma^2))
0084         // TDC = mean - (-2*sigma^2*ln(ADC/amp))^0.5
0085         int analytic_TDC = ceil(test_peak_TDC - sqrt(-2 * pow(test_peak_sigma, 2) *
0086                                                      TMath::Log(cfg.adc_range * 0.1 / test_peak)));
0087 
0088         // Constructing input and output as per the algorithm's expected signature
0089         auto input  = std::make_tuple(&time_series_coll);
0090         auto output = std::make_tuple(rawhits_coll.get());
0091 
0092         algo.process(input, output);
0093 
0094         REQUIRE(rawhits_coll->size() == 1);
0095         auto hit = (*rawhits_coll)[0];
0096         REQUIRE(hit.getCellID() == cellID);
0097         REQUIRE(hit.getCharge() == test_peak);
0098         if(time < 0) REQUIRE(hit.getTimeStamp() == analytic_TDC - cfg.tdc_range);
0099         else if(time == 0) REQUIRE(hit.getTimeStamp() == analytic_TDC);
0100         else REQUIRE(hit.getTimeStamp() == analytic_TDC + cfg.tdc_range);
0101       }
0102     }
0103   }
0104 
0105   SECTION("ADC scan") {
0106     logger->info("Begin ADC scan");
0107 
0108     // test pulse with gaussian shape
0109     for (double adc_frac = 0.4; adc_frac < 1; adc_frac += 0.1) {
0110       edm4hep::RawTimeSeriesCollection time_series_coll;
0111       auto rawhits_coll = std::make_unique<edm4eic::RawTrackerHitCollection>();
0112 
0113       auto pulse = time_series_coll.create();
0114       auto cellID =
0115           id_desc.encode({{"system", 0}, {"module", 0}, {"sensor", 1}, {"x", 1}, {"y", 1}});
0116 
0117       pulse.setCellID(cellID);
0118       pulse.setCharge(1.); // placeholder
0119       pulse.setTime(0.);   // placeholder
0120       pulse.setInterval(1);
0121 
0122       int test_peak_TDC   = static_cast<int>(0.5 * cfg.tdc_range);
0123       int test_peak       = static_cast<int>(adc_frac * cfg.adc_range);
0124       int test_peak_sigma = static_cast<int>(0.1 * cfg.tdc_range);
0125 
0126       for (int i = 0; i < cfg.tdc_range; ++i) {
0127         int ADC =
0128             -test_peak *
0129             TMath::Exp(-0.5 * pow((i - test_peak_TDC) / static_cast<double>(test_peak_sigma), 2));
0130         pulse.addToAdcCounts(ADC);
0131       }
0132 
0133       // Constructing input and output as per the algorithm's expected signature
0134       auto input  = std::make_tuple(&time_series_coll);
0135       auto output = std::make_tuple(rawhits_coll.get());
0136 
0137       algo.process(input, output);
0138 
0139       REQUIRE(rawhits_coll->size() == 1);
0140       auto hit = (*rawhits_coll)[0];
0141       REQUIRE(hit.getCellID() == cellID);
0142       REQUIRE(hit.getCharge() == test_peak);
0143     }
0144   }
0145 }