From 8123783f534586043697d3e129cb1ef977281661 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Thu, 18 Jul 2024 16:52:45 -0400 Subject: [PATCH 01/77] First commit of BTOF digitization code! --- src/algorithms/digi/BTOFHitDigiConfig.h | 21 ++ src/detectors/BTOF/BTOFHitDigi.cc | 196 +++++++++++++++++ src/detectors/BTOF/BTOFHitDigi.h | 95 ++++++++ src/detectors/BTOF/BarrelTOFNeighborFinder.cc | 202 ++++++++++++++++++ src/detectors/BTOF/BarrelTOFNeighborFinder.h | 65 ++++++ src/factories/digi/BTOFHitDigi_factory.h | 63 ++++++ src/global/reco/reco.cc | 9 + src/services/io/podio/JEventProcessorPODIO.cc | 1 + 8 files changed, 652 insertions(+) create mode 100644 src/algorithms/digi/BTOFHitDigiConfig.h create mode 100644 src/detectors/BTOF/BTOFHitDigi.cc create mode 100644 src/detectors/BTOF/BTOFHitDigi.h create mode 100644 src/detectors/BTOF/BarrelTOFNeighborFinder.cc create mode 100644 src/detectors/BTOF/BarrelTOFNeighborFinder.h create mode 100644 src/factories/digi/BTOFHitDigi_factory.h diff --git a/src/algorithms/digi/BTOFHitDigiConfig.h b/src/algorithms/digi/BTOFHitDigiConfig.h new file mode 100644 index 0000000000..a73a272ca3 --- /dev/null +++ b/src/algorithms/digi/BTOFHitDigiConfig.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul + +#pragma once + +#include + +namespace eicrecon { + + struct BTOFHitDigiConfig { + // single hit energy deposition threshold + double threshold{1.0*dd4hep::keV}; + double tRes = 0.1; /// TODO 8 of what units??? Same TODO in juggler. Probably [ns] + // digitization settings + //unsigned int pedMeanADC{0}; + //double pedSigmaADC{0}; + double resolutionTDC{1}; + double resolutionADC{1}; + }; + +} // eicrecon diff --git a/src/detectors/BTOF/BTOFHitDigi.cc b/src/detectors/BTOF/BTOFHitDigi.cc new file mode 100644 index 0000000000..3e38d54916 --- /dev/null +++ b/src/detectors/BTOF/BTOFHitDigi.cc @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul, Kolja Kauder, Prithwish Tribedy, Chun Yuen Tsang + +// A general digitization for BToFHit from simulation +// 1. Smear energy deposit with a/sqrt(E/GeV) + b + c/E or a/sqrt(E/GeV) (relative value) +// 2. Digitize the energy with dynamic ADC range and add pedestal (mean +- sigma) +// 3. Time conversion with smearing resolution (absolute value) +// 4. Signal is summed if the SumFields are provided +// +// Author: Souvik Paul, Chun Yuen Tsang +// Date: 18/07/2024 + + +#include +#include +#include +#include +#include +#include "TMath.h" +#include "TF1.h" +#include +#include "DDRec/Surface.h" +#include "DD4hep/Detector.h" + +#include "BTOFHitDigi.h" +#include "algorithms/digi/BTOFHitDigiConfig.h" + +//using namespace dd4hep; +//using namespace dd4hep::Geometry; +//using namespace dd4hep::DDRec; +//using namespace eicrecon; +using namespace dd4hep::xml; + +namespace eicrecon { + + +std::vector BTOFHitDigi::ToDigitalCode(int value, int numBits) { + std::bitset<32> binary(value); // Convert integer to binary representation + std::vector digitalCode; + + for (int i = numBits - 1; i >= 0; --i) { + digitalCode.push_back(binary.test(i)); + } + + return digitalCode; +} + + +void BTOFHitDigi::init(const dd4hep::Detector *detector, std::shared_ptr& logger) { + //m_detector = detector; + m_log = logger; + + adc_range = pow(2,adc_bit); + tdc_range = pow(2,tdc_bit); + + // using juggler internal units (GeV, mm, radian, ns) + tRes = m_cfg.tRes / dd4hep::ns; + stepTDC = dd4hep::ns / m_cfg.resolutionTDC; + + _neighborFinder.init(detector); + +} + + +std::unique_ptr BTOFHitDigi::execute(const edm4hep::SimTrackerHitCollection *simhits) { + //auto rawhits = std::make_unique(); + auto rawhits = std::make_unique(); + //const auto [sim_hits] = simhits; + + // find the hits that belong to the same group (for merging) + std::unordered_map> merge_map; + std::size_t ix = 0; + for (const auto &ahit : *simhits) { + uint64_t hid = ahit.getCellID(); + merge_map[hid].push_back(ix); + + ix++; + } + + double thres[int(adc_range)]; + thres[0]=0.0; + thres[1]=-0.005; + double Vm=-0.05; + + for (int t = 2; t < adc_range; t++) + { + thres[t] = thres[1] + t*(Vm-thres[1])/(adc_range-1); + } + + double scalingFactor; + + // signal sum + // NOTE: we take the cellID of the most energetic hit in this group so it is a real cellID from an MC hit + for (const auto &[id, ixs] : merge_map) { + double edep = 0; + double time = 0;//std::numeric_limits::max(); + double max_edep = 0; + auto mid = (*simhits)[ixs[0]].getCellID(); + if(mid == 0) continue; + double sum_charge = 0.0; + double sigma_sharing = 0.8; + + //CellIDPositionConverter converter(detector, subdet.readout()); + //Position position = converter.position(cellID); + + double mpv_analog = 0.0; //SP + + // sum energy, take time from the most energetic hit + for (size_t i = 0; i < ixs.size(); ++i) { + auto hit = (*simhits)[ixs[i]]; + + time = hit.getTime(); + edep = hit.getEDep(); + sum_charge = edep*gain; + + // Use DetPosProcessor to process hits + //m_detPosProcessor->ProcessSequential(hit); + + auto localPos_hit = _neighborFinder.cell2LocalPosition(mid); + auto neighbours = _neighborFinder.findAllNeighborInSensor(mid); // Accessing NeighbourFinder through DetPosProcessor + + for (const auto& neighbour : neighbours) { + + auto localPos_neighbour = _neighborFinder.cell2LocalPosition(neighbour); + + double distanceX = localPos_hit.x() - localPos_neighbour.x(); + double distanceY = localPos_hit.y() - localPos_neighbour.y(); + + double exponent = -0.5 * ((pow((distanceX) / sigma_sharing, 2)) + (pow((distanceY) / sigma_sharing, 2))); + double charge = exp(exponent) / (2 * TMath::Pi() * sigma_sharing * sigma_sharing); + + + //std::cout<= thres[1] && y2 <= thres[1])) { + intersectionX = x1 + (x2 - x1) * (thres[1] - y1) / (y2 - y1); + + tdc = /*BTOFHitDigi::ToDigitalCode(*/ceil(intersectionX/0.02);//, tdc_bit); + break; + } + } + + double V=0.0; + + for (int j = 0; j < nBins - 1; j++) { + double x1, y1, x2, y2; + glandau.GetPoint(j, x1, y1); + glandau.GetPoint(j+1, x2, y2); + + if (abs(y2) < abs(y1))//To get peak of the Analog signal + { + V=y1; + break; + } + } + + adc = round(V/Vm*adc_range); + rawhits -> create(neighbour, adc, tdc); + + } +//----------------------------------------------------------- + + } + + } + return std::move(rawhits); + +} // BTOFHitDigi:process +} // namespace eicrecon + + diff --git a/src/detectors/BTOF/BTOFHitDigi.h b/src/detectors/BTOF/BTOFHitDigi.h new file mode 100644 index 0000000000..5d378673dc --- /dev/null +++ b/src/detectors/BTOF/BTOFHitDigi.h @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul, Kolja Kauder, Prithwish Tribedy + +// A general digitization for CalorimeterHit from simulation +// 1. Smear energy deposit with a/sqrt(E/GeV) + b + c/E or a/sqrt(E/GeV) (relative value) +// 2. Digitize the energy with dynamic ADC range and add pedestal (mean +- sigma) +// 3. Time conversion with smearing resolution (absolute value) +// 4. Signal is summed if the SumFields are provided +// +// Author: Souvik Paul, Chun Yuen Tsang +// Date: 18/07/2024 + + +#pragma once + +#include +#include +#include "TF1.h" +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "DDRec/Surface.h" +#include "DD4hep/Detector.h" + +#include "algorithms/digi/BTOFHitDigiConfig.h" +#include "algorithms/interfaces/WithPodConfig.h" +#include "BarrelTOFNeighborFinder.h" + +namespace eicrecon { + + class BTOFHitDigi : public WithPodConfig { + + public: + BTOFHitDigi() + : _neighborFinder(64, 4, 3.2, 4), + fLandau("landau", [](Double_t* x, Double_t* par) { + Double_t mean = par[0]; // Mean + Double_t std = par[1]; // Standard deviation + Double_t C = - 113.766; + + Double_t landau = C*TMath::Landau((x[0]), mean, std, kTRUE); + + return landau; }, tMin, tMax, 2){} + + + void init(const dd4hep::Detector *detector, + std::shared_ptr& logger); + + std::unique_ptr execute(const edm4hep::SimTrackerHitCollection *simhits) ; + std::vector ToDigitalCode(int value, int numBits); + + protected: + BarrelTOFNeighborFinder _neighborFinder; + std::shared_ptr m_log; + + // unitless counterparts of inputs + double dyRangeADC{0}, stepTDC{0}, tRes{0}; + const double pi = TMath::Pi(); + const double tMin = 0.1; + const double tMax = 100.0; + const int total_time = ceil(tMax - tMin); + const int time_period = 25; + const int nBins = 10000; + const int adc_bit = 8; + const int tdc_bit = 10; + + // Parameters of AC-LGAD signal generation - Added by Souvik + const double mpv = 1.56075e-04; + const double sigma = 1.92005e-05; + const double gain = 80; + const double risetime = 0.45;//0.02; //in ns + const double std = risetime/5; + const double mean = 3.65; + const double sigma_analog = 0.293951; + + int adc_range; + int tdc_range; + + uint64_t id_mask{0}; + TF1 fLandau; + + + std::default_random_engine generator; // TODO: need something more appropriate here + std::normal_distribution m_normDist; // defaults to mean=0, sigma=1 + + }; + +} // namespace eicrecon diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc new file mode 100644 index 0000000000..7fd2ee45e3 --- /dev/null +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Chun Yuen Tsang +// +// Find cells that are in the same sensor in BTOF +// +// Author: Chun Yuen Tsang +// Date: 18/07/2024 + +#include "BarrelTOFNeighborFinder.h" + +// Include appropriate class headers. e.g. +#include "TGeoManager.h" +#include "TAxis.h" +#include "TCanvas.h" + +#include +#include + +//------------------------------------------- +// InitWithGlobalRootLock +//------------------------------------------- +BarrelTOFNeighborFinder::BarrelTOFNeighborFinder(int cellNX, int cellNY, + double sensorWidth, double sensorLength) : + _sensorWidth(sensorWidth), _sensorLength(sensorLength), + _cellWidth(sensorWidth/cellNX), _cellLength(sensorLength/cellNY) { + +} + +void BarrelTOFNeighborFinder::init(const dd4hep::Detector* detector) { + _detector = detector; + _converter = std::make_unique(*detector); +} + +int BarrelTOFNeighborFinder::_findBin(double value, double minRange, double binSize) { + int bin = static_cast((value - minRange) / binSize + 1e-10); + // Make sure bin is within range + return std::max(0, bin); +} + +double BarrelTOFNeighborFinder::_binCenter(int bin, double minRange, double binSize) { + return binSize/2 + bin*binSize + minRange; +} + +double BarrelTOFNeighborFinder::_binLowEdge(int bin, double minRange, double binSize) { + return bin*binSize + minRange; +} + +void BarrelTOFNeighborFinder::setLogger(const std::shared_ptr& log) { + _log = log; +} + + + +// return cell bin (defined internally within DetPosProcessor) list for all neighbors in a sensor +void BarrelTOFNeighborFinder::_findAllNeighborsInSensor(int cellBinX, int cellBinY, + int sensorBinX, int sensorBinY, + std::vector>& ans, + std::vector>& dp) { + // use MST to find all neighbor within a sensor + // I can probably write down the formula by hand, but why do things manually when computer do everything for you? + const std::vector> searchDirs{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + for(const auto& dir : searchDirs) { + int testCellBinX = cellBinX + dir.first; + int testCellBinY = cellBinY + dir.second; + if(testCellBinX >= 0 && testCellBinX < _cellNX && + testCellBinY >= 0 && testCellBinY < _cellNY) { + // only look for cells that have not been searched + if(!dp[testCellBinX][testCellBinY]) { + dp[testCellBinX][testCellBinY] = true; + double testX = this -> _binCenter(testCellBinX, _staveXMin, _cellWidth); + double testY = this -> _binCenter(testCellBinY, _staveYMin, _cellLength); + int testSensorBinX = this -> _findBin(testX, _staveXMin, _sensorWidth); + int testSensorBinY = this -> _findBin(testY, _staveYMin, _sensorLength); + if(testSensorBinX == sensorBinX && testSensorBinY == sensorBinY) { + // inside the same sensor + ans.push_back({testCellBinX, testCellBinY}); + this -> _findAllNeighborsInSensor(testCellBinX, testCellBinY, + sensorBinX, sensorBinY, + ans, dp); + } + } + } + } +} + +void BarrelTOFNeighborFinder::_searchNOBins(const dd4hep::rec::CellID& cellID, bool length, bool width) { + // find the readout limits of the staves + // It's too unreliable to ask users for it + auto localPos = this -> cell2LocalPosition(cellID); + auto currentMatrix = _currMatrix; + std::vector> searchDirs; + if(length) { + searchDirs.push_back({0, 1}); + searchDirs.push_back({0, -1}); + } + if(width) { + searchDirs.push_back({1, 0}); + searchDirs.push_back({-1, 0}); + } + + double l[3], g[3]; + localPos.GetCoordinates(l); + + _staveXMin = std::min(_staveXMin, l[0] - _cellWidth/2); + _staveXMax = std::max(_staveXMax, l[0] + _cellWidth/2); + _staveYMin = std::min(_staveYMin, l[1] - _cellLength/2); + _staveYMax = std::max(_staveYMax, l[1] + _cellLength/2); + _cellNX = std::max(_cellNX, static_cast((_staveXMax - _staveXMin)/_cellWidth)); + _cellNY = std::max(_cellNY, static_cast((_staveYMax - _staveYMin)/_cellLength)); + _sensorNX = std::max(_sensorNX, static_cast((_staveXMax - _staveXMin)/_sensorWidth)); + _sensorNY = std::max(_sensorNY, static_cast((_staveYMax - _staveYMin)/_sensorLength)); + + for(const auto& dir : searchDirs) { + localPos.GetCoordinates(l); + l[0] += dir.first*_cellWidth; + l[1] += dir.second*_cellLength; + if(l[0] < _staveXMin || l[0] > _staveXMax || l[1] < _staveYMin || l[1] > _staveYMax) { + currentMatrix -> LocalToMaster(l, g); + try { + auto testCellID = this -> globalPosition2Cell(dd4hep::Position(g[0], g[1], g[2])); + if(testCellID != cellID) { + // cell ID change means there is more cells beyond the current edges + this -> _searchNOBins(testCellID, length, width); + } + } catch(...) { + // position not in stave. Will not proceed there + } + } + } + // find previous cell +} + + +dd4hep::Position BarrelTOFNeighborFinder::cell2GlobalPosition(const dd4hep::rec::CellID& cell) { + return _converter -> position(cell); +} + +dd4hep::rec::CellID BarrelTOFNeighborFinder::globalPosition2Cell(const dd4hep::Position& pos) { + return _converter -> cellID(pos); +} + + + +dd4hep::Position BarrelTOFNeighborFinder::cell2LocalPosition(const dd4hep::rec::CellID& cell) { + auto geoManager = _detector->world().volume() -> GetGeoManager(); + auto position = this -> cell2GlobalPosition(cell); + auto node = geoManager -> FindNode(position.x(), position.y(), position.z()); + _currMatrix = geoManager -> GetCurrentMatrix(); + + double g[3], l[3]; + position.GetCoordinates(g); + _currMatrix -> MasterToLocal(g, l); + position.SetCoordinates(l); + return position; +} + +std::vector BarrelTOFNeighborFinder::findAllNeighborInSensor(const dd4hep::rec::CellID& hitCell) { + // need to find readout grid boundaries the first time this function is called + if(_staveYMin >= _staveYMax || _staveXMin >= _staveXMax) { + if(_log) _log -> info("Searching for all the active cells in a stave. Will stamble upon empty volume a few times. Don't worry about a few empty volume below."); + this -> _searchNOBins(hitCell, true, false); + this -> _searchNOBins(hitCell, false, true); + if(_log) { + _log -> info("BarrelTOFNeighborFinder finds {} cells and {} sensors along the long direction.", _cellNX, _sensorNX); + _log -> info("Finds {} cells and {} sensors along the short direction.", _cellNY, _sensorNY); + _log -> info("Dimension for the active area of a stave is {} < length < {} cm and {} < width < {} cm.", _staveYMin, _staveYMax, _staveXMin, _staveXMax); + _log -> info("The search for cells starts at cellID = {}, with steps along the long direction = {} cm, short direction = {} cm", hitCell, _cellLength, _cellWidth); + } + } + + auto localPos = this -> cell2LocalPosition(hitCell); // this set the _currMatrix and current position + double g[3], l[3]; + localPos.GetCoordinates(l); + std::vector neighbors; + + // find cell bin with respect to the upper left hand corner + int cellBinX = this -> _findBin(l[0], _staveXMin, _cellWidth); + int cellBinY = this -> _findBin(l[1], _staveYMin, _cellLength); + + int sensorBinX = this -> _findBin(l[0], _staveXMin, _sensorWidth); + int sensorBinY = this -> _findBin(l[1], _staveYMin, _sensorLength); + + // find neighboring bin + std::vector> neighborBins; + std::vector> dp(_cellNX, std::vector(_cellNY, false)); + this -> _findAllNeighborsInSensor(cellBinX, cellBinY, + sensorBinX, sensorBinY, + neighborBins, dp); + for(const auto& bin : neighborBins) { + // convert bin to global position + l[0] = this -> _binCenter(bin.first, _staveXMin, _cellWidth); + l[1] = this -> _binCenter(bin.second, _staveYMin, _cellLength); + + _currMatrix -> LocalToMaster(l, g); + + // find cellID + neighbors.push_back(_converter -> cellID(dd4hep::Position(g[0], g[1], g[2]))); + } + + return std::move(neighbors); +} + diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.h b/src/detectors/BTOF/BarrelTOFNeighborFinder.h new file mode 100644 index 0000000000..07c76a74bf --- /dev/null +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.h @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Chun Yuen Tsang +// +// Find cells that are in the same sensor in BTOF +// +// Author: Chun Yuen Tsang +// Date: 18/07/2024 + + +#ifndef BARRELTOFNEIGHBORFINDER_H +#define BARRELTOFNEIGHBORFINDER_H + +#include +#include +#include +#include +#include + +#include "TGeoMatrix.h" +#include +#include +#include + +class BarrelTOFNeighborFinder{ +private: + + int _cellNX = 0, _cellNY = 0; + int _sensorNX = 0, _sensorNY = 0; + TGeoHMatrix *_currMatrix = nullptr; + double _staveXMin = 1e5, _staveYMin = 1e5; + double _staveXMax = -1e5, _staveYMax = -1e5; + double _sensorWidth, _sensorLength; + double _cellWidth, _cellLength; + std::shared_ptr _log; + + double _binCenter(int bin, double minRange, double binSize); + double _binLowEdge(int bin, double minRange, double binSize); + int _findBin(double value, double minRange, double binSize); + void _findAllNeighborsInSensor(int cellBinX, int cellBinY, + int sensorBinX, int sensorBinY, + std::vector>& ans, + std::vector>& dp); + + void _searchNOBins(const dd4hep::rec::CellID& cellID, bool length, bool width); // seed hit point to scan number of cells each side + + std::unique_ptr _converter; + const dd4hep::Detector *_detector = nullptr; + +public: + BarrelTOFNeighborFinder(int cellNX, int cellNY, + double sensorWidth, double sensorLength); + + + + void init(const dd4hep::Detector* detector); + + void setLogger(const std::shared_ptr& log); + std::vector findAllNeighborInSensor(const dd4hep::rec::CellID& hitCell); + dd4hep::Position cell2GlobalPosition(const dd4hep::rec::CellID& cell); + dd4hep::Position cell2LocalPosition(const dd4hep::rec::CellID& cell); + dd4hep::rec::CellID globalPosition2Cell(const dd4hep::Position& pos); + int counter = 0; +}; + +#endif diff --git a/src/factories/digi/BTOFHitDigi_factory.h b/src/factories/digi/BTOFHitDigi_factory.h new file mode 100644 index 0000000000..dd192b1126 --- /dev/null +++ b/src/factories/digi/BTOFHitDigi_factory.h @@ -0,0 +1,63 @@ +#pragma once + +#include "extensions/jana/JOmniFactory.h" + +#include "detectors/BTOF/BTOFHitDigi.h" +#include + +namespace eicrecon { + +class BTOFHitDigi_factory : public JOmniFactory { +private: + + // Underlying algorithm + std::unique_ptr m_algo; + + // Declare inputs + PodioInput m_in_sim_track {this};//, "TOFBarrelRawHits"}; + + // Declare outputs + PodioOutput m_out_reco_particles{this}; + + // Declare services here, e.g. + Service m_geoSvc {this}; + +public: + void Configure() { + // This is called when the factory is instantiated. + // Use this callback to make sure the algorithm is configured. + // The logger, parameters, and services have all been fetched before this is called + m_algo = std::make_unique(); + + // Pass config object to algorithm + m_algo->applyConfig(config()); + + // If we needed geometry, we'd obtain it like so + // m_algo->init(m_geoSvc().detector(), m_geoSvc().converter(), logger()); + + m_algo->init(m_geoSvc().detector(), logger()); + } + + void ChangeRun(int64_t run_number) { + // This is called whenever the run number is changed. + // Use this callback to retrieve state that is keyed off of run number. + // This state should usually be managed by a Service. + // Note: You usually don't need this, because you can declare a Resource instead. + } + + void Process(int64_t run_number, uint64_t event_number) { + // This is called on every event. + // Use this callback to call your Algorithm using all inputs and outputs + // The inputs will have already been fetched for you at this point. + auto output = m_algo->execute( + m_in_sim_track() + ); + + logger()->debug( "Event {}: Found {} reconstructed electron candidates", event_number, output->size() ); + + m_out_reco_particles() = std::move(output); + // JANA will take care of publishing the outputs for you. + } +}; +} // namespace eicrecon + diff --git a/src/global/reco/reco.cc b/src/global/reco/reco.cc index 00014018a9..4d5dd3212f 100644 --- a/src/global/reco/reco.cc +++ b/src/global/reco/reco.cc @@ -39,6 +39,7 @@ #if EDM4EIC_VERSION_MAJOR >= 6 #include "factories/reco/HadronicFinalState_factory.h" #endif +#include "factories/digi/BTOFHitDigi_factory.h" #include "factories/reco/UndoAfterBurnerMCParticles_factory.h" #include "global/reco/ChargedReconstructedParticleSelector_factory.h" #include "global/reco/MC2SmearedParticle_factory.h" @@ -371,6 +372,14 @@ void InitPlugin(JApplication *app) { app )); + app->Add(new JOmniFactoryGeneratorT( + "BTOFHitDigi", + {"TOFBarrelHits"}, + {"TOFBarrelADCTDC"}, + {}, + app + )); + } } // extern "C" diff --git a/src/services/io/podio/JEventProcessorPODIO.cc b/src/services/io/podio/JEventProcessorPODIO.cc index 8869e1e2fd..0508b7f78b 100644 --- a/src/services/io/podio/JEventProcessorPODIO.cc +++ b/src/services/io/podio/JEventProcessorPODIO.cc @@ -97,6 +97,7 @@ JEventProcessorPODIO::JEventProcessorPODIO() { "TOFBarrelHitAssociations", "TOFEndcapHitAssociations", + "BTOFHitDigi", "CombinedTOFParticleIDs", "CombinedTOFSeededParticleIDs", From 2332d18f4ed231d8f1f0a3b91935f3c812b7752e Mon Sep 17 00:00:00 2001 From: Souvik Paul <136603463+eicsouvik@users.noreply.github.com> Date: Fri, 19 Jul 2024 00:22:02 -0400 Subject: [PATCH 02/77] Update BTOFHitDigi.cc --- src/detectors/BTOF/BTOFHitDigi.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/detectors/BTOF/BTOFHitDigi.cc b/src/detectors/BTOF/BTOFHitDigi.cc index 3e38d54916..be7c786ba1 100644 --- a/src/detectors/BTOF/BTOFHitDigi.cc +++ b/src/detectors/BTOF/BTOFHitDigi.cc @@ -1,5 +1,6 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Souvik Paul, Kolja Kauder, Prithwish Tribedy, Chun Yuen Tsang +// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy +// Special Acknowledgement: Kolja Kauder // A general digitization for BToFHit from simulation // 1. Smear energy deposit with a/sqrt(E/GeV) + b + c/E or a/sqrt(E/GeV) (relative value) @@ -8,7 +9,7 @@ // 4. Signal is summed if the SumFields are provided // // Author: Souvik Paul, Chun Yuen Tsang -// Date: 18/07/2024 +// Date: 19/07/2024 #include From 4b907cb010ce739afb74d50988ed5265d08b496f Mon Sep 17 00:00:00 2001 From: Souvik Paul <136603463+eicsouvik@users.noreply.github.com> Date: Fri, 19 Jul 2024 00:23:36 -0400 Subject: [PATCH 03/77] Update BTOFHitDigi.h --- src/detectors/BTOF/BTOFHitDigi.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/detectors/BTOF/BTOFHitDigi.h b/src/detectors/BTOF/BTOFHitDigi.h index 5d378673dc..50e3d9fb79 100644 --- a/src/detectors/BTOF/BTOFHitDigi.h +++ b/src/detectors/BTOF/BTOFHitDigi.h @@ -1,5 +1,6 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Souvik Paul, Kolja Kauder, Prithwish Tribedy +// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy +// Special Acknowledgement: Kolja Kauder // A general digitization for CalorimeterHit from simulation // 1. Smear energy deposit with a/sqrt(E/GeV) + b + c/E or a/sqrt(E/GeV) (relative value) @@ -8,7 +9,7 @@ // 4. Signal is summed if the SumFields are provided // // Author: Souvik Paul, Chun Yuen Tsang -// Date: 18/07/2024 +// Date: 19/07/2024 #pragma once From 204d472252613d56d98bc2f942d0fc1651081de7 Mon Sep 17 00:00:00 2001 From: Souvik Paul <136603463+eicsouvik@users.noreply.github.com> Date: Fri, 19 Jul 2024 00:25:20 -0400 Subject: [PATCH 04/77] Update BTOFHitDigi.cc --- src/detectors/BTOF/BTOFHitDigi.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/detectors/BTOF/BTOFHitDigi.cc b/src/detectors/BTOF/BTOFHitDigi.cc index 3e38d54916..be7c786ba1 100644 --- a/src/detectors/BTOF/BTOFHitDigi.cc +++ b/src/detectors/BTOF/BTOFHitDigi.cc @@ -1,5 +1,6 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Souvik Paul, Kolja Kauder, Prithwish Tribedy, Chun Yuen Tsang +// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy +// Special Acknowledgement: Kolja Kauder // A general digitization for BToFHit from simulation // 1. Smear energy deposit with a/sqrt(E/GeV) + b + c/E or a/sqrt(E/GeV) (relative value) @@ -8,7 +9,7 @@ // 4. Signal is summed if the SumFields are provided // // Author: Souvik Paul, Chun Yuen Tsang -// Date: 18/07/2024 +// Date: 19/07/2024 #include From 9fbe64092cede91aa9b1e39b0764ab56e0bdbc27 Mon Sep 17 00:00:00 2001 From: Desktop ssedd1123 Date: Fri, 19 Jul 2024 09:39:25 -0400 Subject: [PATCH 05/77] Changed the algorithm of BarrelTOFNeighborFinder so it's more intuitative. --- src/detectors/BTOF/BTOFHitDigi.cc | 2 +- src/detectors/BTOF/BTOFHitDigi.h | 4 +- src/detectors/BTOF/BarrelTOFNeighborFinder.cc | 310 ++++++++---------- src/detectors/BTOF/BarrelTOFNeighborFinder.h | 87 +++-- 4 files changed, 191 insertions(+), 212 deletions(-) diff --git a/src/detectors/BTOF/BTOFHitDigi.cc b/src/detectors/BTOF/BTOFHitDigi.cc index 3e38d54916..53971cca90 100644 --- a/src/detectors/BTOF/BTOFHitDigi.cc +++ b/src/detectors/BTOF/BTOFHitDigi.cc @@ -119,7 +119,7 @@ std::unique_ptr BTOFHitDigi::execute(const edm auto localPos_hit = _neighborFinder.cell2LocalPosition(mid); auto neighbours = _neighborFinder.findAllNeighborInSensor(mid); // Accessing NeighbourFinder through DetPosProcessor - for (const auto& neighbour : neighbours) { + for (const auto& neighbour : *neighbours) { auto localPos_neighbour = _neighborFinder.cell2LocalPosition(neighbour); diff --git a/src/detectors/BTOF/BTOFHitDigi.h b/src/detectors/BTOF/BTOFHitDigi.h index 5d378673dc..2c2e335775 100644 --- a/src/detectors/BTOF/BTOFHitDigi.h +++ b/src/detectors/BTOF/BTOFHitDigi.h @@ -39,7 +39,9 @@ namespace eicrecon { public: BTOFHitDigi() - : _neighborFinder(64, 4, 3.2, 4), + : _neighborFinder(160, 4, 5), // 160-cells in a sensors in x-direction, 4 in y, and 5 means we ignore 4 cells for each cells so it steps 5 sensors at a time. + // TBD: There are only 32 cells in a sensor in x-direction in reality. The geometry needs to be fixed + // As of July 19 2024, x-lenght of a cell is 2*0.1 mm when it should have been 2*0.5mm. Check grid_size_x in tof_barrel.xml fLandau("landau", [](Double_t* x, Double_t* par) { Double_t mean = par[0]; // Mean Double_t std = par[1]; // Standard deviation diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc index 7fd2ee45e3..18944d350f 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc @@ -1,202 +1,182 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Chun Yuen Tsang + // -// Find cells that are in the same sensor in BTOF +// Template for this file generated with eicmkplugin.py // -// Author: Chun Yuen Tsang -// Date: 18/07/2024 #include "BarrelTOFNeighborFinder.h" +#include "services/geometry/richgeo/RichGeo.h" // Include appropriate class headers. e.g. -#include "TGeoManager.h" #include "TAxis.h" #include "TCanvas.h" +#include "TGeoManager.h" -#include #include +#include -//------------------------------------------- -// InitWithGlobalRootLock -//------------------------------------------- -BarrelTOFNeighborFinder::BarrelTOFNeighborFinder(int cellNX, int cellNY, - double sensorWidth, double sensorLength) : - _sensorWidth(sensorWidth), _sensorLength(sensorLength), - _cellWidth(sensorWidth/cellNX), _cellLength(sensorLength/cellNY) { - -} +BarrelTOFNeighborFinder::BarrelTOFNeighborFinder(int cellNX, int cellNY, int stepNX) : _cellNX(cellNX), _cellNY(cellNY), _stepNX(stepNX) {} void BarrelTOFNeighborFinder::init(const dd4hep::Detector* detector) { - _detector = detector; - _converter = std::make_unique(*detector); + // you need to init the class before calling any other methods + // What about RAII? + _detector = detector; + _converter = std::make_unique(*detector); } -int BarrelTOFNeighborFinder::_findBin(double value, double minRange, double binSize) { - int bin = static_cast((value - minRange) / binSize + 1e-10); - // Make sure bin is within range - return std::max(0, bin); -} +// return cell bin (defined internally within DetPosProcessor) list for all neighbors in a sensor +void BarrelTOFNeighborFinder::_findAllNeighborsInSensor( + dd4hep::rec::CellID hitCell, std::shared_ptr>& ans, + std::unordered_set& dp) { + // use MST to find all neighbor within a sensor + // I can probably write down the formula by hand, but why do things manually when computer do + // everything for you? + const std::vector> searchDirs{{0, 1}, {0, -1}, {_stepNX, 0}, {-_stepNX, 0}}; + ans->push_back(hitCell); + dp.insert(hitCell); + if (isDeadCell(hitCell)) + return; // dead cell + + auto sensorID = _getSensorID(hitCell); + auto xID = _decoder -> get(hitCell, "x"); + auto yID = _decoder -> get(hitCell, "y"); + for (const auto& dir : searchDirs) { + auto testCell = hitCell; + try { + _decoder -> set(testCell, "x", xID + dir.first); + _decoder -> set(testCell, "y", yID + dir.second); + } catch (const std::runtime_error& err) { + // catch overflow error + // ignore if invalid position ID + continue; + } -double BarrelTOFNeighborFinder::_binCenter(int bin, double minRange, double binSize) { - return binSize/2 + bin*binSize + minRange; -} + try { + _converter -> position(testCell); + } catch (const std::invalid_argument& err) { + // Ignore CellID that is invalid + continue; + } -double BarrelTOFNeighborFinder::_binLowEdge(int bin, double minRange, double binSize) { - return bin*binSize + minRange; + // only look for cells that have not been searched + if (dp.find(testCell) == dp.end()) { + auto testSensorID = _getSensorID(testCell); + if (testSensorID == sensorID) { + // inside the same sensor + this->_findAllNeighborsInSensor(testCell, ans, dp); + } + } + } } -void BarrelTOFNeighborFinder::setLogger(const std::shared_ptr& log) { - _log = log; +void BarrelTOFNeighborFinder::_initWithCell(const dd4hep::rec::CellID& hitCell) { + if (!_decoder) { + // cell dimensions, cellID converter and bit decoder will be fetched on first use + if (_log) + _log->info("Retrieving cellID decoder."); + // retrieve segmentation class + const auto det = _converter->findContext(hitCell)->element; + auto readout = _converter->findReadout(det); + auto seg = readout.segmentation(); + auto type = seg.type(); + if (type != "CartesianGridXY") + throw std::runtime_error("Unsupported segmentation type: " + type + + ". BarrelTOF must use CartesianGridXY."); + // retrieve meaning of cellID bits + _decoder = seg.decoder(); + } } +const std::shared_ptr> +BarrelTOFNeighborFinder::findAllNeighborInSensor(const dd4hep::rec::CellID& hitCell) { + _initWithCell(hitCell); + // look for cache. If exist, return cache value + if (_useCache) { + auto it = _cache.find(hitCell); + if (it != _cache.end()) + return it->second; + } -// return cell bin (defined internally within DetPosProcessor) list for all neighbors in a sensor -void BarrelTOFNeighborFinder::_findAllNeighborsInSensor(int cellBinX, int cellBinY, - int sensorBinX, int sensorBinY, - std::vector>& ans, - std::vector>& dp) { - // use MST to find all neighbor within a sensor - // I can probably write down the formula by hand, but why do things manually when computer do everything for you? - const std::vector> searchDirs{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; - for(const auto& dir : searchDirs) { - int testCellBinX = cellBinX + dir.first; - int testCellBinY = cellBinY + dir.second; - if(testCellBinX >= 0 && testCellBinX < _cellNX && - testCellBinY >= 0 && testCellBinY < _cellNY) { - // only look for cells that have not been searched - if(!dp[testCellBinX][testCellBinY]) { - dp[testCellBinX][testCellBinY] = true; - double testX = this -> _binCenter(testCellBinX, _staveXMin, _cellWidth); - double testY = this -> _binCenter(testCellBinY, _staveYMin, _cellLength); - int testSensorBinX = this -> _findBin(testX, _staveXMin, _sensorWidth); - int testSensorBinY = this -> _findBin(testY, _staveYMin, _sensorLength); - if(testSensorBinX == sensorBinX && testSensorBinY == sensorBinY) { - // inside the same sensor - ans.push_back({testCellBinX, testCellBinY}); - this -> _findAllNeighborsInSensor(testCellBinX, testCellBinY, - sensorBinX, sensorBinY, - ans, dp); - } - } - } - } -} + std::unordered_set dp; + // fill cache + std::shared_ptr> neighbors = + std::make_shared>(); + this->_findAllNeighborsInSensor(hitCell, neighbors, dp); -void BarrelTOFNeighborFinder::_searchNOBins(const dd4hep::rec::CellID& cellID, bool length, bool width) { - // find the readout limits of the staves - // It's too unreliable to ask users for it - auto localPos = this -> cell2LocalPosition(cellID); - auto currentMatrix = _currMatrix; - std::vector> searchDirs; - if(length) { - searchDirs.push_back({0, 1}); - searchDirs.push_back({0, -1}); - } - if(width) { - searchDirs.push_back({1, 0}); - searchDirs.push_back({-1, 0}); - } + if (_useCache) + for (auto cell : *neighbors) + _cache[cell] = neighbors; - double l[3], g[3]; - localPos.GetCoordinates(l); - - _staveXMin = std::min(_staveXMin, l[0] - _cellWidth/2); - _staveXMax = std::max(_staveXMax, l[0] + _cellWidth/2); - _staveYMin = std::min(_staveYMin, l[1] - _cellLength/2); - _staveYMax = std::max(_staveYMax, l[1] + _cellLength/2); - _cellNX = std::max(_cellNX, static_cast((_staveXMax - _staveXMin)/_cellWidth)); - _cellNY = std::max(_cellNY, static_cast((_staveYMax - _staveYMin)/_cellLength)); - _sensorNX = std::max(_sensorNX, static_cast((_staveXMax - _staveXMin)/_sensorWidth)); - _sensorNY = std::max(_sensorNY, static_cast((_staveYMax - _staveYMin)/_sensorLength)); - - for(const auto& dir : searchDirs) { - localPos.GetCoordinates(l); - l[0] += dir.first*_cellWidth; - l[1] += dir.second*_cellLength; - if(l[0] < _staveXMin || l[0] > _staveXMax || l[1] < _staveYMin || l[1] > _staveYMax) { - currentMatrix -> LocalToMaster(l, g); - try { - auto testCellID = this -> globalPosition2Cell(dd4hep::Position(g[0], g[1], g[2])); - if(testCellID != cellID) { - // cell ID change means there is more cells beyond the current edges - this -> _searchNOBins(testCellID, length, width); - } - } catch(...) { - // position not in stave. Will not proceed there - } - } - } - // find previous cell + return neighbors; } +std::pair +BarrelTOFNeighborFinder::_getSensorID(const dd4hep::rec::CellID& hitCell) { + _initWithCell(hitCell); + return {_decoder->get(hitCell, "x")/_cellNX, _decoder->get(hitCell, "y")/_cellNY}; +} -dd4hep::Position BarrelTOFNeighborFinder::cell2GlobalPosition(const dd4hep::rec::CellID& cell) { - return _converter -> position(cell); +bool BarrelTOFNeighborFinder::isDeadCell(const dd4hep::rec::CellID& hitCell) { + // no dead space in CartesianGridXY + return false; //Not implemented } -dd4hep::rec::CellID BarrelTOFNeighborFinder::globalPosition2Cell(const dd4hep::Position& pos) { - return _converter -> cellID(pos); -} +/**************************************** + * Functions below aren't needed anymore to find neighbors + * They are still handy so I keep them + * *************************************/ +dd4hep::Position BarrelTOFNeighborFinder::cell2GlobalPosition(const dd4hep::rec::CellID& cell) { + if (!_converter) + throw std::runtime_error( + "CellIDPositionConverter not initialized in BarrelTOFNeighborFinder. Have you called " + "BarrelTOFNeighborFinder::init(/* detector */) first?"); + return _converter->position(cell); +} +dd4hep::rec::CellID BarrelTOFNeighborFinder::globalPosition2Cell(const dd4hep::Position& pos) { + if (!_converter) + throw std::runtime_error( + "CellIDPositionConverter not initialized in BarrelTOFNeighborFinder. Have you called " + "BarrelTOFNeighborFinder::init(/* detector */) first?"); + return _converter->cellID(pos); +} +dd4hep::Position +BarrelTOFNeighborFinder::local2GlobalInStaveFromCell(const dd4hep::rec::CellID& cell, + const dd4hep::Position& pos) { + // convert local position to global position + // assuming the local position is located at the same volume as cell + if (!_detector) + throw std::runtime_error("Detector ptr not initialized in BarrelTOFNeighborFinder. Have you " + "called BarrelTOFNeighborFinder::init(/* detector */) first?"); + + auto geoManager = _detector->world().volume()->GetGeoManager(); + auto position = this->cell2GlobalPosition(cell); + auto node = geoManager->FindNode(position.x(), position.y(), position.z()); + auto currMatrix = geoManager->GetCurrentMatrix(); + + double g[3], l[3]; + pos.GetCoordinates(l); + currMatrix->LocalToMaster(l, g); // <- only different from cell2LocalPosition + position.SetCoordinates(g); // <- only different from cell2LocalPosition + return position; +} dd4hep::Position BarrelTOFNeighborFinder::cell2LocalPosition(const dd4hep::rec::CellID& cell) { - auto geoManager = _detector->world().volume() -> GetGeoManager(); - auto position = this -> cell2GlobalPosition(cell); - auto node = geoManager -> FindNode(position.x(), position.y(), position.z()); - _currMatrix = geoManager -> GetCurrentMatrix(); - - double g[3], l[3]; - position.GetCoordinates(g); - _currMatrix -> MasterToLocal(g, l); - position.SetCoordinates(l); - return position; + if (!_detector) + throw std::runtime_error("Detector ptr not initialized in BarrelTOFNeighborFinder. Have you " + "called BarrelTOFNeighborFinder::init(/* detector */) first?"); + + auto geoManager = _detector->world().volume()->GetGeoManager(); + auto position = this->cell2GlobalPosition(cell); + auto node = geoManager->FindNode(position.x(), position.y(), position.z()); + auto currMatrix = geoManager->GetCurrentMatrix(); + + double g[3], l[3]; + position.GetCoordinates(g); + currMatrix->MasterToLocal(g, l); + position.SetCoordinates(l); + return position; } -std::vector BarrelTOFNeighborFinder::findAllNeighborInSensor(const dd4hep::rec::CellID& hitCell) { - // need to find readout grid boundaries the first time this function is called - if(_staveYMin >= _staveYMax || _staveXMin >= _staveXMax) { - if(_log) _log -> info("Searching for all the active cells in a stave. Will stamble upon empty volume a few times. Don't worry about a few empty volume below."); - this -> _searchNOBins(hitCell, true, false); - this -> _searchNOBins(hitCell, false, true); - if(_log) { - _log -> info("BarrelTOFNeighborFinder finds {} cells and {} sensors along the long direction.", _cellNX, _sensorNX); - _log -> info("Finds {} cells and {} sensors along the short direction.", _cellNY, _sensorNY); - _log -> info("Dimension for the active area of a stave is {} < length < {} cm and {} < width < {} cm.", _staveYMin, _staveYMax, _staveXMin, _staveXMax); - _log -> info("The search for cells starts at cellID = {}, with steps along the long direction = {} cm, short direction = {} cm", hitCell, _cellLength, _cellWidth); - } - } - - auto localPos = this -> cell2LocalPosition(hitCell); // this set the _currMatrix and current position - double g[3], l[3]; - localPos.GetCoordinates(l); - std::vector neighbors; - - // find cell bin with respect to the upper left hand corner - int cellBinX = this -> _findBin(l[0], _staveXMin, _cellWidth); - int cellBinY = this -> _findBin(l[1], _staveYMin, _cellLength); - - int sensorBinX = this -> _findBin(l[0], _staveXMin, _sensorWidth); - int sensorBinY = this -> _findBin(l[1], _staveYMin, _sensorLength); - - // find neighboring bin - std::vector> neighborBins; - std::vector> dp(_cellNX, std::vector(_cellNY, false)); - this -> _findAllNeighborsInSensor(cellBinX, cellBinY, - sensorBinX, sensorBinY, - neighborBins, dp); - for(const auto& bin : neighborBins) { - // convert bin to global position - l[0] = this -> _binCenter(bin.first, _staveXMin, _cellWidth); - l[1] = this -> _binCenter(bin.second, _staveYMin, _cellLength); - - _currMatrix -> LocalToMaster(l, g); - - // find cellID - neighbors.push_back(_converter -> cellID(dd4hep::Position(g[0], g[1], g[2]))); - } - - return std::move(neighbors); -} diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.h b/src/detectors/BTOF/BarrelTOFNeighborFinder.h index 07c76a74bf..23ec217a5c 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.h +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.h @@ -1,65 +1,62 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Chun Yuen Tsang -// -// Find cells that are in the same sensor in BTOF -// -// Author: Chun Yuen Tsang -// Date: 18/07/2024 - #ifndef BARRELTOFNEIGHBORFINDER_H #define BARRELTOFNEIGHBORFINDER_H -#include -#include +#include #include #include -#include +#include +#include +#include #include "TGeoMatrix.h" -#include #include +#include +#include +#include #include -class BarrelTOFNeighborFinder{ -private: - - int _cellNX = 0, _cellNY = 0; - int _sensorNX = 0, _sensorNY = 0; - TGeoHMatrix *_currMatrix = nullptr; - double _staveXMin = 1e5, _staveYMin = 1e5; - double _staveXMax = -1e5, _staveYMax = -1e5; - double _sensorWidth, _sensorLength; - double _cellWidth, _cellLength; - std::shared_ptr _log; - - double _binCenter(int bin, double minRange, double binSize); - double _binLowEdge(int bin, double minRange, double binSize); - int _findBin(double value, double minRange, double binSize); - void _findAllNeighborsInSensor(int cellBinX, int cellBinY, - int sensorBinX, int sensorBinY, - std::vector>& ans, - std::vector>& dp); - - void _searchNOBins(const dd4hep::rec::CellID& cellID, bool length, bool width); // seed hit point to scan number of cells each side +class BarrelTOFNeighborFinder { +public: + BarrelTOFNeighborFinder(int cellNX, int cellNY, int stepNX=1); + + void init(const dd4hep::Detector* detector); + void useCache(bool value = true) { _useCache = value; }; + void setLogger(const std::shared_ptr& log) { _log = log; }; + bool isDeadCell(const dd4hep::rec::CellID& hitCell); + const std::shared_ptr> + findAllNeighborInSensor(const dd4hep::rec::CellID& hitCell); + + // functions below are helper function. Isn't needed to find neighbors. + dd4hep::Position cell2GlobalPosition(const dd4hep::rec::CellID& cell); + dd4hep::Position cell2LocalPosition(const dd4hep::rec::CellID& cell); + dd4hep::Position local2GlobalInStaveFromCell(const dd4hep::rec::CellID& cell, + const dd4hep::Position& pos); + dd4hep::rec::CellID globalPosition2Cell(const dd4hep::Position& pos); - std::unique_ptr _converter; - const dd4hep::Detector *_detector = nullptr; +private: + void _findAllNeighborsInSensor(dd4hep::rec::CellID hitCell, + std::shared_ptr>& ans, + std::unordered_set& dp); + std::pair + _getSensorID(const dd4hep::rec::CellID& hitCell); + // need to initialize the class with a cell from Barrel TOF + void _initWithCell(const dd4hep::rec::CellID& hitCell); -public: - BarrelTOFNeighborFinder(int cellNX, int cellNY, - double sensorWidth, double sensorLength); + bool _useCache = true; + const dd4hep::DDSegmentation::BitFieldCoder* _decoder = nullptr; + const dd4hep::Detector* _detector = nullptr; + int _cellNX = 0; + int _cellNY = 0; + int _stepNX = 0; - void init(const dd4hep::Detector* detector); + std::unique_ptr _converter; + std::shared_ptr _log; + std::unordered_map>> _cache; - void setLogger(const std::shared_ptr& log); - std::vector findAllNeighborInSensor(const dd4hep::rec::CellID& hitCell); - dd4hep::Position cell2GlobalPosition(const dd4hep::rec::CellID& cell); - dd4hep::Position cell2LocalPosition(const dd4hep::rec::CellID& cell); - dd4hep::rec::CellID globalPosition2Cell(const dd4hep::Position& pos); - int counter = 0; }; #endif From 52a9b334b3df210019f1919d20af9b2ee7dcfdc5 Mon Sep 17 00:00:00 2001 From: Desktop ssedd1123 Date: Fri, 19 Jul 2024 12:19:08 -0400 Subject: [PATCH 06/77] Changed spread calculation. Originally the spread were estimated with distance relative to the center of the center cell. Now it's changed so spread is calculated relative to the true hit location. --- src/detectors/BTOF/BTOFHitDigi.cc | 11 +++------- src/detectors/BTOF/BarrelTOFNeighborFinder.cc | 21 +++++++++++++++++++ src/detectors/BTOF/BarrelTOFNeighborFinder.h | 1 + 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/detectors/BTOF/BTOFHitDigi.cc b/src/detectors/BTOF/BTOFHitDigi.cc index c200178d39..e6c39c4a1b 100644 --- a/src/detectors/BTOF/BTOFHitDigi.cc +++ b/src/detectors/BTOF/BTOFHitDigi.cc @@ -97,13 +97,12 @@ std::unique_ptr BTOFHitDigi::execute(const edm double time = 0;//std::numeric_limits::max(); double max_edep = 0; auto mid = (*simhits)[ixs[0]].getCellID(); - if(mid == 0) continue; + auto truePos = (*simhits)[ixs[0]].getPosition(); + auto localPos_hit = _neighborFinder.global2Local(dd4hep::Position(truePos.x/10., truePos.y/10., truePos.z/10.)); + double sum_charge = 0.0; double sigma_sharing = 0.8; - //CellIDPositionConverter converter(detector, subdet.readout()); - //Position position = converter.position(cellID); - double mpv_analog = 0.0; //SP // sum energy, take time from the most energetic hit @@ -117,7 +116,6 @@ std::unique_ptr BTOFHitDigi::execute(const edm // Use DetPosProcessor to process hits //m_detPosProcessor->ProcessSequential(hit); - auto localPos_hit = _neighborFinder.cell2LocalPosition(mid); auto neighbours = _neighborFinder.findAllNeighborInSensor(mid); // Accessing NeighbourFinder through DetPosProcessor for (const auto& neighbour : *neighbours) { @@ -131,9 +129,6 @@ std::unique_ptr BTOFHitDigi::execute(const edm double charge = exp(exponent) / (2 * TMath::Pi() * sigma_sharing * sigma_sharing); - //std::cout<world().volume()->GetGeoManager(); + auto node = geoManager->FindNode(pos.x(), pos.y(), pos.z()); + auto currMatrix = geoManager->GetCurrentMatrix(); + + double g[3], l[3]; + pos.GetCoordinates(g); + currMatrix->MasterToLocal(g, l); + dd4hep::Position position; + position.SetCoordinates(l); + return position; +} + + + dd4hep::Position BarrelTOFNeighborFinder::cell2LocalPosition(const dd4hep::rec::CellID& cell) { if (!_detector) throw std::runtime_error("Detector ptr not initialized in BarrelTOFNeighborFinder. Have you " diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.h b/src/detectors/BTOF/BarrelTOFNeighborFinder.h index 23ec217a5c..6098d45740 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.h +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.h @@ -30,6 +30,7 @@ class BarrelTOFNeighborFinder { // functions below are helper function. Isn't needed to find neighbors. dd4hep::Position cell2GlobalPosition(const dd4hep::rec::CellID& cell); dd4hep::Position cell2LocalPosition(const dd4hep::rec::CellID& cell); + dd4hep::Position global2Local(const dd4hep::Position& pos); dd4hep::Position local2GlobalInStaveFromCell(const dd4hep::rec::CellID& cell, const dd4hep::Position& pos); dd4hep::rec::CellID globalPosition2Cell(const dd4hep::Position& pos); From 54024b650e6ea11346129126ccf227c1282a31f1 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Wed, 24 Jul 2024 23:32:19 -0400 Subject: [PATCH 07/77] Fixed bugs when sensor ID from barrelTOFNeighborFinder gives wrong neighbors when cell ID from BitFieldDecoder for cellID is negative. --- src/detectors/BTOF/BTOFHitDigi.h | 6 +++--- src/detectors/BTOF/BarrelTOFNeighborFinder.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detectors/BTOF/BTOFHitDigi.h b/src/detectors/BTOF/BTOFHitDigi.h index d3519c09cc..553b7fcfea 100644 --- a/src/detectors/BTOF/BTOFHitDigi.h +++ b/src/detectors/BTOF/BTOFHitDigi.h @@ -40,9 +40,9 @@ namespace eicrecon { public: BTOFHitDigi() - : _neighborFinder(160, 4, 5), // 160-cells in a sensors in x-direction, 4 in y, and 5 means we ignore 4 cells for each cells so it steps 5 sensors at a time. - // TBD: There are only 32 cells in a sensor in x-direction in reality. The geometry needs to be fixed - // As of July 19 2024, x-lenght of a cell is 2*0.1 mm when it should have been 2*0.5mm. Check grid_size_x in tof_barrel.xml + : _neighborFinder(320, 4, 5), // 320-cells in a sensors in x-direction, 4 in y, and 5 means we ignore 4 cells for each cells so it steps 5 sensors at a time. + // TBD: There are only 64 cells in a sensor in x-direction in reality. The geometry needs to be fixed + // As of July 19 2024, x-lenght of a cell is 0.1 mm when it should have been 0.5mm. Check grid_size_x in tof_barrel.xml fLandau("landau", [](Double_t* x, Double_t* par) { Double_t mean = par[0]; // Mean Double_t std = par[1]; // Standard deviation diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc index 25974fd644..f6e0b1d856 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc @@ -113,7 +113,7 @@ BarrelTOFNeighborFinder::findAllNeighborInSensor(const dd4hep::rec::CellID& hitC std::pair BarrelTOFNeighborFinder::_getSensorID(const dd4hep::rec::CellID& hitCell) { _initWithCell(hitCell); - return {_decoder->get(hitCell, "x")/_cellNX, _decoder->get(hitCell, "y")/_cellNY}; + return {std::floor(_decoder->get(hitCell, "x")/double(_cellNX)), std::floor(_decoder->get(hitCell, "y")/double(_cellNY))}; } bool BarrelTOFNeighborFinder::isDeadCell(const dd4hep::rec::CellID& hitCell) { From 40abca06610aff524592b6485ab056942697ac17 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Sat, 3 Aug 2024 04:47:30 -0400 Subject: [PATCH 08/77] Updated BTOF neighbor finder. To be used with updated epic geometry with dead spaces implemented. --- src/algorithms/digi/BTOFHitDigiConfig.h | 7 +++++++ src/detectors/BTOF/BTOFHitDigi.cc | 12 +++++------- src/detectors/BTOF/BTOFHitDigi.h | 15 ++------------- src/detectors/BTOF/BarrelTOFNeighborFinder.cc | 19 ++++++------------- src/detectors/BTOF/BarrelTOFNeighborFinder.h | 8 +------- 5 files changed, 21 insertions(+), 40 deletions(-) diff --git a/src/algorithms/digi/BTOFHitDigiConfig.h b/src/algorithms/digi/BTOFHitDigiConfig.h index a73a272ca3..90da079379 100644 --- a/src/algorithms/digi/BTOFHitDigiConfig.h +++ b/src/algorithms/digi/BTOFHitDigiConfig.h @@ -16,6 +16,13 @@ namespace eicrecon { //double pedSigmaADC{0}; double resolutionTDC{1}; double resolutionADC{1}; + + // Parameters of AC-LGAD signal generation - Added by Souvik + double gain = 80; + double risetime = 0.45;//0.02; //in ns + double sigma_analog = 0.293951; + double sigma_sharing = 0.8; + }; } // eicrecon diff --git a/src/detectors/BTOF/BTOFHitDigi.cc b/src/detectors/BTOF/BTOFHitDigi.cc index e6c39c4a1b..50aafc7997 100644 --- a/src/detectors/BTOF/BTOFHitDigi.cc +++ b/src/detectors/BTOF/BTOFHitDigi.cc @@ -101,8 +101,6 @@ std::unique_ptr BTOFHitDigi::execute(const edm auto localPos_hit = _neighborFinder.global2Local(dd4hep::Position(truePos.x/10., truePos.y/10., truePos.z/10.)); double sum_charge = 0.0; - double sigma_sharing = 0.8; - double mpv_analog = 0.0; //SP // sum energy, take time from the most energetic hit @@ -111,7 +109,7 @@ std::unique_ptr BTOFHitDigi::execute(const edm time = hit.getTime(); edep = hit.getEDep(); - sum_charge = edep*gain; + sum_charge = edep*m_cfg.gain; // Use DetPosProcessor to process hits //m_detPosProcessor->ProcessSequential(hit); @@ -125,14 +123,14 @@ std::unique_ptr BTOFHitDigi::execute(const edm double distanceX = localPos_hit.x() - localPos_neighbour.x(); double distanceY = localPos_hit.y() - localPos_neighbour.y(); - double exponent = -0.5 * ((pow((distanceX) / sigma_sharing, 2)) + (pow((distanceY) / sigma_sharing, 2))); - double charge = exp(exponent) / (2 * TMath::Pi() * sigma_sharing * sigma_sharing); + double exponent = -0.5 * ((pow((distanceX) / m_cfg.sigma_sharing, 2)) + (pow((distanceY) / m_cfg.sigma_sharing, 2))); + double charge = exp(exponent) / (2 * TMath::Pi() * m_cfg.sigma_sharing * m_cfg.sigma_sharing); //Added by SP //------------------------------------------------------------- - mpv_analog = time + risetime; - fLandau.SetParameters(mpv_analog, sigma_analog); + mpv_analog = time + m_cfg.risetime; + fLandau.SetParameters(mpv_analog, m_cfg.sigma_analog); TGraph glandau; scalingFactor=charge/fLandau.Integral(tMin, tMax); diff --git a/src/detectors/BTOF/BTOFHitDigi.h b/src/detectors/BTOF/BTOFHitDigi.h index 553b7fcfea..4b3af80886 100644 --- a/src/detectors/BTOF/BTOFHitDigi.h +++ b/src/detectors/BTOF/BTOFHitDigi.h @@ -40,10 +40,7 @@ namespace eicrecon { public: BTOFHitDigi() - : _neighborFinder(320, 4, 5), // 320-cells in a sensors in x-direction, 4 in y, and 5 means we ignore 4 cells for each cells so it steps 5 sensors at a time. - // TBD: There are only 64 cells in a sensor in x-direction in reality. The geometry needs to be fixed - // As of July 19 2024, x-lenght of a cell is 0.1 mm when it should have been 0.5mm. Check grid_size_x in tof_barrel.xml - fLandau("landau", [](Double_t* x, Double_t* par) { + : fLandau("landau", [](Double_t* x, Double_t* par) { Double_t mean = par[0]; // Mean Double_t std = par[1]; // Standard deviation Double_t C = - 113.766; @@ -74,15 +71,7 @@ namespace eicrecon { const int adc_bit = 8; const int tdc_bit = 10; - // Parameters of AC-LGAD signal generation - Added by Souvik - const double mpv = 1.56075e-04; - const double sigma = 1.92005e-05; - const double gain = 80; - const double risetime = 0.45;//0.02; //in ns - const double std = risetime/5; - const double mean = 3.65; - const double sigma_analog = 0.293951; - + int adc_range; int tdc_range; diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc index f6e0b1d856..e229965b8b 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc @@ -14,8 +14,6 @@ #include #include -BarrelTOFNeighborFinder::BarrelTOFNeighborFinder(int cellNX, int cellNY, int stepNX) : _cellNX(cellNX), _cellNY(cellNY), _stepNX(stepNX) {} - void BarrelTOFNeighborFinder::init(const dd4hep::Detector* detector) { // you need to init the class before calling any other methods // What about RAII? @@ -30,11 +28,9 @@ void BarrelTOFNeighborFinder::_findAllNeighborsInSensor( // use MST to find all neighbor within a sensor // I can probably write down the formula by hand, but why do things manually when computer do // everything for you? - const std::vector> searchDirs{{0, 1}, {0, -1}, {_stepNX, 0}, {-_stepNX, 0}}; + const std::vector> searchDirs{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; ans->push_back(hitCell); dp.insert(hitCell); - if (isDeadCell(hitCell)) - return; // dead cell auto sensorID = _getSensorID(hitCell); auto xID = _decoder -> get(hitCell, "x"); @@ -110,15 +106,12 @@ BarrelTOFNeighborFinder::findAllNeighborInSensor(const dd4hep::rec::CellID& hitC return neighbors; } -std::pair -BarrelTOFNeighborFinder::_getSensorID(const dd4hep::rec::CellID& hitCell) { +int BarrelTOFNeighborFinder::_getSensorID(const dd4hep::rec::CellID& hitCell) { _initWithCell(hitCell); - return {std::floor(_decoder->get(hitCell, "x")/double(_cellNX)), std::floor(_decoder->get(hitCell, "y")/double(_cellNY))}; -} - -bool BarrelTOFNeighborFinder::isDeadCell(const dd4hep::rec::CellID& hitCell) { - // no dead space in CartesianGridXY - return false; //Not implemented + // when x or y-index goes out of bound, sometimes the position will corresponds to a new sensor + // will fetch the new cellID here + auto newID = _converter->cellID(_converter->position(hitCell)); + return _decoder->get(newID, "sensor"); } /**************************************** diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.h b/src/detectors/BTOF/BarrelTOFNeighborFinder.h index 6098d45740..5d92685b20 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.h +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.h @@ -18,8 +18,6 @@ class BarrelTOFNeighborFinder { public: - BarrelTOFNeighborFinder(int cellNX, int cellNY, int stepNX=1); - void init(const dd4hep::Detector* detector); void useCache(bool value = true) { _useCache = value; }; void setLogger(const std::shared_ptr& log) { _log = log; }; @@ -39,8 +37,7 @@ class BarrelTOFNeighborFinder { void _findAllNeighborsInSensor(dd4hep::rec::CellID hitCell, std::shared_ptr>& ans, std::unordered_set& dp); - std::pair - _getSensorID(const dd4hep::rec::CellID& hitCell); + int _getSensorID(const dd4hep::rec::CellID& hitCell); // need to initialize the class with a cell from Barrel TOF void _initWithCell(const dd4hep::rec::CellID& hitCell); @@ -49,9 +46,6 @@ class BarrelTOFNeighborFinder { bool _useCache = true; const dd4hep::DDSegmentation::BitFieldCoder* _decoder = nullptr; const dd4hep::Detector* _detector = nullptr; - int _cellNX = 0; - int _cellNY = 0; - int _stepNX = 0; std::unique_ptr _converter; std::shared_ptr _log; From f373972c6669e1cbadcb3a9a518e6f61e1169fbf Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Tue, 24 Sep 2024 14:28:22 -0400 Subject: [PATCH 09/77] Added missing closing parenthesis. --- src/global/reco/reco.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/global/reco/reco.cc b/src/global/reco/reco.cc index b6f701e898..5b85f81ed1 100644 --- a/src/global/reco/reco.cc +++ b/src/global/reco/reco.cc @@ -407,7 +407,7 @@ void InitPlugin(JApplication *app) { {"TOFBarrelADCTDC"}, {}, app - + )); } } // extern "C" From 0725492e0fcc8cc51fd698f39ccaf9ea73f60c91 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Thu, 26 Sep 2024 23:48:12 -0400 Subject: [PATCH 10/77] Use more realistic charge sharing parameters and bug fix on ADC heights. --- src/algorithms/digi/BTOFHitDigiConfig.h | 5 +- src/detectors/BTOF/BTOFHitDigi.cc | 53 +++++++++++-------- src/detectors/BTOF/BTOFHitDigi.h | 1 + src/detectors/BTOF/BarrelTOFNeighborFinder.cc | 5 +- src/detectors/BTOF/BarrelTOFNeighborFinder.h | 1 + 5 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/algorithms/digi/BTOFHitDigiConfig.h b/src/algorithms/digi/BTOFHitDigiConfig.h index 90da079379..329a8f39ef 100644 --- a/src/algorithms/digi/BTOFHitDigiConfig.h +++ b/src/algorithms/digi/BTOFHitDigiConfig.h @@ -21,7 +21,10 @@ namespace eicrecon { double gain = 80; double risetime = 0.45;//0.02; //in ns double sigma_analog = 0.293951; - double sigma_sharing = 0.8; + double sigma_sharingx = 0.05; + double sigma_sharingy = 0.5; + double Vm = -1.2e-4*gain; + double t_thres = 0.1*Vm; }; diff --git a/src/detectors/BTOF/BTOFHitDigi.cc b/src/detectors/BTOF/BTOFHitDigi.cc index 50aafc7997..c85ff69d19 100644 --- a/src/detectors/BTOF/BTOFHitDigi.cc +++ b/src/detectors/BTOF/BTOFHitDigi.cc @@ -25,6 +25,7 @@ #include "BTOFHitDigi.h" #include "algorithms/digi/BTOFHitDigiConfig.h" +#include "Math/SpecFunc.h" //using namespace dd4hep; //using namespace dd4hep::Geometry; @@ -62,6 +63,12 @@ void BTOFHitDigi::init(const dd4hep::Detector *detector, std::shared_ptr BTOFHitDigi::execute(const edm4hep::SimTrackerHitCollection *simhits) { //auto rawhits = std::make_unique(); @@ -79,9 +86,11 @@ std::unique_ptr BTOFHitDigi::execute(const edm } double thres[int(adc_range)]; - thres[0]=0.0; - thres[1]=-0.005; - double Vm=-0.05; + thres[0] = 0.0; + thres[1] = m_cfg.t_thres; + //double Vm=-0.05; + // SP noted that max dE experienced by LGAD should be 0.8 keV + double Vm = m_cfg.Vm; for (int t = 2; t < adc_range; t++) { @@ -99,6 +108,7 @@ std::unique_ptr BTOFHitDigi::execute(const edm auto mid = (*simhits)[ixs[0]].getCellID(); auto truePos = (*simhits)[ixs[0]].getPosition(); auto localPos_hit = _neighborFinder.global2Local(dd4hep::Position(truePos.x/10., truePos.y/10., truePos.z/10.)); + auto cellDimension = _neighborFinder.cellDimension(mid); double sum_charge = 0.0; double mpv_analog = 0.0; //SP @@ -120,11 +130,10 @@ std::unique_ptr BTOFHitDigi::execute(const edm auto localPos_neighbour = _neighborFinder.cell2LocalPosition(neighbour); - double distanceX = localPos_hit.x() - localPos_neighbour.x(); - double distanceY = localPos_hit.y() - localPos_neighbour.y(); - - double exponent = -0.5 * ((pow((distanceX) / m_cfg.sigma_sharing, 2)) + (pow((distanceY) / m_cfg.sigma_sharing, 2))); - double charge = exp(exponent) / (2 * TMath::Pi() * m_cfg.sigma_sharing * m_cfg.sigma_sharing); + double charge = sum_charge*_integralGaus(localPos_hit.x(), m_cfg.sigma_sharingx, + localPos_neighbour.x()-0.5*cellDimension[0], localPos_neighbour.x()+0.5*cellDimension[0]) + *_integralGaus(localPos_hit.y(), m_cfg.sigma_sharingy, + localPos_neighbour.y()-0.5*cellDimension[1], localPos_neighbour.y()+0.5*cellDimension[1]); //Added by SP @@ -143,8 +152,9 @@ std::unique_ptr BTOFHitDigi::execute(const edm //Added by SP //------------------------------------------------------------- double intersectionX=0.0; - int tdc = 0; + int tdc = std::numeric_limits::max(); int adc = 0; + double V=0.0; for (int j = 0; j < nBins - 1; j++) { double x1, y1, x2, y2; @@ -155,24 +165,23 @@ std::unique_ptr BTOFHitDigi::execute(const edm intersectionX = x1 + (x2 - x1) * (thres[1] - y1) / (y2 - y1); tdc = /*BTOFHitDigi::ToDigitalCode(*/ceil(intersectionX/0.02);//, tdc_bit); + for (j = 0; j < nBins - 1; j++) { + //double x1, y1, x2, y2; + glandau.GetPoint(j, x1, y1); + glandau.GetPoint(j+1, x2, y2); + + if (abs(y2) < abs(y1))//To get peak of the Analog signal + { + V=y1; + break; + } + } break; } } - double V=0.0; - for (int j = 0; j < nBins - 1; j++) { - double x1, y1, x2, y2; - glandau.GetPoint(j, x1, y1); - glandau.GetPoint(j+1, x2, y2); - - if (abs(y2) < abs(y1))//To get peak of the Analog signal - { - V=y1; - break; - } - } - + adc = round(V/Vm*adc_range); rawhits -> create(neighbour, adc, tdc); diff --git a/src/detectors/BTOF/BTOFHitDigi.h b/src/detectors/BTOF/BTOFHitDigi.h index 4b3af80886..a09beea057 100644 --- a/src/detectors/BTOF/BTOFHitDigi.h +++ b/src/detectors/BTOF/BTOFHitDigi.h @@ -59,6 +59,7 @@ namespace eicrecon { protected: BarrelTOFNeighborFinder _neighborFinder; std::shared_ptr m_log; + double _integralGaus(double mean, double sd, double low_lim, double up_lim); // unitless counterparts of inputs double dyRangeADC{0}, stepTDC{0}, tRes{0}; diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc index e229965b8b..6addd4858b 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc @@ -193,4 +193,7 @@ dd4hep::Position BarrelTOFNeighborFinder::cell2LocalPosition(const dd4hep::rec:: return position; } - +std::vector BarrelTOFNeighborFinder::cellDimension(const dd4hep::rec::CellID& hitCell) { + if(!_converter) _initWithCell(hitCell); + return _converter -> cellDimensions(hitCell); +} diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.h b/src/detectors/BTOF/BarrelTOFNeighborFinder.h index 5d92685b20..3961229233 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.h +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.h @@ -32,6 +32,7 @@ class BarrelTOFNeighborFinder { dd4hep::Position local2GlobalInStaveFromCell(const dd4hep::rec::CellID& cell, const dd4hep::Position& pos); dd4hep::rec::CellID globalPosition2Cell(const dd4hep::Position& pos); + std::vector cellDimension(const dd4hep::rec::CellID& cell); private: void _findAllNeighborsInSensor(dd4hep::rec::CellID hitCell, From ce9122dee6e9a46571f0863c165aa337ae0f2932 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Tue, 8 Oct 2024 10:47:05 -0400 Subject: [PATCH 11/77] Fixed incorrect threshold for ADC TDC. --- src/algorithms/digi/BTOFHitDigiConfig.h | 6 +++--- src/detectors/BTOF/BTOFHitDigi.cc | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/algorithms/digi/BTOFHitDigiConfig.h b/src/algorithms/digi/BTOFHitDigiConfig.h index 329a8f39ef..bd94119b99 100644 --- a/src/algorithms/digi/BTOFHitDigiConfig.h +++ b/src/algorithms/digi/BTOFHitDigiConfig.h @@ -21,10 +21,10 @@ namespace eicrecon { double gain = 80; double risetime = 0.45;//0.02; //in ns double sigma_analog = 0.293951; - double sigma_sharingx = 0.05; + double sigma_sharingx = 0.1; double sigma_sharingy = 0.5; - double Vm = -1.2e-4*gain; - double t_thres = 0.1*Vm; + double Vm = -1e-4*gain; + double t_thres = 0.01*Vm; }; diff --git a/src/detectors/BTOF/BTOFHitDigi.cc b/src/detectors/BTOF/BTOFHitDigi.cc index c85ff69d19..097bf19190 100644 --- a/src/detectors/BTOF/BTOFHitDigi.cc +++ b/src/detectors/BTOF/BTOFHitDigi.cc @@ -142,7 +142,7 @@ std::unique_ptr BTOFHitDigi::execute(const edm fLandau.SetParameters(mpv_analog, m_cfg.sigma_analog); TGraph glandau; - scalingFactor=charge/fLandau.Integral(tMin, tMax); + scalingFactor = -charge/Vm/fLandau.GetMinimum(tMin, tMax)*adc_range; for (int j = 0; j < nBins; ++j) { double x = fLandau.GetXmin() + j * (fLandau.GetXmax() - fLandau.GetXmin()) / (nBins - 1); double y = -1 * fLandau.Eval(x) * scalingFactor; @@ -161,11 +161,11 @@ std::unique_ptr BTOFHitDigi::execute(const edm glandau.GetPoint(j, x1, y1); glandau.GetPoint(j + 1, x2, y2); - if ((y1 >= thres[1] && y2 <= thres[1])) { + if ((y1 >= (-thres[1]*adc_range/Vm) && y2 <= (-thres[1]*adc_range/Vm))) { intersectionX = x1 + (x2 - x1) * (thres[1] - y1) / (y2 - y1); tdc = /*BTOFHitDigi::ToDigitalCode(*/ceil(intersectionX/0.02);//, tdc_bit); - for (j = 0; j < nBins - 1; j++) { + for (; j < nBins - 1; j++) { //double x1, y1, x2, y2; glandau.GetPoint(j, x1, y1); glandau.GetPoint(j+1, x2, y2); @@ -182,7 +182,7 @@ std::unique_ptr BTOFHitDigi::execute(const edm - adc = round(V/Vm*adc_range); + adc = round(-V); rawhits -> create(neighbour, adc, tdc); } From 350ca3bd933886d5a4b6997fdea89661c4a94303 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Mon, 14 Oct 2024 22:18:28 -0400 Subject: [PATCH 12/77] Move digitization code to the main branch. --- .../tracking/BTOFHitReconstruction.cc | 152 ++++++++++++++++++ .../tracking/BTOFHitReconstruction.h | 44 +++++ .../tracking/BTOFHitReconstructionConfig.h | 13 ++ src/detectors/BTOF/BTOF.cc | 7 +- src/detectors/BTOF/BTOFHitDigi.cc | 12 +- src/detectors/BTOF/BarrelTOFNeighborFinder.cc | 17 +- src/detectors/BTOF/BarrelTOFNeighborFinder.h | 2 +- .../tracking/BTOFHitReconstruction_factory.h | 36 +++++ 8 files changed, 268 insertions(+), 15 deletions(-) create mode 100644 src/algorithms/tracking/BTOFHitReconstruction.cc create mode 100644 src/algorithms/tracking/BTOFHitReconstruction.h create mode 100644 src/algorithms/tracking/BTOFHitReconstructionConfig.h create mode 100644 src/factories/tracking/BTOFHitReconstruction_factory.h diff --git a/src/algorithms/tracking/BTOFHitReconstruction.cc b/src/algorithms/tracking/BTOFHitReconstruction.cc new file mode 100644 index 0000000000..129388b733 --- /dev/null +++ b/src/algorithms/tracking/BTOFHitReconstruction.cc @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2022 Whitney Armstrong, Sylvester Joosten, Wouter Deconinck, Dmitry Romanov + +#include "BTOFHitReconstruction.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TMatrixT.h" + +namespace eicrecon { + +void BTOFHitReconstruction::init(const dd4hep::rec::CellIDPositionConverter* converter, + const dd4hep::Detector* detector, + std::shared_ptr& logger) { + + m_log = logger; + + m_converter = converter; + m_detector = detector; +} + +dd4hep::rec::CellID BTOFHitReconstruction::getDetInfos(const dd4hep::rec::CellID& id) { + // retrieve segmentation class if that hasn't been done + if(! m_decoder) { + const auto det = m_converter -> findContext(id) -> element; + auto readout = m_converter -> findReadout(det); + auto seg = readout.segmentation(); + m_decoder = seg.decoder(); + } + + // CellID for BarrelTOF is composed of 6 parts + // system, layer, module, sensor, x, y + // If we fix x and y to zero, what remains will be the detector information only + auto id_return = id; + m_decoder -> set(id_return, "x", 0); + m_decoder -> set(id_return, "y", 0); + return id_return; +} + +std::unique_ptr BTOFHitReconstruction::process(const edm4eic::RawTrackerHitCollection& TDCADC_hits) { + using dd4hep::mm; + + auto rec_hits { std::make_unique() }; + + // collection of ADC values from all sensors + std::unordered_map> hitsBySensors; + + for (const auto& TDCADC_hit : TDCADC_hits) { + + auto id = TDCADC_hit.getCellID(); + + // Get position and dimension + auto pos = m_converter->position(id); + // Get sensors info + auto detID = this -> getDetInfos(id); + hitsBySensors[detID].emplace_back(pos.x(), pos.y(), pos.z(), int(TDCADC_hit.getCharge()), int(TDCADC_hit.getTimeStamp()), id); + + } + + auto geoManager = m_detector -> world().volume() -> GetGeoManager(); + + // loop through each sensors for Hit information + TMatrixT varLocal(3, 3); + for(int i = 0; i < 3; ++i) + for(int j = 0; j < 3; ++j) + varLocal[i][j] = 0; + + for (const auto& sensor : hitsBySensors) { + // INSERT clustering algorithm for each sensors here + // Right now I just perform a simple average over all hits in a sensors + // Will be problematic near the edges, but it's just an illustration + double ave_x = 0, ave_y = 0, ave_z = 0; + double tot_charge = 0; + const auto& hits = sensor.second; + // find cellID for the cell with maximum ADC value within a sensor + // I don't know why you need cellID for reconstructed hits, but we'll do it anyway + auto id = hits[0].id; + auto curr_adc = hits[0].adc; + auto first_tdc = hits[0].tdc; + for(const auto& hit : hits) { + // weigh all hits by ADC value + ave_x += hit.adc*hit.x; + ave_y += hit.adc*hit.y; + ave_z += hit.adc*hit.z; + + tot_charge += hit.adc; + if(hit.adc > curr_adc) { + curr_adc = hit.adc; + id = hit.id; + } + first_tdc = std::min(first_tdc, hit.tdc); + } + + ave_x /= tot_charge; + ave_y /= tot_charge; + ave_z /= tot_charge; + + auto cellSize = m_converter -> cellDimensions(id); + + // get rotation matrix + auto node = geoManager -> FindNode(hits[0].x, hits[0].y, hits[0].z); + auto currMatrix = geoManager -> GetCurrentMatrix(); + auto rotMatrixElements = currMatrix -> GetRotationMatrix(); + + // rotMatrix transforms local coordinates to global coordinates + // see line 342 of https://root.cern.ch/doc/master/TGeoMatrix_8cxx_source.html#l00342 + TMatrixT rot(3, 3, rotMatrixElements); + TMatrixT rotT(3, 3); + rotT.Transpose(rot); + + varLocal[0][0] = cellSize[0]*cellSize[0] / mm / mm / 12.; // final division by 12 because I assumed uniform distribution + varLocal[1][1] = cellSize[1]*cellSize[1] / mm / mm / 12.; // Std. dev of uniformation = width/sqrt(12) + varLocal[2][2] = 0; + + // transform variance. see https://robotics.stackexchange.com/questions/2556/how-to-rotate-covariance + auto varGlobal = rot*varLocal*rotT; + + + // adc to charge + float charge = tot_charge * m_cfg.c_slope + m_cfg.c_intercept; + // TDC to time + float time = first_tdc * m_cfg.t_slope + m_cfg.t_intercept; + // >oO trace + rec_hits->create( + id, + edm4hep::Vector3f{static_cast(ave_x / mm), + static_cast(ave_y / mm), + static_cast(ave_z / mm)}, // mm + edm4eic::CovDiag3f{varGlobal[0][0], varGlobal[1][1], varGlobal[2][2]}, // should be the covariance of position + time, // ns + 0.0F, // covariance of time + charge, // total ADC sum + 0.0F); // Error on the energy + + } + + return std::move(rec_hits); +} + +} // namespace eicrecon diff --git a/src/algorithms/tracking/BTOFHitReconstruction.h b/src/algorithms/tracking/BTOFHitReconstruction.h new file mode 100644 index 0000000000..3f2ddeb797 --- /dev/null +++ b/src/algorithms/tracking/BTOFHitReconstruction.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2022 Whitney Armstrong, Sylvester Joosten, Wouter Deconinck, Dmitry Romanov + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "BTOFHitReconstructionConfig.h" +#include "algorithms/interfaces/WithPodConfig.h" + +namespace eicrecon { + + /** + * Produces edm4eic::TrackerHit with geometric info from edm4eic::RawTrackerHit + */ + class BTOFHitReconstruction : public WithPodConfig { + + public: + /// Once in a lifetime initialization + void init(const dd4hep::rec::CellIDPositionConverter* converter, const dd4hep::Detector* detector, std::shared_ptr& logger); + + /// Processes RawTrackerHit and produces a TrackerHit + std::unique_ptr process(const edm4eic::RawTrackerHitCollection& TDCADC_hits); + + private: + struct HitInfo{ double x, y, z; int adc, tdc; dd4hep::rec::CellID id;}; + dd4hep::rec::CellID getDetInfos(const dd4hep::rec::CellID& id); + /** algorithm logger */ + std::shared_ptr m_log; + + /// Cell ID position converter + const dd4hep::rec::CellIDPositionConverter* m_converter = nullptr; + + /// fetch sensor information from cellID + const dd4hep::DDSegmentation::BitFieldCoder* m_decoder = nullptr; + + const dd4hep::Detector* m_detector = nullptr; + }; +} diff --git a/src/algorithms/tracking/BTOFHitReconstructionConfig.h b/src/algorithms/tracking/BTOFHitReconstructionConfig.h new file mode 100644 index 0000000000..57e6a23b6e --- /dev/null +++ b/src/algorithms/tracking/BTOFHitReconstructionConfig.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2022 Whitney Armstrong, Sylvester Joosten, Wouter Deconinck, Dmitry Romanov + +#pragma once + +namespace eicrecon { + struct BTOFHitReconstructionConfig { + // parameters that convert ADC to EDep + double c_slope = 3.86976e-7, c_intercept=2.42716e-5; + // parameters that convert TDC to hit time (ns) + double t_slope = 0.0197305, t_intercept = 0.208047; + }; +} diff --git a/src/detectors/BTOF/BTOF.cc b/src/detectors/BTOF/BTOF.cc index de32d22126..7e657d487e 100644 --- a/src/detectors/BTOF/BTOF.cc +++ b/src/detectors/BTOF/BTOF.cc @@ -17,7 +17,7 @@ #include "algorithms/pid_lut/PIDLookupConfig.h" #include "extensions/jana/JOmniFactoryGeneratorT.h" #include "factories/digi/SiliconTrackerDigi_factory.h" -#include "factories/tracking/TrackerHitReconstruction_factory.h" +#include "factories/tracking/BTOFHitReconstruction_factory.h" #include "global/pid_lut/PIDLookup_factory.h" #include "services/geometry/dd4hep/DD4hep_service.h" @@ -45,12 +45,11 @@ void InitPlugin(JApplication *app) { )); // Convert raw digitized hits into hits with geometry info (ready for tracking) - app->Add(new JOmniFactoryGeneratorT( + app->Add(new JOmniFactoryGeneratorT( "TOFBarrelRecHit", - {"TOFBarrelRawHit"}, // Input data collection tags + {"TOFBarrelADCTDC"}, // Input data collection tags {"TOFBarrelRecHit"}, // Output data tag { - .timeResolution = 10, }, app )); // Hit reco default config for factories diff --git a/src/detectors/BTOF/BTOFHitDigi.cc b/src/detectors/BTOF/BTOFHitDigi.cc index 097bf19190..5f4bd392a8 100644 --- a/src/detectors/BTOF/BTOFHitDigi.cc +++ b/src/detectors/BTOF/BTOFHitDigi.cc @@ -161,8 +161,9 @@ std::unique_ptr BTOFHitDigi::execute(const edm glandau.GetPoint(j, x1, y1); glandau.GetPoint(j + 1, x2, y2); - if ((y1 >= (-thres[1]*adc_range/Vm) && y2 <= (-thres[1]*adc_range/Vm))) { - intersectionX = x1 + (x2 - x1) * (thres[1] - y1) / (y2 - y1); + double norm_threshold = -thres[1]*adc_range/Vm; + if (y1 >= norm_threshold && y2 <= norm_threshold) { + intersectionX = x1 + (x2 - x1) * (norm_threshold - y1) / (y2 - y1); tdc = /*BTOFHitDigi::ToDigitalCode(*/ceil(intersectionX/0.02);//, tdc_bit); for (; j < nBins - 1; j++) { @@ -182,8 +183,11 @@ std::unique_ptr BTOFHitDigi::execute(const edm - adc = round(-V); - rawhits -> create(neighbour, adc, tdc); + // limit the range of adc values + adc = std::min(static_cast(adc_range), round(-V)); + // only store valid hits + if(tdc < std::numeric_limits::max() && adc > 0) + rawhits -> create(neighbour, adc, tdc); } //----------------------------------------------------------- diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc index 6addd4858b..d16ba97a5e 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc @@ -47,7 +47,9 @@ void BarrelTOFNeighborFinder::_findAllNeighborsInSensor( } try { - _converter -> position(testCell); + auto pos = _converter -> position(testCell); + if(testCell != _converter -> cellID(pos)) + continue; } catch (const std::invalid_argument& err) { // Ignore CellID that is invalid continue; @@ -106,12 +108,15 @@ BarrelTOFNeighborFinder::findAllNeighborInSensor(const dd4hep::rec::CellID& hitC return neighbors; } -int BarrelTOFNeighborFinder::_getSensorID(const dd4hep::rec::CellID& hitCell) { +const dd4hep::rec::CellID BarrelTOFNeighborFinder::_getSensorID(const dd4hep::rec::CellID& hitCell) { _initWithCell(hitCell); - // when x or y-index goes out of bound, sometimes the position will corresponds to a new sensor - // will fetch the new cellID here - auto newID = _converter->cellID(_converter->position(hitCell)); - return _decoder->get(newID, "sensor"); + // fix x-y, what you left with are ids that corresponds to sensor info + // cellID may change when position changes. + auto sensorID = hitCell;//_converter -> cellID(_converter -> position(hitCell)); + _decoder -> set(sensorID, "x", 0); + _decoder -> set(sensorID, "y", 0); + + return sensorID; } /**************************************** diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.h b/src/detectors/BTOF/BarrelTOFNeighborFinder.h index 3961229233..1b495f4986 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.h +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.h @@ -38,7 +38,7 @@ class BarrelTOFNeighborFinder { void _findAllNeighborsInSensor(dd4hep::rec::CellID hitCell, std::shared_ptr>& ans, std::unordered_set& dp); - int _getSensorID(const dd4hep::rec::CellID& hitCell); + const dd4hep::rec::CellID _getSensorID(const dd4hep::rec::CellID& hitCell); // need to initialize the class with a cell from Barrel TOF void _initWithCell(const dd4hep::rec::CellID& hitCell); diff --git a/src/factories/tracking/BTOFHitReconstruction_factory.h b/src/factories/tracking/BTOFHitReconstruction_factory.h new file mode 100644 index 0000000000..1766b1a8e1 --- /dev/null +++ b/src/factories/tracking/BTOFHitReconstruction_factory.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2023 Wouter Deconinck + +#pragma once + +#include "algorithms/tracking/BTOFHitReconstruction.h" +#include "services/geometry/dd4hep/DD4hep_service.h" +#include "extensions/jana/JOmniFactory.h" + +namespace eicrecon { + +class BTOFHitReconstruction_factory : +public JOmniFactory { + private: + eicrecon::BTOFHitReconstruction m_algo; + + PodioInput m_raw_hits_input {this}; + PodioOutput m_rec_hits_output {this}; + + Service m_geoSvc {this}; + +public: + void Configure() { + m_algo.applyConfig(config()); + m_algo.init(m_geoSvc().converter(), m_geoSvc().detector(), logger()); + } + + void ChangeRun(int64_t run_number) { + } + + void Process(int64_t run_number, uint64_t event_number) { + m_rec_hits_output() = m_algo.process(*m_raw_hits_input()); + } +}; + +} // eicrecon From 4f892eeb4fbe5e307dd87d40b392feb059c43c02 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Tue, 15 Oct 2024 10:04:47 -0400 Subject: [PATCH 13/77] Formated files. --- src/algorithms/digi/BTOFHitDigiConfig.h | 39 ++- .../tracking/BTOFHitReconstruction.cc | 249 +++++++------- .../tracking/BTOFHitReconstruction.h | 66 ++-- .../tracking/BTOFHitReconstructionConfig.h | 5 +- src/detectors/BTOF/BTOF.cc | 115 +++---- src/detectors/BTOF/BTOFHitDigi.cc | 309 +++++++++--------- src/detectors/BTOF/BTOFHitDigi.h | 109 +++--- src/detectors/BTOF/BarrelTOFNeighborFinder.cc | 47 ++- src/detectors/BTOF/BarrelTOFNeighborFinder.h | 27 +- src/factories/digi/BTOFHitDigi_factory.h | 4 + 10 files changed, 490 insertions(+), 480 deletions(-) diff --git a/src/algorithms/digi/BTOFHitDigiConfig.h b/src/algorithms/digi/BTOFHitDigiConfig.h index bd94119b99..af0d151fa8 100644 --- a/src/algorithms/digi/BTOFHitDigiConfig.h +++ b/src/algorithms/digi/BTOFHitDigiConfig.h @@ -7,25 +7,24 @@ namespace eicrecon { - struct BTOFHitDigiConfig { - // single hit energy deposition threshold - double threshold{1.0*dd4hep::keV}; - double tRes = 0.1; /// TODO 8 of what units??? Same TODO in juggler. Probably [ns] - // digitization settings - //unsigned int pedMeanADC{0}; - //double pedSigmaADC{0}; - double resolutionTDC{1}; - double resolutionADC{1}; +struct BTOFHitDigiConfig { + // single hit energy deposition threshold + double threshold{1.0 * dd4hep::keV}; + double tRes = 0.1; /// TODO 8 of what units??? Same TODO in juggler. Probably [ns] + // digitization settings + // unsigned int pedMeanADC{0}; + // double pedSigmaADC{0}; + double resolutionTDC{1}; + double resolutionADC{1}; - // Parameters of AC-LGAD signal generation - Added by Souvik - double gain = 80; - double risetime = 0.45;//0.02; //in ns - double sigma_analog = 0.293951; - double sigma_sharingx = 0.1; - double sigma_sharingy = 0.5; - double Vm = -1e-4*gain; - double t_thres = 0.01*Vm; - - }; + // Parameters of AC-LGAD signal generation - Added by Souvik + double gain = 80; + double risetime = 0.45; // 0.02; //in ns + double sigma_analog = 0.293951; + double sigma_sharingx = 0.1; + double sigma_sharingy = 0.5; + double Vm = -1e-4 * gain; + double t_thres = 0.1 * Vm; +}; -} // eicrecon +} // namespace eicrecon diff --git a/src/algorithms/tracking/BTOFHitReconstruction.cc b/src/algorithms/tracking/BTOFHitReconstruction.cc index 129388b733..03a39e0c7b 100644 --- a/src/algorithms/tracking/BTOFHitReconstruction.cc +++ b/src/algorithms/tracking/BTOFHitReconstruction.cc @@ -1,18 +1,18 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2022 Whitney Armstrong, Sylvester Joosten, Wouter Deconinck, Dmitry Romanov +// Copyright (C) 2024 Chun Yuen Tsang #include "BTOFHitReconstruction.h" #include #include #include -#include #include +#include #include #include +#include #include #include -#include #include #include @@ -20,133 +20,156 @@ namespace eicrecon { -void BTOFHitReconstruction::init(const dd4hep::rec::CellIDPositionConverter* converter, - const dd4hep::Detector* detector, - std::shared_ptr& logger) { +void BTOFHitReconstruction::init(const dd4hep::rec::CellIDPositionConverter* converter, + const dd4hep::Detector* detector, + std::shared_ptr& logger) { - m_log = logger; + m_log = logger; - m_converter = converter; - m_detector = detector; + m_converter = converter; + m_detector = detector; } dd4hep::rec::CellID BTOFHitReconstruction::getDetInfos(const dd4hep::rec::CellID& id) { - // retrieve segmentation class if that hasn't been done - if(! m_decoder) { - const auto det = m_converter -> findContext(id) -> element; - auto readout = m_converter -> findReadout(det); - auto seg = readout.segmentation(); - m_decoder = seg.decoder(); - } - - // CellID for BarrelTOF is composed of 6 parts - // system, layer, module, sensor, x, y - // If we fix x and y to zero, what remains will be the detector information only - auto id_return = id; - m_decoder -> set(id_return, "x", 0); - m_decoder -> set(id_return, "y", 0); - return id_return; + // retrieve segmentation class if that hasn't been done + if (!m_decoder) { + const auto det = m_converter->findContext(id)->element; + auto readout = m_converter->findReadout(det); + auto seg = readout.segmentation(); + m_decoder = seg.decoder(); + } + + // CellID for BarrelTOF is composed of 6 parts + // system, layer, module, sensor, x, y + // If we fix x and y to zero, what remains will be the detector information only + auto id_return = id; + m_decoder->set(id_return, "x", 0); + m_decoder->set(id_return, "y", 0); + return id_return; } -std::unique_ptr BTOFHitReconstruction::process(const edm4eic::RawTrackerHitCollection& TDCADC_hits) { - using dd4hep::mm; - - auto rec_hits { std::make_unique() }; - - // collection of ADC values from all sensors - std::unordered_map> hitsBySensors; - - for (const auto& TDCADC_hit : TDCADC_hits) { +std::unique_ptr +BTOFHitReconstruction::process(const edm4eic::RawTrackerHitCollection& TDCADC_hits) { + using dd4hep::mm; + + auto rec_hits{std::make_unique()}; + + // collection of ADC values from all sensors + std::unordered_map> hitsBySensors; + + for (const auto& TDCADC_hit : TDCADC_hits) { + + auto id = TDCADC_hit.getCellID(); + + // Get position and dimension + auto pos = m_converter->position(id); + // Get sensors info + auto detID = this->getDetInfos(id); + hitsBySensors[detID].emplace_back(pos.x(), pos.y(), pos.z(), int(TDCADC_hit.getCharge()), + int(TDCADC_hit.getTimeStamp()), id); + } + + auto geoManager = m_detector->world().volume()->GetGeoManager(); + + for (const auto& sensor : hitsBySensors) { + // INSERT clustering algorithm for each sensors here + // Right now I just perform a simple average over all hits in a sensors + // Will be problematic near the edges, but it's just an illustration + double ave_x = 0, ave_y = 0, ave_z = 0; + double tot_charge = 0; + const auto& hits = sensor.second; + // find cellID for the cell with maximum ADC value within a sensor + // I don't know why you need cellID for reconstructed hits, but we'll do it anyway + auto id = hits[0].id; + auto curr_adc = hits[0].adc; + auto first_tdc = hits[0].tdc; + double maxADC_x = hits[0].x; + double maxADC_y = hits[0].y; + double maxADC_z = hits[0].z; + + for (const auto& hit : hits) { + // weigh all hits by ADC value + ave_x += hit.adc * hit.x; + ave_y += hit.adc * hit.y; + ave_z += hit.adc * hit.z; + + tot_charge += hit.adc; + if (hit.adc > curr_adc) { + maxADC_x = hit.x; + maxADC_y = hit.y; + maxADC_z = hit.z; + curr_adc = hit.adc; + id = hit.id; + } + first_tdc = std::min(first_tdc, hit.tdc); + } - auto id = TDCADC_hit.getCellID(); + ave_x /= tot_charge; + ave_y /= tot_charge; + ave_z /= tot_charge; - // Get position and dimension - auto pos = m_converter->position(id); - // Get sensors info - auto detID = this -> getDetInfos(id); - hitsBySensors[detID].emplace_back(pos.x(), pos.y(), pos.z(), int(TDCADC_hit.getCharge()), int(TDCADC_hit.getTimeStamp()), id); + auto cellSize = m_converter->cellDimensions(id); - } + /** NVM. covariance is defined in sensor frame + * but the central position is defined in global frame + // get rotation matrix + auto node = geoManager -> FindNode(hits[0].x, hits[0].y, hits[0].z); + auto currMatrix = geoManager -> GetCurrentMatrix(); + auto rotMatrixElements = currMatrix -> GetRotationMatrix(); - auto geoManager = m_detector -> world().volume() -> GetGeoManager(); + // rotMatrix transforms local coordinates to global coordinates + // see line 342 of https://root.cern.ch/doc/master/TGeoMatrix_8cxx_source.html#l00342 + TMatrixT rot(3, 3, rotMatrixElements); + TMatrixT rotT(3, 3); + rotT.Transpose(rot); // loop through each sensors for Hit information TMatrixT varLocal(3, 3); for(int i = 0; i < 3; ++i) - for(int j = 0; j < 3; ++j) - varLocal[i][j] = 0; - - for (const auto& sensor : hitsBySensors) { - // INSERT clustering algorithm for each sensors here - // Right now I just perform a simple average over all hits in a sensors - // Will be problematic near the edges, but it's just an illustration - double ave_x = 0, ave_y = 0, ave_z = 0; - double tot_charge = 0; - const auto& hits = sensor.second; - // find cellID for the cell with maximum ADC value within a sensor - // I don't know why you need cellID for reconstructed hits, but we'll do it anyway - auto id = hits[0].id; - auto curr_adc = hits[0].adc; - auto first_tdc = hits[0].tdc; - for(const auto& hit : hits) { - // weigh all hits by ADC value - ave_x += hit.adc*hit.x; - ave_y += hit.adc*hit.y; - ave_z += hit.adc*hit.z; - - tot_charge += hit.adc; - if(hit.adc > curr_adc) { - curr_adc = hit.adc; - id = hit.id; - } - first_tdc = std::min(first_tdc, hit.tdc); - } - - ave_x /= tot_charge; - ave_y /= tot_charge; - ave_z /= tot_charge; - - auto cellSize = m_converter -> cellDimensions(id); - - // get rotation matrix - auto node = geoManager -> FindNode(hits[0].x, hits[0].y, hits[0].z); - auto currMatrix = geoManager -> GetCurrentMatrix(); - auto rotMatrixElements = currMatrix -> GetRotationMatrix(); - - // rotMatrix transforms local coordinates to global coordinates - // see line 342 of https://root.cern.ch/doc/master/TGeoMatrix_8cxx_source.html#l00342 - TMatrixT rot(3, 3, rotMatrixElements); - TMatrixT rotT(3, 3); - rotT.Transpose(rot); - - varLocal[0][0] = cellSize[0]*cellSize[0] / mm / mm / 12.; // final division by 12 because I assumed uniform distribution - varLocal[1][1] = cellSize[1]*cellSize[1] / mm / mm / 12.; // Std. dev of uniformation = width/sqrt(12) - varLocal[2][2] = 0; - - // transform variance. see https://robotics.stackexchange.com/questions/2556/how-to-rotate-covariance - auto varGlobal = rot*varLocal*rotT; - - - // adc to charge - float charge = tot_charge * m_cfg.c_slope + m_cfg.c_intercept; - // TDC to time - float time = first_tdc * m_cfg.t_slope + m_cfg.t_intercept; - // >oO trace - rec_hits->create( - id, - edm4hep::Vector3f{static_cast(ave_x / mm), - static_cast(ave_y / mm), - static_cast(ave_z / mm)}, // mm - edm4eic::CovDiag3f{varGlobal[0][0], varGlobal[1][1], varGlobal[2][2]}, // should be the covariance of position - time, // ns - 0.0F, // covariance of time - charge, // total ADC sum - 0.0F); // Error on the energy - + for(int j = 0; j < 3; ++j) + varLocal[i][j] = 0; + + + varLocal[0][0] = cellSize[0]*cellSize[0] / mm / mm / 12.; // final division by 12 because I + assumed uniform distribution varLocal[1][1] = cellSize[1]*cellSize[1] / mm / mm / 12.; // Std. + dev of uniformation = width/sqrt(12) varLocal[2][2] = 0; + + // transform variance. see + https://robotics.stackexchange.com/questions/2556/how-to-rotate-covariance auto varGlobal = + rot*varLocal*rotT; + */ + + // adc to charge + float charge = tot_charge * m_cfg.c_slope + m_cfg.c_intercept; + // TDC to time + float time = first_tdc * m_cfg.t_slope + m_cfg.t_intercept; + // >oO trace + if (m_cfg.use_ave) { + rec_hits->create(id, + edm4hep::Vector3f{static_cast(ave_x / mm), + static_cast(ave_y / mm), + static_cast(ave_z / mm)}, // mm + edm4eic::CovDiag3f{cellSize[0] / mm, cellSize[1] / mm, + cellSize[2] / mm}, // should be the covariance of position + time, // ns + 0.0F, // covariance of time + charge, // total ADC sum + 0.0F); // Error on the energy + } else { + rec_hits->create(id, + edm4hep::Vector3f{static_cast(maxADC_x / mm), + static_cast(maxADC_y / mm), + static_cast(maxADC_z / mm)}, // mm + edm4eic::CovDiag3f{cellSize[0] / mm, cellSize[1] / mm, + cellSize[2] / mm}, // should be the covariance of position + time, // ns + 0.0F, // covariance of time + charge, // total ADC sum + 0.0F); // Error on the energy } + } - return std::move(rec_hits); + return std::move(rec_hits); } } // namespace eicrecon diff --git a/src/algorithms/tracking/BTOFHitReconstruction.h b/src/algorithms/tracking/BTOFHitReconstruction.h index 3f2ddeb797..53cf7305fd 100644 --- a/src/algorithms/tracking/BTOFHitReconstruction.h +++ b/src/algorithms/tracking/BTOFHitReconstruction.h @@ -1,44 +1,50 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2022 Whitney Armstrong, Sylvester Joosten, Wouter Deconinck, Dmitry Romanov +// Copyright (C) 2024 Chun Yuen Tsang #pragma once -#include #include +#include #include #include -#include #include +#include #include "BTOFHitReconstructionConfig.h" #include "algorithms/interfaces/WithPodConfig.h" namespace eicrecon { - /** - * Produces edm4eic::TrackerHit with geometric info from edm4eic::RawTrackerHit - */ - class BTOFHitReconstruction : public WithPodConfig { - - public: - /// Once in a lifetime initialization - void init(const dd4hep::rec::CellIDPositionConverter* converter, const dd4hep::Detector* detector, std::shared_ptr& logger); - - /// Processes RawTrackerHit and produces a TrackerHit - std::unique_ptr process(const edm4eic::RawTrackerHitCollection& TDCADC_hits); - - private: - struct HitInfo{ double x, y, z; int adc, tdc; dd4hep::rec::CellID id;}; - dd4hep::rec::CellID getDetInfos(const dd4hep::rec::CellID& id); - /** algorithm logger */ - std::shared_ptr m_log; - - /// Cell ID position converter - const dd4hep::rec::CellIDPositionConverter* m_converter = nullptr; - - /// fetch sensor information from cellID - const dd4hep::DDSegmentation::BitFieldCoder* m_decoder = nullptr; - - const dd4hep::Detector* m_detector = nullptr; - }; -} +/** + * Produces edm4eic::TrackerHit with geometric info from edm4eic::RawTrackerHit + */ +class BTOFHitReconstruction : public WithPodConfig { + +public: + /// Once in a lifetime initialization + void init(const dd4hep::rec::CellIDPositionConverter* converter, const dd4hep::Detector* detector, + std::shared_ptr& logger); + + /// Processes RawTrackerHit and produces a TrackerHit + std::unique_ptr + process(const edm4eic::RawTrackerHitCollection& TDCADC_hits); + +private: + struct HitInfo { + double x, y, z; + int adc, tdc; + dd4hep::rec::CellID id; + }; + dd4hep::rec::CellID getDetInfos(const dd4hep::rec::CellID& id); + /** algorithm logger */ + std::shared_ptr m_log; + + /// Cell ID position converter + const dd4hep::rec::CellIDPositionConverter* m_converter = nullptr; + + /// fetch sensor information from cellID + const dd4hep::DDSegmentation::BitFieldCoder* m_decoder = nullptr; + + const dd4hep::Detector* m_detector = nullptr; +}; +} // namespace eicrecon diff --git a/src/algorithms/tracking/BTOFHitReconstructionConfig.h b/src/algorithms/tracking/BTOFHitReconstructionConfig.h index 57e6a23b6e..a80eb756c0 100644 --- a/src/algorithms/tracking/BTOFHitReconstructionConfig.h +++ b/src/algorithms/tracking/BTOFHitReconstructionConfig.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2022 Whitney Armstrong, Sylvester Joosten, Wouter Deconinck, Dmitry Romanov +// Copyright (C) 2024 Chun Yuen Tsang #pragma once @@ -9,5 +9,8 @@ namespace eicrecon { double c_slope = 3.86976e-7, c_intercept=2.42716e-5; // parameters that convert TDC to hit time (ns) double t_slope = 0.0197305, t_intercept = 0.208047; + // if false, we use weighted ADC averages for position. + // By default, the position is just the center of cell with max ADC value in a sensor + bool use_ave = true; }; } diff --git a/src/detectors/BTOF/BTOF.cc b/src/detectors/BTOF/BTOF.cc index 7e657d487e..cf30eca342 100644 --- a/src/detectors/BTOF/BTOF.cc +++ b/src/detectors/BTOF/BTOF.cc @@ -22,85 +22,72 @@ #include "services/geometry/dd4hep/DD4hep_service.h" extern "C" { -void InitPlugin(JApplication *app) { - InitJANAPlugin(app); +void InitPlugin(JApplication* app) { + InitJANAPlugin(app); - using namespace eicrecon; + using namespace eicrecon; - // Digitization - app->Add(new JOmniFactoryGeneratorT( - "TOFBarrelRawHit", - { - "TOFBarrelHits" - }, - { - "TOFBarrelRawHit", - "TOFBarrelRawHitAssociations" - }, - { - .threshold = 6.0 * dd4hep::keV, - .timeResolution = 0.025, // [ns] - }, - app - )); + // Digitization + app->Add(new JOmniFactoryGeneratorT( + "TOFBarrelRawHit", {"TOFBarrelHits"}, {"TOFBarrelRawHit", "TOFBarrelRawHitAssociations"}, + { + .threshold = 6.0 * dd4hep::keV, + .timeResolution = 0.025, // [ns] + }, + app)); - // Convert raw digitized hits into hits with geometry info (ready for tracking) - app->Add(new JOmniFactoryGeneratorT( - "TOFBarrelRecHit", - {"TOFBarrelADCTDC"}, // Input data collection tags - {"TOFBarrelRecHit"}, // Output data tag - { - }, - app - )); // Hit reco default config for factories + // Convert raw digitized hits into hits with geometry info (ready for tracking) + app->Add(new JOmniFactoryGeneratorT( + "TOFBarrelRecHit", {"TOFBarrelADCTDC"}, // Input data collection tags + {"TOFBarrelRecHit"}, // Output data tag + {}, + app)); // Hit reco default config for factories - int BarrelTOF_ID = 0; - try { - auto detector = app->GetService()->detector(); - BarrelTOF_ID = detector->constant("BarrelTOF_ID"); - } catch(const std::runtime_error&) { - // Nothing - } - PIDLookupConfig pid_cfg { - .filename="calibrations/tof.lut", - .system=BarrelTOF_ID, - .pdg_values={11, 211, 321, 2212}, - .charge_values={1}, - .momentum_edges={0.0, 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7, 3.0, 3.3, 3.6, 3.9, 4.2, 4.5, 4.8, 5.1, 5.4, 5.7, 6.0}, - .polar_edges={2.50, 10.95, 19.40, 27.85, 36.30, 44.75, 53.20, 61.65, 70.10, 78.55, 87.00, 95.45, 103.90, 112.35, 120.80, 129.25, 137.70, 146.15, 154.60}, - .azimuthal_binning={0., 360., 360.}, // lower, upper, step - .momentum_bin_centers_in_lut=true, - .polar_bin_centers_in_lut=true, - }; + int BarrelTOF_ID = 0; + try { + auto detector = app->GetService()->detector(); + BarrelTOF_ID = detector->constant("BarrelTOF_ID"); + } catch (const std::runtime_error&) { + // Nothing + } + PIDLookupConfig pid_cfg{ + .filename = "calibrations/tof.lut", + .system = BarrelTOF_ID, + .pdg_values = {11, 211, 321, 2212}, + .charge_values = {1}, + .momentum_edges = {0.0, 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7, 3.0, + 3.3, 3.6, 3.9, 4.2, 4.5, 4.8, 5.1, 5.4, 5.7, 6.0}, + .polar_edges = {2.50, 10.95, 19.40, 27.85, 36.30, 44.75, 53.20, 61.65, 70.10, 78.55, 87.00, + 95.45, 103.90, 112.35, 120.80, 129.25, 137.70, 146.15, 154.60}, + .azimuthal_binning = {0., 360., 360.}, // lower, upper, step + .momentum_bin_centers_in_lut = true, + .polar_bin_centers_in_lut = true, + }; - app->Add(new JOmniFactoryGeneratorT( - "CombinedTOFTruthSeededLUTPID", - { + app->Add(new JOmniFactoryGeneratorT( + "CombinedTOFTruthSeededLUTPID", + { "ReconstructedTruthSeededChargedWithPFRICHPIDParticles", "ReconstructedTruthSeededChargedWithPFRICHPIDParticleAssociations", - }, - { + }, + { "ReconstructedTruthSeededChargedWithPFRICHTOFPIDParticles", "ReconstructedTruthSeededChargedWithPFRICHTOFPIDParticleAssociations", "CombinedTOFTruthSeededParticleIDs", - }, - pid_cfg, - app - )); + }, + pid_cfg, app)); - app->Add(new JOmniFactoryGeneratorT( - "CombinedTOFLUTPID", - { + app->Add(new JOmniFactoryGeneratorT( + "CombinedTOFLUTPID", + { "ReconstructedChargedWithPFRICHPIDParticles", "ReconstructedChargedWithPFRICHPIDParticleAssociations", - }, - { + }, + { "ReconstructedChargedWithPFRICHTOFPIDParticles", "ReconstructedChargedWithPFRICHTOFPIDParticleAssociations", "CombinedTOFParticleIDs", - }, - pid_cfg, - app - )); + }, + pid_cfg, app)); } } // extern "C" diff --git a/src/detectors/BTOF/BTOFHitDigi.cc b/src/detectors/BTOF/BTOFHitDigi.cc index 5f4bd392a8..5df9d3047d 100644 --- a/src/detectors/BTOF/BTOFHitDigi.cc +++ b/src/detectors/BTOF/BTOFHitDigi.cc @@ -11,193 +11,186 @@ // Author: Souvik Paul, Chun Yuen Tsang // Date: 19/07/2024 - -#include +#include "DD4hep/Detector.h" +#include "DDRec/Surface.h" +#include "TF1.h" +#include "TMath.h" #include -#include -#include #include -#include "TMath.h" -#include "TF1.h" +#include +#include #include -#include "DDRec/Surface.h" -#include "DD4hep/Detector.h" +#include #include "BTOFHitDigi.h" -#include "algorithms/digi/BTOFHitDigiConfig.h" #include "Math/SpecFunc.h" +#include "algorithms/digi/BTOFHitDigiConfig.h" -//using namespace dd4hep; -//using namespace dd4hep::Geometry; -//using namespace dd4hep::DDRec; -//using namespace eicrecon; +// using namespace dd4hep; +// using namespace dd4hep::Geometry; +// using namespace dd4hep::DDRec; +// using namespace eicrecon; using namespace dd4hep::xml; namespace eicrecon { - std::vector BTOFHitDigi::ToDigitalCode(int value, int numBits) { - std::bitset<32> binary(value); // Convert integer to binary representation - std::vector digitalCode; + std::bitset<32> binary(value); // Convert integer to binary representation + std::vector digitalCode; - for (int i = numBits - 1; i >= 0; --i) { - digitalCode.push_back(binary.test(i)); - } + for (int i = numBits - 1; i >= 0; --i) { + digitalCode.push_back(binary.test(i)); + } - return digitalCode; + return digitalCode; } +void BTOFHitDigi::init(const dd4hep::Detector* detector, std::shared_ptr& logger) { + // m_detector = detector; + m_log = logger; -void BTOFHitDigi::init(const dd4hep::Detector *detector, std::shared_ptr& logger) { - //m_detector = detector; - m_log = logger; - - adc_range = pow(2,adc_bit); - tdc_range = pow(2,tdc_bit); - - // using juggler internal units (GeV, mm, radian, ns) - tRes = m_cfg.tRes / dd4hep::ns; - stepTDC = dd4hep::ns / m_cfg.resolutionTDC; + adc_range = pow(2, adc_bit); + tdc_range = pow(2, tdc_bit); - _neighborFinder.init(detector); + // using juggler internal units (GeV, mm, radian, ns) + tRes = m_cfg.tRes / dd4hep::ns; + stepTDC = dd4hep::ns / m_cfg.resolutionTDC; + _neighborFinder.init(detector); } double BTOFHitDigi::_integralGaus(double mean, double sd, double low_lim, double up_lim) { - double up = -0.5*ROOT::Math::erf(TMath::Sqrt(2)*(mean - up_lim)/sd); - double low = -0.5*ROOT::Math::erf(TMath::Sqrt(2)*(mean - low_lim)/sd); - return up - low; + double up = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - up_lim) / sd); + double low = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - low_lim) / sd); + return up - low; } - -std::unique_ptr BTOFHitDigi::execute(const edm4hep::SimTrackerHitCollection *simhits) { - //auto rawhits = std::make_unique(); - auto rawhits = std::make_unique(); - //const auto [sim_hits] = simhits; - - // find the hits that belong to the same group (for merging) - std::unordered_map> merge_map; - std::size_t ix = 0; - for (const auto &ahit : *simhits) { - uint64_t hid = ahit.getCellID(); - merge_map[hid].push_back(ix); - - ix++; - } - - double thres[int(adc_range)]; - thres[0] = 0.0; - thres[1] = m_cfg.t_thres; - //double Vm=-0.05; - // SP noted that max dE experienced by LGAD should be 0.8 keV - double Vm = m_cfg.Vm; - - for (int t = 2; t < adc_range; t++) - { - thres[t] = thres[1] + t*(Vm-thres[1])/(adc_range-1); +std::unique_ptr +BTOFHitDigi::execute(const edm4hep::SimTrackerHitCollection* simhits) { + // auto rawhits = std::make_unique(); + auto rawhits = std::make_unique(); + // const auto [sim_hits] = simhits; + + // find the hits that belong to the same group (for merging) + std::unordered_map> merge_map; + std::size_t ix = 0; + for (const auto& ahit : *simhits) { + uint64_t hid = ahit.getCellID(); + merge_map[hid].push_back(ix); + + ix++; + } + + double thres[int(adc_range)]; + thres[0] = 0.0; + thres[1] = m_cfg.t_thres; + // double Vm=-0.05; + // SP noted that max dE experienced by LGAD should be 0.8 keV + double Vm = m_cfg.Vm; + + for (int t = 2; t < adc_range; t++) { + thres[t] = thres[1] + t * (Vm - thres[1]) / (adc_range - 1); + } + + double scalingFactor; + + // signal sum + // NOTE: we take the cellID of the most energetic hit in this group so it is a real cellID from an + // MC hit + for (const auto& [id, ixs] : merge_map) { + double edep = 0; + double time = 0; // std::numeric_limits::max(); + double max_edep = 0; + auto mid = (*simhits)[ixs[0]].getCellID(); + auto truePos = (*simhits)[ixs[0]].getPosition(); + auto localPos_hit = _neighborFinder.global2Local( + dd4hep::Position(truePos.x / 10., truePos.y / 10., truePos.z / 10.)); + auto cellDimension = _neighborFinder.cellDimension(mid); + + double sum_charge = 0.0; + double mpv_analog = 0.0; // SP + + // sum energy, take time from the most energetic hit + for (size_t i = 0; i < ixs.size(); ++i) { + auto hit = (*simhits)[ixs[i]]; + + time = hit.getTime(); + edep = hit.getEDep(); + sum_charge = edep * m_cfg.gain; + + // Use DetPosProcessor to process hits + // m_detPosProcessor->ProcessSequential(hit); + + auto neighbours = _neighborFinder.findAllNeighborInSensor( + mid); // Accessing NeighbourFinder through DetPosProcessor + + for (const auto& neighbour : *neighbours) { + + auto localPos_neighbour = _neighborFinder.cell2LocalPosition(neighbour); + + double charge = sum_charge * + _integralGaus(localPos_hit.x(), m_cfg.sigma_sharingx, + localPos_neighbour.x() - 0.5 * cellDimension[0], + localPos_neighbour.x() + 0.5 * cellDimension[0]) * + _integralGaus(localPos_hit.y(), m_cfg.sigma_sharingy, + localPos_neighbour.y() - 0.5 * cellDimension[1], + localPos_neighbour.y() + 0.5 * cellDimension[1]); + + // Added by SP + //------------------------------------------------------------- + mpv_analog = time + m_cfg.risetime; + fLandau.SetParameters(mpv_analog, m_cfg.sigma_analog); + + TGraph glandau; + scalingFactor = -charge / Vm / fLandau.GetMinimum(tMin, tMax) * adc_range; + for (int j = 0; j < nBins; ++j) { + double x = fLandau.GetXmin() + j * (fLandau.GetXmax() - fLandau.GetXmin()) / (nBins - 1); + double y = -1 * fLandau.Eval(x) * scalingFactor; + glandau.SetPoint(j, x, y); } - - double scalingFactor; - - // signal sum - // NOTE: we take the cellID of the most energetic hit in this group so it is a real cellID from an MC hit - for (const auto &[id, ixs] : merge_map) { - double edep = 0; - double time = 0;//std::numeric_limits::max(); - double max_edep = 0; - auto mid = (*simhits)[ixs[0]].getCellID(); - auto truePos = (*simhits)[ixs[0]].getPosition(); - auto localPos_hit = _neighborFinder.global2Local(dd4hep::Position(truePos.x/10., truePos.y/10., truePos.z/10.)); - auto cellDimension = _neighborFinder.cellDimension(mid); - - double sum_charge = 0.0; - double mpv_analog = 0.0; //SP - - // sum energy, take time from the most energetic hit - for (size_t i = 0; i < ixs.size(); ++i) { - auto hit = (*simhits)[ixs[i]]; - - time = hit.getTime(); - edep = hit.getEDep(); - sum_charge = edep*m_cfg.gain; - - // Use DetPosProcessor to process hits - //m_detPosProcessor->ProcessSequential(hit); - - auto neighbours = _neighborFinder.findAllNeighborInSensor(mid); // Accessing NeighbourFinder through DetPosProcessor - - for (const auto& neighbour : *neighbours) { - - auto localPos_neighbour = _neighborFinder.cell2LocalPosition(neighbour); - - double charge = sum_charge*_integralGaus(localPos_hit.x(), m_cfg.sigma_sharingx, - localPos_neighbour.x()-0.5*cellDimension[0], localPos_neighbour.x()+0.5*cellDimension[0]) - *_integralGaus(localPos_hit.y(), m_cfg.sigma_sharingy, - localPos_neighbour.y()-0.5*cellDimension[1], localPos_neighbour.y()+0.5*cellDimension[1]); - - - //Added by SP -//------------------------------------------------------------- - mpv_analog = time + m_cfg.risetime; - fLandau.SetParameters(mpv_analog, m_cfg.sigma_analog); - - TGraph glandau; - scalingFactor = -charge/Vm/fLandau.GetMinimum(tMin, tMax)*adc_range; - for (int j = 0; j < nBins; ++j) { - double x = fLandau.GetXmin() + j * (fLandau.GetXmax() - fLandau.GetXmin()) / (nBins - 1); - double y = -1 * fLandau.Eval(x) * scalingFactor; - glandau.SetPoint(j, x, y); - } - - //Added by SP -//------------------------------------------------------------- - double intersectionX=0.0; - int tdc = std::numeric_limits::max(); - int adc = 0; - double V=0.0; - - for (int j = 0; j < nBins - 1; j++) { - double x1, y1, x2, y2; - glandau.GetPoint(j, x1, y1); - glandau.GetPoint(j + 1, x2, y2); - - double norm_threshold = -thres[1]*adc_range/Vm; - if (y1 >= norm_threshold && y2 <= norm_threshold) { - intersectionX = x1 + (x2 - x1) * (norm_threshold - y1) / (y2 - y1); - - tdc = /*BTOFHitDigi::ToDigitalCode(*/ceil(intersectionX/0.02);//, tdc_bit); - for (; j < nBins - 1; j++) { - //double x1, y1, x2, y2; - glandau.GetPoint(j, x1, y1); - glandau.GetPoint(j+1, x2, y2); - - if (abs(y2) < abs(y1))//To get peak of the Analog signal - { - V=y1; - break; - } - } - break; - } - } - - - - // limit the range of adc values - adc = std::min(static_cast(adc_range), round(-V)); - // only store valid hits - if(tdc < std::numeric_limits::max() && adc > 0) - rawhits -> create(neighbour, adc, tdc); + // Added by SP + //------------------------------------------------------------- + double intersectionX = 0.0; + int tdc = std::numeric_limits::max(); + int adc = 0; + double V = 0.0; + + for (int j = 0; j < nBins - 1; j++) { + double x1, y1, x2, y2; + glandau.GetPoint(j, x1, y1); + glandau.GetPoint(j + 1, x2, y2); + + double norm_threshold = -thres[1] * adc_range / Vm; + if (y1 >= norm_threshold && y2 <= norm_threshold) { + intersectionX = x1 + (x2 - x1) * (norm_threshold - y1) / (y2 - y1); + + tdc = /*BTOFHitDigi::ToDigitalCode(*/ ceil(intersectionX / 0.02); //, tdc_bit); + for (; j < nBins - 1; j++) { + // double x1, y1, x2, y2; + glandau.GetPoint(j, x1, y1); + glandau.GetPoint(j + 1, x2, y2); + + if (abs(y2) < abs(y1)) // To get peak of the Analog signal + { + V = y1; + break; + } } -//----------------------------------------------------------- - - } + break; + } + } + // limit the range of adc values + adc = std::min(static_cast(adc_range), round(-V)); + // only store valid hits + if (tdc < std::numeric_limits::max() && adc > 0) + rawhits->create(neighbour, adc, tdc); + } + //----------------------------------------------------------- } - return std::move(rawhits); + } + return std::move(rawhits); } // BTOFHitDigi:process } // namespace eicrecon - - diff --git a/src/detectors/BTOF/BTOFHitDigi.h b/src/detectors/BTOF/BTOFHitDigi.h index a09beea057..b3732fb2fc 100644 --- a/src/detectors/BTOF/BTOFHitDigi.h +++ b/src/detectors/BTOF/BTOFHitDigi.h @@ -11,78 +11,77 @@ // Author: Souvik Paul, Chun Yuen Tsang // Date: 19/07/2024 - #pragma once +#include "TF1.h" +#include #include #include -#include "TF1.h" #include -#include #include #include -#include #include +#include #include -#include -#include "DDRec/Surface.h" #include "DD4hep/Detector.h" +#include "DDRec/Surface.h" +#include +#include "BarrelTOFNeighborFinder.h" #include "algorithms/digi/BTOFHitDigiConfig.h" #include "algorithms/interfaces/WithPodConfig.h" -#include "BarrelTOFNeighborFinder.h" namespace eicrecon { - class BTOFHitDigi : public WithPodConfig { - - public: - BTOFHitDigi() - : fLandau("landau", [](Double_t* x, Double_t* par) { - Double_t mean = par[0]; // Mean - Double_t std = par[1]; // Standard deviation - Double_t C = - 113.766; - - Double_t landau = C*TMath::Landau((x[0]), mean, std, kTRUE); - - return landau; }, tMin, tMax, 2){} - - - void init(const dd4hep::Detector *detector, - std::shared_ptr& logger); - - std::unique_ptr execute(const edm4hep::SimTrackerHitCollection *simhits) ; - std::vector ToDigitalCode(int value, int numBits); - - protected: - BarrelTOFNeighborFinder _neighborFinder; - std::shared_ptr m_log; - double _integralGaus(double mean, double sd, double low_lim, double up_lim); - - // unitless counterparts of inputs - double dyRangeADC{0}, stepTDC{0}, tRes{0}; - const double pi = TMath::Pi(); - const double tMin = 0.1; - const double tMax = 100.0; - const int total_time = ceil(tMax - tMin); - const int time_period = 25; - const int nBins = 10000; - const int adc_bit = 8; - const int tdc_bit = 10; - - - int adc_range; - int tdc_range; - - uint64_t id_mask{0}; - TF1 fLandau; - - - std::default_random_engine generator; // TODO: need something more appropriate here - std::normal_distribution m_normDist; // defaults to mean=0, sigma=1 - - }; +class BTOFHitDigi : public WithPodConfig { + +public: + BTOFHitDigi() + : fLandau( + "landau", + [](Double_t* x, Double_t* par) { + Double_t mean = par[0]; // Mean + Double_t std = par[1]; // Standard deviation + Double_t C = -113.766; + + Double_t landau = C * TMath::Landau((x[0]), mean, std, kTRUE); + + return landau; + }, + tMin, tMax, 2) {} + + void init(const dd4hep::Detector* detector, std::shared_ptr& logger); + + std::unique_ptr + execute(const edm4hep::SimTrackerHitCollection* simhits); + std::vector ToDigitalCode(int value, int numBits); + +protected: + BarrelTOFNeighborFinder _neighborFinder; + std::shared_ptr m_log; + double _integralGaus(double mean, double sd, double low_lim, double up_lim); + + // unitless counterparts of inputs + double dyRangeADC{0}, stepTDC{0}, tRes{0}; + const double pi = TMath::Pi(); + const double tMin = 0.1; + const double tMax = 100.0; + const int total_time = ceil(tMax - tMin); + const int time_period = 25; + const int nBins = 10000; + const int adc_bit = 8; + const int tdc_bit = 10; + + int adc_range; + int tdc_range; + + uint64_t id_mask{0}; + TF1 fLandau; + + std::default_random_engine generator; // TODO: need something more appropriate here + std::normal_distribution m_normDist; // defaults to mean=0, sigma=1 +}; } // namespace eicrecon diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc index d16ba97a5e..6e27a4c8c2 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc @@ -1,7 +1,6 @@ - -// -// Template for this file generated with eicmkplugin.py -// +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Chun Yuen Tsang, Souvik Paul, Prithwish Tribedy +// Date: 10/15/2024 #include "BarrelTOFNeighborFinder.h" #include "services/geometry/richgeo/RichGeo.h" @@ -33,13 +32,13 @@ void BarrelTOFNeighborFinder::_findAllNeighborsInSensor( dp.insert(hitCell); auto sensorID = _getSensorID(hitCell); - auto xID = _decoder -> get(hitCell, "x"); - auto yID = _decoder -> get(hitCell, "y"); + auto xID = _decoder->get(hitCell, "x"); + auto yID = _decoder->get(hitCell, "y"); for (const auto& dir : searchDirs) { auto testCell = hitCell; try { - _decoder -> set(testCell, "x", xID + dir.first); - _decoder -> set(testCell, "y", yID + dir.second); + _decoder->set(testCell, "x", xID + dir.first); + _decoder->set(testCell, "y", yID + dir.second); } catch (const std::runtime_error& err) { // catch overflow error // ignore if invalid position ID @@ -47,8 +46,8 @@ void BarrelTOFNeighborFinder::_findAllNeighborsInSensor( } try { - auto pos = _converter -> position(testCell); - if(testCell != _converter -> cellID(pos)) + auto pos = _converter->position(testCell); + if (testCell != _converter->cellID(pos)) continue; } catch (const std::invalid_argument& err) { // Ignore CellID that is invalid @@ -84,7 +83,6 @@ void BarrelTOFNeighborFinder::_initWithCell(const dd4hep::rec::CellID& hitCell) } } - const std::shared_ptr> BarrelTOFNeighborFinder::findAllNeighborInSensor(const dd4hep::rec::CellID& hitCell) { _initWithCell(hitCell); @@ -108,15 +106,16 @@ BarrelTOFNeighborFinder::findAllNeighborInSensor(const dd4hep::rec::CellID& hitC return neighbors; } -const dd4hep::rec::CellID BarrelTOFNeighborFinder::_getSensorID(const dd4hep::rec::CellID& hitCell) { +const dd4hep::rec::CellID +BarrelTOFNeighborFinder::_getSensorID(const dd4hep::rec::CellID& hitCell) { _initWithCell(hitCell); // fix x-y, what you left with are ids that corresponds to sensor info - // cellID may change when position changes. - auto sensorID = hitCell;//_converter -> cellID(_converter -> position(hitCell)); - _decoder -> set(sensorID, "x", 0); - _decoder -> set(sensorID, "y", 0); + // cellID may change when position changes. + auto sensorID = hitCell; //_converter -> cellID(_converter -> position(hitCell)); + _decoder->set(sensorID, "x", 0); + _decoder->set(sensorID, "y", 0); - return sensorID; + return sensorID; } /**************************************** @@ -160,8 +159,7 @@ BarrelTOFNeighborFinder::local2GlobalInStaveFromCell(const dd4hep::rec::CellID& return position; } -dd4hep::Position -BarrelTOFNeighborFinder::global2Local(const dd4hep::Position& pos) { +dd4hep::Position BarrelTOFNeighborFinder::global2Local(const dd4hep::Position& pos) { // convert local position to global position // assuming the local position is located at the same volume as cell if (!_detector) @@ -173,14 +171,12 @@ BarrelTOFNeighborFinder::global2Local(const dd4hep::Position& pos) { double g[3], l[3]; pos.GetCoordinates(g); - currMatrix->MasterToLocal(g, l); + currMatrix->MasterToLocal(g, l); dd4hep::Position position; - position.SetCoordinates(l); + position.SetCoordinates(l); return position; } - - dd4hep::Position BarrelTOFNeighborFinder::cell2LocalPosition(const dd4hep::rec::CellID& cell) { if (!_detector) throw std::runtime_error("Detector ptr not initialized in BarrelTOFNeighborFinder. Have you " @@ -199,6 +195,7 @@ dd4hep::Position BarrelTOFNeighborFinder::cell2LocalPosition(const dd4hep::rec:: } std::vector BarrelTOFNeighborFinder::cellDimension(const dd4hep::rec::CellID& hitCell) { - if(!_converter) _initWithCell(hitCell); - return _converter -> cellDimensions(hitCell); + if (!_converter) + _initWithCell(hitCell); + return _converter->cellDimensions(hitCell); } diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.h b/src/detectors/BTOF/BarrelTOFNeighborFinder.h index 1b495f4986..b392e760d3 100644 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.h +++ b/src/detectors/BTOF/BarrelTOFNeighborFinder.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Chun Yuen Tsang, Souvik Paul, Prithwish Tribedy +// Date: 10/15/2024 #ifndef BARRELTOFNEIGHBORFINDER_H #define BARRELTOFNEIGHBORFINDER_H @@ -22,15 +25,15 @@ class BarrelTOFNeighborFinder { void useCache(bool value = true) { _useCache = value; }; void setLogger(const std::shared_ptr& log) { _log = log; }; bool isDeadCell(const dd4hep::rec::CellID& hitCell); - const std::shared_ptr> - findAllNeighborInSensor(const dd4hep::rec::CellID& hitCell); + const std::shared_ptr> + findAllNeighborInSensor(const dd4hep::rec::CellID& hitCell); // functions below are helper function. Isn't needed to find neighbors. - dd4hep::Position cell2GlobalPosition(const dd4hep::rec::CellID& cell); - dd4hep::Position cell2LocalPosition(const dd4hep::rec::CellID& cell); - dd4hep::Position global2Local(const dd4hep::Position& pos); - dd4hep::Position local2GlobalInStaveFromCell(const dd4hep::rec::CellID& cell, - const dd4hep::Position& pos); + dd4hep::Position cell2GlobalPosition(const dd4hep::rec::CellID& cell); + dd4hep::Position cell2LocalPosition(const dd4hep::rec::CellID& cell); + dd4hep::Position global2Local(const dd4hep::Position& pos); + dd4hep::Position local2GlobalInStaveFromCell(const dd4hep::rec::CellID& cell, + const dd4hep::Position& pos); dd4hep::rec::CellID globalPosition2Cell(const dd4hep::Position& pos); std::vector cellDimension(const dd4hep::rec::CellID& cell); @@ -42,17 +45,13 @@ class BarrelTOFNeighborFinder { // need to initialize the class with a cell from Barrel TOF void _initWithCell(const dd4hep::rec::CellID& hitCell); - - bool _useCache = true; const dd4hep::DDSegmentation::BitFieldCoder* _decoder = nullptr; const dd4hep::Detector* _detector = nullptr; - std::unique_ptr _converter; - std::shared_ptr _log; - std::unordered_map>> _cache; - + std::unique_ptr _converter; + std::shared_ptr _log; + std::unordered_map>> _cache; }; #endif diff --git a/src/factories/digi/BTOFHitDigi_factory.h b/src/factories/digi/BTOFHitDigi_factory.h index dd192b1126..ec4eed253e 100644 --- a/src/factories/digi/BTOFHitDigi_factory.h +++ b/src/factories/digi/BTOFHitDigi_factory.h @@ -1,3 +1,7 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Chun Yuen Tsang + + #pragma once #include "extensions/jana/JOmniFactory.h" From 8d8a12a24c00a39112854faa28ae82effd59abb8 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Tue, 15 Oct 2024 14:48:36 -0400 Subject: [PATCH 14/77] Included config content in parameter ref. --- src/factories/digi/BTOFHitDigi_factory.h | 91 ++++++++++--------- .../tracking/BTOFHitReconstruction_factory.h | 41 +++++---- 2 files changed, 69 insertions(+), 63 deletions(-) diff --git a/src/factories/digi/BTOFHitDigi_factory.h b/src/factories/digi/BTOFHitDigi_factory.h index ec4eed253e..eee61794f3 100644 --- a/src/factories/digi/BTOFHitDigi_factory.h +++ b/src/factories/digi/BTOFHitDigi_factory.h @@ -1,7 +1,6 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // Copyright (C) 2024 Chun Yuen Tsang - #pragma once #include "extensions/jana/JOmniFactory.h" @@ -13,55 +12,57 @@ namespace eicrecon { class BTOFHitDigi_factory : public JOmniFactory { private: + // Underlying algorithm + std::unique_ptr m_algo; - // Underlying algorithm - std::unique_ptr m_algo; + // Declare inputs + PodioInput m_in_sim_track{this}; //, "TOFBarrelRawHits"}; - // Declare inputs - PodioInput m_in_sim_track {this};//, "TOFBarrelRawHits"}; + // Declare outputs + PodioOutput m_out_reco_particles{this}; - // Declare outputs - PodioOutput m_out_reco_particles{this}; + // Declare services here, e.g. + Service m_geoSvc{this}; - // Declare services here, e.g. - Service m_geoSvc {this}; + ParameterRef m_sigma_sharingx{this, "sigma_sharingx", config().sigma_sharingx}; + ParameterRef m_sigma_sharingy{this, "sigma_sharingy", config().sigma_sharingy}; + ParameterRef m_Vm{this, "Vm", config().Vm}; + ParameterRef m_t_thres{this, "t_thres", config().t_thres}; public: - void Configure() { - // This is called when the factory is instantiated. - // Use this callback to make sure the algorithm is configured. - // The logger, parameters, and services have all been fetched before this is called - m_algo = std::make_unique(); - - // Pass config object to algorithm - m_algo->applyConfig(config()); - - // If we needed geometry, we'd obtain it like so - // m_algo->init(m_geoSvc().detector(), m_geoSvc().converter(), logger()); - - m_algo->init(m_geoSvc().detector(), logger()); - } - - void ChangeRun(int64_t run_number) { - // This is called whenever the run number is changed. - // Use this callback to retrieve state that is keyed off of run number. - // This state should usually be managed by a Service. - // Note: You usually don't need this, because you can declare a Resource instead. - } - - void Process(int64_t run_number, uint64_t event_number) { - // This is called on every event. - // Use this callback to call your Algorithm using all inputs and outputs - // The inputs will have already been fetched for you at this point. - auto output = m_algo->execute( - m_in_sim_track() - ); - - logger()->debug( "Event {}: Found {} reconstructed electron candidates", event_number, output->size() ); - - m_out_reco_particles() = std::move(output); - // JANA will take care of publishing the outputs for you. - } + void Configure() { + // This is called when the factory is instantiated. + // Use this callback to make sure the algorithm is configured. + // The logger, parameters, and services have all been fetched before this is called + m_algo = std::make_unique(); + + // Pass config object to algorithm + m_algo->applyConfig(config()); + + // If we needed geometry, we'd obtain it like so + // m_algo->init(m_geoSvc().detector(), m_geoSvc().converter(), logger()); + + m_algo->init(m_geoSvc().detector(), logger()); + } + + void ChangeRun(int64_t run_number) { + // This is called whenever the run number is changed. + // Use this callback to retrieve state that is keyed off of run number. + // This state should usually be managed by a Service. + // Note: You usually don't need this, because you can declare a Resource instead. + } + + void Process(int64_t run_number, uint64_t event_number) { + // This is called on every event. + // Use this callback to call your Algorithm using all inputs and outputs + // The inputs will have already been fetched for you at this point. + auto output = m_algo->execute(m_in_sim_track()); + + logger()->debug("Event {}: Found {} reconstructed electron candidates", event_number, + output->size()); + + m_out_reco_particles() = std::move(output); + // JANA will take care of publishing the outputs for you. + } }; } // namespace eicrecon - diff --git a/src/factories/tracking/BTOFHitReconstruction_factory.h b/src/factories/tracking/BTOFHitReconstruction_factory.h index 1766b1a8e1..da42c779a1 100644 --- a/src/factories/tracking/BTOFHitReconstruction_factory.h +++ b/src/factories/tracking/BTOFHitReconstruction_factory.h @@ -4,33 +4,38 @@ #pragma once #include "algorithms/tracking/BTOFHitReconstruction.h" -#include "services/geometry/dd4hep/DD4hep_service.h" #include "extensions/jana/JOmniFactory.h" +#include "services/geometry/dd4hep/DD4hep_service.h" namespace eicrecon { -class BTOFHitReconstruction_factory : -public JOmniFactory { - private: - eicrecon::BTOFHitReconstruction m_algo; +class BTOFHitReconstruction_factory + : public JOmniFactory { +private: + eicrecon::BTOFHitReconstruction m_algo; + + PodioInput m_raw_hits_input{this}; + PodioOutput m_rec_hits_output{this}; - PodioInput m_raw_hits_input {this}; - PodioOutput m_rec_hits_output {this}; + Service m_geoSvc{this}; - Service m_geoSvc {this}; + ParameterRef m_c_slope{this, "c_slope", config().c_slope}; + ParameterRef m_c_intercept{this, "c_intercept", config().c_intercept}; + ParameterRef m_t_slope{this, "t_slope", config().t_slope}; + ParameterRef m_t_intercept{this, "t_intercept", config().t_intercept}; + ParameterRef m_use_ave{this, "use_ave", config().use_ave}; public: - void Configure() { - m_algo.applyConfig(config()); - m_algo.init(m_geoSvc().converter(), m_geoSvc().detector(), logger()); - } + void Configure() { + m_algo.applyConfig(config()); + m_algo.init(m_geoSvc().converter(), m_geoSvc().detector(), logger()); + } - void ChangeRun(int64_t run_number) { - } + void ChangeRun(int64_t run_number) {} - void Process(int64_t run_number, uint64_t event_number) { - m_rec_hits_output() = m_algo.process(*m_raw_hits_input()); - } + void Process(int64_t run_number, uint64_t event_number) { + m_rec_hits_output() = m_algo.process(*m_raw_hits_input()); + } }; -} // eicrecon +} // namespace eicrecon From 875f0f49d0ba38b0e941f1b08a7bd3b0df3f143b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 20:08:51 +0000 Subject: [PATCH 15/77] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../tracking/BTOFHitReconstructionConfig.h | 12 ++++++------ src/services/io/podio/JEventProcessorPODIO.cc | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/algorithms/tracking/BTOFHitReconstructionConfig.h b/src/algorithms/tracking/BTOFHitReconstructionConfig.h index a80eb756c0..bbe8653d6a 100644 --- a/src/algorithms/tracking/BTOFHitReconstructionConfig.h +++ b/src/algorithms/tracking/BTOFHitReconstructionConfig.h @@ -6,11 +6,11 @@ namespace eicrecon { struct BTOFHitReconstructionConfig { // parameters that convert ADC to EDep - double c_slope = 3.86976e-7, c_intercept=2.42716e-5; - // parameters that convert TDC to hit time (ns) - double t_slope = 0.0197305, t_intercept = 0.208047; - // if false, we use weighted ADC averages for position. - // By default, the position is just the center of cell with max ADC value in a sensor - bool use_ave = true; + double c_slope = 3.86976e-7, c_intercept=2.42716e-5; + // parameters that convert TDC to hit time (ns) + double t_slope = 0.0197305, t_intercept = 0.208047; + // if false, we use weighted ADC averages for position. + // By default, the position is just the center of cell with max ADC value in a sensor + bool use_ave = true; }; } diff --git a/src/services/io/podio/JEventProcessorPODIO.cc b/src/services/io/podio/JEventProcessorPODIO.cc index fcab82ce77..b69551db6b 100644 --- a/src/services/io/podio/JEventProcessorPODIO.cc +++ b/src/services/io/podio/JEventProcessorPODIO.cc @@ -98,7 +98,7 @@ JEventProcessorPODIO::JEventProcessorPODIO() { "TOFEndcapRawHitAssociations", "CombinedTOFTruthSeededParticleIDs", - "BTOFHitDigi", + "BTOFHitDigi", "CombinedTOFParticleIDs", // DRICH From b12ee388e1dbf24473e72e69bcc9fd1bae8f14fe Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Tue, 15 Oct 2024 16:30:27 -0400 Subject: [PATCH 16/77] Fixed BTOF reco uncertainty estimation bug. --- src/algorithms/tracking/BTOFHitReconstruction.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/algorithms/tracking/BTOFHitReconstruction.cc b/src/algorithms/tracking/BTOFHitReconstruction.cc index 03a39e0c7b..48527f7eff 100644 --- a/src/algorithms/tracking/BTOFHitReconstruction.cc +++ b/src/algorithms/tracking/BTOFHitReconstruction.cc @@ -144,13 +144,19 @@ BTOFHitReconstruction::process(const edm4eic::RawTrackerHitCollection& TDCADC_hi // TDC to time float time = first_tdc * m_cfg.t_slope + m_cfg.t_intercept; // >oO trace + double varX = cellSize[0] / mm; + varX *= varX; + double varY = cellSize[1] / mm; + varY *= varY; + double varZ = cellSize.size() > 2? cellSize[2] / mm : 0; + varZ *= varZ; + if (m_cfg.use_ave) { rec_hits->create(id, edm4hep::Vector3f{static_cast(ave_x / mm), static_cast(ave_y / mm), static_cast(ave_z / mm)}, // mm - edm4eic::CovDiag3f{cellSize[0] / mm, cellSize[1] / mm, - cellSize[2] / mm}, // should be the covariance of position + edm4eic::CovDiag3f{varX, varY, varZ}, // should be the covariance of position time, // ns 0.0F, // covariance of time charge, // total ADC sum @@ -160,8 +166,7 @@ BTOFHitReconstruction::process(const edm4eic::RawTrackerHitCollection& TDCADC_hi edm4hep::Vector3f{static_cast(maxADC_x / mm), static_cast(maxADC_y / mm), static_cast(maxADC_z / mm)}, // mm - edm4eic::CovDiag3f{cellSize[0] / mm, cellSize[1] / mm, - cellSize[2] / mm}, // should be the covariance of position + edm4eic::CovDiag3f{varX, varY, varZ}, // should be the covariance of position time, // ns 0.0F, // covariance of time charge, // total ADC sum From 34f4daaabe68645537f502bc05d599b82ac753cc Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Wed, 23 Oct 2024 10:51:50 -0400 Subject: [PATCH 17/77] Removed reconstruction for later pull request. Breaks TOF digi into three parts: 1. Charge sharing, 2. Pulse generation, 3. Pulse digitization. --- ...BTOFHitDigiConfig.h => TOFHitDigiConfig.h} | 16 +- .../tracking/BTOFHitReconstruction.cc | 180 ---------------- .../tracking/BTOFHitReconstruction.h | 50 ----- .../tracking/BTOFHitReconstructionConfig.h | 16 -- src/detectors/BTOF/BTOF.cc | 43 +++- src/detectors/BTOF/BTOFChargeSharing.cc | 176 +++++++++++++++ src/detectors/BTOF/BTOFChargeSharing.h | 69 ++++++ src/detectors/BTOF/BTOFHitDigi.cc | 196 ----------------- src/detectors/BTOF/BTOFHitDigi.h | 87 -------- src/detectors/BTOF/BarrelTOFNeighborFinder.cc | 201 ------------------ src/detectors/BTOF/BarrelTOFNeighborFinder.h | 57 ----- src/detectors/BTOF/TOFPulseDigitization.cc | 80 +++++++ src/detectors/BTOF/TOFPulseDigitization.h | 50 +++++ src/detectors/BTOF/TOFPulseGeneration.cc | 105 +++++++++ src/detectors/BTOF/TOFPulseGeneration.h | 53 +++++ ..._factory.h => BTOFChargeSharing_factory.h} | 25 +-- .../digi/TOFPulseDigitization_factory.h | 58 +++++ .../digi/TOFPulseGeneration_factory.h | 64 ++++++ .../tracking/BTOFHitReconstruction_factory.h | 41 ---- src/global/reco/reco.cc | 9 - 20 files changed, 714 insertions(+), 862 deletions(-) rename src/algorithms/digi/{BTOFHitDigiConfig.h => TOFHitDigiConfig.h} (59%) delete mode 100644 src/algorithms/tracking/BTOFHitReconstruction.cc delete mode 100644 src/algorithms/tracking/BTOFHitReconstruction.h delete mode 100644 src/algorithms/tracking/BTOFHitReconstructionConfig.h create mode 100644 src/detectors/BTOF/BTOFChargeSharing.cc create mode 100644 src/detectors/BTOF/BTOFChargeSharing.h delete mode 100644 src/detectors/BTOF/BTOFHitDigi.cc delete mode 100644 src/detectors/BTOF/BTOFHitDigi.h delete mode 100644 src/detectors/BTOF/BarrelTOFNeighborFinder.cc delete mode 100644 src/detectors/BTOF/BarrelTOFNeighborFinder.h create mode 100644 src/detectors/BTOF/TOFPulseDigitization.cc create mode 100644 src/detectors/BTOF/TOFPulseDigitization.h create mode 100644 src/detectors/BTOF/TOFPulseGeneration.cc create mode 100644 src/detectors/BTOF/TOFPulseGeneration.h rename src/factories/digi/{BTOFHitDigi_factory.h => BTOFChargeSharing_factory.h} (70%) create mode 100644 src/factories/digi/TOFPulseDigitization_factory.h create mode 100644 src/factories/digi/TOFPulseGeneration_factory.h delete mode 100644 src/factories/tracking/BTOFHitReconstruction_factory.h diff --git a/src/algorithms/digi/BTOFHitDigiConfig.h b/src/algorithms/digi/TOFHitDigiConfig.h similarity index 59% rename from src/algorithms/digi/BTOFHitDigiConfig.h rename to src/algorithms/digi/TOFHitDigiConfig.h index af0d151fa8..94fab4ca96 100644 --- a/src/algorithms/digi/BTOFHitDigiConfig.h +++ b/src/algorithms/digi/TOFHitDigiConfig.h @@ -7,7 +7,7 @@ namespace eicrecon { -struct BTOFHitDigiConfig { +struct TOFHitDigiConfig { // single hit energy deposition threshold double threshold{1.0 * dd4hep::keV}; double tRes = 0.1; /// TODO 8 of what units??? Same TODO in juggler. Probably [ns] @@ -23,8 +23,20 @@ struct BTOFHitDigiConfig { double sigma_analog = 0.293951; double sigma_sharingx = 0.1; double sigma_sharingy = 0.5; - double Vm = -1e-4 * gain; + double Vm = -1e-4 * gain; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage corresponds to ADC = adc_max double t_thres = 0.1 * Vm; + double ignore_thres = 0.01 * Vm; // If EDep below this value, digitization for the cell will be ignored. Speed up calculation + // + double tMin = 0.1; + double tMax = 100.0; + int total_time = ceil(tMax - tMin); + int time_period = 25; + int nBins = 1024; + int adc_bit = 8; + int tdc_bit = 10; + + int adc_range = pow(2, adc_bit); + int tdc_range = pow(2, tdc_bit); }; } // namespace eicrecon diff --git a/src/algorithms/tracking/BTOFHitReconstruction.cc b/src/algorithms/tracking/BTOFHitReconstruction.cc deleted file mode 100644 index 48527f7eff..0000000000 --- a/src/algorithms/tracking/BTOFHitReconstruction.cc +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Chun Yuen Tsang - -#include "BTOFHitReconstruction.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "TMatrixT.h" - -namespace eicrecon { - -void BTOFHitReconstruction::init(const dd4hep::rec::CellIDPositionConverter* converter, - const dd4hep::Detector* detector, - std::shared_ptr& logger) { - - m_log = logger; - - m_converter = converter; - m_detector = detector; -} - -dd4hep::rec::CellID BTOFHitReconstruction::getDetInfos(const dd4hep::rec::CellID& id) { - // retrieve segmentation class if that hasn't been done - if (!m_decoder) { - const auto det = m_converter->findContext(id)->element; - auto readout = m_converter->findReadout(det); - auto seg = readout.segmentation(); - m_decoder = seg.decoder(); - } - - // CellID for BarrelTOF is composed of 6 parts - // system, layer, module, sensor, x, y - // If we fix x and y to zero, what remains will be the detector information only - auto id_return = id; - m_decoder->set(id_return, "x", 0); - m_decoder->set(id_return, "y", 0); - return id_return; -} - -std::unique_ptr -BTOFHitReconstruction::process(const edm4eic::RawTrackerHitCollection& TDCADC_hits) { - using dd4hep::mm; - - auto rec_hits{std::make_unique()}; - - // collection of ADC values from all sensors - std::unordered_map> hitsBySensors; - - for (const auto& TDCADC_hit : TDCADC_hits) { - - auto id = TDCADC_hit.getCellID(); - - // Get position and dimension - auto pos = m_converter->position(id); - // Get sensors info - auto detID = this->getDetInfos(id); - hitsBySensors[detID].emplace_back(pos.x(), pos.y(), pos.z(), int(TDCADC_hit.getCharge()), - int(TDCADC_hit.getTimeStamp()), id); - } - - auto geoManager = m_detector->world().volume()->GetGeoManager(); - - for (const auto& sensor : hitsBySensors) { - // INSERT clustering algorithm for each sensors here - // Right now I just perform a simple average over all hits in a sensors - // Will be problematic near the edges, but it's just an illustration - double ave_x = 0, ave_y = 0, ave_z = 0; - double tot_charge = 0; - const auto& hits = sensor.second; - // find cellID for the cell with maximum ADC value within a sensor - // I don't know why you need cellID for reconstructed hits, but we'll do it anyway - auto id = hits[0].id; - auto curr_adc = hits[0].adc; - auto first_tdc = hits[0].tdc; - double maxADC_x = hits[0].x; - double maxADC_y = hits[0].y; - double maxADC_z = hits[0].z; - - for (const auto& hit : hits) { - // weigh all hits by ADC value - ave_x += hit.adc * hit.x; - ave_y += hit.adc * hit.y; - ave_z += hit.adc * hit.z; - - tot_charge += hit.adc; - if (hit.adc > curr_adc) { - maxADC_x = hit.x; - maxADC_y = hit.y; - maxADC_z = hit.z; - curr_adc = hit.adc; - id = hit.id; - } - first_tdc = std::min(first_tdc, hit.tdc); - } - - ave_x /= tot_charge; - ave_y /= tot_charge; - ave_z /= tot_charge; - - auto cellSize = m_converter->cellDimensions(id); - - /** NVM. covariance is defined in sensor frame - * but the central position is defined in global frame - // get rotation matrix - auto node = geoManager -> FindNode(hits[0].x, hits[0].y, hits[0].z); - auto currMatrix = geoManager -> GetCurrentMatrix(); - auto rotMatrixElements = currMatrix -> GetRotationMatrix(); - - // rotMatrix transforms local coordinates to global coordinates - // see line 342 of https://root.cern.ch/doc/master/TGeoMatrix_8cxx_source.html#l00342 - TMatrixT rot(3, 3, rotMatrixElements); - TMatrixT rotT(3, 3); - rotT.Transpose(rot); - - // loop through each sensors for Hit information - TMatrixT varLocal(3, 3); - for(int i = 0; i < 3; ++i) - for(int j = 0; j < 3; ++j) - varLocal[i][j] = 0; - - - varLocal[0][0] = cellSize[0]*cellSize[0] / mm / mm / 12.; // final division by 12 because I - assumed uniform distribution varLocal[1][1] = cellSize[1]*cellSize[1] / mm / mm / 12.; // Std. - dev of uniformation = width/sqrt(12) varLocal[2][2] = 0; - - // transform variance. see - https://robotics.stackexchange.com/questions/2556/how-to-rotate-covariance auto varGlobal = - rot*varLocal*rotT; - */ - - // adc to charge - float charge = tot_charge * m_cfg.c_slope + m_cfg.c_intercept; - // TDC to time - float time = first_tdc * m_cfg.t_slope + m_cfg.t_intercept; - // >oO trace - double varX = cellSize[0] / mm; - varX *= varX; - double varY = cellSize[1] / mm; - varY *= varY; - double varZ = cellSize.size() > 2? cellSize[2] / mm : 0; - varZ *= varZ; - - if (m_cfg.use_ave) { - rec_hits->create(id, - edm4hep::Vector3f{static_cast(ave_x / mm), - static_cast(ave_y / mm), - static_cast(ave_z / mm)}, // mm - edm4eic::CovDiag3f{varX, varY, varZ}, // should be the covariance of position - time, // ns - 0.0F, // covariance of time - charge, // total ADC sum - 0.0F); // Error on the energy - } else { - rec_hits->create(id, - edm4hep::Vector3f{static_cast(maxADC_x / mm), - static_cast(maxADC_y / mm), - static_cast(maxADC_z / mm)}, // mm - edm4eic::CovDiag3f{varX, varY, varZ}, // should be the covariance of position - time, // ns - 0.0F, // covariance of time - charge, // total ADC sum - 0.0F); // Error on the energy - } - } - - return std::move(rec_hits); -} - -} // namespace eicrecon diff --git a/src/algorithms/tracking/BTOFHitReconstruction.h b/src/algorithms/tracking/BTOFHitReconstruction.h deleted file mode 100644 index 53cf7305fd..0000000000 --- a/src/algorithms/tracking/BTOFHitReconstruction.h +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Chun Yuen Tsang - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "BTOFHitReconstructionConfig.h" -#include "algorithms/interfaces/WithPodConfig.h" - -namespace eicrecon { - -/** - * Produces edm4eic::TrackerHit with geometric info from edm4eic::RawTrackerHit - */ -class BTOFHitReconstruction : public WithPodConfig { - -public: - /// Once in a lifetime initialization - void init(const dd4hep::rec::CellIDPositionConverter* converter, const dd4hep::Detector* detector, - std::shared_ptr& logger); - - /// Processes RawTrackerHit and produces a TrackerHit - std::unique_ptr - process(const edm4eic::RawTrackerHitCollection& TDCADC_hits); - -private: - struct HitInfo { - double x, y, z; - int adc, tdc; - dd4hep::rec::CellID id; - }; - dd4hep::rec::CellID getDetInfos(const dd4hep::rec::CellID& id); - /** algorithm logger */ - std::shared_ptr m_log; - - /// Cell ID position converter - const dd4hep::rec::CellIDPositionConverter* m_converter = nullptr; - - /// fetch sensor information from cellID - const dd4hep::DDSegmentation::BitFieldCoder* m_decoder = nullptr; - - const dd4hep::Detector* m_detector = nullptr; -}; -} // namespace eicrecon diff --git a/src/algorithms/tracking/BTOFHitReconstructionConfig.h b/src/algorithms/tracking/BTOFHitReconstructionConfig.h deleted file mode 100644 index bbe8653d6a..0000000000 --- a/src/algorithms/tracking/BTOFHitReconstructionConfig.h +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Chun Yuen Tsang - -#pragma once - -namespace eicrecon { - struct BTOFHitReconstructionConfig { - // parameters that convert ADC to EDep - double c_slope = 3.86976e-7, c_intercept=2.42716e-5; - // parameters that convert TDC to hit time (ns) - double t_slope = 0.0197305, t_intercept = 0.208047; - // if false, we use weighted ADC averages for position. - // By default, the position is just the center of cell with max ADC value in a sensor - bool use_ave = true; - }; -} diff --git a/src/detectors/BTOF/BTOF.cc b/src/detectors/BTOF/BTOF.cc index cf30eca342..1bb05e9bd6 100644 --- a/src/detectors/BTOF/BTOF.cc +++ b/src/detectors/BTOF/BTOF.cc @@ -17,7 +17,10 @@ #include "algorithms/pid_lut/PIDLookupConfig.h" #include "extensions/jana/JOmniFactoryGeneratorT.h" #include "factories/digi/SiliconTrackerDigi_factory.h" -#include "factories/tracking/BTOFHitReconstruction_factory.h" +#include "factories/tracking/TrackerHitReconstruction_factory.h" +#include "factories/digi/BTOFChargeSharing_factory.h" +#include "factories/digi/TOFPulseGeneration_factory.h" +#include "factories/digi/TOFPulseDigitization_factory.h" #include "global/pid_lut/PIDLookup_factory.h" #include "services/geometry/dd4hep/DD4hep_service.h" @@ -36,12 +39,40 @@ void InitPlugin(JApplication* app) { }, app)); - // Convert raw digitized hits into hits with geometry info (ready for tracking) - app->Add(new JOmniFactoryGeneratorT( - "TOFBarrelRecHit", {"TOFBarrelADCTDC"}, // Input data collection tags - {"TOFBarrelRecHit"}, // Output data tag +// Convert raw digitized hits into hits with geometry info (ready for tracking) + app->Add(new JOmniFactoryGeneratorT( + "TOFBarrelRecHit", + {"TOFBarrelRawHit"}, // Input data collection tags + {"TOFBarrelRecHit"}, // Output data tag + { + .timeResolution = 10, + }, + app + )); // Hit reco default config for factories + + app->Add(new JOmniFactoryGeneratorT( + "BTOFChargeSharing", + {"TOFBarrelHits"}, + {"TOFBarrelSharedHits"}, + {}, + app + )); + + app->Add(new JOmniFactoryGeneratorT( + "BTOFPulseGeneration", + {"TOFBarrelSharedHits"}, + {"TOFBarrelPulse"}, + {}, + app + )); + + app->Add(new JOmniFactoryGeneratorT( + "BTOFPulseDigitization", + {"TOFBarrelPulse"}, + {"TOFBarrelADCTDC"}, {}, - app)); // Hit reco default config for factories + app + )); int BarrelTOF_ID = 0; try { diff --git a/src/detectors/BTOF/BTOFChargeSharing.cc b/src/detectors/BTOF/BTOFChargeSharing.cc new file mode 100644 index 0000000000..bd6be8df9e --- /dev/null +++ b/src/detectors/BTOF/BTOFChargeSharing.cc @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Chun Yuen Tsang, Prithwish Tribedy +// +// Spread energy desposition from one strip to neighboring strips within sensor boundaries + +// Author: Chun Yuen Tsang +// Date: 10/22/2024 + +#include "DD4hep/Detector.h" +#include "DDRec/Surface.h" +#include "TF1.h" +#include "TMath.h" +#include +#include +#include +#include +#include +#include + +#include "BTOFChargeSharing.h" +#include "Math/SpecFunc.h" +#include "algorithms/digi/TOFHitDigiConfig.h" +#include + +// using namespace dd4hep; +// using namespace dd4hep::Geometry; +// using namespace dd4hep::DDRec; +// using namespace eicrecon; +using namespace dd4hep::xml; + +namespace eicrecon { + +void BTOFChargeSharing::init() { + m_detector = algorithms::GeoSvc::instance().detector();; + m_converter = algorithms::GeoSvc::instance().cellIDPositionConverter(); + + auto seg = m_detector->readout("TOFBarrelHits").segmentation(); + auto type = seg.type(); + if (type != "CartesianGridXY") + throw std::runtime_error("Unsupported segmentation type: " + type + + ". BarrelTOF must use CartesianGridXY."); + // retrieve meaning of cellID bits + m_decoder = seg.decoder(); +} + +void BTOFChargeSharing::_findAllNeighborsInSensor( + dd4hep::rec::CellID hitCell, std::shared_ptr>& ans, + std::unordered_set& dp) const { + // use MST to find all neighbor within a sensor + // I can probably write down the formula by hand, but why do things manually when computer do + // everything for you? + const std::vector> searchDirs{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + ans->push_back(hitCell); + dp.insert(hitCell); + + auto sensorID = this -> _getSensorID(hitCell); + auto xID = m_decoder->get(hitCell, "x"); + auto yID = m_decoder->get(hitCell, "y"); + for (const auto& dir : searchDirs) { + auto testCell = hitCell; + try { + m_decoder->set(testCell, "x", xID + dir.first); + m_decoder->set(testCell, "y", yID + dir.second); + } catch (const std::runtime_error& err) { + // catch overflow error + // ignore if invalid position ID + continue; + } + + try { + auto pos = m_converter->position(testCell); + if (testCell != m_converter->cellID(pos)) + continue; + } catch (const std::invalid_argument& err) { + // Ignore CellID that is invalid + continue; + } + + // only look for cells that have not been searched + if (dp.find(testCell) == dp.end()) { + auto testSensorID = _getSensorID(testCell); + if (testSensorID == sensorID) { + // inside the same sensor + this->_findAllNeighborsInSensor(testCell, ans, dp); + } + } + } +} + +const dd4hep::rec::CellID +BTOFChargeSharing::_getSensorID(const dd4hep::rec::CellID& hitCell) const { + // fix x-y, what you left with are ids that corresponds to sensor info + // cellID may change when position changes. + auto sensorID = hitCell; //_converter -> cellID(_converter -> position(hitCell)); + m_decoder->set(sensorID, "x", 0); + m_decoder->set(sensorID, "y", 0); + + return sensorID; +} + +double BTOFChargeSharing::_integralGaus(double mean, double sd, double low_lim, double up_lim) const { + // return integral Gauss(mean, sd) dx from x = low_lim to x = up_lim + double up = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - up_lim) / sd); + double low = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - low_lim) / sd); + return up - low; +} + +dd4hep::Position BTOFChargeSharing::_cell2LocalPosition(const dd4hep::rec::CellID& cell) const { + auto geoManager = m_detector->world().volume()->GetGeoManager(); + auto position = m_converter -> position(cell); // global position + auto node = geoManager->FindNode(position.x(), position.y(), position.z()); + auto currMatrix = geoManager->GetCurrentMatrix(); + + double g[3], l[3]; + position.GetCoordinates(g); + currMatrix->MasterToLocal(g, l); + position.SetCoordinates(l); + return position; +} + +void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, + const BTOFChargeSharing::Output& output) const { + const auto [simhits] = input; + auto [sharedHits] = output; + std::shared_ptr> neighbors; + + for(const auto & hit : *simhits) { + auto cellID = hit.getCellID(); + /*if(m_useCache) { + auto it = m_cache.find(cellID); + if(it != m_cache.end()) + neighbors = it -> second; + }*/ + + if(!neighbors){ + std::unordered_set dp; + neighbors = std::make_shared>(); + this -> _findAllNeighborsInSensor(cellID, neighbors, dp); + + // fill cache + /*if(m_useCache) + for(const auto cell : *neighbors) + m_cache[cell] = neighbors;*/ + } + + double edep = hit.getEDep(); + double time = hit.getTime(); + auto momentum = hit.getMomentum(); + auto localPos_hit = this -> _cell2LocalPosition(cellID); + + for(const auto neighbor : *neighbors) { + // integrate over neighbor area to get total energy deposition + auto localPos_neighbor = this -> _cell2LocalPosition(neighbor); + auto cellDimension = m_converter -> cellDimensions(neighbor); + + double edep_cell = edep * + _integralGaus(localPos_hit.x(), m_cfg.sigma_sharingx, + localPos_neighbor.x() - 0.5 * cellDimension[0], + localPos_neighbor.x() + 0.5 * cellDimension[0]) * + _integralGaus(localPos_hit.y(), m_cfg.sigma_sharingy, + localPos_neighbor.y() - 0.5 * cellDimension[1], + localPos_neighbor.y() + 0.5 * cellDimension[1]); + + if(edep_cell > 0) { + auto globalPos = m_converter -> position(neighbor); + auto hit = sharedHits->create(); + hit.setCellID(neighbor); + hit.setEDep(edep_cell); + hit.setTime(time); + hit.setPosition({globalPos.x(), globalPos.y(), globalPos.z()}); + hit.setMomentum({momentum.x, momentum.y, momentum.z}); + } + } + } +} // BTOFChargeSharing:process +} // namespace eicrecon diff --git a/src/detectors/BTOF/BTOFChargeSharing.h b/src/detectors/BTOF/BTOFChargeSharing.h new file mode 100644 index 0000000000..81ad5005f5 --- /dev/null +++ b/src/detectors/BTOF/BTOFChargeSharing.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Chun Yuen Tsang, Prithwish Tribedy +// +// Spread energy desposition from one strip to neighboring strips within sensor boundaries + +// Author: Chun Yuen Tsang +// Date: 10/22/2024 + +#pragma once + +#include "TF1.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "DD4hep/Detector.h" +#include "DDRec/Surface.h" +#include + +#include "algorithms/digi/TOFHitDigiConfig.h" +#include "algorithms/interfaces/WithPodConfig.h" + +namespace eicrecon { + +using BTOFChargeSharingAlgorithm = + algorithms::Algorithm, + algorithms::Output>; + +class BTOFChargeSharing : public BTOFChargeSharingAlgorithm, + public WithPodConfig { + +public: + BTOFChargeSharing(std::string_view name) : BTOFChargeSharingAlgorithm{name, + {"TOFBarrelHits"}, + {"TOFBarrelSharedHits"}, + ""} {}; + + void init() final; + void process(const Input&, const Output&) const final; +protected: + void _findAllNeighborsInSensor(dd4hep::rec::CellID hitCell, + std::shared_ptr>& ans, + std::unordered_set& dp) const; + const dd4hep::rec::CellID _getSensorID(const dd4hep::rec::CellID& hitCell) const; + double _integralGaus(double mean, double sd, double low_lim, double up_lim) const; + dd4hep::Position _cell2LocalPosition(const dd4hep::rec::CellID& cell) const; + + + // can't cache our results if process has to be const + //bool m_useCache = true; + const dd4hep::DDSegmentation::BitFieldCoder* m_decoder = nullptr; + const dd4hep::Detector* m_detector = nullptr; + const dd4hep::rec::CellIDPositionConverter* m_converter = nullptr; + + //std::unordered_map>> m_cache; + +}; + +} // namespace eicrecon diff --git a/src/detectors/BTOF/BTOFHitDigi.cc b/src/detectors/BTOF/BTOFHitDigi.cc deleted file mode 100644 index 5df9d3047d..0000000000 --- a/src/detectors/BTOF/BTOFHitDigi.cc +++ /dev/null @@ -1,196 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy -// Special Acknowledgement: Kolja Kauder - -// A general digitization for BToFHit from simulation -// 1. Smear energy deposit with a/sqrt(E/GeV) + b + c/E or a/sqrt(E/GeV) (relative value) -// 2. Digitize the energy with dynamic ADC range and add pedestal (mean +- sigma) -// 3. Time conversion with smearing resolution (absolute value) -// 4. Signal is summed if the SumFields are provided -// -// Author: Souvik Paul, Chun Yuen Tsang -// Date: 19/07/2024 - -#include "DD4hep/Detector.h" -#include "DDRec/Surface.h" -#include "TF1.h" -#include "TMath.h" -#include -#include -#include -#include -#include -#include - -#include "BTOFHitDigi.h" -#include "Math/SpecFunc.h" -#include "algorithms/digi/BTOFHitDigiConfig.h" - -// using namespace dd4hep; -// using namespace dd4hep::Geometry; -// using namespace dd4hep::DDRec; -// using namespace eicrecon; -using namespace dd4hep::xml; - -namespace eicrecon { - -std::vector BTOFHitDigi::ToDigitalCode(int value, int numBits) { - std::bitset<32> binary(value); // Convert integer to binary representation - std::vector digitalCode; - - for (int i = numBits - 1; i >= 0; --i) { - digitalCode.push_back(binary.test(i)); - } - - return digitalCode; -} - -void BTOFHitDigi::init(const dd4hep::Detector* detector, std::shared_ptr& logger) { - // m_detector = detector; - m_log = logger; - - adc_range = pow(2, adc_bit); - tdc_range = pow(2, tdc_bit); - - // using juggler internal units (GeV, mm, radian, ns) - tRes = m_cfg.tRes / dd4hep::ns; - stepTDC = dd4hep::ns / m_cfg.resolutionTDC; - - _neighborFinder.init(detector); -} - -double BTOFHitDigi::_integralGaus(double mean, double sd, double low_lim, double up_lim) { - double up = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - up_lim) / sd); - double low = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - low_lim) / sd); - return up - low; -} - -std::unique_ptr -BTOFHitDigi::execute(const edm4hep::SimTrackerHitCollection* simhits) { - // auto rawhits = std::make_unique(); - auto rawhits = std::make_unique(); - // const auto [sim_hits] = simhits; - - // find the hits that belong to the same group (for merging) - std::unordered_map> merge_map; - std::size_t ix = 0; - for (const auto& ahit : *simhits) { - uint64_t hid = ahit.getCellID(); - merge_map[hid].push_back(ix); - - ix++; - } - - double thres[int(adc_range)]; - thres[0] = 0.0; - thres[1] = m_cfg.t_thres; - // double Vm=-0.05; - // SP noted that max dE experienced by LGAD should be 0.8 keV - double Vm = m_cfg.Vm; - - for (int t = 2; t < adc_range; t++) { - thres[t] = thres[1] + t * (Vm - thres[1]) / (adc_range - 1); - } - - double scalingFactor; - - // signal sum - // NOTE: we take the cellID of the most energetic hit in this group so it is a real cellID from an - // MC hit - for (const auto& [id, ixs] : merge_map) { - double edep = 0; - double time = 0; // std::numeric_limits::max(); - double max_edep = 0; - auto mid = (*simhits)[ixs[0]].getCellID(); - auto truePos = (*simhits)[ixs[0]].getPosition(); - auto localPos_hit = _neighborFinder.global2Local( - dd4hep::Position(truePos.x / 10., truePos.y / 10., truePos.z / 10.)); - auto cellDimension = _neighborFinder.cellDimension(mid); - - double sum_charge = 0.0; - double mpv_analog = 0.0; // SP - - // sum energy, take time from the most energetic hit - for (size_t i = 0; i < ixs.size(); ++i) { - auto hit = (*simhits)[ixs[i]]; - - time = hit.getTime(); - edep = hit.getEDep(); - sum_charge = edep * m_cfg.gain; - - // Use DetPosProcessor to process hits - // m_detPosProcessor->ProcessSequential(hit); - - auto neighbours = _neighborFinder.findAllNeighborInSensor( - mid); // Accessing NeighbourFinder through DetPosProcessor - - for (const auto& neighbour : *neighbours) { - - auto localPos_neighbour = _neighborFinder.cell2LocalPosition(neighbour); - - double charge = sum_charge * - _integralGaus(localPos_hit.x(), m_cfg.sigma_sharingx, - localPos_neighbour.x() - 0.5 * cellDimension[0], - localPos_neighbour.x() + 0.5 * cellDimension[0]) * - _integralGaus(localPos_hit.y(), m_cfg.sigma_sharingy, - localPos_neighbour.y() - 0.5 * cellDimension[1], - localPos_neighbour.y() + 0.5 * cellDimension[1]); - - // Added by SP - //------------------------------------------------------------- - mpv_analog = time + m_cfg.risetime; - fLandau.SetParameters(mpv_analog, m_cfg.sigma_analog); - - TGraph glandau; - scalingFactor = -charge / Vm / fLandau.GetMinimum(tMin, tMax) * adc_range; - for (int j = 0; j < nBins; ++j) { - double x = fLandau.GetXmin() + j * (fLandau.GetXmax() - fLandau.GetXmin()) / (nBins - 1); - double y = -1 * fLandau.Eval(x) * scalingFactor; - glandau.SetPoint(j, x, y); - } - - // Added by SP - //------------------------------------------------------------- - double intersectionX = 0.0; - int tdc = std::numeric_limits::max(); - int adc = 0; - double V = 0.0; - - for (int j = 0; j < nBins - 1; j++) { - double x1, y1, x2, y2; - glandau.GetPoint(j, x1, y1); - glandau.GetPoint(j + 1, x2, y2); - - double norm_threshold = -thres[1] * adc_range / Vm; - if (y1 >= norm_threshold && y2 <= norm_threshold) { - intersectionX = x1 + (x2 - x1) * (norm_threshold - y1) / (y2 - y1); - - tdc = /*BTOFHitDigi::ToDigitalCode(*/ ceil(intersectionX / 0.02); //, tdc_bit); - for (; j < nBins - 1; j++) { - // double x1, y1, x2, y2; - glandau.GetPoint(j, x1, y1); - glandau.GetPoint(j + 1, x2, y2); - - if (abs(y2) < abs(y1)) // To get peak of the Analog signal - { - V = y1; - break; - } - } - break; - } - } - - // limit the range of adc values - adc = std::min(static_cast(adc_range), round(-V)); - // only store valid hits - if (tdc < std::numeric_limits::max() && adc > 0) - rawhits->create(neighbour, adc, tdc); - } - //----------------------------------------------------------- - } - } - return std::move(rawhits); - -} // BTOFHitDigi:process -} // namespace eicrecon diff --git a/src/detectors/BTOF/BTOFHitDigi.h b/src/detectors/BTOF/BTOFHitDigi.h deleted file mode 100644 index b3732fb2fc..0000000000 --- a/src/detectors/BTOF/BTOFHitDigi.h +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy -// Special Acknowledgement: Kolja Kauder - -// A general digitization for CalorimeterHit from simulation -// 1. Smear energy deposit with a/sqrt(E/GeV) + b + c/E or a/sqrt(E/GeV) (relative value) -// 2. Digitize the energy with dynamic ADC range and add pedestal (mean +- sigma) -// 3. Time conversion with smearing resolution (absolute value) -// 4. Signal is summed if the SumFields are provided -// -// Author: Souvik Paul, Chun Yuen Tsang -// Date: 19/07/2024 - -#pragma once - -#include "TF1.h" -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "DD4hep/Detector.h" -#include "DDRec/Surface.h" -#include - -#include "BarrelTOFNeighborFinder.h" -#include "algorithms/digi/BTOFHitDigiConfig.h" -#include "algorithms/interfaces/WithPodConfig.h" - -namespace eicrecon { - -class BTOFHitDigi : public WithPodConfig { - -public: - BTOFHitDigi() - : fLandau( - "landau", - [](Double_t* x, Double_t* par) { - Double_t mean = par[0]; // Mean - Double_t std = par[1]; // Standard deviation - Double_t C = -113.766; - - Double_t landau = C * TMath::Landau((x[0]), mean, std, kTRUE); - - return landau; - }, - tMin, tMax, 2) {} - - void init(const dd4hep::Detector* detector, std::shared_ptr& logger); - - std::unique_ptr - execute(const edm4hep::SimTrackerHitCollection* simhits); - std::vector ToDigitalCode(int value, int numBits); - -protected: - BarrelTOFNeighborFinder _neighborFinder; - std::shared_ptr m_log; - double _integralGaus(double mean, double sd, double low_lim, double up_lim); - - // unitless counterparts of inputs - double dyRangeADC{0}, stepTDC{0}, tRes{0}; - const double pi = TMath::Pi(); - const double tMin = 0.1; - const double tMax = 100.0; - const int total_time = ceil(tMax - tMin); - const int time_period = 25; - const int nBins = 10000; - const int adc_bit = 8; - const int tdc_bit = 10; - - int adc_range; - int tdc_range; - - uint64_t id_mask{0}; - TF1 fLandau; - - std::default_random_engine generator; // TODO: need something more appropriate here - std::normal_distribution m_normDist; // defaults to mean=0, sigma=1 -}; - -} // namespace eicrecon diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc b/src/detectors/BTOF/BarrelTOFNeighborFinder.cc deleted file mode 100644 index 6e27a4c8c2..0000000000 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.cc +++ /dev/null @@ -1,201 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Chun Yuen Tsang, Souvik Paul, Prithwish Tribedy -// Date: 10/15/2024 - -#include "BarrelTOFNeighborFinder.h" -#include "services/geometry/richgeo/RichGeo.h" - -// Include appropriate class headers. e.g. -#include "TAxis.h" -#include "TCanvas.h" -#include "TGeoManager.h" - -#include -#include - -void BarrelTOFNeighborFinder::init(const dd4hep::Detector* detector) { - // you need to init the class before calling any other methods - // What about RAII? - _detector = detector; - _converter = std::make_unique(*detector); -} - -// return cell bin (defined internally within DetPosProcessor) list for all neighbors in a sensor -void BarrelTOFNeighborFinder::_findAllNeighborsInSensor( - dd4hep::rec::CellID hitCell, std::shared_ptr>& ans, - std::unordered_set& dp) { - // use MST to find all neighbor within a sensor - // I can probably write down the formula by hand, but why do things manually when computer do - // everything for you? - const std::vector> searchDirs{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; - ans->push_back(hitCell); - dp.insert(hitCell); - - auto sensorID = _getSensorID(hitCell); - auto xID = _decoder->get(hitCell, "x"); - auto yID = _decoder->get(hitCell, "y"); - for (const auto& dir : searchDirs) { - auto testCell = hitCell; - try { - _decoder->set(testCell, "x", xID + dir.first); - _decoder->set(testCell, "y", yID + dir.second); - } catch (const std::runtime_error& err) { - // catch overflow error - // ignore if invalid position ID - continue; - } - - try { - auto pos = _converter->position(testCell); - if (testCell != _converter->cellID(pos)) - continue; - } catch (const std::invalid_argument& err) { - // Ignore CellID that is invalid - continue; - } - - // only look for cells that have not been searched - if (dp.find(testCell) == dp.end()) { - auto testSensorID = _getSensorID(testCell); - if (testSensorID == sensorID) { - // inside the same sensor - this->_findAllNeighborsInSensor(testCell, ans, dp); - } - } - } -} - -void BarrelTOFNeighborFinder::_initWithCell(const dd4hep::rec::CellID& hitCell) { - if (!_decoder) { - // cell dimensions, cellID converter and bit decoder will be fetched on first use - if (_log) - _log->info("Retrieving cellID decoder."); - // retrieve segmentation class - const auto det = _converter->findContext(hitCell)->element; - auto readout = _converter->findReadout(det); - auto seg = readout.segmentation(); - auto type = seg.type(); - if (type != "CartesianGridXY") - throw std::runtime_error("Unsupported segmentation type: " + type + - ". BarrelTOF must use CartesianGridXY."); - // retrieve meaning of cellID bits - _decoder = seg.decoder(); - } -} - -const std::shared_ptr> -BarrelTOFNeighborFinder::findAllNeighborInSensor(const dd4hep::rec::CellID& hitCell) { - _initWithCell(hitCell); - // look for cache. If exist, return cache value - if (_useCache) { - auto it = _cache.find(hitCell); - if (it != _cache.end()) - return it->second; - } - - std::unordered_set dp; - // fill cache - std::shared_ptr> neighbors = - std::make_shared>(); - this->_findAllNeighborsInSensor(hitCell, neighbors, dp); - - if (_useCache) - for (auto cell : *neighbors) - _cache[cell] = neighbors; - - return neighbors; -} - -const dd4hep::rec::CellID -BarrelTOFNeighborFinder::_getSensorID(const dd4hep::rec::CellID& hitCell) { - _initWithCell(hitCell); - // fix x-y, what you left with are ids that corresponds to sensor info - // cellID may change when position changes. - auto sensorID = hitCell; //_converter -> cellID(_converter -> position(hitCell)); - _decoder->set(sensorID, "x", 0); - _decoder->set(sensorID, "y", 0); - - return sensorID; -} - -/**************************************** - * Functions below aren't needed anymore to find neighbors - * They are still handy so I keep them - * *************************************/ -dd4hep::Position BarrelTOFNeighborFinder::cell2GlobalPosition(const dd4hep::rec::CellID& cell) { - if (!_converter) - throw std::runtime_error( - "CellIDPositionConverter not initialized in BarrelTOFNeighborFinder. Have you called " - "BarrelTOFNeighborFinder::init(/* detector */) first?"); - return _converter->position(cell); -} - -dd4hep::rec::CellID BarrelTOFNeighborFinder::globalPosition2Cell(const dd4hep::Position& pos) { - if (!_converter) - throw std::runtime_error( - "CellIDPositionConverter not initialized in BarrelTOFNeighborFinder. Have you called " - "BarrelTOFNeighborFinder::init(/* detector */) first?"); - return _converter->cellID(pos); -} - -dd4hep::Position -BarrelTOFNeighborFinder::local2GlobalInStaveFromCell(const dd4hep::rec::CellID& cell, - const dd4hep::Position& pos) { - // convert local position to global position - // assuming the local position is located at the same volume as cell - if (!_detector) - throw std::runtime_error("Detector ptr not initialized in BarrelTOFNeighborFinder. Have you " - "called BarrelTOFNeighborFinder::init(/* detector */) first?"); - - auto geoManager = _detector->world().volume()->GetGeoManager(); - auto position = this->cell2GlobalPosition(cell); - auto node = geoManager->FindNode(position.x(), position.y(), position.z()); - auto currMatrix = geoManager->GetCurrentMatrix(); - - double g[3], l[3]; - pos.GetCoordinates(l); - currMatrix->LocalToMaster(l, g); // <- only different from cell2LocalPosition - position.SetCoordinates(g); // <- only different from cell2LocalPosition - return position; -} - -dd4hep::Position BarrelTOFNeighborFinder::global2Local(const dd4hep::Position& pos) { - // convert local position to global position - // assuming the local position is located at the same volume as cell - if (!_detector) - throw std::runtime_error("Detector ptr not initialized in BarrelTOFNeighborFinder. Have you " - "called BarrelTOFNeighborFinder::init(/* detector */) first?"); - auto geoManager = _detector->world().volume()->GetGeoManager(); - auto node = geoManager->FindNode(pos.x(), pos.y(), pos.z()); - auto currMatrix = geoManager->GetCurrentMatrix(); - - double g[3], l[3]; - pos.GetCoordinates(g); - currMatrix->MasterToLocal(g, l); - dd4hep::Position position; - position.SetCoordinates(l); - return position; -} - -dd4hep::Position BarrelTOFNeighborFinder::cell2LocalPosition(const dd4hep::rec::CellID& cell) { - if (!_detector) - throw std::runtime_error("Detector ptr not initialized in BarrelTOFNeighborFinder. Have you " - "called BarrelTOFNeighborFinder::init(/* detector */) first?"); - - auto geoManager = _detector->world().volume()->GetGeoManager(); - auto position = this->cell2GlobalPosition(cell); - auto node = geoManager->FindNode(position.x(), position.y(), position.z()); - auto currMatrix = geoManager->GetCurrentMatrix(); - - double g[3], l[3]; - position.GetCoordinates(g); - currMatrix->MasterToLocal(g, l); - position.SetCoordinates(l); - return position; -} - -std::vector BarrelTOFNeighborFinder::cellDimension(const dd4hep::rec::CellID& hitCell) { - if (!_converter) - _initWithCell(hitCell); - return _converter->cellDimensions(hitCell); -} diff --git a/src/detectors/BTOF/BarrelTOFNeighborFinder.h b/src/detectors/BTOF/BarrelTOFNeighborFinder.h deleted file mode 100644 index b392e760d3..0000000000 --- a/src/detectors/BTOF/BarrelTOFNeighborFinder.h +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Chun Yuen Tsang, Souvik Paul, Prithwish Tribedy -// Date: 10/15/2024 - -#ifndef BARRELTOFNEIGHBORFINDER_H -#define BARRELTOFNEIGHBORFINDER_H - -#include -#include -#include -#include -#include -#include - -#include "TGeoMatrix.h" -#include -#include -#include -#include -#include - -class BarrelTOFNeighborFinder { -public: - void init(const dd4hep::Detector* detector); - void useCache(bool value = true) { _useCache = value; }; - void setLogger(const std::shared_ptr& log) { _log = log; }; - bool isDeadCell(const dd4hep::rec::CellID& hitCell); - const std::shared_ptr> - findAllNeighborInSensor(const dd4hep::rec::CellID& hitCell); - - // functions below are helper function. Isn't needed to find neighbors. - dd4hep::Position cell2GlobalPosition(const dd4hep::rec::CellID& cell); - dd4hep::Position cell2LocalPosition(const dd4hep::rec::CellID& cell); - dd4hep::Position global2Local(const dd4hep::Position& pos); - dd4hep::Position local2GlobalInStaveFromCell(const dd4hep::rec::CellID& cell, - const dd4hep::Position& pos); - dd4hep::rec::CellID globalPosition2Cell(const dd4hep::Position& pos); - std::vector cellDimension(const dd4hep::rec::CellID& cell); - -private: - void _findAllNeighborsInSensor(dd4hep::rec::CellID hitCell, - std::shared_ptr>& ans, - std::unordered_set& dp); - const dd4hep::rec::CellID _getSensorID(const dd4hep::rec::CellID& hitCell); - // need to initialize the class with a cell from Barrel TOF - void _initWithCell(const dd4hep::rec::CellID& hitCell); - - bool _useCache = true; - const dd4hep::DDSegmentation::BitFieldCoder* _decoder = nullptr; - const dd4hep::Detector* _detector = nullptr; - - std::unique_ptr _converter; - std::shared_ptr _log; - std::unordered_map>> _cache; -}; - -#endif diff --git a/src/detectors/BTOF/TOFPulseDigitization.cc b/src/detectors/BTOF/TOFPulseDigitization.cc new file mode 100644 index 0000000000..209428aac0 --- /dev/null +++ b/src/detectors/BTOF/TOFPulseDigitization.cc @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy +// Special Acknowledgement: Kolja Kauder +// +// Convert ADC pulses from TOFPulseGeneration into ADC and TDC values +// +// Author: Souvik Paul, Chun Yuen Tsang +// Date: 22/10/2024 + +#include "DD4hep/Detector.h" +#include "DDRec/Surface.h" +#include "TF1.h" +#include "TMath.h" +#include +#include +#include +#include +#include +#include + +#include "TOFPulseDigitization.h" +#include "Math/SpecFunc.h" +#include "algorithms/digi/TOFHitDigiConfig.h" + +// using namespace dd4hep; +// using namespace dd4hep::Geometry; +// using namespace dd4hep::DDRec; +// using namespace eicrecon; +using namespace dd4hep::xml; + +namespace eicrecon { + +void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, + const TOFPulseDigitization::Output& output) const { + const auto [simhits] = input; + auto [rawhits] = output; + + double thres = m_cfg.t_thres; + // double Vm=-0.05; + // SP noted that max dE experienced by LGAD should be 0.8 keV + double Vm = m_cfg.Vm; + int adc_range = m_cfg.adc_range; + + // normalized time threshold + // convert threshold EDep to voltage + double norm_threshold = -thres * adc_range / Vm; + + for(const auto& pulse : *simhits) { + // Added by SP + //------------------------------------------------------------- + double intersectionX = 0.0; + int tdc = std::numeric_limits::max(); + int adc = 0; + double V = 0.0; + + int time_bin = 0; + double adc_prev = 0; + double time_interval = pulse.getInterval(); + auto adcs = pulse.getAdcCounts(); + for (const auto adc : adcs) { + if (adc_prev >= norm_threshold && adc <= norm_threshold) { + intersectionX = time_bin*time_interval + time_interval * (norm_threshold - adc_prev) / (adc - adc_prev); + tdc = ceil(intersectionX / 0.02); + } + if (abs(adc) > abs(V)) // To get peak of the Analog signal + V = adc; + adc_prev = adc; + ++time_bin; + } + + // limit the range of adc values + adc = std::min(static_cast(adc_range), round(-V)); + // only store valid hits + if (tdc < std::numeric_limits::max()) + rawhits->create(pulse.getCellID(), adc, tdc); + //----------------------------------------------------------- + + } +} // TOFPulseDigitization:process +} // namespace eicrecon diff --git a/src/detectors/BTOF/TOFPulseDigitization.h b/src/detectors/BTOF/TOFPulseDigitization.h new file mode 100644 index 0000000000..79afaddd72 --- /dev/null +++ b/src/detectors/BTOF/TOFPulseDigitization.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy +// Special Acknowledgement: Kolja Kauder +// +// Convert ADC pulses from TOFPulseGeneration into ADC and TDC values +// +// Author: Souvik Paul, Chun Yuen Tsang +// Date: 22/10/2024 + +#pragma once + +#include "TF1.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "DD4hep/Detector.h" +#include "DDRec/Surface.h" +#include + +#include "algorithms/digi/TOFHitDigiConfig.h" +#include "algorithms/interfaces/WithPodConfig.h" + +namespace eicrecon { + +using TOFPulseDigitizationAlgorithm = + algorithms::Algorithm, + algorithms::Output>; + +class TOFPulseDigitization : public TOFPulseDigitizationAlgorithm, + public WithPodConfig { + +public: + TOFPulseDigitization(std::string_view name) : + TOFPulseDigitizationAlgorithm{name, + {"TOFBarrelPulse"}, + {"TOFBarrelADCTDC"}, + {}} {} + void init() {}; + void process(const Input&, const Output&) const final; +}; + +} // namespace eicrecon diff --git a/src/detectors/BTOF/TOFPulseGeneration.cc b/src/detectors/BTOF/TOFPulseGeneration.cc new file mode 100644 index 0000000000..baf3024792 --- /dev/null +++ b/src/detectors/BTOF/TOFPulseGeneration.cc @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy +// Special Acknowledgement: Kolja Kauder +// +// Convert energy deposition into ADC pulses +// ADC pulses are assumed to follow the shape of landau function +// +// Author: Souvik Paul, Chun Yuen Tsang +// Date: 22/10/2024 + +#include "DD4hep/Detector.h" +#include "DDRec/Surface.h" +#include "TF1.h" +#include "TMath.h" +#include +#include +#include +#include +#include +#include + +#include "TOFPulseGeneration.h" +#include "Math/SpecFunc.h" +#include "algorithms/digi/TOFHitDigiConfig.h" + +// using namespace dd4hep; +// using namespace dd4hep::Geometry; +// using namespace dd4hep::DDRec; +// using namespace eicrecon; +using namespace dd4hep::xml; + +namespace eicrecon { + +double TOFPulseGeneration::_Landau(double x, double mean, double std) const { + double C = -113.755; + return C * TMath::Landau(x, mean, std, kTRUE); +} + +void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, + const TOFPulseGeneration::Output& output) const { + const auto [simhits] = input; + auto [rawADCs] = output; + + // SP noted that max dE experienced by LGAD should be 0.8 keV + double Vm = m_cfg.Vm; + double tMin = m_cfg.tMin; + double tMax = m_cfg.tMax; + int adc_range = m_cfg.adc_range; + int tdc_range = m_cfg.tdc_range; + int nBins = m_cfg.nBins; + + // signal sum + // NOTE: we take the cellID of the most energetic hit in this group so it is a real cellID from an + // MC hit + std::unordered_map> adc_sum; + double interval = (tMax - tMin) / (nBins - 1); + + for (const auto& hit : *simhits) { + auto cellID = hit.getCellID(); + double sum_charge = 0.0; + double mpv_analog = 0.0; // SP + + double time = hit.getTime(); + double charge = hit.getEDep() * m_cfg.gain; + // reduce computation power by not simulating low-charge hits + if(charge < m_cfg.ignore_thres) continue; + + auto& ADCs = adc_sum[cellID]; + if(ADCs.size() == 0) ADCs.resize(nBins, 0); + + // Added by SP + //------------------------------------------------------------- + mpv_analog = time + m_cfg.risetime; + + double landau_min = this -> _Landau(0, mpv_analog, m_cfg.sigma_analog); + // find minimum of the landau function + // minimum = peak because prefactor is negative + for (int j = 0; j < nBins; ++j) { + double x = tMin + j * interval; + landau_min = std::min(landau_min, this -> _Landau(x, mpv_analog, m_cfg.sigma_analog)); + } + + double scalingFactor = -1. / Vm / landau_min * adc_range; + + for (int j = 0; j < nBins; ++j) { + double x = tMin + j * interval; + double y = -1 * charge * this -> _Landau(x, mpv_analog, m_cfg.sigma_analog) * scalingFactor; + ADCs[j] += y;; + } + + } + + // convert vector of ADC values to RawTimeSeries + for(const auto &[cellID, ADCs] : adc_sum) { + auto time_series = rawADCs -> create(); + time_series.setCellID(cellID); + time_series.setTime(1.); // placeholder. Don't know what to assign when there are two or more hits + time_series.setCharge(1.); // placeholder. Don't know what to assign when there are two or more hits + time_series.setInterval(interval); + + for(const auto ADC : ADCs) + time_series.addToAdcCounts(ADC); + } +} // TOFPulseGeneration:process +} // namespace eicrecon diff --git a/src/detectors/BTOF/TOFPulseGeneration.h b/src/detectors/BTOF/TOFPulseGeneration.h new file mode 100644 index 0000000000..2f79becc4a --- /dev/null +++ b/src/detectors/BTOF/TOFPulseGeneration.h @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy +// Special Acknowledgement: Kolja Kauder +// +// Convert energy deposition into ADC pulses +// ADC pulses are assumed to follow the shape of landau function +// +// Author: Souvik Paul, Chun Yuen Tsang +// Date: 22/10/2024 + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "DD4hep/Detector.h" +#include "DDRec/Surface.h" +#include + +#include "algorithms/digi/TOFHitDigiConfig.h" +#include "algorithms/interfaces/WithPodConfig.h" + +namespace eicrecon { + +using TOFPulseGenerationAlgorithm = + algorithms::Algorithm, + algorithms::Output>; + +class TOFPulseGeneration : public TOFPulseGenerationAlgorithm, + public WithPodConfig { + +public: + TOFPulseGeneration(std::string_view name) + : TOFPulseGenerationAlgorithm{name, + {"TOFBarrelSharedHits"}, + {"TOFBarrelPulse"}, + {}} {} + void init() {}; + void process(const Input&, const Output&) const final; + +protected: + double _Landau(double x, double mean, double std) const; +}; + +} // namespace eicrecon diff --git a/src/factories/digi/BTOFHitDigi_factory.h b/src/factories/digi/BTOFChargeSharing_factory.h similarity index 70% rename from src/factories/digi/BTOFHitDigi_factory.h rename to src/factories/digi/BTOFChargeSharing_factory.h index eee61794f3..0039da79c0 100644 --- a/src/factories/digi/BTOFHitDigi_factory.h +++ b/src/factories/digi/BTOFChargeSharing_factory.h @@ -5,44 +5,40 @@ #include "extensions/jana/JOmniFactory.h" -#include "detectors/BTOF/BTOFHitDigi.h" +#include "detectors/BTOF/BTOFChargeSharing.h" #include namespace eicrecon { -class BTOFHitDigi_factory : public JOmniFactory { +class BTOFChargeSharing_factory : public JOmniFactory { private: // Underlying algorithm - std::unique_ptr m_algo; + std::unique_ptr m_algo; // Declare inputs PodioInput m_in_sim_track{this}; //, "TOFBarrelRawHits"}; // Declare outputs - PodioOutput m_out_reco_particles{this}; + PodioOutput m_out_reco_particles{this}; // Declare services here, e.g. Service m_geoSvc{this}; ParameterRef m_sigma_sharingx{this, "sigma_sharingx", config().sigma_sharingx}; ParameterRef m_sigma_sharingy{this, "sigma_sharingy", config().sigma_sharingy}; - ParameterRef m_Vm{this, "Vm", config().Vm}; - ParameterRef m_t_thres{this, "t_thres", config().t_thres}; - public: void Configure() { // This is called when the factory is instantiated. // Use this callback to make sure the algorithm is configured. // The logger, parameters, and services have all been fetched before this is called - m_algo = std::make_unique(); - + m_algo = std::make_unique(GetPrefix()); + m_algo->level(static_cast(logger()->level())); // Pass config object to algorithm m_algo->applyConfig(config()); // If we needed geometry, we'd obtain it like so // m_algo->init(m_geoSvc().detector(), m_geoSvc().converter(), logger()); - - m_algo->init(m_geoSvc().detector(), logger()); + m_algo->init(); } void ChangeRun(int64_t run_number) { @@ -56,12 +52,7 @@ class BTOFHitDigi_factory : public JOmniFactoryexecute(m_in_sim_track()); - - logger()->debug("Event {}: Found {} reconstructed electron candidates", event_number, - output->size()); - - m_out_reco_particles() = std::move(output); + m_algo->process({m_in_sim_track()}, {m_out_reco_particles().get()}); // JANA will take care of publishing the outputs for you. } }; diff --git a/src/factories/digi/TOFPulseDigitization_factory.h b/src/factories/digi/TOFPulseDigitization_factory.h new file mode 100644 index 0000000000..6f9c49b27a --- /dev/null +++ b/src/factories/digi/TOFPulseDigitization_factory.h @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Chun Yuen Tsang + +#pragma once + +#include "extensions/jana/JOmniFactory.h" + +#include "detectors/BTOF/TOFPulseDigitization.h" +#include + +namespace eicrecon { + +class TOFPulseDigitization_factory : public JOmniFactory { +private: + // Underlying algorithm + std::unique_ptr m_algo; + + // Declare inputs + PodioInput m_in_sim_track{this}; //, "TOFBarrelRawHits"}; + + // Declare outputs + PodioOutput m_out_reco_particles{this}; + + // Declare services here, e.g. + Service m_geoSvc{this}; + + ParameterRef m_t_thres{this, "t_thres", config().t_thres}; +public: + void Configure() { + // This is called when the factory is instantiated. + // Use this callback to make sure the algorithm is configured. + // The logger, parameters, and services have all been fetched before this is called + m_algo = std::make_unique(GetPrefix()); + m_algo->level(static_cast(logger()->level())); + // Pass config object to algorithm + m_algo->applyConfig(config()); + + // If we needed geometry, we'd obtain it like so + // m_algo->init(m_geoSvc().detector(), m_geoSvc().converter(), logger()); + m_algo->init(); + } + + void ChangeRun(int64_t run_number) { + // This is called whenever the run number is changed. + // Use this callback to retrieve state that is keyed off of run number. + // This state should usually be managed by a Service. + // Note: You usually don't need this, because you can declare a Resource instead. + } + + void Process(int64_t run_number, uint64_t event_number) { + // This is called on every event. + // Use this callback to call your Algorithm using all inputs and outputs + // The inputs will have already been fetched for you at this point. + m_algo->process({m_in_sim_track()}, {m_out_reco_particles().get()}); + // JANA will take care of publishing the outputs for you. + } +}; +} // namespace eicrecon diff --git a/src/factories/digi/TOFPulseGeneration_factory.h b/src/factories/digi/TOFPulseGeneration_factory.h new file mode 100644 index 0000000000..340aa63f60 --- /dev/null +++ b/src/factories/digi/TOFPulseGeneration_factory.h @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Chun Yuen Tsang + +#pragma once + +#include "extensions/jana/JOmniFactory.h" + +#include "detectors/BTOF/TOFPulseGeneration.h" +#include + +namespace eicrecon { + +class TOFPulseGeneration_factory : public JOmniFactory { +private: + // Underlying algorithm + std::unique_ptr m_algo; + + // Declare inputs + PodioInput m_in_sim_track{this}; //, "TOFBarrelRawHits"}; + + // Declare outputs + PodioOutput m_out_reco_particles{this}; + + // Declare services here, e.g. + Service m_geoSvc{this}; + + ParameterRef m_Vm{this, "Vm", config().Vm}; + ParameterRef m_tMin{this, "tMin", config().tMin}; + ParameterRef m_tMax{this, "tMax", config().tMax}; + ParameterRef m_adc_range{this, "adc_range", config().adc_range}; + ParameterRef m_tdc_range{this, "tdc_range", config().tdc_range}; + ParameterRef m_nBins{this, "nBins", config().nBins}; + ParameterRef m_ignore_thres{this, "ignore_thres", config().ignore_thres}; +public: + void Configure() { + // This is called when the factory is instantiated. + // Use this callback to make sure the algorithm is configured. + // The logger, parameters, and services have all been fetched before this is called + m_algo = std::make_unique(GetPrefix()); + m_algo->level(static_cast(logger()->level())); + // Pass config object to algorithm + m_algo->applyConfig(config()); + + // If we needed geometry, we'd obtain it like so + // m_algo->init(m_geoSvc().detector(), m_geoSvc().converter(), logger()); + m_algo->init(); + } + + void ChangeRun(int64_t run_number) { + // This is called whenever the run number is changed. + // Use this callback to retrieve state that is keyed off of run number. + // This state should usually be managed by a Service. + // Note: You usually don't need this, because you can declare a Resource instead. + } + + void Process(int64_t run_number, uint64_t event_number) { + // This is called on every event. + // Use this callback to call your Algorithm using all inputs and outputs + // The inputs will have already been fetched for you at this point. + m_algo->process({m_in_sim_track()}, {m_out_reco_particles().get()}); + // JANA will take care of publishing the outputs for you. + } +}; +} // namespace eicrecon diff --git a/src/factories/tracking/BTOFHitReconstruction_factory.h b/src/factories/tracking/BTOFHitReconstruction_factory.h deleted file mode 100644 index da42c779a1..0000000000 --- a/src/factories/tracking/BTOFHitReconstruction_factory.h +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2023 Wouter Deconinck - -#pragma once - -#include "algorithms/tracking/BTOFHitReconstruction.h" -#include "extensions/jana/JOmniFactory.h" -#include "services/geometry/dd4hep/DD4hep_service.h" - -namespace eicrecon { - -class BTOFHitReconstruction_factory - : public JOmniFactory { -private: - eicrecon::BTOFHitReconstruction m_algo; - - PodioInput m_raw_hits_input{this}; - PodioOutput m_rec_hits_output{this}; - - Service m_geoSvc{this}; - - ParameterRef m_c_slope{this, "c_slope", config().c_slope}; - ParameterRef m_c_intercept{this, "c_intercept", config().c_intercept}; - ParameterRef m_t_slope{this, "t_slope", config().t_slope}; - ParameterRef m_t_intercept{this, "t_intercept", config().t_intercept}; - ParameterRef m_use_ave{this, "use_ave", config().use_ave}; - -public: - void Configure() { - m_algo.applyConfig(config()); - m_algo.init(m_geoSvc().converter(), m_geoSvc().detector(), logger()); - } - - void ChangeRun(int64_t run_number) {} - - void Process(int64_t run_number, uint64_t event_number) { - m_rec_hits_output() = m_algo.process(*m_raw_hits_input()); - } -}; - -} // namespace eicrecon diff --git a/src/global/reco/reco.cc b/src/global/reco/reco.cc index 5b85f81ed1..0c8e373bcc 100644 --- a/src/global/reco/reco.cc +++ b/src/global/reco/reco.cc @@ -41,7 +41,6 @@ #if EDM4EIC_VERSION_MAJOR >= 6 #include "factories/reco/HadronicFinalState_factory.h" #endif -#include "factories/digi/BTOFHitDigi_factory.h" #include "factories/reco/UndoAfterBurnerMCParticles_factory.h" #include "global/reco/ChargedReconstructedParticleSelector_factory.h" #include "global/reco/MC2SmearedParticle_factory.h" @@ -401,13 +400,5 @@ void InitPlugin(JApplication *app) { )); - app->Add(new JOmniFactoryGeneratorT( - "BTOFHitDigi", - {"TOFBarrelHits"}, - {"TOFBarrelADCTDC"}, - {}, - app - )); - } } // extern "C" From 9ab01c9c40ab6d9650055a4ed2caebb23c29b827 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:52:48 +0000 Subject: [PATCH 18/77] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/TOFHitDigiConfig.h | 2 +- src/detectors/BTOF/BTOFChargeSharing.cc | 18 +++++++++--------- src/detectors/BTOF/BTOFChargeSharing.h | 18 +++++++++--------- src/detectors/BTOF/TOFPulseDigitization.cc | 8 ++++---- src/detectors/BTOF/TOFPulseDigitization.h | 14 +++++++------- src/detectors/BTOF/TOFPulseGeneration.cc | 4 ++-- src/detectors/BTOF/TOFPulseGeneration.h | 12 ++++++------ 7 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/algorithms/digi/TOFHitDigiConfig.h b/src/algorithms/digi/TOFHitDigiConfig.h index 94fab4ca96..572b6a5151 100644 --- a/src/algorithms/digi/TOFHitDigiConfig.h +++ b/src/algorithms/digi/TOFHitDigiConfig.h @@ -26,7 +26,7 @@ struct TOFHitDigiConfig { double Vm = -1e-4 * gain; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage corresponds to ADC = adc_max double t_thres = 0.1 * Vm; double ignore_thres = 0.01 * Vm; // If EDep below this value, digitization for the cell will be ignored. Speed up calculation - // + // double tMin = 0.1; double tMax = 100.0; int total_time = ceil(tMax - tMin); diff --git a/src/detectors/BTOF/BTOFChargeSharing.cc b/src/detectors/BTOF/BTOFChargeSharing.cc index bd6be8df9e..3ac517aa17 100644 --- a/src/detectors/BTOF/BTOFChargeSharing.cc +++ b/src/detectors/BTOF/BTOFChargeSharing.cc @@ -1,6 +1,6 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // Copyright (C) 2024 Chun Yuen Tsang, Prithwish Tribedy -// +// // Spread energy desposition from one strip to neighboring strips within sensor boundaries // Author: Chun Yuen Tsang @@ -118,8 +118,8 @@ dd4hep::Position BTOFChargeSharing::_cell2LocalPosition(const dd4hep::rec::CellI return position; } -void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, - const BTOFChargeSharing::Output& output) const { +void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, + const BTOFChargeSharing::Output& output) const { const auto [simhits] = input; auto [sharedHits] = output; std::shared_ptr> neighbors; @@ -131,14 +131,14 @@ void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, if(it != m_cache.end()) neighbors = it -> second; }*/ - - if(!neighbors){ + + if(!neighbors){ std::unordered_set dp; neighbors = std::make_shared>(); this -> _findAllNeighborsInSensor(cellID, neighbors, dp); // fill cache - /*if(m_useCache) + /*if(m_useCache) for(const auto cell : *neighbors) m_cache[cell] = neighbors;*/ } @@ -152,7 +152,7 @@ void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, // integrate over neighbor area to get total energy deposition auto localPos_neighbor = this -> _cell2LocalPosition(neighbor); auto cellDimension = m_converter -> cellDimensions(neighbor); - + double edep_cell = edep * _integralGaus(localPos_hit.x(), m_cfg.sigma_sharingx, localPos_neighbor.x() - 0.5 * cellDimension[0], @@ -164,8 +164,8 @@ void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, if(edep_cell > 0) { auto globalPos = m_converter -> position(neighbor); auto hit = sharedHits->create(); - hit.setCellID(neighbor); - hit.setEDep(edep_cell); + hit.setCellID(neighbor); + hit.setEDep(edep_cell); hit.setTime(time); hit.setPosition({globalPos.x(), globalPos.y(), globalPos.z()}); hit.setMomentum({momentum.x, momentum.y, momentum.z}); diff --git a/src/detectors/BTOF/BTOFChargeSharing.h b/src/detectors/BTOF/BTOFChargeSharing.h index 81ad5005f5..0672860ba8 100644 --- a/src/detectors/BTOF/BTOFChargeSharing.h +++ b/src/detectors/BTOF/BTOFChargeSharing.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // Copyright (C) 2024 Chun Yuen Tsang, Prithwish Tribedy -// +// // Spread energy desposition from one strip to neighboring strips within sensor boundaries // Author: Chun Yuen Tsang @@ -32,18 +32,18 @@ namespace eicrecon { -using BTOFChargeSharingAlgorithm = - algorithms::Algorithm, - algorithms::Output>; +using BTOFChargeSharingAlgorithm = + algorithms::Algorithm, + algorithms::Output>; -class BTOFChargeSharing : public BTOFChargeSharingAlgorithm, - public WithPodConfig { +class BTOFChargeSharing : public BTOFChargeSharingAlgorithm, + public WithPodConfig { public: BTOFChargeSharing(std::string_view name) : BTOFChargeSharingAlgorithm{name, - {"TOFBarrelHits"}, - {"TOFBarrelSharedHits"}, - ""} {}; + {"TOFBarrelHits"}, + {"TOFBarrelSharedHits"}, + ""} {}; void init() final; void process(const Input&, const Output&) const final; diff --git a/src/detectors/BTOF/TOFPulseDigitization.cc b/src/detectors/BTOF/TOFPulseDigitization.cc index 209428aac0..f5010a071f 100644 --- a/src/detectors/BTOF/TOFPulseDigitization.cc +++ b/src/detectors/BTOF/TOFPulseDigitization.cc @@ -30,8 +30,8 @@ using namespace dd4hep::xml; namespace eicrecon { -void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, - const TOFPulseDigitization::Output& output) const { +void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, + const TOFPulseDigitization::Output& output) const { const auto [simhits] = input; auto [rawhits] = output; @@ -41,7 +41,7 @@ void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, double Vm = m_cfg.Vm; int adc_range = m_cfg.adc_range; - // normalized time threshold + // normalized time threshold // convert threshold EDep to voltage double norm_threshold = -thres * adc_range / Vm; @@ -74,7 +74,7 @@ void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, if (tdc < std::numeric_limits::max()) rawhits->create(pulse.getCellID(), adc, tdc); //----------------------------------------------------------- - + } } // TOFPulseDigitization:process } // namespace eicrecon diff --git a/src/detectors/BTOF/TOFPulseDigitization.h b/src/detectors/BTOF/TOFPulseDigitization.h index 79afaddd72..5398fb4d40 100644 --- a/src/detectors/BTOF/TOFPulseDigitization.h +++ b/src/detectors/BTOF/TOFPulseDigitization.h @@ -30,19 +30,19 @@ namespace eicrecon { -using TOFPulseDigitizationAlgorithm = - algorithms::Algorithm, - algorithms::Output>; +using TOFPulseDigitizationAlgorithm = + algorithms::Algorithm, + algorithms::Output>; class TOFPulseDigitization : public TOFPulseDigitizationAlgorithm, - public WithPodConfig { + public WithPodConfig { public: - TOFPulseDigitization(std::string_view name) : - TOFPulseDigitizationAlgorithm{name, + TOFPulseDigitization(std::string_view name) : + TOFPulseDigitizationAlgorithm{name, {"TOFBarrelPulse"}, {"TOFBarrelADCTDC"}, - {}} {} + {}} {} void init() {}; void process(const Input&, const Output&) const final; }; diff --git a/src/detectors/BTOF/TOFPulseGeneration.cc b/src/detectors/BTOF/TOFPulseGeneration.cc index baf3024792..046782dea4 100644 --- a/src/detectors/BTOF/TOFPulseGeneration.cc +++ b/src/detectors/BTOF/TOFPulseGeneration.cc @@ -37,7 +37,7 @@ double TOFPulseGeneration::_Landau(double x, double mean, double std) const { } void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, - const TOFPulseGeneration::Output& output) const { + const TOFPulseGeneration::Output& output) const { const auto [simhits] = input; auto [rawADCs] = output; @@ -98,7 +98,7 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, time_series.setCharge(1.); // placeholder. Don't know what to assign when there are two or more hits time_series.setInterval(interval); - for(const auto ADC : ADCs) + for(const auto ADC : ADCs) time_series.addToAdcCounts(ADC); } } // TOFPulseGeneration:process diff --git a/src/detectors/BTOF/TOFPulseGeneration.h b/src/detectors/BTOF/TOFPulseGeneration.h index 2f79becc4a..7d0e0a3618 100644 --- a/src/detectors/BTOF/TOFPulseGeneration.h +++ b/src/detectors/BTOF/TOFPulseGeneration.h @@ -30,17 +30,17 @@ namespace eicrecon { -using TOFPulseGenerationAlgorithm = - algorithms::Algorithm, - algorithms::Output>; +using TOFPulseGenerationAlgorithm = + algorithms::Algorithm, + algorithms::Output>; class TOFPulseGeneration : public TOFPulseGenerationAlgorithm, - public WithPodConfig { + public WithPodConfig { public: TOFPulseGeneration(std::string_view name) - : TOFPulseGenerationAlgorithm{name, - {"TOFBarrelSharedHits"}, + : TOFPulseGenerationAlgorithm{name, + {"TOFBarrelSharedHits"}, {"TOFBarrelPulse"}, {}} {} void init() {}; From 4cf121655b51ca06d256b6f0ede7b119ce39c909 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Wed, 23 Oct 2024 11:11:33 -0400 Subject: [PATCH 19/77] Removed legacy modification to JEventProcessorPODIO.cc --- src/services/io/podio/JEventProcessorPODIO.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/services/io/podio/JEventProcessorPODIO.cc b/src/services/io/podio/JEventProcessorPODIO.cc index b69551db6b..f510c3df52 100644 --- a/src/services/io/podio/JEventProcessorPODIO.cc +++ b/src/services/io/podio/JEventProcessorPODIO.cc @@ -98,7 +98,6 @@ JEventProcessorPODIO::JEventProcessorPODIO() { "TOFEndcapRawHitAssociations", "CombinedTOFTruthSeededParticleIDs", - "BTOFHitDigi", "CombinedTOFParticleIDs", // DRICH From 14889debe1ddc1facd27ab1426511041c35f3362 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Wed, 23 Oct 2024 12:42:44 -0400 Subject: [PATCH 20/77] Fixed bugs on charge sharing calculation. It was assumed that all geant hits on BTOF occurs at the center of a BTOF cell. That may not be true. It has been fixed. --- src/detectors/BTOF/BTOFChargeSharing.cc | 14 ++++++++++---- src/detectors/BTOF/BTOFChargeSharing.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/detectors/BTOF/BTOFChargeSharing.cc b/src/detectors/BTOF/BTOFChargeSharing.cc index 3ac517aa17..629c034c2a 100644 --- a/src/detectors/BTOF/BTOFChargeSharing.cc +++ b/src/detectors/BTOF/BTOFChargeSharing.cc @@ -106,14 +106,19 @@ double BTOFChargeSharing::_integralGaus(double mean, double sd, double low_lim, } dd4hep::Position BTOFChargeSharing::_cell2LocalPosition(const dd4hep::rec::CellID& cell) const { - auto geoManager = m_detector->world().volume()->GetGeoManager(); auto position = m_converter -> position(cell); // global position - auto node = geoManager->FindNode(position.x(), position.y(), position.z()); + return this -> _global2Local(position); +} + +dd4hep::Position BTOFChargeSharing::_global2Local(const dd4hep::Position& pos) const { + auto geoManager = m_detector->world().volume()->GetGeoManager(); + auto node = geoManager->FindNode(pos.x(), pos.y(), pos.z()); auto currMatrix = geoManager->GetCurrentMatrix(); double g[3], l[3]; - position.GetCoordinates(g); + pos.GetCoordinates(g); currMatrix->MasterToLocal(g, l); + dd4hep::Position position; position.SetCoordinates(l); return position; } @@ -146,7 +151,8 @@ void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, double edep = hit.getEDep(); double time = hit.getTime(); auto momentum = hit.getMomentum(); - auto localPos_hit = this -> _cell2LocalPosition(cellID); + auto truePos = hit.getPosition(); + auto localPos_hit = this -> _global2Local(dd4hep::Position(truePos.x / 10., truePos.y / 10., truePos.z / 10.)); for(const auto neighbor : *neighbors) { // integrate over neighbor area to get total energy deposition diff --git a/src/detectors/BTOF/BTOFChargeSharing.h b/src/detectors/BTOF/BTOFChargeSharing.h index 0672860ba8..33108909b8 100644 --- a/src/detectors/BTOF/BTOFChargeSharing.h +++ b/src/detectors/BTOF/BTOFChargeSharing.h @@ -54,6 +54,7 @@ class BTOFChargeSharing : public BTOFChargeSharingAlgorithm, const dd4hep::rec::CellID _getSensorID(const dd4hep::rec::CellID& hitCell) const; double _integralGaus(double mean, double sd, double low_lim, double up_lim) const; dd4hep::Position _cell2LocalPosition(const dd4hep::rec::CellID& cell) const; + dd4hep::Position _global2Local(const dd4hep::Position& pos) const; // can't cache our results if process has to be const From 569090d486ca825f0493561effe95eba6331cbd2 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Wed, 23 Oct 2024 17:31:05 -0400 Subject: [PATCH 21/77] Moved algorithms away from src/detectors. --- src/{detectors/BTOF => algorithms/digi}/BTOFChargeSharing.cc | 0 src/{detectors/BTOF => algorithms/digi}/BTOFChargeSharing.h | 0 src/{detectors/BTOF => algorithms/digi}/TOFPulseDigitization.cc | 0 src/{detectors/BTOF => algorithms/digi}/TOFPulseDigitization.h | 0 src/{detectors/BTOF => algorithms/digi}/TOFPulseGeneration.cc | 0 src/{detectors/BTOF => algorithms/digi}/TOFPulseGeneration.h | 0 src/factories/digi/BTOFChargeSharing_factory.h | 2 +- src/factories/digi/TOFPulseDigitization_factory.h | 2 +- src/factories/digi/TOFPulseGeneration_factory.h | 2 +- 9 files changed, 3 insertions(+), 3 deletions(-) rename src/{detectors/BTOF => algorithms/digi}/BTOFChargeSharing.cc (100%) rename src/{detectors/BTOF => algorithms/digi}/BTOFChargeSharing.h (100%) rename src/{detectors/BTOF => algorithms/digi}/TOFPulseDigitization.cc (100%) rename src/{detectors/BTOF => algorithms/digi}/TOFPulseDigitization.h (100%) rename src/{detectors/BTOF => algorithms/digi}/TOFPulseGeneration.cc (100%) rename src/{detectors/BTOF => algorithms/digi}/TOFPulseGeneration.h (100%) diff --git a/src/detectors/BTOF/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc similarity index 100% rename from src/detectors/BTOF/BTOFChargeSharing.cc rename to src/algorithms/digi/BTOFChargeSharing.cc diff --git a/src/detectors/BTOF/BTOFChargeSharing.h b/src/algorithms/digi/BTOFChargeSharing.h similarity index 100% rename from src/detectors/BTOF/BTOFChargeSharing.h rename to src/algorithms/digi/BTOFChargeSharing.h diff --git a/src/detectors/BTOF/TOFPulseDigitization.cc b/src/algorithms/digi/TOFPulseDigitization.cc similarity index 100% rename from src/detectors/BTOF/TOFPulseDigitization.cc rename to src/algorithms/digi/TOFPulseDigitization.cc diff --git a/src/detectors/BTOF/TOFPulseDigitization.h b/src/algorithms/digi/TOFPulseDigitization.h similarity index 100% rename from src/detectors/BTOF/TOFPulseDigitization.h rename to src/algorithms/digi/TOFPulseDigitization.h diff --git a/src/detectors/BTOF/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc similarity index 100% rename from src/detectors/BTOF/TOFPulseGeneration.cc rename to src/algorithms/digi/TOFPulseGeneration.cc diff --git a/src/detectors/BTOF/TOFPulseGeneration.h b/src/algorithms/digi/TOFPulseGeneration.h similarity index 100% rename from src/detectors/BTOF/TOFPulseGeneration.h rename to src/algorithms/digi/TOFPulseGeneration.h diff --git a/src/factories/digi/BTOFChargeSharing_factory.h b/src/factories/digi/BTOFChargeSharing_factory.h index 0039da79c0..36c6095269 100644 --- a/src/factories/digi/BTOFChargeSharing_factory.h +++ b/src/factories/digi/BTOFChargeSharing_factory.h @@ -5,7 +5,7 @@ #include "extensions/jana/JOmniFactory.h" -#include "detectors/BTOF/BTOFChargeSharing.h" +#include "algorithms/digi/BTOFChargeSharing.h" #include namespace eicrecon { diff --git a/src/factories/digi/TOFPulseDigitization_factory.h b/src/factories/digi/TOFPulseDigitization_factory.h index 6f9c49b27a..76ad3da4f4 100644 --- a/src/factories/digi/TOFPulseDigitization_factory.h +++ b/src/factories/digi/TOFPulseDigitization_factory.h @@ -5,7 +5,7 @@ #include "extensions/jana/JOmniFactory.h" -#include "detectors/BTOF/TOFPulseDigitization.h" +#include "algorithms/digi/TOFPulseDigitization.h" #include namespace eicrecon { diff --git a/src/factories/digi/TOFPulseGeneration_factory.h b/src/factories/digi/TOFPulseGeneration_factory.h index 340aa63f60..fe08cfd3db 100644 --- a/src/factories/digi/TOFPulseGeneration_factory.h +++ b/src/factories/digi/TOFPulseGeneration_factory.h @@ -5,7 +5,7 @@ #include "extensions/jana/JOmniFactory.h" -#include "detectors/BTOF/TOFPulseGeneration.h" +#include "algorithms/digi/TOFPulseGeneration.h" #include namespace eicrecon { From 33c65871e90e1e6b8fd499712a738aae43b8b859 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Thu, 24 Oct 2024 16:08:34 -0400 Subject: [PATCH 22/77] Fix spelling mistakes to make codespell happy. --- src/algorithms/digi/BTOFChargeSharing.cc | 8 ++++---- src/algorithms/digi/BTOFChargeSharing.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index 629c034c2a..1bc2dc3a3b 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // Copyright (C) 2024 Chun Yuen Tsang, Prithwish Tribedy // -// Spread energy desposition from one strip to neighboring strips within sensor boundaries +// Spread energy deposition from one strip to neighboring strips within sensor boundaries // Author: Chun Yuen Tsang // Date: 10/22/2024 @@ -44,13 +44,13 @@ void BTOFChargeSharing::init() { } void BTOFChargeSharing::_findAllNeighborsInSensor( - dd4hep::rec::CellID hitCell, std::shared_ptr>& ans, + dd4hep::rec::CellID hitCell, std::shared_ptr>& answer, std::unordered_set& dp) const { // use MST to find all neighbor within a sensor // I can probably write down the formula by hand, but why do things manually when computer do // everything for you? const std::vector> searchDirs{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; - ans->push_back(hitCell); + answer->push_back(hitCell); dp.insert(hitCell); auto sensorID = this -> _getSensorID(hitCell); @@ -81,7 +81,7 @@ void BTOFChargeSharing::_findAllNeighborsInSensor( auto testSensorID = _getSensorID(testCell); if (testSensorID == sensorID) { // inside the same sensor - this->_findAllNeighborsInSensor(testCell, ans, dp); + this->_findAllNeighborsInSensor(testCell, answer, dp); } } } diff --git a/src/algorithms/digi/BTOFChargeSharing.h b/src/algorithms/digi/BTOFChargeSharing.h index 33108909b8..30a55e3eab 100644 --- a/src/algorithms/digi/BTOFChargeSharing.h +++ b/src/algorithms/digi/BTOFChargeSharing.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // Copyright (C) 2024 Chun Yuen Tsang, Prithwish Tribedy // -// Spread energy desposition from one strip to neighboring strips within sensor boundaries +// Spread energy deposition from one strip to neighboring strips within sensor boundaries // Author: Chun Yuen Tsang // Date: 10/22/2024 @@ -49,7 +49,7 @@ class BTOFChargeSharing : public BTOFChargeSharingAlgorithm, void process(const Input&, const Output&) const final; protected: void _findAllNeighborsInSensor(dd4hep::rec::CellID hitCell, - std::shared_ptr>& ans, + std::shared_ptr>& answer, std::unordered_set& dp) const; const dd4hep::rec::CellID _getSensorID(const dd4hep::rec::CellID& hitCell) const; double _integralGaus(double mean, double sd, double low_lim, double up_lim) const; From b28d49fb8ad644a77f7ad6042e9ed71a72256541 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Fri, 25 Oct 2024 00:02:33 -0400 Subject: [PATCH 23/77] Removed unnecessary header files. --- src/algorithms/digi/BTOFChargeSharing.cc | 30 +++++++++++++-------- src/algorithms/digi/BTOFChargeSharing.h | 21 +++++---------- src/algorithms/digi/TOFPulseDigitization.cc | 17 +++++------- src/algorithms/digi/TOFPulseDigitization.h | 14 ++-------- src/algorithms/digi/TOFPulseGeneration.cc | 17 +++++------- src/algorithms/digi/TOFPulseGeneration.h | 13 ++------- 6 files changed, 44 insertions(+), 68 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index 1bc2dc3a3b..41f7afc23a 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -6,21 +6,29 @@ // Author: Chun Yuen Tsang // Date: 10/22/2024 -#include "DD4hep/Detector.h" -#include "DDRec/Surface.h" -#include "TF1.h" -#include "TMath.h" -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "BTOFChargeSharing.h" -#include "Math/SpecFunc.h" +#include "DD4hep/Detector.h" +#include "TMath.h" #include "algorithms/digi/TOFHitDigiConfig.h" -#include // using namespace dd4hep; // using namespace dd4hep::Geometry; diff --git a/src/algorithms/digi/BTOFChargeSharing.h b/src/algorithms/digi/BTOFChargeSharing.h index 30a55e3eab..57dc71967b 100644 --- a/src/algorithms/digi/BTOFChargeSharing.h +++ b/src/algorithms/digi/BTOFChargeSharing.h @@ -8,25 +8,18 @@ #pragma once -#include "TF1.h" -#include +#include +#include +#include +#include +#include #include +#include #include -#include -#include #include - -#include -#include -#include -#include -#include -#include +#include #include "DD4hep/Detector.h" -#include "DDRec/Surface.h" -#include - #include "algorithms/digi/TOFHitDigiConfig.h" #include "algorithms/interfaces/WithPodConfig.h" diff --git a/src/algorithms/digi/TOFPulseDigitization.cc b/src/algorithms/digi/TOFPulseDigitization.cc index f5010a071f..6570b806d3 100644 --- a/src/algorithms/digi/TOFPulseDigitization.cc +++ b/src/algorithms/digi/TOFPulseDigitization.cc @@ -7,19 +7,16 @@ // Author: Souvik Paul, Chun Yuen Tsang // Date: 22/10/2024 -#include "DD4hep/Detector.h" -#include "DDRec/Surface.h" -#include "TF1.h" -#include "TMath.h" -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include +#include "DD4hep/Detector.h" #include "TOFPulseDigitization.h" -#include "Math/SpecFunc.h" #include "algorithms/digi/TOFHitDigiConfig.h" // using namespace dd4hep; diff --git a/src/algorithms/digi/TOFPulseDigitization.h b/src/algorithms/digi/TOFPulseDigitization.h index 5398fb4d40..f5cf79baa8 100644 --- a/src/algorithms/digi/TOFPulseDigitization.h +++ b/src/algorithms/digi/TOFPulseDigitization.h @@ -9,21 +9,11 @@ #pragma once -#include "TF1.h" -#include -#include -#include -#include - -#include #include #include #include -#include - -#include "DD4hep/Detector.h" -#include "DDRec/Surface.h" -#include +#include +#include #include "algorithms/digi/TOFHitDigiConfig.h" #include "algorithms/interfaces/WithPodConfig.h" diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index 046782dea4..2691f0c024 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -8,19 +8,16 @@ // Author: Souvik Paul, Chun Yuen Tsang // Date: 22/10/2024 -#include "DD4hep/Detector.h" -#include "DDRec/Surface.h" -#include "TF1.h" -#include "TMath.h" -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include +#include "DD4hep/Detector.h" +#include "TMath.h" #include "TOFPulseGeneration.h" -#include "Math/SpecFunc.h" #include "algorithms/digi/TOFHitDigiConfig.h" // using namespace dd4hep; diff --git a/src/algorithms/digi/TOFPulseGeneration.h b/src/algorithms/digi/TOFPulseGeneration.h index 7d0e0a3618..8aa62834c5 100644 --- a/src/algorithms/digi/TOFPulseGeneration.h +++ b/src/algorithms/digi/TOFPulseGeneration.h @@ -10,20 +10,11 @@ #pragma once -#include -#include -#include -#include - -#include #include #include #include -#include - -#include "DD4hep/Detector.h" -#include "DDRec/Surface.h" -#include +#include +#include #include "algorithms/digi/TOFHitDigiConfig.h" #include "algorithms/interfaces/WithPodConfig.h" From 8f0158712e9f9d9f9a89e7f3f6dc5ce2fa5102dc Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Fri, 25 Oct 2024 01:06:50 -0400 Subject: [PATCH 24/77] Trigger Build From a4b52117eefa3f5aec696143d6a2f5477e7d829b Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Fri, 1 Nov 2024 17:25:25 -0400 Subject: [PATCH 25/77] Update src/algorithms/digi/BTOFChargeSharing.cc Co-authored-by: Dmitry Kalinkin --- src/algorithms/digi/BTOFChargeSharing.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index 41f7afc23a..e60352b635 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -3,9 +3,6 @@ // // Spread energy deposition from one strip to neighboring strips within sensor boundaries -// Author: Chun Yuen Tsang -// Date: 10/22/2024 - #include #include #include From f4f3204257ce5e97627e6ccb5f5c452d400c7deb Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Fri, 1 Nov 2024 17:25:37 -0400 Subject: [PATCH 26/77] Update src/algorithms/digi/TOFPulseDigitization.cc Co-authored-by: Dmitry Kalinkin --- src/algorithms/digi/TOFPulseDigitization.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/algorithms/digi/TOFPulseDigitization.cc b/src/algorithms/digi/TOFPulseDigitization.cc index 6570b806d3..59ebb5f65e 100644 --- a/src/algorithms/digi/TOFPulseDigitization.cc +++ b/src/algorithms/digi/TOFPulseDigitization.cc @@ -3,9 +3,6 @@ // Special Acknowledgement: Kolja Kauder // // Convert ADC pulses from TOFPulseGeneration into ADC and TDC values -// -// Author: Souvik Paul, Chun Yuen Tsang -// Date: 22/10/2024 #include #include From 76fccd886bd776a51867e632448d6ca6e9de4bf7 Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Fri, 1 Nov 2024 17:25:53 -0400 Subject: [PATCH 27/77] Update src/algorithms/digi/TOFPulseDigitization.cc Co-authored-by: Dmitry Kalinkin --- src/algorithms/digi/TOFPulseDigitization.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/algorithms/digi/TOFPulseDigitization.cc b/src/algorithms/digi/TOFPulseDigitization.cc index 59ebb5f65e..4acf33adf0 100644 --- a/src/algorithms/digi/TOFPulseDigitization.cc +++ b/src/algorithms/digi/TOFPulseDigitization.cc @@ -16,11 +16,6 @@ #include "TOFPulseDigitization.h" #include "algorithms/digi/TOFHitDigiConfig.h" -// using namespace dd4hep; -// using namespace dd4hep::Geometry; -// using namespace dd4hep::DDRec; -// using namespace eicrecon; -using namespace dd4hep::xml; namespace eicrecon { From 310c51065afe192b5076d308789b439fcc687696 Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Fri, 1 Nov 2024 17:26:28 -0400 Subject: [PATCH 28/77] Update src/algorithms/digi/BTOFChargeSharing.cc Co-authored-by: Dmitry Kalinkin --- src/algorithms/digi/BTOFChargeSharing.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index e60352b635..75a8d82996 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -27,11 +27,6 @@ #include "TMath.h" #include "algorithms/digi/TOFHitDigiConfig.h" -// using namespace dd4hep; -// using namespace dd4hep::Geometry; -// using namespace dd4hep::DDRec; -// using namespace eicrecon; -using namespace dd4hep::xml; namespace eicrecon { From 6e443181de259b4c787652d69193c0de0e70c9b3 Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Fri, 1 Nov 2024 17:26:42 -0400 Subject: [PATCH 29/77] Update src/algorithms/digi/TOFPulseDigitization.h Co-authored-by: Dmitry Kalinkin --- src/algorithms/digi/TOFPulseDigitization.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/algorithms/digi/TOFPulseDigitization.h b/src/algorithms/digi/TOFPulseDigitization.h index f5cf79baa8..cf99a8eca4 100644 --- a/src/algorithms/digi/TOFPulseDigitization.h +++ b/src/algorithms/digi/TOFPulseDigitization.h @@ -3,9 +3,6 @@ // Special Acknowledgement: Kolja Kauder // // Convert ADC pulses from TOFPulseGeneration into ADC and TDC values -// -// Author: Souvik Paul, Chun Yuen Tsang -// Date: 22/10/2024 #pragma once From 7ecc458010da7fde76bb2446034964fe0e000454 Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Fri, 1 Nov 2024 17:26:58 -0400 Subject: [PATCH 30/77] Update src/algorithms/digi/TOFPulseGeneration.h Co-authored-by: Dmitry Kalinkin --- src/algorithms/digi/TOFPulseGeneration.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/algorithms/digi/TOFPulseGeneration.h b/src/algorithms/digi/TOFPulseGeneration.h index 8aa62834c5..20f9c910cb 100644 --- a/src/algorithms/digi/TOFPulseGeneration.h +++ b/src/algorithms/digi/TOFPulseGeneration.h @@ -4,9 +4,6 @@ // // Convert energy deposition into ADC pulses // ADC pulses are assumed to follow the shape of landau function -// -// Author: Souvik Paul, Chun Yuen Tsang -// Date: 22/10/2024 #pragma once From 41614b8587f817ba730ebf4b13180ee292de387d Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Fri, 1 Nov 2024 17:27:17 -0400 Subject: [PATCH 31/77] Update src/algorithms/digi/BTOFChargeSharing.cc Co-authored-by: Dmitry Kalinkin --- src/algorithms/digi/BTOFChargeSharing.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index 75a8d82996..6a7082210f 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -131,11 +131,6 @@ void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, for(const auto & hit : *simhits) { auto cellID = hit.getCellID(); - /*if(m_useCache) { - auto it = m_cache.find(cellID); - if(it != m_cache.end()) - neighbors = it -> second; - }*/ if(!neighbors){ std::unordered_set dp; From 7ca28d394793a6598feddcbae7b3448e6d75ab54 Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Fri, 1 Nov 2024 17:27:27 -0400 Subject: [PATCH 32/77] Update src/algorithms/digi/BTOFChargeSharing.h Co-authored-by: Dmitry Kalinkin --- src/algorithms/digi/BTOFChargeSharing.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.h b/src/algorithms/digi/BTOFChargeSharing.h index 57dc71967b..1a5897ebb2 100644 --- a/src/algorithms/digi/BTOFChargeSharing.h +++ b/src/algorithms/digi/BTOFChargeSharing.h @@ -3,9 +3,6 @@ // // Spread energy deposition from one strip to neighboring strips within sensor boundaries -// Author: Chun Yuen Tsang -// Date: 10/22/2024 - #pragma once #include From 576055cf981d696d57189c06863666b7b0595752 Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Fri, 1 Nov 2024 17:27:38 -0400 Subject: [PATCH 33/77] Update src/algorithms/digi/BTOFChargeSharing.cc Co-authored-by: Dmitry Kalinkin --- src/algorithms/digi/BTOFChargeSharing.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index 6a7082210f..bd78475df0 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -136,11 +136,6 @@ void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, std::unordered_set dp; neighbors = std::make_shared>(); this -> _findAllNeighborsInSensor(cellID, neighbors, dp); - - // fill cache - /*if(m_useCache) - for(const auto cell : *neighbors) - m_cache[cell] = neighbors;*/ } double edep = hit.getEDep(); From 232a3ef5598b7c7c30e229bd95b6bd7108ff034a Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Fri, 1 Nov 2024 17:53:23 -0400 Subject: [PATCH 34/77] Replaced magic number in BTOFChargeSharing with the correct unit. --- src/algorithms/digi/BTOFChargeSharing.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index bd78475df0..e021c7cb3f 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -142,7 +142,7 @@ void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, double time = hit.getTime(); auto momentum = hit.getMomentum(); auto truePos = hit.getPosition(); - auto localPos_hit = this -> _global2Local(dd4hep::Position(truePos.x / 10., truePos.y / 10., truePos.z / 10.)); + auto localPos_hit = this -> _global2Local(dd4hep::Position(truePos.x*dd4hep::mm, truePos.y*dd4hep::mm, truePos.z*dd4hep::mm)); for(const auto neighbor : *neighbors) { // integrate over neighbor area to get total energy deposition From 8043bff8dc4cd435903e225f30398aa87ce982a0 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Fri, 1 Nov 2024 18:08:35 -0400 Subject: [PATCH 35/77] Make clang-tidy-iwyu happy. --- src/algorithms/digi/BTOFChargeSharing.cc | 1 + src/algorithms/digi/TOFPulseDigitization.cc | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index e021c7cb3f..3b5761e9fe 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/src/algorithms/digi/TOFPulseDigitization.cc b/src/algorithms/digi/TOFPulseDigitization.cc index 4acf33adf0..73ab5e442b 100644 --- a/src/algorithms/digi/TOFPulseDigitization.cc +++ b/src/algorithms/digi/TOFPulseDigitization.cc @@ -12,7 +12,6 @@ #include #include -#include "DD4hep/Detector.h" #include "TOFPulseDigitization.h" #include "algorithms/digi/TOFHitDigiConfig.h" From 837900ace8fb5e73549142435048608454ea039d Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Sat, 2 Nov 2024 12:01:47 -0400 Subject: [PATCH 36/77] Trigger Build From e51c0073c2608170912072d7ad7b9e78f0a5e00c Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Sat, 2 Nov 2024 17:53:27 -0400 Subject: [PATCH 37/77] Update src/algorithms/digi/TOFPulseGeneration.cc Co-authored-by: Dmitry Kalinkin --- src/algorithms/digi/TOFPulseGeneration.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index 2691f0c024..7a72eada7b 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -4,9 +4,6 @@ // // Convert energy deposition into ADC pulses // ADC pulses are assumed to follow the shape of landau function -// -// Author: Souvik Paul, Chun Yuen Tsang -// Date: 22/10/2024 #include #include From 1d3f592ece4c81d67a46b1f46145f3caca3db780 Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Sat, 2 Nov 2024 17:53:34 -0400 Subject: [PATCH 38/77] Update src/algorithms/digi/TOFPulseGeneration.cc Co-authored-by: Dmitry Kalinkin --- src/algorithms/digi/TOFPulseGeneration.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index 7a72eada7b..3265979e58 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -17,11 +17,6 @@ #include "TOFPulseGeneration.h" #include "algorithms/digi/TOFHitDigiConfig.h" -// using namespace dd4hep; -// using namespace dd4hep::Geometry; -// using namespace dd4hep::DDRec; -// using namespace eicrecon; -using namespace dd4hep::xml; namespace eicrecon { From 3e0afdcbcbdfc8aa360ec131f785ee5211877289 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Sat, 2 Nov 2024 18:52:13 -0400 Subject: [PATCH 39/77] Make clang-tidy-iwyu happy. --- src/algorithms/digi/TOFPulseGeneration.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index 3265979e58..55302a0228 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -12,7 +12,6 @@ #include #include -#include "DD4hep/Detector.h" #include "TMath.h" #include "TOFPulseGeneration.h" #include "algorithms/digi/TOFHitDigiConfig.h" From 89452f4d08a4efa61cb0ae353a20a51af86054a6 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Mon, 4 Nov 2024 16:23:31 -0500 Subject: [PATCH 40/77] TOFPulseGeneration_factory.h: mixedCase for parameter names --- .../digi/TOFPulseGeneration_factory.h | 34 +++++-------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/factories/digi/TOFPulseGeneration_factory.h b/src/factories/digi/TOFPulseGeneration_factory.h index fe08cfd3db..92c2c3a800 100644 --- a/src/factories/digi/TOFPulseGeneration_factory.h +++ b/src/factories/digi/TOFPulseGeneration_factory.h @@ -11,54 +11,36 @@ namespace eicrecon { class TOFPulseGeneration_factory : public JOmniFactory { +public: + using AlgoT = eicrecon::TOFPulseGeneration; private: - // Underlying algorithm - std::unique_ptr m_algo; + std::unique_ptr m_algo; - // Declare inputs - PodioInput m_in_sim_track{this}; //, "TOFBarrelRawHits"}; + PodioInput m_in_sim_track{this}; - // Declare outputs PodioOutput m_out_reco_particles{this}; - // Declare services here, e.g. - Service m_geoSvc{this}; - ParameterRef m_Vm{this, "Vm", config().Vm}; ParameterRef m_tMin{this, "tMin", config().tMin}; ParameterRef m_tMax{this, "tMax", config().tMax}; - ParameterRef m_adc_range{this, "adc_range", config().adc_range}; - ParameterRef m_tdc_range{this, "tdc_range", config().tdc_range}; + ParameterRef m_adc_range{this, "adcRange", config().adc_range}; + ParameterRef m_tdc_range{this, "tdcRange", config().tdc_range}; ParameterRef m_nBins{this, "nBins", config().nBins}; - ParameterRef m_ignore_thres{this, "ignore_thres", config().ignore_thres}; + ParameterRef m_ignore_thres{this, "ignoreThreshold", config().ignore_thres}; public: void Configure() { - // This is called when the factory is instantiated. - // Use this callback to make sure the algorithm is configured. - // The logger, parameters, and services have all been fetched before this is called m_algo = std::make_unique(GetPrefix()); m_algo->level(static_cast(logger()->level())); - // Pass config object to algorithm m_algo->applyConfig(config()); - - // If we needed geometry, we'd obtain it like so - // m_algo->init(m_geoSvc().detector(), m_geoSvc().converter(), logger()); m_algo->init(); } void ChangeRun(int64_t run_number) { - // This is called whenever the run number is changed. - // Use this callback to retrieve state that is keyed off of run number. - // This state should usually be managed by a Service. - // Note: You usually don't need this, because you can declare a Resource instead. } void Process(int64_t run_number, uint64_t event_number) { - // This is called on every event. - // Use this callback to call your Algorithm using all inputs and outputs - // The inputs will have already been fetched for you at this point. m_algo->process({m_in_sim_track()}, {m_out_reco_particles().get()}); - // JANA will take care of publishing the outputs for you. } }; + } // namespace eicrecon From d0040c66a33c76416e145be8a2726e2d9395990d Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Mon, 4 Nov 2024 16:24:53 -0500 Subject: [PATCH 41/77] TOFPulseDigitization_factory.h: ditto --- .../digi/TOFPulseDigitization_factory.h | 27 +++---------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/src/factories/digi/TOFPulseDigitization_factory.h b/src/factories/digi/TOFPulseDigitization_factory.h index 76ad3da4f4..9e096e831e 100644 --- a/src/factories/digi/TOFPulseDigitization_factory.h +++ b/src/factories/digi/TOFPulseDigitization_factory.h @@ -11,48 +11,29 @@ namespace eicrecon { class TOFPulseDigitization_factory : public JOmniFactory { +public: + using AlgoT = eicrecon::TOFPulseDigitization; private: - // Underlying algorithm - std::unique_ptr m_algo; + std::unique_ptr m_algo; - // Declare inputs - PodioInput m_in_sim_track{this}; //, "TOFBarrelRawHits"}; + PodioInput m_in_sim_track{this}; - // Declare outputs PodioOutput m_out_reco_particles{this}; - // Declare services here, e.g. - Service m_geoSvc{this}; - ParameterRef m_t_thres{this, "t_thres", config().t_thres}; public: void Configure() { - // This is called when the factory is instantiated. - // Use this callback to make sure the algorithm is configured. - // The logger, parameters, and services have all been fetched before this is called m_algo = std::make_unique(GetPrefix()); m_algo->level(static_cast(logger()->level())); - // Pass config object to algorithm m_algo->applyConfig(config()); - - // If we needed geometry, we'd obtain it like so - // m_algo->init(m_geoSvc().detector(), m_geoSvc().converter(), logger()); m_algo->init(); } void ChangeRun(int64_t run_number) { - // This is called whenever the run number is changed. - // Use this callback to retrieve state that is keyed off of run number. - // This state should usually be managed by a Service. - // Note: You usually don't need this, because you can declare a Resource instead. } void Process(int64_t run_number, uint64_t event_number) { - // This is called on every event. - // Use this callback to call your Algorithm using all inputs and outputs - // The inputs will have already been fetched for you at this point. m_algo->process({m_in_sim_track()}, {m_out_reco_particles().get()}); - // JANA will take care of publishing the outputs for you. } }; } // namespace eicrecon From bbc6ab02e4cb66684ac2b3ed5220d37003c54165 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Mon, 4 Nov 2024 16:25:13 -0500 Subject: [PATCH 42/77] TOFPulseDigitization_factory.h: missed --- src/factories/digi/TOFPulseDigitization_factory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/factories/digi/TOFPulseDigitization_factory.h b/src/factories/digi/TOFPulseDigitization_factory.h index 9e096e831e..567a3a436c 100644 --- a/src/factories/digi/TOFPulseDigitization_factory.h +++ b/src/factories/digi/TOFPulseDigitization_factory.h @@ -20,7 +20,7 @@ class TOFPulseDigitization_factory : public JOmniFactory m_out_reco_particles{this}; - ParameterRef m_t_thres{this, "t_thres", config().t_thres}; + ParameterRef m_t_thres{this, "tThreshold", config().t_thres}; public: void Configure() { m_algo = std::make_unique(GetPrefix()); From 566449652e71e9d5137768390df4d60daca34ddd Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Mon, 4 Nov 2024 16:26:25 -0500 Subject: [PATCH 43/77] BTOFChargeSharing_factory.h: ditto --- .../digi/BTOFChargeSharing_factory.h | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/src/factories/digi/BTOFChargeSharing_factory.h b/src/factories/digi/BTOFChargeSharing_factory.h index 36c6095269..c8f5f84eb8 100644 --- a/src/factories/digi/BTOFChargeSharing_factory.h +++ b/src/factories/digi/BTOFChargeSharing_factory.h @@ -11,49 +11,30 @@ namespace eicrecon { class BTOFChargeSharing_factory : public JOmniFactory { +public: + using AlgoT = eicrecon::BTOFChargeSharing; private: - // Underlying algorithm - std::unique_ptr m_algo; + std::unique_ptr m_algo; - // Declare inputs - PodioInput m_in_sim_track{this}; //, "TOFBarrelRawHits"}; + PodioInput m_in_sim_track{this}; - // Declare outputs PodioOutput m_out_reco_particles{this}; - // Declare services here, e.g. - Service m_geoSvc{this}; - - ParameterRef m_sigma_sharingx{this, "sigma_sharingx", config().sigma_sharingx}; - ParameterRef m_sigma_sharingy{this, "sigma_sharingy", config().sigma_sharingy}; + ParameterRef m_sigma_sharingx{this, "sigmaSharingX", config().sigma_sharingx}; + ParameterRef m_sigma_sharingy{this, "sigmaSharingY", config().sigma_sharingy}; public: void Configure() { - // This is called when the factory is instantiated. - // Use this callback to make sure the algorithm is configured. - // The logger, parameters, and services have all been fetched before this is called m_algo = std::make_unique(GetPrefix()); m_algo->level(static_cast(logger()->level())); - // Pass config object to algorithm m_algo->applyConfig(config()); - - // If we needed geometry, we'd obtain it like so - // m_algo->init(m_geoSvc().detector(), m_geoSvc().converter(), logger()); m_algo->init(); } void ChangeRun(int64_t run_number) { - // This is called whenever the run number is changed. - // Use this callback to retrieve state that is keyed off of run number. - // This state should usually be managed by a Service. - // Note: You usually don't need this, because you can declare a Resource instead. } void Process(int64_t run_number, uint64_t event_number) { - // This is called on every event. - // Use this callback to call your Algorithm using all inputs and outputs - // The inputs will have already been fetched for you at this point. m_algo->process({m_in_sim_track()}, {m_out_reco_particles().get()}); - // JANA will take care of publishing the outputs for you. } }; } // namespace eicrecon From 00d18904e88c5de6ecf8df30a6a7c51cb97325c2 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Mon, 4 Nov 2024 16:27:29 -0500 Subject: [PATCH 44/77] TOFHitDigiConfig.h: rm unused suff --- src/algorithms/digi/TOFHitDigiConfig.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/algorithms/digi/TOFHitDigiConfig.h b/src/algorithms/digi/TOFHitDigiConfig.h index 572b6a5151..1c578d85a7 100644 --- a/src/algorithms/digi/TOFHitDigiConfig.h +++ b/src/algorithms/digi/TOFHitDigiConfig.h @@ -12,8 +12,6 @@ struct TOFHitDigiConfig { double threshold{1.0 * dd4hep::keV}; double tRes = 0.1; /// TODO 8 of what units??? Same TODO in juggler. Probably [ns] // digitization settings - // unsigned int pedMeanADC{0}; - // double pedSigmaADC{0}; double resolutionTDC{1}; double resolutionADC{1}; From 3af27a98124b83ae6c3951cdb809952464faf561 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Mon, 4 Nov 2024 16:28:19 -0500 Subject: [PATCH 45/77] BTOFChargeSharing_factory.h: need algorithmsInit --- src/factories/digi/BTOFChargeSharing_factory.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/factories/digi/BTOFChargeSharing_factory.h b/src/factories/digi/BTOFChargeSharing_factory.h index c8f5f84eb8..1927a0a93d 100644 --- a/src/factories/digi/BTOFChargeSharing_factory.h +++ b/src/factories/digi/BTOFChargeSharing_factory.h @@ -12,7 +12,7 @@ namespace eicrecon { class BTOFChargeSharing_factory : public JOmniFactory { public: - using AlgoT = eicrecon::BTOFChargeSharing; + using AlgoT = eicrecon::BTOFChargeSharing; private: std::unique_ptr m_algo; @@ -22,6 +22,8 @@ class BTOFChargeSharing_factory : public JOmniFactory m_sigma_sharingx{this, "sigmaSharingX", config().sigma_sharingx}; ParameterRef m_sigma_sharingy{this, "sigmaSharingY", config().sigma_sharingy}; + + Service m_algorithmsInit {this}; public: void Configure() { m_algo = std::make_unique(GetPrefix()); From cb3209db28218cb092099a6a4223b450f3283eb2 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Mon, 4 Nov 2024 16:28:48 -0500 Subject: [PATCH 46/77] TOFPulseDigitization_factory.h: ditto --- src/factories/digi/TOFPulseDigitization_factory.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/factories/digi/TOFPulseDigitization_factory.h b/src/factories/digi/TOFPulseDigitization_factory.h index 567a3a436c..510ac3f183 100644 --- a/src/factories/digi/TOFPulseDigitization_factory.h +++ b/src/factories/digi/TOFPulseDigitization_factory.h @@ -12,7 +12,7 @@ namespace eicrecon { class TOFPulseDigitization_factory : public JOmniFactory { public: - using AlgoT = eicrecon::TOFPulseDigitization; + using AlgoT = eicrecon::TOFPulseDigitization; private: std::unique_ptr m_algo; @@ -21,6 +21,8 @@ class TOFPulseDigitization_factory : public JOmniFactory m_out_reco_particles{this}; ParameterRef m_t_thres{this, "tThreshold", config().t_thres}; + + Service m_algorithmsInit {this}; public: void Configure() { m_algo = std::make_unique(GetPrefix()); From 6ba7baba14ce9db4e1c9fec0e3309ba694053d85 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Mon, 4 Nov 2024 16:29:10 -0500 Subject: [PATCH 47/77] TOFPulseGeneration_factory.h: ditto --- src/factories/digi/TOFPulseGeneration_factory.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/factories/digi/TOFPulseGeneration_factory.h b/src/factories/digi/TOFPulseGeneration_factory.h index 92c2c3a800..5674303da4 100644 --- a/src/factories/digi/TOFPulseGeneration_factory.h +++ b/src/factories/digi/TOFPulseGeneration_factory.h @@ -12,7 +12,7 @@ namespace eicrecon { class TOFPulseGeneration_factory : public JOmniFactory { public: - using AlgoT = eicrecon::TOFPulseGeneration; + using AlgoT = eicrecon::TOFPulseGeneration; private: std::unique_ptr m_algo; @@ -27,6 +27,8 @@ class TOFPulseGeneration_factory : public JOmniFactory m_tdc_range{this, "tdcRange", config().tdc_range}; ParameterRef m_nBins{this, "nBins", config().nBins}; ParameterRef m_ignore_thres{this, "ignoreThreshold", config().ignore_thres}; + + Service m_algorithmsInit {this}; public: void Configure() { m_algo = std::make_unique(GetPrefix()); From fa7ad552bfb7be97c508d7b0c4ceb7ff31401786 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Mon, 4 Nov 2024 16:30:29 -0500 Subject: [PATCH 48/77] BTOFChargeSharing.h: remove cache stuff for now --- src/algorithms/digi/BTOFChargeSharing.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.h b/src/algorithms/digi/BTOFChargeSharing.h index 1a5897ebb2..7757bd17cb 100644 --- a/src/algorithms/digi/BTOFChargeSharing.h +++ b/src/algorithms/digi/BTOFChargeSharing.h @@ -46,15 +46,10 @@ class BTOFChargeSharing : public BTOFChargeSharingAlgorithm, dd4hep::Position _cell2LocalPosition(const dd4hep::rec::CellID& cell) const; dd4hep::Position _global2Local(const dd4hep::Position& pos) const; - - // can't cache our results if process has to be const - //bool m_useCache = true; const dd4hep::DDSegmentation::BitFieldCoder* m_decoder = nullptr; const dd4hep::Detector* m_detector = nullptr; const dd4hep::rec::CellIDPositionConverter* m_converter = nullptr; - //std::unordered_map>> m_cache; - }; } // namespace eicrecon From ef009444a3ee2aa943698cece4a36649645d05bc Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Tue, 5 Nov 2024 15:59:24 -0500 Subject: [PATCH 49/77] JEventProcessorPODIO.cc: add TOFBarrelADCTDC --- src/services/io/podio/JEventProcessorPODIO.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/io/podio/JEventProcessorPODIO.cc b/src/services/io/podio/JEventProcessorPODIO.cc index 2575c326a9..69881237e5 100644 --- a/src/services/io/podio/JEventProcessorPODIO.cc +++ b/src/services/io/podio/JEventProcessorPODIO.cc @@ -92,6 +92,7 @@ JEventProcessorPODIO::JEventProcessorPODIO() { "TOFEndcapRawHits", "TOFBarrelHits", + "TOFBarrelADCTDC" "TOFEndcapHits", "TOFBarrelRawHitAssociations", From a745e2b33dc83f6b422499be16c9c4075ab4d18c Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Tue, 5 Nov 2024 16:08:21 -0500 Subject: [PATCH 50/77] Update src/services/io/podio/JEventProcessorPODIO.cc --- src/services/io/podio/JEventProcessorPODIO.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/io/podio/JEventProcessorPODIO.cc b/src/services/io/podio/JEventProcessorPODIO.cc index 69881237e5..6df43a4c5a 100644 --- a/src/services/io/podio/JEventProcessorPODIO.cc +++ b/src/services/io/podio/JEventProcessorPODIO.cc @@ -92,7 +92,7 @@ JEventProcessorPODIO::JEventProcessorPODIO() { "TOFEndcapRawHits", "TOFBarrelHits", - "TOFBarrelADCTDC" + "TOFBarrelADCTDC", "TOFEndcapHits", "TOFBarrelRawHitAssociations", From dd95d6ba861693eb4bd980cddff1ff59b11b65af Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Thu, 7 Nov 2024 18:04:34 -0500 Subject: [PATCH 51/77] Added tests for TOFPulseDigitization and TOFPulseGeneration. --- src/algorithms/digi/BTOFChargeSharing.cc | 11 +- src/algorithms/digi/TOFHitDigiConfig.h | 8 +- src/algorithms/digi/TOFPulseDigitization.cc | 2 +- src/algorithms/digi/TOFPulseGeneration.cc | 8 +- .../digi/TOFPulseGeneration_factory.h | 1 - src/tests/algorithms_test/CMakeLists.txt | 2 + src/tests/algorithms_test/algorithmsInit.cc | 9 + .../digi_TOFPulseDigitization.cc | 150 +++++++++++++++++ .../digi_TOFPulseGeneration.cc | 158 ++++++++++++++++++ 9 files changed, 336 insertions(+), 13 deletions(-) create mode 100644 src/tests/algorithms_test/digi_TOFPulseDigitization.cc create mode 100644 src/tests/algorithms_test/digi_TOFPulseGeneration.cc diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index 3b5761e9fe..4787b029e8 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -35,7 +35,7 @@ void BTOFChargeSharing::init() { m_detector = algorithms::GeoSvc::instance().detector();; m_converter = algorithms::GeoSvc::instance().cellIDPositionConverter(); - auto seg = m_detector->readout("TOFBarrelHits").segmentation(); + auto seg = m_detector->readout(m_cfg.readout).segmentation(); auto type = seg.type(); if (type != "CartesianGridXY") throw std::runtime_error("Unsupported segmentation type: " + type + @@ -101,8 +101,13 @@ BTOFChargeSharing::_getSensorID(const dd4hep::rec::CellID& hitCell) const { double BTOFChargeSharing::_integralGaus(double mean, double sd, double low_lim, double up_lim) const { // return integral Gauss(mean, sd) dx from x = low_lim to x = up_lim - double up = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - up_lim) / sd); - double low = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - low_lim) / sd); + // default value is set when sd = 0 + double up = mean > up_lim? -0.5 : 0.5; + double low = mean > low_lim? -0.5 : 0.5; + if(sd > 0) { + up = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - up_lim) / sd); + low = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - low_lim) / sd); + } return up - low; } diff --git a/src/algorithms/digi/TOFHitDigiConfig.h b/src/algorithms/digi/TOFHitDigiConfig.h index 1c578d85a7..dc7b7e5e01 100644 --- a/src/algorithms/digi/TOFHitDigiConfig.h +++ b/src/algorithms/digi/TOFHitDigiConfig.h @@ -21,20 +21,20 @@ struct TOFHitDigiConfig { double sigma_analog = 0.293951; double sigma_sharingx = 0.1; double sigma_sharingy = 0.5; - double Vm = -1e-4 * gain; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage corresponds to ADC = adc_max + double Vm = -1e-4 * dd4hep::GeV; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage corresponds to ADC = adc_max double t_thres = 0.1 * Vm; double ignore_thres = 0.01 * Vm; // If EDep below this value, digitization for the cell will be ignored. Speed up calculation // double tMin = 0.1; - double tMax = 100.0; + double tMax = 25;// 25 ns is the period of 40MHz EIC clock int total_time = ceil(tMax - tMin); - int time_period = 25; - int nBins = 1024; int adc_bit = 8; int tdc_bit = 10; int adc_range = pow(2, adc_bit); int tdc_range = pow(2, tdc_bit); + + std::string readout = "TOFBarrelHits"; }; } // namespace eicrecon diff --git a/src/algorithms/digi/TOFPulseDigitization.cc b/src/algorithms/digi/TOFPulseDigitization.cc index 73ab5e442b..eaa1ca43e2 100644 --- a/src/algorithms/digi/TOFPulseDigitization.cc +++ b/src/algorithms/digi/TOFPulseDigitization.cc @@ -48,7 +48,7 @@ void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, for (const auto adc : adcs) { if (adc_prev >= norm_threshold && adc <= norm_threshold) { intersectionX = time_bin*time_interval + time_interval * (norm_threshold - adc_prev) / (adc - adc_prev); - tdc = ceil(intersectionX / 0.02); + tdc = static_cast(intersectionX / time_interval); } if (abs(adc) > abs(V)) // To get peak of the Analog signal V = adc; diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index 55302a0228..a8aa3845c0 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -35,7 +35,7 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, double tMax = m_cfg.tMax; int adc_range = m_cfg.adc_range; int tdc_range = m_cfg.tdc_range; - int nBins = m_cfg.nBins; + int nBins = m_cfg.tdc_range; // signal sum // NOTE: we take the cellID of the most energetic hit in this group so it is a real cellID from an @@ -49,7 +49,7 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, double mpv_analog = 0.0; // SP double time = hit.getTime(); - double charge = hit.getEDep() * m_cfg.gain; + double charge = hit.getEDep(); // reduce computation power by not simulating low-charge hits if(charge < m_cfg.ignore_thres) continue; @@ -68,11 +68,11 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, landau_min = std::min(landau_min, this -> _Landau(x, mpv_analog, m_cfg.sigma_analog)); } - double scalingFactor = -1. / Vm / landau_min * adc_range; + double scalingFactor = -1. / Vm / m_cfg.gain / landau_min * adc_range; for (int j = 0; j < nBins; ++j) { double x = tMin + j * interval; - double y = -1 * charge * this -> _Landau(x, mpv_analog, m_cfg.sigma_analog) * scalingFactor; + double y = -1 * charge * m_cfg.gain * this -> _Landau(x, mpv_analog, m_cfg.sigma_analog) * scalingFactor; ADCs[j] += y;; } diff --git a/src/factories/digi/TOFPulseGeneration_factory.h b/src/factories/digi/TOFPulseGeneration_factory.h index 5674303da4..cd3956f46b 100644 --- a/src/factories/digi/TOFPulseGeneration_factory.h +++ b/src/factories/digi/TOFPulseGeneration_factory.h @@ -25,7 +25,6 @@ class TOFPulseGeneration_factory : public JOmniFactory m_tMax{this, "tMax", config().tMax}; ParameterRef m_adc_range{this, "adcRange", config().adc_range}; ParameterRef m_tdc_range{this, "tdcRange", config().tdc_range}; - ParameterRef m_nBins{this, "nBins", config().nBins}; ParameterRef m_ignore_thres{this, "ignoreThreshold", config().ignore_thres}; Service m_algorithmsInit {this}; diff --git a/src/tests/algorithms_test/CMakeLists.txt b/src/tests/algorithms_test/CMakeLists.txt index 57ecd29c88..b6b2531ca5 100644 --- a/src/tests/algorithms_test/CMakeLists.txt +++ b/src/tests/algorithms_test/CMakeLists.txt @@ -11,6 +11,8 @@ add_executable( calorimetry_CalorimeterHitDigi.cc calorimetry_CalorimeterClusterRecoCoG.cc calorimetry_HEXPLIT.cc + digi_TOFPulseGeneration.cc + digi_TOFPulseDigitization.cc pid_MergeTracks.cc pid_MergeParticleID.cc pid_lut_PIDLookup.cc diff --git a/src/tests/algorithms_test/algorithmsInit.cc b/src/tests/algorithms_test/algorithmsInit.cc index 357e928001..1d5a839e28 100644 --- a/src/tests/algorithms_test/algorithmsInit.cc +++ b/src/tests/algorithms_test/algorithmsInit.cc @@ -44,6 +44,15 @@ class algorithmsInitListener : public Catch::EventListenerBase { detector->add(id_desc_tracker); detector->add(readoutTracker); + dd4hep::Readout readoutTOF(std::string("MockTOFHits")); + dd4hep::IDDescriptor id_desc_TOF("MockTOFHits", "system:8,layer:4,module:12,sensor:10,x:40:-8,y:-16"); + //Create segmentation with 1x1 mm pixels + dd4hep::Segmentation segmentation_TOF("CartesianGridXY","TOFHitsSeg", id_desc_tracker.decoder()); + readoutTOF.setIDDescriptor(id_desc_TOF); + readoutTOF.setSegmentation(segmentation_TOF); + detector->add(id_desc_TOF); + detector->add(readoutTOF); + m_detector = std::move(detector); auto& serviceSvc = algorithms::ServiceSvc::instance(); diff --git a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc new file mode 100644 index 0000000000..f431086530 --- /dev/null +++ b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024, Chun Yuen Tsang, Prithwish Tribedy + +#include // for AssertionHandler, operator""_catch_sr, StringRef, REQUIRE, operator<, operator==, operator>, TEST_CASE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access +#include // for level_enum +#include // for logger +#include // for default_logger +#include +#include + +#include "algorithms/digi/TOFHitDigiConfig.h" +#include "algorithms/digi/TOFPulseDigitization.h" +#include +#include +#include +#include +#include + +#include "TF1.h" +#include "TGraphErrors.h" + +TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseDigitization]") { + const float EPSILON = 1e-5; + + eicrecon::TOFPulseDigitization algo("TOFPulseDigitization"); + + std::shared_ptr logger = spdlog::default_logger()->clone("TOFPulseDigitization"); + logger->set_level(spdlog::level::trace); + + eicrecon::TOFHitDigiConfig cfg; + cfg.readout = "MockTOFHits"; + + auto detector = algorithms::GeoSvc::instance().detector(); + auto id_desc = detector->readout(cfg.readout).idSpec(); + + cfg.gain = 10; + cfg.Vm = -1e-4; + cfg.ignore_thres = 1e-4 / 5; + cfg.t_thres = cfg.Vm * 0.1; + cfg.tdc_bit = 8; + cfg.adc_bit = 7; + cfg.tdc_range = pow(2, cfg.tdc_bit); + cfg.adc_range = pow(2, cfg.adc_bit); + + // check if max pulse height is linearly proportional to the initial Edep + algo.applyConfig(cfg); + algo.init(); + + SECTION("TDC vs analytic solution scan") { + + // test pulse with gaussian shape + for (double tdc_frac = 0.4; tdc_frac < 1; tdc_frac += 0.1) { + edm4hep::RawTimeSeriesCollection time_series_coll; + auto rawhits_coll = std::make_unique(); + + auto pulse = time_series_coll.create(); + auto cellID = + id_desc.encode({{"system", 0}, {"module", 0}, {"sensor", 1}, {"x", 1}, {"y", 1}}); + + pulse.setCellID(cellID); + pulse.setCharge(1.); // placeholder + pulse.setTime(1.); // placeholder + pulse.setInterval(1); + + int test_peak_TDC = static_cast(tdc_frac * cfg.tdc_range); + int test_peak = static_cast(0.7 * cfg.adc_range); + int test_peak_sigma = static_cast(0.1 * cfg.tdc_range); + + for (int i = 0; i < cfg.tdc_range; ++i) { + int ADC = + -test_peak * + TMath::Exp(-0.5 * pow((i - test_peak_TDC) / static_cast(test_peak_sigma), 2)); + pulse.addToAdcCounts(ADC); + } + + // calculate analytically when the pulse passes t_thres + // ADC = amp*exp(-(TDC - mean)^2/(2sigma^2)) + // TDC = mean - (-2*sigma^2*ln(ADC/amp))^0.5 + int analytic_TDC = ceil(test_peak_TDC - sqrt(-2 * pow(test_peak_sigma, 2) * + TMath::Log(cfg.adc_range * 0.1 / test_peak))); + + // Constructing input and output as per the algorithm's expected signature + auto input = std::make_tuple(&time_series_coll); + auto output = std::make_tuple(rawhits_coll.get()); + + algo.process(input, output); + + REQUIRE(rawhits_coll->size() == 1); + auto hit = (*rawhits_coll)[0]; + REQUIRE(hit.getCellID() == cellID); + REQUIRE(hit.getCharge() == test_peak); + REQUIRE(hit.getTimeStamp() == analytic_TDC); + } + } + + SECTION("ADC scan") { + + // test pulse with gaussian shape + for (double adc_frac = 0.4; adc_frac < 1; adc_frac += 0.1) { + edm4hep::RawTimeSeriesCollection time_series_coll; + auto rawhits_coll = std::make_unique(); + + auto pulse = time_series_coll.create(); + auto cellID = + id_desc.encode({{"system", 0}, {"module", 0}, {"sensor", 1}, {"x", 1}, {"y", 1}}); + + pulse.setCellID(cellID); + pulse.setCharge(1.); // placeholder + pulse.setTime(1.); // placeholder + pulse.setInterval(1); + + int test_peak_TDC = static_cast(0.5 * cfg.tdc_range); + int test_peak = static_cast(adc_frac * cfg.adc_range); + int test_peak_sigma = static_cast(0.1 * cfg.tdc_range); + + for (int i = 0; i < cfg.tdc_range; ++i) { + int ADC = + -test_peak * + TMath::Exp(-0.5 * pow((i - test_peak_TDC) / static_cast(test_peak_sigma), 2)); + pulse.addToAdcCounts(ADC); + } + + // Constructing input and output as per the algorithm's expected signature + auto input = std::make_tuple(&time_series_coll); + auto output = std::make_tuple(rawhits_coll.get()); + + algo.process(input, output); + + REQUIRE(rawhits_coll->size() == 1); + auto hit = (*rawhits_coll)[0]; + REQUIRE(hit.getCellID() == cellID); + REQUIRE(hit.getCharge() == test_peak); + } + } +} diff --git a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc new file mode 100644 index 0000000000..b09bae1bb2 --- /dev/null +++ b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024, Chun Yuen Tsang, Prithwish Tribedy + +#include // for AssertionHandler, operator""_catch_sr, StringRef, REQUIRE, operator<, operator==, operator>, TEST_CASE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access +#include // for level_enum +#include // for logger +#include // for default_logger +#include +#include + +#include "algorithms/digi/TOFHitDigiConfig.h" +#include "algorithms/digi/TOFPulseGeneration.h" +#include +#include +#include +#include + +#include "TF1.h" +#include "TGraphErrors.h" + +TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { + const float EPSILON = 1e-5; + + eicrecon::TOFPulseGeneration algo("TOFPulseGeneration"); + + std::shared_ptr logger = spdlog::default_logger()->clone("TOFPulseGeneration"); + logger->set_level(spdlog::level::trace); + + eicrecon::TOFHitDigiConfig cfg; + cfg.readout = "MockTOFHits"; + + auto detector = algorithms::GeoSvc::instance().detector(); + auto id_desc = detector->readout(cfg.readout).idSpec(); + + cfg.gain = 10; + cfg.Vm = -1e-4; + cfg.ignore_thres = 1e-4 / 5; + + SECTION("Pulse height linearlity test") { + // check if max pulse height is linearly proportional to the initial Edep + algo.applyConfig(cfg); + algo.init(); + + TGraphErrors graph; + for (double edep = 0; edep <= 1e-4; edep += 1e-4 / 9) { + edm4hep::SimTrackerHitCollection rawhits_coll; + auto time_series_coll = std::make_unique(); + + auto hit = rawhits_coll.create(); + auto cellID = + id_desc.encode({{"system", 0}, {"module", 0}, {"sensor", 1}, {"x", 1}, {"y", 1}}); + + hit.setCellID(cellID); + hit.setEDep( + edep); // in GeV. Since Vm = 1e-4*gain, EDep = 1e-4 GeV corresponds to ADC = max_adc + hit.setTime(1.5); // in ns + + // Constructing input and output as per the algorithm's expected signature + auto input = std::make_tuple(&rawhits_coll); + auto output = std::make_tuple(time_series_coll.get()); + + algo.process(input, output); + + if (edep < 1e-4 / 5) + REQUIRE(time_series_coll->size() == 0); + else { + REQUIRE(time_series_coll->size() == 1); + auto pulse = (*time_series_coll)[0]; + REQUIRE(pulse.getCellID() == cellID); + + auto adcs = pulse.getAdcCounts(); + auto min_adc = std::numeric_limits::max(); + for (const auto adc : adcs) + min_adc = std::min(min_adc, adc); + int npt = graph.GetN(); + graph.SetPoint(npt, edep, min_adc); + graph.SetPointError(npt, 0, 0.5); + + // make sure when energy deposition = Vm, ADC reaches max value + if (edep == 1e-4) + REQUIRE(min_adc == -cfg.adc_range + 1); + } + } + + // test linearlity + TF1 tf1("tf1", "pol1", 0, 1e-4); + graph.Fit(&tf1, "R0"); + double chi2_dof = tf1.GetChisquare() / tf1.GetNDF(); + logger->info("Chi-square/dof value for Edep vs min-adc = {}", chi2_dof); + REQUIRE(chi2_dof < 2); + } + + SECTION("Pulse timing linearlity test") { + // check if max pulse height is linearly proportional to the initial Edep + algo.applyConfig(cfg); + algo.init(); + + TGraphErrors graph; + for (double time = 0; time < 12; time += 1.) { + edm4hep::SimTrackerHitCollection rawhits_coll; + auto time_series_coll = std::make_unique(); + + auto hit = rawhits_coll.create(); + auto cellID = + id_desc.encode({{"system", 0}, {"module", 0}, {"sensor", 1}, {"x", 1}, {"y", 1}}); + + hit.setCellID(cellID); + hit.setEDep( + 0.5e-4); // in GeV. Since Vm = 1e-4*gain, EDep = 1e-4 GeV corresponds to ADC = max_adc + hit.setTime(time); // in ns + + // Constructing input and output as per the algorithm's expected signature + auto input = std::make_tuple(&rawhits_coll); + auto output = std::make_tuple(time_series_coll.get()); + + algo.process(input, output); + + REQUIRE(time_series_coll->size() == 1); + auto pulse = (*time_series_coll)[0]; + REQUIRE(pulse.getCellID() == cellID); + + auto adcs = pulse.getAdcCounts(); + auto min_adc = std::numeric_limits::max(); + unsigned int time_bin = 0; + for (unsigned int i = 0; i < adcs.size(); ++i) { + auto adc = adcs[i]; + if (adc < min_adc) + time_bin = i; + min_adc = std::min(min_adc, adc); + } + int npt = graph.GetN(); + graph.SetPoint(npt, time, time_bin); + graph.SetPointError(npt, 0, 0.5); + } + + // test linearlity + TF1 tf1("tf1", "pol1", 0, 12); + graph.Fit(&tf1, "R0"); + double chi2_dof = tf1.GetChisquare() / tf1.GetNDF(); + logger->info("Chi-square/dof value for time vs TDC-bin = {}", chi2_dof); + REQUIRE(chi2_dof < 2); + } +} From d073d6bcc8f207a1f400499be131241b0b11137b Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Thu, 7 Nov 2024 18:09:48 -0500 Subject: [PATCH 52/77] Removed unnecessary credits. --- src/algorithms/digi/BTOFChargeSharing.cc | 98 +++++++++++---------- src/algorithms/digi/TOFHitDigiConfig.h | 2 +- src/algorithms/digi/TOFPulseDigitization.cc | 5 +- src/algorithms/digi/TOFPulseGeneration.cc | 5 +- 4 files changed, 53 insertions(+), 57 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index 4787b029e8..5704098347 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -44,6 +44,54 @@ void BTOFChargeSharing::init() { m_decoder = seg.decoder(); } +void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, + const BTOFChargeSharing::Output& output) const { + const auto [simhits] = input; + auto [sharedHits] = output; + std::shared_ptr> neighbors; + + for(const auto & hit : *simhits) { + auto cellID = hit.getCellID(); + + if(!neighbors){ + std::unordered_set dp; + neighbors = std::make_shared>(); + this -> _findAllNeighborsInSensor(cellID, neighbors, dp); + } + + double edep = hit.getEDep(); + double time = hit.getTime(); + auto momentum = hit.getMomentum(); + auto truePos = hit.getPosition(); + auto localPos_hit = this -> _global2Local(dd4hep::Position(truePos.x*dd4hep::mm, truePos.y*dd4hep::mm, truePos.z*dd4hep::mm)); + + for(const auto neighbor : *neighbors) { + // integrate over neighbor area to get total energy deposition + auto localPos_neighbor = this -> _cell2LocalPosition(neighbor); + auto cellDimension = m_converter -> cellDimensions(neighbor); + + double edep_cell = edep * + _integralGaus(localPos_hit.x(), m_cfg.sigma_sharingx, + localPos_neighbor.x() - 0.5 * cellDimension[0], + localPos_neighbor.x() + 0.5 * cellDimension[0]) * + _integralGaus(localPos_hit.y(), m_cfg.sigma_sharingy, + localPos_neighbor.y() - 0.5 * cellDimension[1], + localPos_neighbor.y() + 0.5 * cellDimension[1]); + + if(edep_cell > 0) { + auto globalPos = m_converter -> position(neighbor); + auto hit = sharedHits->create(); + hit.setCellID(neighbor); + hit.setEDep(edep_cell); + hit.setTime(time); + hit.setPosition({globalPos.x(), globalPos.y(), globalPos.z()}); + hit.setMomentum({momentum.x, momentum.y, momentum.z}); + } + } + } +} // BTOFChargeSharing:process + + void BTOFChargeSharing::_findAllNeighborsInSensor( dd4hep::rec::CellID hitCell, std::shared_ptr>& answer, std::unordered_set& dp) const { @@ -105,8 +153,8 @@ double BTOFChargeSharing::_integralGaus(double mean, double sd, double low_lim, double up = mean > up_lim? -0.5 : 0.5; double low = mean > low_lim? -0.5 : 0.5; if(sd > 0) { - up = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - up_lim) / sd); - low = -0.5 * ROOT::Math::erf(TMath::Sqrt(2) * (mean - low_lim) / sd); + up = -0.5 * std::erf(std::sqrt(2) * (mean - up_lim) / sd); + low = -0.5 * std::erf(std::sqrt(2) * (mean - low_lim) / sd); } return up - low; } @@ -129,50 +177,4 @@ dd4hep::Position BTOFChargeSharing::_global2Local(const dd4hep::Position& pos) c return position; } -void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, - const BTOFChargeSharing::Output& output) const { - const auto [simhits] = input; - auto [sharedHits] = output; - std::shared_ptr> neighbors; - - for(const auto & hit : *simhits) { - auto cellID = hit.getCellID(); - - if(!neighbors){ - std::unordered_set dp; - neighbors = std::make_shared>(); - this -> _findAllNeighborsInSensor(cellID, neighbors, dp); - } - - double edep = hit.getEDep(); - double time = hit.getTime(); - auto momentum = hit.getMomentum(); - auto truePos = hit.getPosition(); - auto localPos_hit = this -> _global2Local(dd4hep::Position(truePos.x*dd4hep::mm, truePos.y*dd4hep::mm, truePos.z*dd4hep::mm)); - - for(const auto neighbor : *neighbors) { - // integrate over neighbor area to get total energy deposition - auto localPos_neighbor = this -> _cell2LocalPosition(neighbor); - auto cellDimension = m_converter -> cellDimensions(neighbor); - - double edep_cell = edep * - _integralGaus(localPos_hit.x(), m_cfg.sigma_sharingx, - localPos_neighbor.x() - 0.5 * cellDimension[0], - localPos_neighbor.x() + 0.5 * cellDimension[0]) * - _integralGaus(localPos_hit.y(), m_cfg.sigma_sharingy, - localPos_neighbor.y() - 0.5 * cellDimension[1], - localPos_neighbor.y() + 0.5 * cellDimension[1]); - - if(edep_cell > 0) { - auto globalPos = m_converter -> position(neighbor); - auto hit = sharedHits->create(); - hit.setCellID(neighbor); - hit.setEDep(edep_cell); - hit.setTime(time); - hit.setPosition({globalPos.x(), globalPos.y(), globalPos.z()}); - hit.setMomentum({momentum.x, momentum.y, momentum.z}); - } - } - } -} // BTOFChargeSharing:process } // namespace eicrecon diff --git a/src/algorithms/digi/TOFHitDigiConfig.h b/src/algorithms/digi/TOFHitDigiConfig.h index dc7b7e5e01..51697b9707 100644 --- a/src/algorithms/digi/TOFHitDigiConfig.h +++ b/src/algorithms/digi/TOFHitDigiConfig.h @@ -15,7 +15,7 @@ struct TOFHitDigiConfig { double resolutionTDC{1}; double resolutionADC{1}; - // Parameters of AC-LGAD signal generation - Added by Souvik + // Parameters of AC-LGAD signal generation double gain = 80; double risetime = 0.45; // 0.02; //in ns double sigma_analog = 0.293951; diff --git a/src/algorithms/digi/TOFPulseDigitization.cc b/src/algorithms/digi/TOFPulseDigitization.cc index eaa1ca43e2..550f463f46 100644 --- a/src/algorithms/digi/TOFPulseDigitization.cc +++ b/src/algorithms/digi/TOFPulseDigitization.cc @@ -24,8 +24,7 @@ void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, auto [rawhits] = output; double thres = m_cfg.t_thres; - // double Vm=-0.05; - // SP noted that max dE experienced by LGAD should be 0.8 keV + // Vm in unit of GeV. When Edep = Vm, ADC = cfg.adc_range-1 double Vm = m_cfg.Vm; int adc_range = m_cfg.adc_range; @@ -34,8 +33,6 @@ void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, double norm_threshold = -thres * adc_range / Vm; for(const auto& pulse : *simhits) { - // Added by SP - //------------------------------------------------------------- double intersectionX = 0.0; int tdc = std::numeric_limits::max(); int adc = 0; diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index a8aa3845c0..c890fc71ca 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -29,7 +29,6 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, const auto [simhits] = input; auto [rawADCs] = output; - // SP noted that max dE experienced by LGAD should be 0.8 keV double Vm = m_cfg.Vm; double tMin = m_cfg.tMin; double tMax = m_cfg.tMax; @@ -46,7 +45,7 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, for (const auto& hit : *simhits) { auto cellID = hit.getCellID(); double sum_charge = 0.0; - double mpv_analog = 0.0; // SP + double mpv_analog = 0.0; double time = hit.getTime(); double charge = hit.getEDep(); @@ -56,8 +55,6 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, auto& ADCs = adc_sum[cellID]; if(ADCs.size() == 0) ADCs.resize(nBins, 0); - // Added by SP - //------------------------------------------------------------- mpv_analog = time + m_cfg.risetime; double landau_min = this -> _Landau(0, mpv_analog, m_cfg.sigma_analog); From 6e34d8a87313ca5438d0ac81edfd88a1d7aad2ef Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 7 Nov 2024 23:11:02 +0000 Subject: [PATCH 53/77] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/TOFPulseGeneration.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index c890fc71ca..aca923fca5 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -45,7 +45,7 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, for (const auto& hit : *simhits) { auto cellID = hit.getCellID(); double sum_charge = 0.0; - double mpv_analog = 0.0; + double mpv_analog = 0.0; double time = hit.getTime(); double charge = hit.getEDep(); From d7325502f7fc378177066e01edbd4fb92cb0aa0f Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Thu, 21 Nov 2024 16:24:31 -0500 Subject: [PATCH 54/77] Update src/algorithms/digi/TOFHitDigiConfig.h Co-authored-by: Derek M Anderson --- src/algorithms/digi/TOFHitDigiConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/TOFHitDigiConfig.h b/src/algorithms/digi/TOFHitDigiConfig.h index 51697b9707..e2bc9b7b48 100644 --- a/src/algorithms/digi/TOFHitDigiConfig.h +++ b/src/algorithms/digi/TOFHitDigiConfig.h @@ -17,7 +17,7 @@ struct TOFHitDigiConfig { // Parameters of AC-LGAD signal generation double gain = 80; - double risetime = 0.45; // 0.02; //in ns + double risetime = 0.45; //in ns double sigma_analog = 0.293951; double sigma_sharingx = 0.1; double sigma_sharingy = 0.5; From 40cf8258eb3b124098879e7521da8ec0b1fae175 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Thu, 21 Nov 2024 18:00:06 -0500 Subject: [PATCH 55/77] Amplitude of Landau pulse is now a configurable parameter. --- src/algorithms/digi/TOFHitDigiConfig.h | 2 +- src/algorithms/digi/TOFPulseGeneration.cc | 23 ++++++++----------- src/algorithms/digi/TOFPulseGeneration.h | 2 +- .../digi_TOFPulseGeneration.cc | 2 +- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/algorithms/digi/TOFHitDigiConfig.h b/src/algorithms/digi/TOFHitDigiConfig.h index e2bc9b7b48..92c79e65e0 100644 --- a/src/algorithms/digi/TOFHitDigiConfig.h +++ b/src/algorithms/digi/TOFHitDigiConfig.h @@ -16,7 +16,7 @@ struct TOFHitDigiConfig { double resolutionADC{1}; // Parameters of AC-LGAD signal generation - double gain = 80; + double gain = 113.755; double risetime = 0.45; //in ns double sigma_analog = 0.293951; double sigma_sharingx = 0.1; diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index aca923fca5..d7f909fb3b 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -19,9 +19,8 @@ namespace eicrecon { -double TOFPulseGeneration::_Landau(double x, double mean, double std) const { - double C = -113.755; - return C * TMath::Landau(x, mean, std, kTRUE); +double TOFPulseGeneration::_Landau(double amp, double x, double mean, double std) const { + return amp*TMath::Landau(x, mean, std, kTRUE); } void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, @@ -57,19 +56,17 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, mpv_analog = time + m_cfg.risetime; - double landau_min = this -> _Landau(0, mpv_analog, m_cfg.sigma_analog); - // find minimum of the landau function - // minimum = peak because prefactor is negative - for (int j = 0; j < nBins; ++j) { - double x = tMin + j * interval; - landau_min = std::min(landau_min, this -> _Landau(x, mpv_analog, m_cfg.sigma_analog)); - } - - double scalingFactor = -1. / Vm / m_cfg.gain / landau_min * adc_range; + // amplitude has to be negative + // because voltage is negative + // calculation of the extreme values for Landau distribution can be found on lin 514-520 of https://root.cern.ch/root/html524/src/TMath.cxx.html#fsokrB + // Landau reaches minimum for mpv = 0 and sigma = 1 at x = -0.22278 + const double x_when_landau_min = -0.22278; + double landau_min = this -> _Landau(-m_cfg.gain, x_when_landau_min, 0, 1)/m_cfg.sigma_analog; + double scalingFactor = 1. / Vm / landau_min * adc_range; for (int j = 0; j < nBins; ++j) { double x = tMin + j * interval; - double y = -1 * charge * m_cfg.gain * this -> _Landau(x, mpv_analog, m_cfg.sigma_analog) * scalingFactor; + double y = charge * this -> _Landau(-m_cfg.gain, x, mpv_analog, m_cfg.sigma_analog) * scalingFactor; ADCs[j] += y;; } diff --git a/src/algorithms/digi/TOFPulseGeneration.h b/src/algorithms/digi/TOFPulseGeneration.h index 20f9c910cb..98b27154d4 100644 --- a/src/algorithms/digi/TOFPulseGeneration.h +++ b/src/algorithms/digi/TOFPulseGeneration.h @@ -35,7 +35,7 @@ class TOFPulseGeneration : public TOFPulseGenerationAlgorithm, void process(const Input&, const Output&) const final; protected: - double _Landau(double x, double mean, double std) const; + double _Landau(double amp, double x, double mean, double std) const; }; } // namespace eicrecon diff --git a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc index b09bae1bb2..f0e10af1c8 100644 --- a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc +++ b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc @@ -47,7 +47,7 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { auto detector = algorithms::GeoSvc::instance().detector(); auto id_desc = detector->readout(cfg.readout).idSpec(); - cfg.gain = 10; + cfg.gain = 113; cfg.Vm = -1e-4; cfg.ignore_thres = 1e-4 / 5; From fbde72c314b6b58c27d51c9d6bf801d2911423eb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 23:01:20 +0000 Subject: [PATCH 56/77] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/TOFPulseGeneration.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index d7f909fb3b..afb6fe64a4 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -60,7 +60,7 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, // because voltage is negative // calculation of the extreme values for Landau distribution can be found on lin 514-520 of https://root.cern.ch/root/html524/src/TMath.cxx.html#fsokrB // Landau reaches minimum for mpv = 0 and sigma = 1 at x = -0.22278 - const double x_when_landau_min = -0.22278; + const double x_when_landau_min = -0.22278; double landau_min = this -> _Landau(-m_cfg.gain, x_when_landau_min, 0, 1)/m_cfg.sigma_analog; double scalingFactor = 1. / Vm / landau_min * adc_range; From da1321b6aee9746b25745806bafceccb4a8a8a8c Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Fri, 22 Nov 2024 11:23:18 -0500 Subject: [PATCH 57/77] Beginning time of TOFPulse is now aligned to the beginning of clock cycle. Units are also added to TOFHitDigiConfig. --- src/algorithms/digi/TOFHitDigiConfig.h | 29 +++++++++---------- src/algorithms/digi/TOFPulseGeneration.cc | 25 +++++++++------- src/algorithms/digi/TOFPulseGeneration.h | 1 + .../digi_TOFPulseDigitization.cc | 2 ++ 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/algorithms/digi/TOFHitDigiConfig.h b/src/algorithms/digi/TOFHitDigiConfig.h index 92c79e65e0..e9489b2f89 100644 --- a/src/algorithms/digi/TOFHitDigiConfig.h +++ b/src/algorithms/digi/TOFHitDigiConfig.h @@ -8,32 +8,29 @@ namespace eicrecon { struct TOFHitDigiConfig { - // single hit energy deposition threshold - double threshold{1.0 * dd4hep::keV}; - double tRes = 0.1; /// TODO 8 of what units??? Same TODO in juggler. Probably [ns] - // digitization settings - double resolutionTDC{1}; - double resolutionADC{1}; - // Parameters of AC-LGAD signal generation double gain = 113.755; - double risetime = 0.45; //in ns - double sigma_analog = 0.293951; - double sigma_sharingx = 0.1; - double sigma_sharingy = 0.5; + double risetime = 0.45 * dd4hep::ns; + double sigma_analog = 0.293951 * dd4hep::ns; + double sigma_sharingx = 0.1 * dd4hep::cm; + double sigma_sharingy = 0.5 * dd4hep::cm; double Vm = -1e-4 * dd4hep::GeV; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage corresponds to ADC = adc_max - double t_thres = 0.1 * Vm; + double t_thres = 0.1 * Vm; // TDC value = time when pulse exceed t_thres double ignore_thres = 0.01 * Vm; // If EDep below this value, digitization for the cell will be ignored. Speed up calculation - // - double tMin = 0.1; - double tMax = 25;// 25 ns is the period of 40MHz EIC clock - int total_time = ceil(tMax - tMin); + int adc_bit = 8; int tdc_bit = 10; + // total number of TDC/ADC values + // Since digitizer starts at zero, max ADC value = adc_range - 1 + // Similar for TDC int adc_range = pow(2, adc_bit); int tdc_range = pow(2, tdc_bit); + // period of the sensor clock. Time internal to sensor will all be digitized to integer multiple of tInterval + double tInterval = 25 * dd4hep::ns/(tdc_range - 1); + double tMin = 0.; + double tMax = 25 * dd4hep::ns; // 25 ns is the period of 40MHz EIC clock std::string readout = "TOFBarrelHits"; }; diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index afb6fe64a4..3fb05d410e 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -23,14 +23,20 @@ double TOFPulseGeneration::_Landau(double amp, double x, double mean, double std return amp*TMath::Landau(x, mean, std, kTRUE); } +double TOFPulseGeneration::_DigitizeTime(double time) const { + // digitization always round down to tbe previous bin + return static_cast(time/m_cfg.tInterval + 1e-3)*m_cfg.tInterval; +} + void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, const TOFPulseGeneration::Output& output) const { const auto [simhits] = input; auto [rawADCs] = output; + double interval = m_cfg.tInterval; double Vm = m_cfg.Vm; - double tMin = m_cfg.tMin; - double tMax = m_cfg.tMax; + double tMin = _DigitizeTime(m_cfg.tMin); + double tMax = _DigitizeTime(m_cfg.tMax); int adc_range = m_cfg.adc_range; int tdc_range = m_cfg.tdc_range; int nBins = m_cfg.tdc_range; @@ -39,14 +45,13 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, // NOTE: we take the cellID of the most energetic hit in this group so it is a real cellID from an // MC hit std::unordered_map> adc_sum; - double interval = (tMax - tMin) / (nBins - 1); for (const auto& hit : *simhits) { auto cellID = hit.getCellID(); double sum_charge = 0.0; double mpv_analog = 0.0; - double time = hit.getTime(); + double time = hit.getTime() * dd4hep::ns; double charge = hit.getEDep(); // reduce computation power by not simulating low-charge hits if(charge < m_cfg.ignore_thres) continue; @@ -63,11 +68,11 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, const double x_when_landau_min = -0.22278; double landau_min = this -> _Landau(-m_cfg.gain, x_when_landau_min, 0, 1)/m_cfg.sigma_analog; double scalingFactor = 1. / Vm / landau_min * adc_range; - - for (int j = 0; j < nBins; ++j) { - double x = tMin + j * interval; - double y = charge * this -> _Landau(-m_cfg.gain, x, mpv_analog, m_cfg.sigma_analog) * scalingFactor; - ADCs[j] += y;; + + { + int j; + for (double t = tMin, j = 0; t < tMax; ++j, t += interval) + ADCs[j] += charge * this -> _Landau(-m_cfg.gain, t, mpv_analog, m_cfg.sigma_analog) * scalingFactor; } } @@ -76,7 +81,7 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, for(const auto &[cellID, ADCs] : adc_sum) { auto time_series = rawADCs -> create(); time_series.setCellID(cellID); - time_series.setTime(1.); // placeholder. Don't know what to assign when there are two or more hits + time_series.setTime(tMin); time_series.setCharge(1.); // placeholder. Don't know what to assign when there are two or more hits time_series.setInterval(interval); diff --git a/src/algorithms/digi/TOFPulseGeneration.h b/src/algorithms/digi/TOFPulseGeneration.h index 98b27154d4..593fba67b6 100644 --- a/src/algorithms/digi/TOFPulseGeneration.h +++ b/src/algorithms/digi/TOFPulseGeneration.h @@ -36,6 +36,7 @@ class TOFPulseGeneration : public TOFPulseGenerationAlgorithm, protected: double _Landau(double amp, double x, double mean, double std) const; + double _DigitizeTime(double time) const; }; } // namespace eicrecon diff --git a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc index f431086530..bc7ec530b7 100644 --- a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc +++ b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc @@ -62,6 +62,7 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseDigitization]") { algo.init(); SECTION("TDC vs analytic solution scan") { + logger->info("Begin TDC vs analytic solution scan"); // test pulse with gaussian shape for (double tdc_frac = 0.4; tdc_frac < 1; tdc_frac += 0.1) { @@ -109,6 +110,7 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseDigitization]") { } SECTION("ADC scan") { + logger->info("Begin ADC scan"); // test pulse with gaussian shape for (double adc_frac = 0.4; adc_frac < 1; adc_frac += 0.1) { From 515eba40992b15d03f3573533d5fa7f8f57a36d3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:24:10 +0000 Subject: [PATCH 58/77] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/TOFHitDigiConfig.h | 8 ++++---- src/algorithms/digi/TOFPulseGeneration.cc | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/algorithms/digi/TOFHitDigiConfig.h b/src/algorithms/digi/TOFHitDigiConfig.h index e9489b2f89..2f5740020a 100644 --- a/src/algorithms/digi/TOFHitDigiConfig.h +++ b/src/algorithms/digi/TOFHitDigiConfig.h @@ -10,25 +10,25 @@ namespace eicrecon { struct TOFHitDigiConfig { // Parameters of AC-LGAD signal generation double gain = 113.755; - double risetime = 0.45 * dd4hep::ns; + double risetime = 0.45 * dd4hep::ns; double sigma_analog = 0.293951 * dd4hep::ns; double sigma_sharingx = 0.1 * dd4hep::cm; double sigma_sharingy = 0.5 * dd4hep::cm; double Vm = -1e-4 * dd4hep::GeV; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage corresponds to ADC = adc_max double t_thres = 0.1 * Vm; // TDC value = time when pulse exceed t_thres double ignore_thres = 0.01 * Vm; // If EDep below this value, digitization for the cell will be ignored. Speed up calculation - + int adc_bit = 8; int tdc_bit = 10; - // total number of TDC/ADC values + // total number of TDC/ADC values // Since digitizer starts at zero, max ADC value = adc_range - 1 // Similar for TDC int adc_range = pow(2, adc_bit); int tdc_range = pow(2, tdc_bit); // period of the sensor clock. Time internal to sensor will all be digitized to integer multiple of tInterval - double tInterval = 25 * dd4hep::ns/(tdc_range - 1); + double tInterval = 25 * dd4hep::ns/(tdc_range - 1); double tMin = 0.; double tMax = 25 * dd4hep::ns; // 25 ns is the period of 40MHz EIC clock std::string readout = "TOFBarrelHits"; diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index 3fb05d410e..0c1a86da2c 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -33,7 +33,7 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, const auto [simhits] = input; auto [rawADCs] = output; - double interval = m_cfg.tInterval; + double interval = m_cfg.tInterval; double Vm = m_cfg.Vm; double tMin = _DigitizeTime(m_cfg.tMin); double tMax = _DigitizeTime(m_cfg.tMax); @@ -68,10 +68,10 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, const double x_when_landau_min = -0.22278; double landau_min = this -> _Landau(-m_cfg.gain, x_when_landau_min, 0, 1)/m_cfg.sigma_analog; double scalingFactor = 1. / Vm / landau_min * adc_range; - + { int j; - for (double t = tMin, j = 0; t < tMax; ++j, t += interval) + for (double t = tMin, j = 0; t < tMax; ++j, t += interval) ADCs[j] += charge * this -> _Landau(-m_cfg.gain, t, mpv_analog, m_cfg.sigma_analog) * scalingFactor; } @@ -81,7 +81,7 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, for(const auto &[cellID, ADCs] : adc_sum) { auto time_series = rawADCs -> create(); time_series.setCellID(cellID); - time_series.setTime(tMin); + time_series.setTime(tMin); time_series.setCharge(1.); // placeholder. Don't know what to assign when there are two or more hits time_series.setInterval(interval); From fcb0e072d98c4e34bb2c3e61a0e27017bfefaf15 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Fri, 22 Nov 2024 14:10:38 -0500 Subject: [PATCH 59/77] Make clang-tidy-iwyu happy. --- src/algorithms/digi/BTOFChargeSharing.cc | 3 +- src/algorithms/digi/TOFPulseGeneration.cc | 2 +- .../digi_TOFPulseDigitization.cc | 35 ++++++------------- .../digi_TOFPulseGeneration.cc | 35 ++++++++----------- 4 files changed, 27 insertions(+), 48 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index 5704098347..d4c05d05f5 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -11,13 +11,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -25,7 +25,6 @@ #include "BTOFChargeSharing.h" #include "DD4hep/Detector.h" -#include "TMath.h" #include "algorithms/digi/TOFHitDigiConfig.h" diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index 0c1a86da2c..c69d3c7274 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -6,8 +6,8 @@ // ADC pulses are assumed to follow the shape of landau function #include +#include #include -#include #include #include #include diff --git a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc index bc7ec530b7..dc322c176e 100644 --- a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc +++ b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc @@ -1,38 +1,25 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // Copyright (C) 2024, Chun Yuen Tsang, Prithwish Tribedy +#include +#include +#include +#include +#include #include // for AssertionHandler, operator""_catch_sr, StringRef, REQUIRE, operator<, operator==, operator>, TEST_CASE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access +#include +#include #include // for level_enum #include // for logger #include // for default_logger +#include +#include +#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access #include -#include +#include #include "algorithms/digi/TOFHitDigiConfig.h" #include "algorithms/digi/TOFPulseDigitization.h" -#include -#include -#include -#include -#include - -#include "TF1.h" -#include "TGraphErrors.h" TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseDigitization]") { const float EPSILON = 1e-5; diff --git a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc index f0e10af1c8..1f6e5e8cc7 100644 --- a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc +++ b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc @@ -1,37 +1,30 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // Copyright (C) 2024, Chun Yuen Tsang, Prithwish Tribedy +#include +#include +#include +#include #include // for AssertionHandler, operator""_catch_sr, StringRef, REQUIRE, operator<, operator==, operator>, TEST_CASE -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access +#include +#include #include // for level_enum #include // for logger #include // for default_logger +#include +#include +#include +#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access #include +#include #include -#include "algorithms/digi/TOFHitDigiConfig.h" -#include "algorithms/digi/TOFPulseGeneration.h" -#include -#include -#include -#include - #include "TF1.h" #include "TGraphErrors.h" +#include "algorithms/digi/TOFHitDigiConfig.h" +#include "algorithms/digi/TOFPulseGeneration.h" TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { const float EPSILON = 1e-5; From 955196452168e16fdc885c1f155895611f9a3ee6 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Mon, 25 Nov 2024 13:25:42 -0500 Subject: [PATCH 60/77] Fix typo in code. --- src/algorithms/digi/TOFPulseGeneration.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index c69d3c7274..0d4dd02318 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -24,7 +24,7 @@ double TOFPulseGeneration::_Landau(double amp, double x, double mean, double std } double TOFPulseGeneration::_DigitizeTime(double time) const { - // digitization always round down to tbe previous bin + // digitization always round down to the previous bin return static_cast(time/m_cfg.tInterval + 1e-3)*m_cfg.tInterval; } From 3d4638c962a518ccce5316ba2a74d979b52dbba9 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Tue, 26 Nov 2024 16:25:47 -0500 Subject: [PATCH 61/77] Trigger Build From 29239b7a2b58640f29c0c5814047eeed65286306 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Sun, 1 Dec 2024 18:44:48 -0500 Subject: [PATCH 62/77] apply clang-format --- src/algorithms/digi/BTOFChargeSharing.cc | 90 +++++++++---------- src/algorithms/digi/BTOFChargeSharing.h | 12 ++- src/algorithms/digi/TOFHitDigiConfig.h | 21 +++-- src/algorithms/digi/TOFPulseDigitization.cc | 23 +++-- src/algorithms/digi/TOFPulseDigitization.h | 13 ++- src/algorithms/digi/TOFPulseGeneration.cc | 57 ++++++------ src/algorithms/digi/TOFPulseGeneration.h | 11 +-- .../digi/BTOFChargeSharing_factory.h | 7 +- .../digi/TOFPulseDigitization_factory.h | 10 ++- .../digi/TOFPulseGeneration_factory.h | 10 ++- .../digi_TOFPulseDigitization.cc | 10 +-- .../digi_TOFPulseGeneration.cc | 8 +- 12 files changed, 137 insertions(+), 135 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index d4c05d05f5..3c227e720e 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -15,9 +15,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -27,15 +27,14 @@ #include "DD4hep/Detector.h" #include "algorithms/digi/TOFHitDigiConfig.h" - namespace eicrecon { void BTOFChargeSharing::init() { - m_detector = algorithms::GeoSvc::instance().detector();; + m_detector = algorithms::GeoSvc::instance().detector(); m_converter = algorithms::GeoSvc::instance().cellIDPositionConverter(); - auto seg = m_detector->readout(m_cfg.readout).segmentation(); - auto type = seg.type(); + auto seg = m_detector->readout(m_cfg.readout).segmentation(); + auto type = seg.type(); if (type != "CartesianGridXY") throw std::runtime_error("Unsupported segmentation type: " + type + ". BarrelTOF must use CartesianGridXY."); @@ -46,51 +45,51 @@ void BTOFChargeSharing::init() { void BTOFChargeSharing::process(const BTOFChargeSharing::Input& input, const BTOFChargeSharing::Output& output) const { const auto [simhits] = input; - auto [sharedHits] = output; + auto [sharedHits] = output; std::shared_ptr> neighbors; - for(const auto & hit : *simhits) { + for (const auto& hit : *simhits) { auto cellID = hit.getCellID(); - if(!neighbors){ + if (!neighbors) { std::unordered_set dp; neighbors = std::make_shared>(); - this -> _findAllNeighborsInSensor(cellID, neighbors, dp); + this->_findAllNeighborsInSensor(cellID, neighbors, dp); } - double edep = hit.getEDep(); - double time = hit.getTime(); - auto momentum = hit.getMomentum(); - auto truePos = hit.getPosition(); - auto localPos_hit = this -> _global2Local(dd4hep::Position(truePos.x*dd4hep::mm, truePos.y*dd4hep::mm, truePos.z*dd4hep::mm)); - - for(const auto neighbor : *neighbors) { - // integrate over neighbor area to get total energy deposition - auto localPos_neighbor = this -> _cell2LocalPosition(neighbor); - auto cellDimension = m_converter -> cellDimensions(neighbor); - - double edep_cell = edep * - _integralGaus(localPos_hit.x(), m_cfg.sigma_sharingx, - localPos_neighbor.x() - 0.5 * cellDimension[0], - localPos_neighbor.x() + 0.5 * cellDimension[0]) * - _integralGaus(localPos_hit.y(), m_cfg.sigma_sharingy, - localPos_neighbor.y() - 0.5 * cellDimension[1], - localPos_neighbor.y() + 0.5 * cellDimension[1]); - - if(edep_cell > 0) { - auto globalPos = m_converter -> position(neighbor); - auto hit = sharedHits->create(); - hit.setCellID(neighbor); - hit.setEDep(edep_cell); - hit.setTime(time); - hit.setPosition({globalPos.x(), globalPos.y(), globalPos.z()}); - hit.setMomentum({momentum.x, momentum.y, momentum.z}); - } + double edep = hit.getEDep(); + double time = hit.getTime(); + auto momentum = hit.getMomentum(); + auto truePos = hit.getPosition(); + auto localPos_hit = this->_global2Local( + dd4hep::Position(truePos.x * dd4hep::mm, truePos.y * dd4hep::mm, truePos.z * dd4hep::mm)); + + for (const auto neighbor : *neighbors) { + // integrate over neighbor area to get total energy deposition + auto localPos_neighbor = this->_cell2LocalPosition(neighbor); + auto cellDimension = m_converter->cellDimensions(neighbor); + + double edep_cell = edep * + _integralGaus(localPos_hit.x(), m_cfg.sigma_sharingx, + localPos_neighbor.x() - 0.5 * cellDimension[0], + localPos_neighbor.x() + 0.5 * cellDimension[0]) * + _integralGaus(localPos_hit.y(), m_cfg.sigma_sharingy, + localPos_neighbor.y() - 0.5 * cellDimension[1], + localPos_neighbor.y() + 0.5 * cellDimension[1]); + + if (edep_cell > 0) { + auto globalPos = m_converter->position(neighbor); + auto hit = sharedHits->create(); + hit.setCellID(neighbor); + hit.setEDep(edep_cell); + hit.setTime(time); + hit.setPosition({globalPos.x(), globalPos.y(), globalPos.z()}); + hit.setMomentum({momentum.x, momentum.y, momentum.z}); + } } } } // BTOFChargeSharing:process - void BTOFChargeSharing::_findAllNeighborsInSensor( dd4hep::rec::CellID hitCell, std::shared_ptr>& answer, std::unordered_set& dp) const { @@ -101,7 +100,7 @@ void BTOFChargeSharing::_findAllNeighborsInSensor( answer->push_back(hitCell); dp.insert(hitCell); - auto sensorID = this -> _getSensorID(hitCell); + auto sensorID = this->_getSensorID(hitCell); auto xID = m_decoder->get(hitCell, "x"); auto yID = m_decoder->get(hitCell, "y"); for (const auto& dir : searchDirs) { @@ -146,12 +145,13 @@ BTOFChargeSharing::_getSensorID(const dd4hep::rec::CellID& hitCell) const { return sensorID; } -double BTOFChargeSharing::_integralGaus(double mean, double sd, double low_lim, double up_lim) const { +double BTOFChargeSharing::_integralGaus(double mean, double sd, double low_lim, + double up_lim) const { // return integral Gauss(mean, sd) dx from x = low_lim to x = up_lim // default value is set when sd = 0 - double up = mean > up_lim? -0.5 : 0.5; - double low = mean > low_lim? -0.5 : 0.5; - if(sd > 0) { + double up = mean > up_lim ? -0.5 : 0.5; + double low = mean > low_lim ? -0.5 : 0.5; + if (sd > 0) { up = -0.5 * std::erf(std::sqrt(2) * (mean - up_lim) / sd); low = -0.5 * std::erf(std::sqrt(2) * (mean - low_lim) / sd); } @@ -159,8 +159,8 @@ double BTOFChargeSharing::_integralGaus(double mean, double sd, double low_lim, } dd4hep::Position BTOFChargeSharing::_cell2LocalPosition(const dd4hep::rec::CellID& cell) const { - auto position = m_converter -> position(cell); // global position - return this -> _global2Local(position); + auto position = m_converter->position(cell); // global position + return this->_global2Local(position); } dd4hep::Position BTOFChargeSharing::_global2Local(const dd4hep::Position& pos) const { diff --git a/src/algorithms/digi/BTOFChargeSharing.h b/src/algorithms/digi/BTOFChargeSharing.h index 7757bd17cb..b87e86989f 100644 --- a/src/algorithms/digi/BTOFChargeSharing.h +++ b/src/algorithms/digi/BTOFChargeSharing.h @@ -23,20 +23,19 @@ namespace eicrecon { using BTOFChargeSharingAlgorithm = - algorithms::Algorithm, - algorithms::Output>; + algorithms::Algorithm, + algorithms::Output>; class BTOFChargeSharing : public BTOFChargeSharingAlgorithm, public WithPodConfig { public: - BTOFChargeSharing(std::string_view name) : BTOFChargeSharingAlgorithm{name, - {"TOFBarrelHits"}, - {"TOFBarrelSharedHits"}, - ""} {}; + BTOFChargeSharing(std::string_view name) + : BTOFChargeSharingAlgorithm{name, {"TOFBarrelHits"}, {"TOFBarrelSharedHits"}, ""} {}; void init() final; void process(const Input&, const Output&) const final; + protected: void _findAllNeighborsInSensor(dd4hep::rec::CellID hitCell, std::shared_ptr>& answer, @@ -49,7 +48,6 @@ class BTOFChargeSharing : public BTOFChargeSharingAlgorithm, const dd4hep::DDSegmentation::BitFieldCoder* m_decoder = nullptr; const dd4hep::Detector* m_detector = nullptr; const dd4hep::rec::CellIDPositionConverter* m_converter = nullptr; - }; } // namespace eicrecon diff --git a/src/algorithms/digi/TOFHitDigiConfig.h b/src/algorithms/digi/TOFHitDigiConfig.h index 2f5740020a..4d68d2d550 100644 --- a/src/algorithms/digi/TOFHitDigiConfig.h +++ b/src/algorithms/digi/TOFHitDigiConfig.h @@ -14,12 +14,14 @@ struct TOFHitDigiConfig { double sigma_analog = 0.293951 * dd4hep::ns; double sigma_sharingx = 0.1 * dd4hep::cm; double sigma_sharingy = 0.5 * dd4hep::cm; - double Vm = -1e-4 * dd4hep::GeV; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage corresponds to ADC = adc_max - double t_thres = 0.1 * Vm; // TDC value = time when pulse exceed t_thres - double ignore_thres = 0.01 * Vm; // If EDep below this value, digitization for the cell will be ignored. Speed up calculation + double Vm = -1e-4 * dd4hep::GeV; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage + // corresponds to ADC = adc_max + double t_thres = 0.1 * Vm; // TDC value = time when pulse exceed t_thres + double ignore_thres = 0.01 * Vm; // If EDep below this value, digitization for the cell will be + // ignored. Speed up calculation - int adc_bit = 8; - int tdc_bit = 10; + int adc_bit = 8; + int tdc_bit = 10; // total number of TDC/ADC values // Since digitizer starts at zero, max ADC value = adc_range - 1 @@ -27,10 +29,11 @@ struct TOFHitDigiConfig { int adc_range = pow(2, adc_bit); int tdc_range = pow(2, tdc_bit); - // period of the sensor clock. Time internal to sensor will all be digitized to integer multiple of tInterval - double tInterval = 25 * dd4hep::ns/(tdc_range - 1); - double tMin = 0.; - double tMax = 25 * dd4hep::ns; // 25 ns is the period of 40MHz EIC clock + // period of the sensor clock. Time internal to sensor will all be digitized to integer multiple + // of tInterval + double tInterval = 25 * dd4hep::ns / (tdc_range - 1); + double tMin = 0.; + double tMax = 25 * dd4hep::ns; // 25 ns is the period of 40MHz EIC clock std::string readout = "TOFBarrelHits"; }; diff --git a/src/algorithms/digi/TOFPulseDigitization.cc b/src/algorithms/digi/TOFPulseDigitization.cc index 550f463f46..cfa544113a 100644 --- a/src/algorithms/digi/TOFPulseDigitization.cc +++ b/src/algorithms/digi/TOFPulseDigitization.cc @@ -4,47 +4,47 @@ // // Convert ADC pulses from TOFPulseGeneration into ADC and TDC values -#include -#include -#include #include #include #include +#include +#include +#include #include #include "TOFPulseDigitization.h" #include "algorithms/digi/TOFHitDigiConfig.h" - namespace eicrecon { void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, const TOFPulseDigitization::Output& output) const { const auto [simhits] = input; - auto [rawhits] = output; + auto [rawhits] = output; double thres = m_cfg.t_thres; // Vm in unit of GeV. When Edep = Vm, ADC = cfg.adc_range-1 - double Vm = m_cfg.Vm; + double Vm = m_cfg.Vm; int adc_range = m_cfg.adc_range; // normalized time threshold // convert threshold EDep to voltage double norm_threshold = -thres * adc_range / Vm; - for(const auto& pulse : *simhits) { + for (const auto& pulse : *simhits) { double intersectionX = 0.0; int tdc = std::numeric_limits::max(); int adc = 0; double V = 0.0; - int time_bin = 0; - double adc_prev = 0; + int time_bin = 0; + double adc_prev = 0; double time_interval = pulse.getInterval(); - auto adcs = pulse.getAdcCounts(); + auto adcs = pulse.getAdcCounts(); for (const auto adc : adcs) { if (adc_prev >= norm_threshold && adc <= norm_threshold) { - intersectionX = time_bin*time_interval + time_interval * (norm_threshold - adc_prev) / (adc - adc_prev); + intersectionX = time_bin * time_interval + + time_interval * (norm_threshold - adc_prev) / (adc - adc_prev); tdc = static_cast(intersectionX / time_interval); } if (abs(adc) > abs(V)) // To get peak of the Analog signal @@ -59,7 +59,6 @@ void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, if (tdc < std::numeric_limits::max()) rawhits->create(pulse.getCellID(), adc, tdc); //----------------------------------------------------------- - } } // TOFPulseDigitization:process } // namespace eicrecon diff --git a/src/algorithms/digi/TOFPulseDigitization.h b/src/algorithms/digi/TOFPulseDigitization.h index cf99a8eca4..a681ee55fc 100644 --- a/src/algorithms/digi/TOFPulseDigitization.h +++ b/src/algorithms/digi/TOFPulseDigitization.h @@ -18,19 +18,16 @@ namespace eicrecon { using TOFPulseDigitizationAlgorithm = - algorithms::Algorithm, - algorithms::Output>; + algorithms::Algorithm, + algorithms::Output>; class TOFPulseDigitization : public TOFPulseDigitizationAlgorithm, public WithPodConfig { public: - TOFPulseDigitization(std::string_view name) : - TOFPulseDigitizationAlgorithm{name, - {"TOFBarrelPulse"}, - {"TOFBarrelADCTDC"}, - {}} {} - void init() {}; + TOFPulseDigitization(std::string_view name) + : TOFPulseDigitizationAlgorithm{name, {"TOFBarrelPulse"}, {"TOFBarrelADCTDC"}, {}} {} + void init(){}; void process(const Input&, const Output&) const final; }; diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc index 0d4dd02318..8592745352 100644 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ b/src/algorithms/digi/TOFPulseGeneration.cc @@ -16,30 +16,29 @@ #include "TOFPulseGeneration.h" #include "algorithms/digi/TOFHitDigiConfig.h" - namespace eicrecon { double TOFPulseGeneration::_Landau(double amp, double x, double mean, double std) const { - return amp*TMath::Landau(x, mean, std, kTRUE); + return amp * TMath::Landau(x, mean, std, kTRUE); } double TOFPulseGeneration::_DigitizeTime(double time) const { // digitization always round down to the previous bin - return static_cast(time/m_cfg.tInterval + 1e-3)*m_cfg.tInterval; + return static_cast(time / m_cfg.tInterval + 1e-3) * m_cfg.tInterval; } void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, const TOFPulseGeneration::Output& output) const { const auto [simhits] = input; - auto [rawADCs] = output; + auto [rawADCs] = output; double interval = m_cfg.tInterval; - double Vm = m_cfg.Vm; - double tMin = _DigitizeTime(m_cfg.tMin); - double tMax = _DigitizeTime(m_cfg.tMax); - int adc_range = m_cfg.adc_range; - int tdc_range = m_cfg.tdc_range; - int nBins = m_cfg.tdc_range; + double Vm = m_cfg.Vm; + double tMin = _DigitizeTime(m_cfg.tMin); + double tMax = _DigitizeTime(m_cfg.tMax); + int adc_range = m_cfg.adc_range; + int tdc_range = m_cfg.tdc_range; + int nBins = m_cfg.tdc_range; // signal sum // NOTE: we take the cellID of the most energetic hit in this group so it is a real cellID from an @@ -47,45 +46,49 @@ void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, std::unordered_map> adc_sum; for (const auto& hit : *simhits) { - auto cellID = hit.getCellID(); + auto cellID = hit.getCellID(); double sum_charge = 0.0; double mpv_analog = 0.0; - double time = hit.getTime() * dd4hep::ns; - double charge = hit.getEDep(); + double time = hit.getTime() * dd4hep::ns; + double charge = hit.getEDep(); // reduce computation power by not simulating low-charge hits - if(charge < m_cfg.ignore_thres) continue; + if (charge < m_cfg.ignore_thres) + continue; auto& ADCs = adc_sum[cellID]; - if(ADCs.size() == 0) ADCs.resize(nBins, 0); + if (ADCs.size() == 0) + ADCs.resize(nBins, 0); mpv_analog = time + m_cfg.risetime; // amplitude has to be negative // because voltage is negative - // calculation of the extreme values for Landau distribution can be found on lin 514-520 of https://root.cern.ch/root/html524/src/TMath.cxx.html#fsokrB - // Landau reaches minimum for mpv = 0 and sigma = 1 at x = -0.22278 + // calculation of the extreme values for Landau distribution can be found on lin 514-520 of + // https://root.cern.ch/root/html524/src/TMath.cxx.html#fsokrB Landau reaches minimum for mpv = + // 0 and sigma = 1 at x = -0.22278 const double x_when_landau_min = -0.22278; - double landau_min = this -> _Landau(-m_cfg.gain, x_when_landau_min, 0, 1)/m_cfg.sigma_analog; + double landau_min = this->_Landau(-m_cfg.gain, x_when_landau_min, 0, 1) / m_cfg.sigma_analog; double scalingFactor = 1. / Vm / landau_min * adc_range; { - int j; - for (double t = tMin, j = 0; t < tMax; ++j, t += interval) - ADCs[j] += charge * this -> _Landau(-m_cfg.gain, t, mpv_analog, m_cfg.sigma_analog) * scalingFactor; + int j; + for (double t = tMin, j = 0; t < tMax; ++j, t += interval) + ADCs[j] += + charge * this->_Landau(-m_cfg.gain, t, mpv_analog, m_cfg.sigma_analog) * scalingFactor; } - } - // convert vector of ADC values to RawTimeSeries - for(const auto &[cellID, ADCs] : adc_sum) { - auto time_series = rawADCs -> create(); + // convert vector of ADC values to RawTimeSeries + for (const auto& [cellID, ADCs] : adc_sum) { + auto time_series = rawADCs->create(); time_series.setCellID(cellID); time_series.setTime(tMin); - time_series.setCharge(1.); // placeholder. Don't know what to assign when there are two or more hits + time_series.setCharge( + 1.); // placeholder. Don't know what to assign when there are two or more hits time_series.setInterval(interval); - for(const auto ADC : ADCs) + for (const auto ADC : ADCs) time_series.addToAdcCounts(ADC); } } // TOFPulseGeneration:process diff --git a/src/algorithms/digi/TOFPulseGeneration.h b/src/algorithms/digi/TOFPulseGeneration.h index 593fba67b6..c4db7b6832 100644 --- a/src/algorithms/digi/TOFPulseGeneration.h +++ b/src/algorithms/digi/TOFPulseGeneration.h @@ -19,19 +19,16 @@ namespace eicrecon { using TOFPulseGenerationAlgorithm = - algorithms::Algorithm, - algorithms::Output>; + algorithms::Algorithm, + algorithms::Output>; class TOFPulseGeneration : public TOFPulseGenerationAlgorithm, public WithPodConfig { public: TOFPulseGeneration(std::string_view name) - : TOFPulseGenerationAlgorithm{name, - {"TOFBarrelSharedHits"}, - {"TOFBarrelPulse"}, - {}} {} - void init() {}; + : TOFPulseGenerationAlgorithm{name, {"TOFBarrelSharedHits"}, {"TOFBarrelPulse"}, {}} {} + void init(){}; void process(const Input&, const Output&) const final; protected: diff --git a/src/factories/digi/BTOFChargeSharing_factory.h b/src/factories/digi/BTOFChargeSharing_factory.h index 1927a0a93d..f5c34f9dce 100644 --- a/src/factories/digi/BTOFChargeSharing_factory.h +++ b/src/factories/digi/BTOFChargeSharing_factory.h @@ -13,6 +13,7 @@ namespace eicrecon { class BTOFChargeSharing_factory : public JOmniFactory { public: using AlgoT = eicrecon::BTOFChargeSharing; + private: std::unique_ptr m_algo; @@ -23,7 +24,8 @@ class BTOFChargeSharing_factory : public JOmniFactory m_sigma_sharingx{this, "sigmaSharingX", config().sigma_sharingx}; ParameterRef m_sigma_sharingy{this, "sigmaSharingY", config().sigma_sharingy}; - Service m_algorithmsInit {this}; + Service m_algorithmsInit{this}; + public: void Configure() { m_algo = std::make_unique(GetPrefix()); @@ -32,8 +34,7 @@ class BTOFChargeSharing_factory : public JOmniFactoryinit(); } - void ChangeRun(int64_t run_number) { - } + void ChangeRun(int64_t run_number) {} void Process(int64_t run_number, uint64_t event_number) { m_algo->process({m_in_sim_track()}, {m_out_reco_particles().get()}); diff --git a/src/factories/digi/TOFPulseDigitization_factory.h b/src/factories/digi/TOFPulseDigitization_factory.h index 510ac3f183..18d3b7349f 100644 --- a/src/factories/digi/TOFPulseDigitization_factory.h +++ b/src/factories/digi/TOFPulseDigitization_factory.h @@ -10,9 +10,11 @@ namespace eicrecon { -class TOFPulseDigitization_factory : public JOmniFactory { +class TOFPulseDigitization_factory + : public JOmniFactory { public: using AlgoT = eicrecon::TOFPulseDigitization; + private: std::unique_ptr m_algo; @@ -22,7 +24,8 @@ class TOFPulseDigitization_factory : public JOmniFactory m_t_thres{this, "tThreshold", config().t_thres}; - Service m_algorithmsInit {this}; + Service m_algorithmsInit{this}; + public: void Configure() { m_algo = std::make_unique(GetPrefix()); @@ -31,8 +34,7 @@ class TOFPulseDigitization_factory : public JOmniFactoryinit(); } - void ChangeRun(int64_t run_number) { - } + void ChangeRun(int64_t run_number) {} void Process(int64_t run_number, uint64_t event_number) { m_algo->process({m_in_sim_track()}, {m_out_reco_particles().get()}); diff --git a/src/factories/digi/TOFPulseGeneration_factory.h b/src/factories/digi/TOFPulseGeneration_factory.h index cd3956f46b..8080239f3d 100644 --- a/src/factories/digi/TOFPulseGeneration_factory.h +++ b/src/factories/digi/TOFPulseGeneration_factory.h @@ -10,9 +10,11 @@ namespace eicrecon { -class TOFPulseGeneration_factory : public JOmniFactory { +class TOFPulseGeneration_factory + : public JOmniFactory { public: using AlgoT = eicrecon::TOFPulseGeneration; + private: std::unique_ptr m_algo; @@ -27,7 +29,8 @@ class TOFPulseGeneration_factory : public JOmniFactory m_tdc_range{this, "tdcRange", config().tdc_range}; ParameterRef m_ignore_thres{this, "ignoreThreshold", config().ignore_thres}; - Service m_algorithmsInit {this}; + Service m_algorithmsInit{this}; + public: void Configure() { m_algo = std::make_unique(GetPrefix()); @@ -36,8 +39,7 @@ class TOFPulseGeneration_factory : public JOmniFactoryinit(); } - void ChangeRun(int64_t run_number) { - } + void ChangeRun(int64_t run_number) {} void Process(int64_t run_number, uint64_t event_number) { m_algo->process({m_in_sim_track()}, {m_out_reco_particles().get()}); diff --git a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc index dc322c176e..426d4f2949 100644 --- a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc +++ b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc @@ -7,14 +7,14 @@ #include #include #include // for AssertionHandler, operator""_catch_sr, StringRef, REQUIRE, operator<, operator==, operator>, TEST_CASE +#include #include #include +#include +#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access #include // for level_enum #include // for logger #include // for default_logger -#include -#include -#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access #include #include @@ -41,8 +41,8 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseDigitization]") { cfg.t_thres = cfg.Vm * 0.1; cfg.tdc_bit = 8; cfg.adc_bit = 7; - cfg.tdc_range = pow(2, cfg.tdc_bit); - cfg.adc_range = pow(2, cfg.adc_bit); + cfg.tdc_range = pow(2, cfg.tdc_bit); + cfg.adc_range = pow(2, cfg.adc_bit); // check if max pulse height is linearly proportional to the initial Edep algo.applyConfig(cfg); diff --git a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc index 1f6e5e8cc7..df9372d206 100644 --- a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc +++ b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc @@ -4,19 +4,19 @@ #include #include #include +#include #include #include // for AssertionHandler, operator""_catch_sr, StringRef, REQUIRE, operator<, operator==, operator>, TEST_CASE #include #include #include +#include +#include +#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access #include #include // for level_enum #include // for logger #include // for default_logger -#include -#include -#include -#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access #include #include #include From 6a67c57ac8e5f717b16f259d509cb9de65ea3b1a Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Mon, 2 Dec 2024 17:14:22 -0500 Subject: [PATCH 63/77] Trigger Build From b1f7166189041baf4d27949409e401a4214d4c16 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Wed, 18 Dec 2024 13:46:39 -0500 Subject: [PATCH 64/77] Added extra bits to show which EIRCOR cycle a timestampe belongs to. --- src/algorithms/digi/BTOFChargeSharing.cc | 2 +- src/algorithms/digi/BTOFChargeSharing.h | 4 +- src/algorithms/digi/BTOFChargeSharingConfig.h | 18 +++ ...DigiConfig.h => LGADChargeSharingConfig.h} | 7 +- src/algorithms/digi/LGADHitDigiConfig.h | 36 ++++++ ...gitization.cc => LGADPulseDigitization.cc} | 15 +-- ...Digitization.h => LGADPulseDigitization.h} | 14 +-- src/algorithms/digi/LGADPulseGeneration.cc | 106 ++++++++++++++++++ src/algorithms/digi/LGADPulseGeneration.h | 64 +++++++++++ src/algorithms/digi/TOFPulseGeneration.cc | 95 ---------------- src/algorithms/digi/TOFPulseGeneration.h | 39 ------- src/detectors/BTOF/BTOF.cc | 8 +- .../digi/BTOFChargeSharing_factory.h | 2 +- ...tory.h => LGADPulseDigitization_factory.h} | 10 +- ...actory.h => LGADPulseGeneration_factory.h} | 13 ++- .../digi_TOFPulseDigitization.cc | 102 +++++++++-------- .../digi_TOFPulseGeneration.cc | 78 ++++++++----- 17 files changed, 363 insertions(+), 250 deletions(-) create mode 100644 src/algorithms/digi/BTOFChargeSharingConfig.h rename src/algorithms/digi/{TOFHitDigiConfig.h => LGADChargeSharingConfig.h} (87%) create mode 100644 src/algorithms/digi/LGADHitDigiConfig.h rename src/algorithms/digi/{TOFPulseDigitization.cc => LGADPulseDigitization.cc} (76%) rename src/algorithms/digi/{TOFPulseDigitization.h => LGADPulseDigitization.h} (61%) create mode 100644 src/algorithms/digi/LGADPulseGeneration.cc create mode 100644 src/algorithms/digi/LGADPulseGeneration.h delete mode 100644 src/algorithms/digi/TOFPulseGeneration.cc delete mode 100644 src/algorithms/digi/TOFPulseGeneration.h rename src/factories/digi/{TOFPulseDigitization_factory.h => LGADPulseDigitization_factory.h} (74%) rename src/factories/digi/{TOFPulseGeneration_factory.h => LGADPulseGeneration_factory.h} (69%) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index 3c227e720e..9210cf6334 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -25,7 +25,7 @@ #include "BTOFChargeSharing.h" #include "DD4hep/Detector.h" -#include "algorithms/digi/TOFHitDigiConfig.h" +#include "algorithms/digi/BTOFChargeSharingConfig.h" namespace eicrecon { diff --git a/src/algorithms/digi/BTOFChargeSharing.h b/src/algorithms/digi/BTOFChargeSharing.h index b87e86989f..ff7c954249 100644 --- a/src/algorithms/digi/BTOFChargeSharing.h +++ b/src/algorithms/digi/BTOFChargeSharing.h @@ -17,7 +17,7 @@ #include #include "DD4hep/Detector.h" -#include "algorithms/digi/TOFHitDigiConfig.h" +#include "algorithms/digi/BTOFChargeSharingConfig.h" #include "algorithms/interfaces/WithPodConfig.h" namespace eicrecon { @@ -27,7 +27,7 @@ using BTOFChargeSharingAlgorithm = algorithms::Output>; class BTOFChargeSharing : public BTOFChargeSharingAlgorithm, - public WithPodConfig { + public WithPodConfig { public: BTOFChargeSharing(std::string_view name) diff --git a/src/algorithms/digi/BTOFChargeSharingConfig.h b/src/algorithms/digi/BTOFChargeSharingConfig.h new file mode 100644 index 0000000000..0d42fa70a9 --- /dev/null +++ b/src/algorithms/digi/BTOFChargeSharingConfig.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul + +#pragma once + +#include + +namespace eicrecon { + +struct BTOFChargeSharingConfig { + // Parameters of AC-LGAD signal generation + double sigma_sharingx = 0.1 * dd4hep::cm; + double sigma_sharingy = 0.5 * dd4hep::cm; + + std::string readout = "TOFBarrelHits"; +}; + +} // namespace eicrecon diff --git a/src/algorithms/digi/TOFHitDigiConfig.h b/src/algorithms/digi/LGADChargeSharingConfig.h similarity index 87% rename from src/algorithms/digi/TOFHitDigiConfig.h rename to src/algorithms/digi/LGADChargeSharingConfig.h index 4d68d2d550..b7cb9f4641 100644 --- a/src/algorithms/digi/TOFHitDigiConfig.h +++ b/src/algorithms/digi/LGADChargeSharingConfig.h @@ -17,9 +17,8 @@ struct TOFHitDigiConfig { double Vm = -1e-4 * dd4hep::GeV; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage // corresponds to ADC = adc_max double t_thres = 0.1 * Vm; // TDC value = time when pulse exceed t_thres - double ignore_thres = 0.01 * Vm; // If EDep below this value, digitization for the cell will be + double ignore_thres = 0.001 * Vm; // If EDep below this value, digitization for the cell will be // ignored. Speed up calculation - int adc_bit = 8; int tdc_bit = 10; @@ -31,9 +30,9 @@ struct TOFHitDigiConfig { // period of the sensor clock. Time internal to sensor will all be digitized to integer multiple // of tInterval - double tInterval = 25 * dd4hep::ns / (tdc_range - 1); - double tMin = 0.; double tMax = 25 * dd4hep::ns; // 25 ns is the period of 40MHz EIC clock + double tInterval = tMax / (tdc_range - 1); + std::string readout = "TOFBarrelHits"; }; diff --git a/src/algorithms/digi/LGADHitDigiConfig.h b/src/algorithms/digi/LGADHitDigiConfig.h new file mode 100644 index 0000000000..80d208f346 --- /dev/null +++ b/src/algorithms/digi/LGADHitDigiConfig.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul + +#pragma once + +#include + +namespace eicrecon { + +struct LGADHitDigiConfig { + // Parameters of AC-LGAD signal generation + double gain = 113.755; + double risetime = 0.45 * dd4hep::ns; + double sigma_analog = 0.293951 * dd4hep::ns; + double Vm = -1e-4 * dd4hep::GeV; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage + // corresponds to ADC = adc_max + double t_thres = 0.1 * Vm; // TDC value = time when pulse exceed t_thres + double ignore_thres = 0.001 * Vm; // If EDep below this value, digitization for the cell will be + // ignored. Speed up calculation + int adc_bit = 8; + int tdc_bit = 10; + + // total number of TDC/ADC values + // Since digitizer starts at zero, max ADC value = adc_range - 1 + // Similar for TDC + int adc_range = pow(2, adc_bit); + int tdc_range = pow(2, tdc_bit); + + // period of the sensor clock. Time internal to sensor will all be digitized to integer multiple + // of tInterval + double tMax = 25 * dd4hep::ns; // 25 ns is the period of 40MHz EIC clock + double tInterval = tMax / (tdc_range - 1); + +}; + +} // namespace eicrecon diff --git a/src/algorithms/digi/TOFPulseDigitization.cc b/src/algorithms/digi/LGADPulseDigitization.cc similarity index 76% rename from src/algorithms/digi/TOFPulseDigitization.cc rename to src/algorithms/digi/LGADPulseDigitization.cc index cfa544113a..df49880378 100644 --- a/src/algorithms/digi/TOFPulseDigitization.cc +++ b/src/algorithms/digi/LGADPulseDigitization.cc @@ -2,7 +2,7 @@ // Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy // Special Acknowledgement: Kolja Kauder // -// Convert ADC pulses from TOFPulseGeneration into ADC and TDC values +// Convert ADC pulses from LGADPulseGeneration into ADC and TDC values #include #include @@ -12,13 +12,13 @@ #include #include -#include "TOFPulseDigitization.h" -#include "algorithms/digi/TOFHitDigiConfig.h" +#include "LGADPulseDigitization.h" +#include "algorithms/digi/LGADHitDigiConfig.h" namespace eicrecon { -void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, - const TOFPulseDigitization::Output& output) const { +void LGADPulseDigitization::process(const LGADPulseDigitization::Input& input, + const LGADPulseDigitization::Output& output) const { const auto [simhits] = input; auto [rawhits] = output; @@ -41,11 +41,12 @@ void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, double adc_prev = 0; double time_interval = pulse.getInterval(); auto adcs = pulse.getAdcCounts(); + double n_EICROC_cycle = int(pulse.getTime()/m_cfg.tMax + 1e-3); for (const auto adc : adcs) { if (adc_prev >= norm_threshold && adc <= norm_threshold) { intersectionX = time_bin * time_interval + time_interval * (norm_threshold - adc_prev) / (adc - adc_prev); - tdc = static_cast(intersectionX / time_interval); + tdc = static_cast(intersectionX / time_interval) + n_EICROC_cycle * m_cfg.tdc_range; } if (abs(adc) > abs(V)) // To get peak of the Analog signal V = adc; @@ -60,5 +61,5 @@ void TOFPulseDigitization::process(const TOFPulseDigitization::Input& input, rawhits->create(pulse.getCellID(), adc, tdc); //----------------------------------------------------------- } -} // TOFPulseDigitization:process +} // LGADPulseDigitization:process } // namespace eicrecon diff --git a/src/algorithms/digi/TOFPulseDigitization.h b/src/algorithms/digi/LGADPulseDigitization.h similarity index 61% rename from src/algorithms/digi/TOFPulseDigitization.h rename to src/algorithms/digi/LGADPulseDigitization.h index a681ee55fc..5ef0927fd6 100644 --- a/src/algorithms/digi/TOFPulseDigitization.h +++ b/src/algorithms/digi/LGADPulseDigitization.h @@ -2,7 +2,7 @@ // Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy // Special Acknowledgement: Kolja Kauder // -// Convert ADC pulses from TOFPulseGeneration into ADC and TDC values +// Convert ADC pulses from LGADPulseGeneration into ADC and TDC values #pragma once @@ -12,21 +12,21 @@ #include #include -#include "algorithms/digi/TOFHitDigiConfig.h" +#include "algorithms/digi/LGADHitDigiConfig.h" #include "algorithms/interfaces/WithPodConfig.h" namespace eicrecon { -using TOFPulseDigitizationAlgorithm = +using LGADPulseDigitizationAlgorithm = algorithms::Algorithm, algorithms::Output>; -class TOFPulseDigitization : public TOFPulseDigitizationAlgorithm, - public WithPodConfig { +class LGADPulseDigitization : public LGADPulseDigitizationAlgorithm, + public WithPodConfig { public: - TOFPulseDigitization(std::string_view name) - : TOFPulseDigitizationAlgorithm{name, {"TOFBarrelPulse"}, {"TOFBarrelADCTDC"}, {}} {} + LGADPulseDigitization(std::string_view name) + : LGADPulseDigitizationAlgorithm{name, {"LGADPulse"}, {"ADCTDCOutput"}, {}} {} void init(){}; void process(const Input&, const Output&) const final; }; diff --git a/src/algorithms/digi/LGADPulseGeneration.cc b/src/algorithms/digi/LGADPulseGeneration.cc new file mode 100644 index 0000000000..f81260ac35 --- /dev/null +++ b/src/algorithms/digi/LGADPulseGeneration.cc @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy +// Special Acknowledgement: Kolja Kauder +// +// Convert energy deposition into ADC pulses +// ADC pulses are assumed to follow the shape of landau function + +#include +#include +#include +#include +#include +#include + +#include "TMath.h" +#include "LGADPulseGeneration.h" +#include "algorithms/digi/LGADHitDigiConfig.h" + +namespace eicrecon { + +LandauPulse::LandauPulse(double gain, double Vm, double sigma_analog, double adc_range) { + m_gain = gain; + m_sigma_analog = sigma_analog; + + // calculation of the extreme values for Landau distribution can be found on lin 514-520 of + // https://root.cern.ch/root/html524/src/TMath.cxx.html#fsokrB Landau reaches minimum for mpv = + // 0 and sigma = 1 at x = -0.22278 + const double x_when_landau_min = -0.22278; + const double landau_min = -gain * TMath::Landau(x_when_landau_min, 0, 1, kTRUE) / m_sigma_analog; + m_scalingFactor = 1. / Vm / landau_min * adc_range; +} + +double LandauPulse::Eval(double time, double hit_time, double charge) { + return charge * m_gain * TMath::Landau(time, hit_time, m_sigma_analog, kTRUE) * m_scalingFactor; +} + +void LGADPulseGeneration::_FillADCArray(AdcArray& adc_sum, double charge, double mpv_analog, int n_EICROC_cycle, dd4hep::rec::CellID cellID) const { + double Vm = m_cfg.Vm; + double t = 0; + double tMax = m_cfg.tMax; + double interval = m_cfg.tInterval; + int adc_range = m_cfg.adc_range; + int nBins = m_cfg.tdc_range; + + // amplitude has to be negative + // because voltage is negative + // fetch the corresponding array + auto& ADCs = adc_sum[cellID][n_EICROC_cycle]; + if (ADCs.size() == 0) + ADCs.resize(nBins, 0); + + // keep filling the array until added amplitude < ignore_thres + for (unsigned int j = 0; j <= ADCs.size(); ++j, t += interval) { + double amplitude = m_pulse -> Eval(t, mpv_analog, charge); + if(std::fabs(amplitude) > std::fabs(m_cfg.ignore_thres * adc_range/m_cfg.Vm)){ + if(j >= ADCs.size()) { + // pulse has to be saved in the next clock cycle + this -> _FillADCArray(adc_sum, charge, mpv_analog - tMax, n_EICROC_cycle+1, cellID); + } else ADCs[j] += amplitude; + } + } + +} + +void LGADPulseGeneration::process(const LGADPulseGeneration::Input& input, + const LGADPulseGeneration::Output& output) const { + const auto [simhits] = input; + auto [rawADCs] = output; + + int tdc_range = m_cfg.tdc_range; + + // signal sum + // NOTE: we take the cellID of the most energetic hit in this group so it is a real cellID from an + // MC hit + AdcArray adc_sum; + + for (const auto& hit : *simhits) { + auto cellID = hit.getCellID(); + + double time = hit.getTime() * dd4hep::ns; + double charge = hit.getEDep(); + // reduce computation power by not simulating low-charge hits + if (charge < m_cfg.ignore_thres) + continue; + + int n_EICROC_cycle = int(time/m_cfg.tMax + 1e-3); + double time_in_cycle = time - n_EICROC_cycle * m_cfg.tMax; + double mpv_analog = time_in_cycle + m_cfg.risetime; + this -> _FillADCArray(adc_sum, charge, mpv_analog, n_EICROC_cycle, cellID); + } + + // convert vector of ADC values to RawTimeSeries + for (const auto& [cellID, nCycleADCs] : adc_sum) { + for (const auto& [nCycle, ADCs] : nCycleADCs) { + auto time_series = rawADCs->create(); + time_series.setCellID(cellID); + time_series.setTime(nCycle * m_cfg.tMax); + time_series.setCharge(1.); // placeholder. Don't know what to assign when there are two or more hits + time_series.setInterval(m_cfg.tInterval); + + for (const auto ADC : ADCs) + time_series.addToAdcCounts(ADC); + } + } +} // LGADPulseGeneration:process +} // namespace eicrecon diff --git a/src/algorithms/digi/LGADPulseGeneration.h b/src/algorithms/digi/LGADPulseGeneration.h new file mode 100644 index 0000000000..8078113d70 --- /dev/null +++ b/src/algorithms/digi/LGADPulseGeneration.h @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy +// Special Acknowledgement: Kolja Kauder +// +// Convert energy deposition into ADC pulses +// ADC pulses are assumed to follow the shape of landau function + +#pragma once + +#include +#include +#include +#include +#include + +#include "algorithms/digi/LGADHitDigiConfig.h" +#include "algorithms/interfaces/WithPodConfig.h" + +namespace eicrecon { + +using LGADPulseGenerationAlgorithm = + algorithms::Algorithm, + algorithms::Output>; + +class PulseShape { +public: + // return voltage in units of ADC value + // ranges from 0 to adc_range + // charge is in unit GeV, it's the EDep in the detector + virtual double Eval(double time, double hit_time, double charge) = 0; + virtual ~PulseShape() {}; +}; + +// default pulse shapt is Landau +class LandauPulse : public PulseShape { +public: + LandauPulse(double gain, double Vm, double sigma_analog, double adc_range); + double Eval(double time, double hit_time, double charge); +private: + double m_gain; + double m_sigma_analog; + double m_scalingFactor; +}; + + +class LGADPulseGeneration : public LGADPulseGenerationAlgorithm, + public WithPodConfig { +// The key pair is +typedef std::unordered_map>> AdcArray; + +public: + LGADPulseGeneration(std::string_view name, std::unique_ptr&& pulse) + : LGADPulseGenerationAlgorithm{name, {"RawHits"}, {"OutputPulses"}, {}}, m_pulse(std::move(pulse)) {} + virtual void init(){}; + void process(const Input&, const Output&) const final; + +protected: + double _Landau(double amp, double x, double mean, double std) const; + void _FillADCArray(AdcArray& adc_sum, double charge, double mpv_analog, + int n_EICROC_cycle, dd4hep::rec::CellID cellID) const; + std::unique_ptr m_pulse; +}; + +} // namespace eicrecon diff --git a/src/algorithms/digi/TOFPulseGeneration.cc b/src/algorithms/digi/TOFPulseGeneration.cc deleted file mode 100644 index 8592745352..0000000000 --- a/src/algorithms/digi/TOFPulseGeneration.cc +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy -// Special Acknowledgement: Kolja Kauder -// -// Convert energy deposition into ADC pulses -// ADC pulses are assumed to follow the shape of landau function - -#include -#include -#include -#include -#include -#include - -#include "TMath.h" -#include "TOFPulseGeneration.h" -#include "algorithms/digi/TOFHitDigiConfig.h" - -namespace eicrecon { - -double TOFPulseGeneration::_Landau(double amp, double x, double mean, double std) const { - return amp * TMath::Landau(x, mean, std, kTRUE); -} - -double TOFPulseGeneration::_DigitizeTime(double time) const { - // digitization always round down to the previous bin - return static_cast(time / m_cfg.tInterval + 1e-3) * m_cfg.tInterval; -} - -void TOFPulseGeneration::process(const TOFPulseGeneration::Input& input, - const TOFPulseGeneration::Output& output) const { - const auto [simhits] = input; - auto [rawADCs] = output; - - double interval = m_cfg.tInterval; - double Vm = m_cfg.Vm; - double tMin = _DigitizeTime(m_cfg.tMin); - double tMax = _DigitizeTime(m_cfg.tMax); - int adc_range = m_cfg.adc_range; - int tdc_range = m_cfg.tdc_range; - int nBins = m_cfg.tdc_range; - - // signal sum - // NOTE: we take the cellID of the most energetic hit in this group so it is a real cellID from an - // MC hit - std::unordered_map> adc_sum; - - for (const auto& hit : *simhits) { - auto cellID = hit.getCellID(); - double sum_charge = 0.0; - double mpv_analog = 0.0; - - double time = hit.getTime() * dd4hep::ns; - double charge = hit.getEDep(); - // reduce computation power by not simulating low-charge hits - if (charge < m_cfg.ignore_thres) - continue; - - auto& ADCs = adc_sum[cellID]; - if (ADCs.size() == 0) - ADCs.resize(nBins, 0); - - mpv_analog = time + m_cfg.risetime; - - // amplitude has to be negative - // because voltage is negative - // calculation of the extreme values for Landau distribution can be found on lin 514-520 of - // https://root.cern.ch/root/html524/src/TMath.cxx.html#fsokrB Landau reaches minimum for mpv = - // 0 and sigma = 1 at x = -0.22278 - const double x_when_landau_min = -0.22278; - double landau_min = this->_Landau(-m_cfg.gain, x_when_landau_min, 0, 1) / m_cfg.sigma_analog; - double scalingFactor = 1. / Vm / landau_min * adc_range; - - { - int j; - for (double t = tMin, j = 0; t < tMax; ++j, t += interval) - ADCs[j] += - charge * this->_Landau(-m_cfg.gain, t, mpv_analog, m_cfg.sigma_analog) * scalingFactor; - } - } - - // convert vector of ADC values to RawTimeSeries - for (const auto& [cellID, ADCs] : adc_sum) { - auto time_series = rawADCs->create(); - time_series.setCellID(cellID); - time_series.setTime(tMin); - time_series.setCharge( - 1.); // placeholder. Don't know what to assign when there are two or more hits - time_series.setInterval(interval); - - for (const auto ADC : ADCs) - time_series.addToAdcCounts(ADC); - } -} // TOFPulseGeneration:process -} // namespace eicrecon diff --git a/src/algorithms/digi/TOFPulseGeneration.h b/src/algorithms/digi/TOFPulseGeneration.h deleted file mode 100644 index c4db7b6832..0000000000 --- a/src/algorithms/digi/TOFPulseGeneration.h +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Souvik Paul, Chun Yuen Tsang, Prithwish Tribedy -// Special Acknowledgement: Kolja Kauder -// -// Convert energy deposition into ADC pulses -// ADC pulses are assumed to follow the shape of landau function - -#pragma once - -#include -#include -#include -#include -#include - -#include "algorithms/digi/TOFHitDigiConfig.h" -#include "algorithms/interfaces/WithPodConfig.h" - -namespace eicrecon { - -using TOFPulseGenerationAlgorithm = - algorithms::Algorithm, - algorithms::Output>; - -class TOFPulseGeneration : public TOFPulseGenerationAlgorithm, - public WithPodConfig { - -public: - TOFPulseGeneration(std::string_view name) - : TOFPulseGenerationAlgorithm{name, {"TOFBarrelSharedHits"}, {"TOFBarrelPulse"}, {}} {} - void init(){}; - void process(const Input&, const Output&) const final; - -protected: - double _Landau(double amp, double x, double mean, double std) const; - double _DigitizeTime(double time) const; -}; - -} // namespace eicrecon diff --git a/src/detectors/BTOF/BTOF.cc b/src/detectors/BTOF/BTOF.cc index 71e86826fa..2a2a41ec24 100644 --- a/src/detectors/BTOF/BTOF.cc +++ b/src/detectors/BTOF/BTOF.cc @@ -19,8 +19,8 @@ #include "factories/digi/SiliconTrackerDigi_factory.h" #include "factories/tracking/TrackerHitReconstruction_factory.h" #include "factories/digi/BTOFChargeSharing_factory.h" -#include "factories/digi/TOFPulseGeneration_factory.h" -#include "factories/digi/TOFPulseDigitization_factory.h" +#include "factories/digi/LGADPulseGeneration_factory.h" +#include "factories/digi/LGADPulseDigitization_factory.h" #include "global/pid_lut/PIDLookup_factory.h" #include "services/geometry/dd4hep/DD4hep_service.h" @@ -66,7 +66,7 @@ void InitPlugin(JApplication* app) { app )); - app->Add(new JOmniFactoryGeneratorT( + app->Add(new JOmniFactoryGeneratorT( "BTOFPulseGeneration", {"TOFBarrelSharedHits"}, {"TOFBarrelPulse"}, @@ -74,7 +74,7 @@ void InitPlugin(JApplication* app) { app )); - app->Add(new JOmniFactoryGeneratorT( + app->Add(new JOmniFactoryGeneratorT( "BTOFPulseDigitization", {"TOFBarrelPulse"}, {"TOFBarrelADCTDC"}, diff --git a/src/factories/digi/BTOFChargeSharing_factory.h b/src/factories/digi/BTOFChargeSharing_factory.h index f5c34f9dce..801d7454ef 100644 --- a/src/factories/digi/BTOFChargeSharing_factory.h +++ b/src/factories/digi/BTOFChargeSharing_factory.h @@ -10,7 +10,7 @@ namespace eicrecon { -class BTOFChargeSharing_factory : public JOmniFactory { +class BTOFChargeSharing_factory : public JOmniFactory { public: using AlgoT = eicrecon::BTOFChargeSharing; diff --git a/src/factories/digi/TOFPulseDigitization_factory.h b/src/factories/digi/LGADPulseDigitization_factory.h similarity index 74% rename from src/factories/digi/TOFPulseDigitization_factory.h rename to src/factories/digi/LGADPulseDigitization_factory.h index 18d3b7349f..1519568da8 100644 --- a/src/factories/digi/TOFPulseDigitization_factory.h +++ b/src/factories/digi/LGADPulseDigitization_factory.h @@ -5,15 +5,15 @@ #include "extensions/jana/JOmniFactory.h" -#include "algorithms/digi/TOFPulseDigitization.h" +#include "algorithms/digi/LGADPulseDigitization.h" #include namespace eicrecon { -class TOFPulseDigitization_factory - : public JOmniFactory { +class LGADPulseDigitization_factory + : public JOmniFactory { public: - using AlgoT = eicrecon::TOFPulseDigitization; + using AlgoT = eicrecon::LGADPulseDigitization; private: std::unique_ptr m_algo; @@ -28,7 +28,7 @@ class TOFPulseDigitization_factory public: void Configure() { - m_algo = std::make_unique(GetPrefix()); + m_algo = std::make_unique(GetPrefix()); m_algo->level(static_cast(logger()->level())); m_algo->applyConfig(config()); m_algo->init(); diff --git a/src/factories/digi/TOFPulseGeneration_factory.h b/src/factories/digi/LGADPulseGeneration_factory.h similarity index 69% rename from src/factories/digi/TOFPulseGeneration_factory.h rename to src/factories/digi/LGADPulseGeneration_factory.h index 8080239f3d..b1b1fecade 100644 --- a/src/factories/digi/TOFPulseGeneration_factory.h +++ b/src/factories/digi/LGADPulseGeneration_factory.h @@ -5,15 +5,15 @@ #include "extensions/jana/JOmniFactory.h" -#include "algorithms/digi/TOFPulseGeneration.h" +#include "algorithms/digi/LGADPulseGeneration.h" #include namespace eicrecon { -class TOFPulseGeneration_factory - : public JOmniFactory { +class LGADPulseGeneration_factory + : public JOmniFactory { public: - using AlgoT = eicrecon::TOFPulseGeneration; + using AlgoT = eicrecon::LGADPulseGeneration; private: std::unique_ptr m_algo; @@ -23,7 +23,6 @@ class TOFPulseGeneration_factory PodioOutput m_out_reco_particles{this}; ParameterRef m_Vm{this, "Vm", config().Vm}; - ParameterRef m_tMin{this, "tMin", config().tMin}; ParameterRef m_tMax{this, "tMax", config().tMax}; ParameterRef m_adc_range{this, "adcRange", config().adc_range}; ParameterRef m_tdc_range{this, "tdcRange", config().tdc_range}; @@ -33,7 +32,9 @@ class TOFPulseGeneration_factory public: void Configure() { - m_algo = std::make_unique(GetPrefix()); + std::unique_ptr landau = std::make_unique(config().gain, config().Vm, + config().sigma_analog, config().adc_range); + m_algo = std::make_unique(GetPrefix(), std::move(landau)); m_algo->level(static_cast(logger()->level())); m_algo->applyConfig(config()); m_algo->init(); diff --git a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc index 426d4f2949..31c5f54737 100644 --- a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc +++ b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc @@ -18,22 +18,21 @@ #include #include -#include "algorithms/digi/TOFHitDigiConfig.h" -#include "algorithms/digi/TOFPulseDigitization.h" +#include "algorithms/digi/LGADHitDigiConfig.h" +#include "algorithms/digi/LGADPulseDigitization.h" TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseDigitization]") { const float EPSILON = 1e-5; - eicrecon::TOFPulseDigitization algo("TOFPulseDigitization"); + eicrecon::LGADPulseDigitization algo("TOFPulseDigitization"); std::shared_ptr logger = spdlog::default_logger()->clone("TOFPulseDigitization"); logger->set_level(spdlog::level::trace); - eicrecon::TOFHitDigiConfig cfg; - cfg.readout = "MockTOFHits"; + eicrecon::LGADHitDigiConfig cfg; auto detector = algorithms::GeoSvc::instance().detector(); - auto id_desc = detector->readout(cfg.readout).idSpec(); + auto id_desc = detector->readout("MockTOFHits").idSpec(); cfg.gain = 10; cfg.Vm = -1e-4; @@ -41,6 +40,7 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseDigitization]") { cfg.t_thres = cfg.Vm * 0.1; cfg.tdc_bit = 8; cfg.adc_bit = 7; + cfg.tMax = 10 * dd4hep::ns; cfg.tdc_range = pow(2, cfg.tdc_bit); cfg.adc_range = pow(2, cfg.adc_bit); @@ -51,48 +51,54 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseDigitization]") { SECTION("TDC vs analytic solution scan") { logger->info("Begin TDC vs analytic solution scan"); - // test pulse with gaussian shape - for (double tdc_frac = 0.4; tdc_frac < 1; tdc_frac += 0.1) { - edm4hep::RawTimeSeriesCollection time_series_coll; - auto rawhits_coll = std::make_unique(); - - auto pulse = time_series_coll.create(); - auto cellID = - id_desc.encode({{"system", 0}, {"module", 0}, {"sensor", 1}, {"x", 1}, {"y", 1}}); - - pulse.setCellID(cellID); - pulse.setCharge(1.); // placeholder - pulse.setTime(1.); // placeholder - pulse.setInterval(1); - - int test_peak_TDC = static_cast(tdc_frac * cfg.tdc_range); - int test_peak = static_cast(0.7 * cfg.adc_range); - int test_peak_sigma = static_cast(0.1 * cfg.tdc_range); - - for (int i = 0; i < cfg.tdc_range; ++i) { - int ADC = - -test_peak * - TMath::Exp(-0.5 * pow((i - test_peak_TDC) / static_cast(test_peak_sigma), 2)); - pulse.addToAdcCounts(ADC); + for(double time = 0; time <= cfg.tMax; time += cfg.tMax) { + if(time == 0) logger->info("Generation pulse at the first EICROC cycle"); + else logger->info("Generation pulse at the second EICROC cycle"); + + // test pulse with gaussian shape + for (double tdc_frac = 0.4; tdc_frac < 1; tdc_frac += 0.1) { + edm4hep::RawTimeSeriesCollection time_series_coll; + auto rawhits_coll = std::make_unique(); + + auto pulse = time_series_coll.create(); + auto cellID = + id_desc.encode({{"system", 0}, {"module", 0}, {"sensor", 1}, {"x", 1}, {"y", 1}}); + + pulse.setCellID(cellID); + pulse.setCharge(1.); // placeholder + pulse.setTime(time); // placeholder + pulse.setInterval(1); + + int test_peak_TDC = static_cast(tdc_frac * cfg.tdc_range); + int test_peak = static_cast(0.7 * cfg.adc_range); + int test_peak_sigma = static_cast(0.1 * cfg.tdc_range); + + for (int i = 0; i < cfg.tdc_range; ++i) { + int ADC = + -test_peak * + TMath::Exp(-0.5 * pow((i - test_peak_TDC) / static_cast(test_peak_sigma), 2)); + pulse.addToAdcCounts(ADC); + } + + // calculate analytically when the pulse passes t_thres + // ADC = amp*exp(-(TDC - mean)^2/(2sigma^2)) + // TDC = mean - (-2*sigma^2*ln(ADC/amp))^0.5 + int analytic_TDC = ceil(test_peak_TDC - sqrt(-2 * pow(test_peak_sigma, 2) * + TMath::Log(cfg.adc_range * 0.1 / test_peak))); + + // Constructing input and output as per the algorithm's expected signature + auto input = std::make_tuple(&time_series_coll); + auto output = std::make_tuple(rawhits_coll.get()); + + algo.process(input, output); + + REQUIRE(rawhits_coll->size() == 1); + auto hit = (*rawhits_coll)[0]; + REQUIRE(hit.getCellID() == cellID); + REQUIRE(hit.getCharge() == test_peak); + if(time == 0) REQUIRE(hit.getTimeStamp() == analytic_TDC); + else REQUIRE(hit.getTimeStamp() == analytic_TDC + cfg.tdc_range); } - - // calculate analytically when the pulse passes t_thres - // ADC = amp*exp(-(TDC - mean)^2/(2sigma^2)) - // TDC = mean - (-2*sigma^2*ln(ADC/amp))^0.5 - int analytic_TDC = ceil(test_peak_TDC - sqrt(-2 * pow(test_peak_sigma, 2) * - TMath::Log(cfg.adc_range * 0.1 / test_peak))); - - // Constructing input and output as per the algorithm's expected signature - auto input = std::make_tuple(&time_series_coll); - auto output = std::make_tuple(rawhits_coll.get()); - - algo.process(input, output); - - REQUIRE(rawhits_coll->size() == 1); - auto hit = (*rawhits_coll)[0]; - REQUIRE(hit.getCellID() == cellID); - REQUIRE(hit.getCharge() == test_peak); - REQUIRE(hit.getTimeStamp() == analytic_TDC); } } @@ -110,7 +116,7 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseDigitization]") { pulse.setCellID(cellID); pulse.setCharge(1.); // placeholder - pulse.setTime(1.); // placeholder + pulse.setTime(0.); // placeholder pulse.setInterval(1); int test_peak_TDC = static_cast(0.5 * cfg.tdc_range); diff --git a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc index df9372d206..8b6c0014df 100644 --- a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc +++ b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc @@ -23,26 +23,30 @@ #include "TF1.h" #include "TGraphErrors.h" -#include "algorithms/digi/TOFHitDigiConfig.h" -#include "algorithms/digi/TOFPulseGeneration.h" +#include "algorithms/digi/LGADHitDigiConfig.h" +#include "algorithms/digi/LGADPulseGeneration.h" TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { const float EPSILON = 1e-5; + eicrecon::LGADHitDigiConfig cfg; + cfg.gain = 113; + cfg.Vm = 1e-4 * dd4hep::GeV; + cfg.ignore_thres = 1e-4 / 5; + cfg.sigma_analog = 0.293951 * dd4hep::ns; + cfg.adc_bit = 8; + cfg.adc_range = pow(2, cfg.adc_bit); - eicrecon::TOFPulseGeneration algo("TOFPulseGeneration"); + std::unique_ptr landau = std::make_unique(cfg.gain, cfg.Vm, + cfg.sigma_analog, cfg.adc_range); + + eicrecon::LGADPulseGeneration algo("TOFPulseGeneration", std::move(landau)); std::shared_ptr logger = spdlog::default_logger()->clone("TOFPulseGeneration"); logger->set_level(spdlog::level::trace); - eicrecon::TOFHitDigiConfig cfg; - cfg.readout = "MockTOFHits"; auto detector = algorithms::GeoSvc::instance().detector(); - auto id_desc = detector->readout(cfg.readout).idSpec(); - - cfg.gain = 113; - cfg.Vm = -1e-4; - cfg.ignore_thres = 1e-4 / 5; + auto id_desc = detector->readout("MockTOFHits").idSpec(); SECTION("Pulse height linearlity test") { // check if max pulse height is linearly proportional to the initial Edep @@ -61,7 +65,7 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { hit.setCellID(cellID); hit.setEDep( edep); // in GeV. Since Vm = 1e-4*gain, EDep = 1e-4 GeV corresponds to ADC = max_adc - hit.setTime(1.5); // in ns + hit.setTime(1.5 * dd4hep::ns); // in ns // Constructing input and output as per the algorithm's expected signature auto input = std::make_tuple(&rawhits_coll); @@ -73,17 +77,16 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { REQUIRE(time_series_coll->size() == 0); else { REQUIRE(time_series_coll->size() == 1); - auto pulse = (*time_series_coll)[0]; - REQUIRE(pulse.getCellID() == cellID); - - auto adcs = pulse.getAdcCounts(); - auto min_adc = std::numeric_limits::max(); - for (const auto adc : adcs) - min_adc = std::min(min_adc, adc); + auto min_adc = std::numeric_limits::max(); + for(const auto& pulse : (*time_series_coll)) { + REQUIRE(pulse.getCellID() == cellID); + auto adcs = pulse.getAdcCounts(); + for (const auto adc : adcs) + min_adc = std::min(min_adc, adc); + } int npt = graph.GetN(); graph.SetPoint(npt, edep, min_adc); graph.SetPointError(npt, 0, 0.5); - // make sure when energy deposition = Vm, ADC reaches max value if (edep == 1e-4) REQUIRE(min_adc == -cfg.adc_range + 1); @@ -93,6 +96,8 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { // test linearlity TF1 tf1("tf1", "pol1", 0, 1e-4); graph.Fit(&tf1, "R0"); + // slope can't be consistent with zero + REQUIRE(!(tf1.GetParameter(1) - tf1.GetParError(1) < 0 && 0 < tf1.GetParameter(1) + tf1.GetParError(1) )); double chi2_dof = tf1.GetChisquare() / tf1.GetNDF(); logger->info("Chi-square/dof value for Edep vs min-adc = {}", chi2_dof); REQUIRE(chi2_dof < 2); @@ -104,7 +109,14 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { algo.init(); TGraphErrors graph; - for (double time = 0; time < 12; time += 1.) { + std::vector times; + + // test within the same EICROC cycle + for (double time = 0; time < 12; time += 1.) times.push_back(time); + // test multiple EICROC cycle + for (double time = 10; time < 101; time += 25.) times.push_back(time); + + for (double time : times) { edm4hep::SimTrackerHitCollection rawhits_coll; auto time_series_coll = std::make_unique(); @@ -114,7 +126,7 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { hit.setCellID(cellID); hit.setEDep( - 0.5e-4); // in GeV. Since Vm = 1e-4*gain, EDep = 1e-4 GeV corresponds to ADC = max_adc + 0.5e-4 * dd4hep::GeV); // in GeV. Since Vm = 1e-4*gain, EDep = 1e-4 GeV corresponds to ADC = max_adc hit.setTime(time); // in ns // Constructing input and output as per the algorithm's expected signature @@ -124,17 +136,19 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { algo.process(input, output); REQUIRE(time_series_coll->size() == 1); - auto pulse = (*time_series_coll)[0]; - REQUIRE(pulse.getCellID() == cellID); - - auto adcs = pulse.getAdcCounts(); auto min_adc = std::numeric_limits::max(); unsigned int time_bin = 0; - for (unsigned int i = 0; i < adcs.size(); ++i) { - auto adc = adcs[i]; - if (adc < min_adc) - time_bin = i; - min_adc = std::min(min_adc, adc); + for(const auto& pulse: *time_series_coll) { + //auto pulse = (*time_series_coll)[0]; + REQUIRE(pulse.getCellID() == cellID); + + auto adcs = pulse.getAdcCounts(); + for (unsigned int i = 0; i < adcs.size(); ++i) { + auto adc = adcs[i]; + if (adc < min_adc) + time_bin = i + pulse.getTime()/cfg.tMax*cfg.tdc_range; + min_adc = std::min(min_adc, adc); + } } int npt = graph.GetN(); graph.SetPoint(npt, time, time_bin); @@ -142,8 +156,10 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { } // test linearlity - TF1 tf1("tf1", "pol1", 0, 12); + TF1 tf1("tf1", "pol1", 0, *std::max_element(times.begin(), times.end())); graph.Fit(&tf1, "R0"); + // slope can't be consistent with zero + REQUIRE(!(tf1.GetParameter(1) - tf1.GetParError(1) < 0 && 0 < tf1.GetParameter(1) + tf1.GetParError(1) )); double chi2_dof = tf1.GetChisquare() / tf1.GetNDF(); logger->info("Chi-square/dof value for time vs TDC-bin = {}", chi2_dof); REQUIRE(chi2_dof < 2); From f31c553847d17374922d53cf00d705313a9a3143 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:47:36 +0000 Subject: [PATCH 65/77] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/LGADPulseGeneration.cc | 2 +- src/algorithms/digi/LGADPulseGeneration.h | 4 ++-- src/factories/digi/LGADPulseGeneration_factory.h | 2 +- src/tests/algorithms_test/digi_TOFPulseDigitization.cc | 4 ++-- src/tests/algorithms_test/digi_TOFPulseGeneration.cc | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/algorithms/digi/LGADPulseGeneration.cc b/src/algorithms/digi/LGADPulseGeneration.cc index f81260ac35..5e9fc2cac5 100644 --- a/src/algorithms/digi/LGADPulseGeneration.cc +++ b/src/algorithms/digi/LGADPulseGeneration.cc @@ -52,7 +52,7 @@ void LGADPulseGeneration::_FillADCArray(AdcArray& adc_sum, double charge, double // keep filling the array until added amplitude < ignore_thres for (unsigned int j = 0; j <= ADCs.size(); ++j, t += interval) { double amplitude = m_pulse -> Eval(t, mpv_analog, charge); - if(std::fabs(amplitude) > std::fabs(m_cfg.ignore_thres * adc_range/m_cfg.Vm)){ + if(std::fabs(amplitude) > std::fabs(m_cfg.ignore_thres * adc_range/m_cfg.Vm)){ if(j >= ADCs.size()) { // pulse has to be saved in the next clock cycle this -> _FillADCArray(adc_sum, charge, mpv_analog - tMax, n_EICROC_cycle+1, cellID); diff --git a/src/algorithms/digi/LGADPulseGeneration.h b/src/algorithms/digi/LGADPulseGeneration.h index 8078113d70..20c95f6b3a 100644 --- a/src/algorithms/digi/LGADPulseGeneration.h +++ b/src/algorithms/digi/LGADPulseGeneration.h @@ -56,8 +56,8 @@ typedef std::unordered_map m_pulse; }; diff --git a/src/factories/digi/LGADPulseGeneration_factory.h b/src/factories/digi/LGADPulseGeneration_factory.h index b1b1fecade..277abd3319 100644 --- a/src/factories/digi/LGADPulseGeneration_factory.h +++ b/src/factories/digi/LGADPulseGeneration_factory.h @@ -33,7 +33,7 @@ class LGADPulseGeneration_factory public: void Configure() { std::unique_ptr landau = std::make_unique(config().gain, config().Vm, - config().sigma_analog, config().adc_range); + config().sigma_analog, config().adc_range); m_algo = std::make_unique(GetPrefix(), std::move(landau)); m_algo->level(static_cast(logger()->level())); m_algo->applyConfig(config()); diff --git a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc index 31c5f54737..8d9e9a10b5 100644 --- a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc +++ b/src/tests/algorithms_test/digi_TOFPulseDigitization.cc @@ -96,8 +96,8 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseDigitization]") { auto hit = (*rawhits_coll)[0]; REQUIRE(hit.getCellID() == cellID); REQUIRE(hit.getCharge() == test_peak); - if(time == 0) REQUIRE(hit.getTimeStamp() == analytic_TDC); - else REQUIRE(hit.getTimeStamp() == analytic_TDC + cfg.tdc_range); + if(time == 0) REQUIRE(hit.getTimeStamp() == analytic_TDC); + else REQUIRE(hit.getTimeStamp() == analytic_TDC + cfg.tdc_range); } } } diff --git a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc index 8b6c0014df..3ea1119fb9 100644 --- a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc +++ b/src/tests/algorithms_test/digi_TOFPulseGeneration.cc @@ -77,13 +77,13 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { REQUIRE(time_series_coll->size() == 0); else { REQUIRE(time_series_coll->size() == 1); - auto min_adc = std::numeric_limits::max(); + auto min_adc = std::numeric_limits::max(); for(const auto& pulse : (*time_series_coll)) { REQUIRE(pulse.getCellID() == cellID); auto adcs = pulse.getAdcCounts(); for (const auto adc : adcs) min_adc = std::min(min_adc, adc); - } + } int npt = graph.GetN(); graph.SetPoint(npt, edep, min_adc); graph.SetPointError(npt, 0, 0.5); @@ -145,7 +145,7 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { auto adcs = pulse.getAdcCounts(); for (unsigned int i = 0; i < adcs.size(); ++i) { auto adc = adcs[i]; - if (adc < min_adc) + if (adc < min_adc) time_bin = i + pulse.getTime()/cfg.tMax*cfg.tdc_range; min_adc = std::min(min_adc, adc); } From 29817885ebcd6dd0279182cfbde2b35ec97fe280 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Wed, 18 Dec 2024 14:17:33 -0500 Subject: [PATCH 66/77] Separate config class for PulseDigitization and PulseGeneration. --- src/algorithms/digi/LGADPulseDigitization.cc | 14 +++------- src/algorithms/digi/LGADPulseDigitization.h | 4 +-- .../digi/LGADPulseDigitizationConfig.h | 26 +++++++++++++++++++ src/algorithms/digi/LGADPulseGeneration.cc | 2 +- src/algorithms/digi/LGADPulseGeneration.h | 6 ++--- ...giConfig.h => LGADPulseGenerationConfig.h} | 3 +-- .../digi/LGADPulseDigitization_factory.h | 2 +- .../digi/LGADPulseGeneration_factory.h | 2 +- src/tests/algorithms_test/CMakeLists.txt | 4 +-- src/tests/algorithms_test/algorithmsInit.cc | 14 +++++----- ...ation.cc => digi_LGADPulseDigitization.cc} | 16 +++++------- ...eration.cc => digi_LGADPulseGeneration.cc} | 11 ++++---- 12 files changed, 59 insertions(+), 45 deletions(-) create mode 100644 src/algorithms/digi/LGADPulseDigitizationConfig.h rename src/algorithms/digi/{LGADHitDigiConfig.h => LGADPulseGenerationConfig.h} (91%) rename src/tests/algorithms_test/{digi_TOFPulseDigitization.cc => digi_LGADPulseDigitization.cc} (91%) rename src/tests/algorithms_test/{digi_TOFPulseGeneration.cc => digi_LGADPulseGeneration.cc} (94%) diff --git a/src/algorithms/digi/LGADPulseDigitization.cc b/src/algorithms/digi/LGADPulseDigitization.cc index df49880378..0df7210527 100644 --- a/src/algorithms/digi/LGADPulseDigitization.cc +++ b/src/algorithms/digi/LGADPulseDigitization.cc @@ -13,7 +13,7 @@ #include #include "LGADPulseDigitization.h" -#include "algorithms/digi/LGADHitDigiConfig.h" +#include "algorithms/digi/LGADPulseDigitizationConfig.h" namespace eicrecon { @@ -22,15 +22,9 @@ void LGADPulseDigitization::process(const LGADPulseDigitization::Input& input, const auto [simhits] = input; auto [rawhits] = output; - double thres = m_cfg.t_thres; - // Vm in unit of GeV. When Edep = Vm, ADC = cfg.adc_range-1 - double Vm = m_cfg.Vm; + double thres = -m_cfg.t_thres; int adc_range = m_cfg.adc_range; - // normalized time threshold - // convert threshold EDep to voltage - double norm_threshold = -thres * adc_range / Vm; - for (const auto& pulse : *simhits) { double intersectionX = 0.0; int tdc = std::numeric_limits::max(); @@ -43,9 +37,9 @@ void LGADPulseDigitization::process(const LGADPulseDigitization::Input& input, auto adcs = pulse.getAdcCounts(); double n_EICROC_cycle = int(pulse.getTime()/m_cfg.tMax + 1e-3); for (const auto adc : adcs) { - if (adc_prev >= norm_threshold && adc <= norm_threshold) { + if (adc_prev >= thres && adc <= thres) { intersectionX = time_bin * time_interval + - time_interval * (norm_threshold - adc_prev) / (adc - adc_prev); + time_interval * (thres - adc_prev) / (adc - adc_prev); tdc = static_cast(intersectionX / time_interval) + n_EICROC_cycle * m_cfg.tdc_range; } if (abs(adc) > abs(V)) // To get peak of the Analog signal diff --git a/src/algorithms/digi/LGADPulseDigitization.h b/src/algorithms/digi/LGADPulseDigitization.h index 5ef0927fd6..09ee182b9e 100644 --- a/src/algorithms/digi/LGADPulseDigitization.h +++ b/src/algorithms/digi/LGADPulseDigitization.h @@ -12,7 +12,7 @@ #include #include -#include "algorithms/digi/LGADHitDigiConfig.h" +#include "algorithms/digi/LGADPulseDigitizationConfig.h" #include "algorithms/interfaces/WithPodConfig.h" namespace eicrecon { @@ -22,7 +22,7 @@ using LGADPulseDigitizationAlgorithm = algorithms::Output>; class LGADPulseDigitization : public LGADPulseDigitizationAlgorithm, - public WithPodConfig { + public WithPodConfig { public: LGADPulseDigitization(std::string_view name) diff --git a/src/algorithms/digi/LGADPulseDigitizationConfig.h b/src/algorithms/digi/LGADPulseDigitizationConfig.h new file mode 100644 index 0000000000..498e907139 --- /dev/null +++ b/src/algorithms/digi/LGADPulseDigitizationConfig.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2024 Souvik Paul + +#pragma once + +#include + +namespace eicrecon { + +struct LGADPulseDigitizationConfig { + int adc_bit = 8; + int tdc_bit = 10; + // total number of TDC/ADC values + // Since digitizer starts at zero, max ADC value = adc_range - 1 + // Similar for TDC + int adc_range = pow(2, adc_bit); + int tdc_range = pow(2, tdc_bit); + + + double t_thres = 0.1 * adc_range; // TDC value = time when pulse exceed t_thres + // period of the sensor clock. Time internal to sensor will all be digitized to integer multiple + // of tInterval + double tMax = 25 * dd4hep::ns; // 25 ns is the period of 40MHz EIC clock +}; + +} // namespace eicrecon diff --git a/src/algorithms/digi/LGADPulseGeneration.cc b/src/algorithms/digi/LGADPulseGeneration.cc index f81260ac35..27c3e54b9e 100644 --- a/src/algorithms/digi/LGADPulseGeneration.cc +++ b/src/algorithms/digi/LGADPulseGeneration.cc @@ -14,7 +14,7 @@ #include "TMath.h" #include "LGADPulseGeneration.h" -#include "algorithms/digi/LGADHitDigiConfig.h" +#include "algorithms/digi/LGADPulseGenerationConfig.h" namespace eicrecon { diff --git a/src/algorithms/digi/LGADPulseGeneration.h b/src/algorithms/digi/LGADPulseGeneration.h index 8078113d70..ab7d5a8308 100644 --- a/src/algorithms/digi/LGADPulseGeneration.h +++ b/src/algorithms/digi/LGADPulseGeneration.h @@ -13,7 +13,7 @@ #include #include -#include "algorithms/digi/LGADHitDigiConfig.h" +#include "algorithms/digi/LGADPulseGenerationConfig.h" #include "algorithms/interfaces/WithPodConfig.h" namespace eicrecon { @@ -31,7 +31,7 @@ class PulseShape { virtual ~PulseShape() {}; }; -// default pulse shapt is Landau +// default pulse shape is Landau class LandauPulse : public PulseShape { public: LandauPulse(double gain, double Vm, double sigma_analog, double adc_range); @@ -44,7 +44,7 @@ class LandauPulse : public PulseShape { class LGADPulseGeneration : public LGADPulseGenerationAlgorithm, - public WithPodConfig { + public WithPodConfig { // The key pair is typedef std::unordered_map>> AdcArray; diff --git a/src/algorithms/digi/LGADHitDigiConfig.h b/src/algorithms/digi/LGADPulseGenerationConfig.h similarity index 91% rename from src/algorithms/digi/LGADHitDigiConfig.h rename to src/algorithms/digi/LGADPulseGenerationConfig.h index 80d208f346..e46d6b85a1 100644 --- a/src/algorithms/digi/LGADHitDigiConfig.h +++ b/src/algorithms/digi/LGADPulseGenerationConfig.h @@ -7,14 +7,13 @@ namespace eicrecon { -struct LGADHitDigiConfig { +struct LGADPulseGenerationConfig { // Parameters of AC-LGAD signal generation double gain = 113.755; double risetime = 0.45 * dd4hep::ns; double sigma_analog = 0.293951 * dd4hep::ns; double Vm = -1e-4 * dd4hep::GeV; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage // corresponds to ADC = adc_max - double t_thres = 0.1 * Vm; // TDC value = time when pulse exceed t_thres double ignore_thres = 0.001 * Vm; // If EDep below this value, digitization for the cell will be // ignored. Speed up calculation int adc_bit = 8; diff --git a/src/factories/digi/LGADPulseDigitization_factory.h b/src/factories/digi/LGADPulseDigitization_factory.h index 1519568da8..e3ef225cdd 100644 --- a/src/factories/digi/LGADPulseDigitization_factory.h +++ b/src/factories/digi/LGADPulseDigitization_factory.h @@ -11,7 +11,7 @@ namespace eicrecon { class LGADPulseDigitization_factory - : public JOmniFactory { + : public JOmniFactory { public: using AlgoT = eicrecon::LGADPulseDigitization; diff --git a/src/factories/digi/LGADPulseGeneration_factory.h b/src/factories/digi/LGADPulseGeneration_factory.h index b1b1fecade..5b211a06e3 100644 --- a/src/factories/digi/LGADPulseGeneration_factory.h +++ b/src/factories/digi/LGADPulseGeneration_factory.h @@ -11,7 +11,7 @@ namespace eicrecon { class LGADPulseGeneration_factory - : public JOmniFactory { + : public JOmniFactory { public: using AlgoT = eicrecon::LGADPulseGeneration; diff --git a/src/tests/algorithms_test/CMakeLists.txt b/src/tests/algorithms_test/CMakeLists.txt index b6b2531ca5..add56f0616 100644 --- a/src/tests/algorithms_test/CMakeLists.txt +++ b/src/tests/algorithms_test/CMakeLists.txt @@ -11,8 +11,8 @@ add_executable( calorimetry_CalorimeterHitDigi.cc calorimetry_CalorimeterClusterRecoCoG.cc calorimetry_HEXPLIT.cc - digi_TOFPulseGeneration.cc - digi_TOFPulseDigitization.cc + digi_LGADPulseGeneration.cc + digi_LGADPulseDigitization.cc pid_MergeTracks.cc pid_MergeParticleID.cc pid_lut_PIDLookup.cc diff --git a/src/tests/algorithms_test/algorithmsInit.cc b/src/tests/algorithms_test/algorithmsInit.cc index 1d5a839e28..bb673c717e 100644 --- a/src/tests/algorithms_test/algorithmsInit.cc +++ b/src/tests/algorithms_test/algorithmsInit.cc @@ -44,14 +44,14 @@ class algorithmsInitListener : public Catch::EventListenerBase { detector->add(id_desc_tracker); detector->add(readoutTracker); - dd4hep::Readout readoutTOF(std::string("MockTOFHits")); - dd4hep::IDDescriptor id_desc_TOF("MockTOFHits", "system:8,layer:4,module:12,sensor:10,x:40:-8,y:-16"); + dd4hep::Readout readoutLGAD(std::string("MockLGADHits")); + dd4hep::IDDescriptor id_desc_LGAD("MockLGADHits", "system:8,layer:4,module:12,sensor:10,x:40:-8,y:-16"); //Create segmentation with 1x1 mm pixels - dd4hep::Segmentation segmentation_TOF("CartesianGridXY","TOFHitsSeg", id_desc_tracker.decoder()); - readoutTOF.setIDDescriptor(id_desc_TOF); - readoutTOF.setSegmentation(segmentation_TOF); - detector->add(id_desc_TOF); - detector->add(readoutTOF); + dd4hep::Segmentation segmentation_LGAD("CartesianGridXY","LGADHitsSeg", id_desc_tracker.decoder()); + readoutLGAD.setIDDescriptor(id_desc_LGAD); + readoutLGAD.setSegmentation(segmentation_LGAD); + detector->add(id_desc_LGAD); + detector->add(readoutLGAD); m_detector = std::move(detector); diff --git a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc b/src/tests/algorithms_test/digi_LGADPulseDigitization.cc similarity index 91% rename from src/tests/algorithms_test/digi_TOFPulseDigitization.cc rename to src/tests/algorithms_test/digi_LGADPulseDigitization.cc index 31c5f54737..509ac54122 100644 --- a/src/tests/algorithms_test/digi_TOFPulseDigitization.cc +++ b/src/tests/algorithms_test/digi_LGADPulseDigitization.cc @@ -18,31 +18,27 @@ #include #include -#include "algorithms/digi/LGADHitDigiConfig.h" #include "algorithms/digi/LGADPulseDigitization.h" -TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseDigitization]") { +TEST_CASE("the LGAD charge sharing algorithm runs", "[LGADPulseDigitization]") { const float EPSILON = 1e-5; - eicrecon::LGADPulseDigitization algo("TOFPulseDigitization"); + eicrecon::LGADPulseDigitization algo("LGADPulseDigitization"); - std::shared_ptr logger = spdlog::default_logger()->clone("TOFPulseDigitization"); + std::shared_ptr logger = spdlog::default_logger()->clone("LGADPulseDigitization"); logger->set_level(spdlog::level::trace); - eicrecon::LGADHitDigiConfig cfg; + eicrecon::LGADPulseDigitizationConfig cfg; auto detector = algorithms::GeoSvc::instance().detector(); - auto id_desc = detector->readout("MockTOFHits").idSpec(); + auto id_desc = detector->readout("MockLGADHits").idSpec(); - cfg.gain = 10; - cfg.Vm = -1e-4; - cfg.ignore_thres = 1e-4 / 5; - cfg.t_thres = cfg.Vm * 0.1; cfg.tdc_bit = 8; cfg.adc_bit = 7; cfg.tMax = 10 * dd4hep::ns; cfg.tdc_range = pow(2, cfg.tdc_bit); cfg.adc_range = pow(2, cfg.adc_bit); + cfg.t_thres = cfg.adc_range * 0.1; // check if max pulse height is linearly proportional to the initial Edep algo.applyConfig(cfg); diff --git a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc b/src/tests/algorithms_test/digi_LGADPulseGeneration.cc similarity index 94% rename from src/tests/algorithms_test/digi_TOFPulseGeneration.cc rename to src/tests/algorithms_test/digi_LGADPulseGeneration.cc index 8b6c0014df..71cf34f4e1 100644 --- a/src/tests/algorithms_test/digi_TOFPulseGeneration.cc +++ b/src/tests/algorithms_test/digi_LGADPulseGeneration.cc @@ -23,12 +23,11 @@ #include "TF1.h" #include "TGraphErrors.h" -#include "algorithms/digi/LGADHitDigiConfig.h" #include "algorithms/digi/LGADPulseGeneration.h" -TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { +TEST_CASE("the LGAD charge sharing algorithm runs", "[LGADPulseGeneration]") { const float EPSILON = 1e-5; - eicrecon::LGADHitDigiConfig cfg; + eicrecon::LGADPulseGenerationConfig cfg; cfg.gain = 113; cfg.Vm = 1e-4 * dd4hep::GeV; cfg.ignore_thres = 1e-4 / 5; @@ -39,14 +38,14 @@ TEST_CASE("the BTOF charge sharing algorithm runs", "[TOFPulseGeneration]") { std::unique_ptr landau = std::make_unique(cfg.gain, cfg.Vm, cfg.sigma_analog, cfg.adc_range); - eicrecon::LGADPulseGeneration algo("TOFPulseGeneration", std::move(landau)); + eicrecon::LGADPulseGeneration algo("LGADPulseGeneration", std::move(landau)); - std::shared_ptr logger = spdlog::default_logger()->clone("TOFPulseGeneration"); + std::shared_ptr logger = spdlog::default_logger()->clone("LGADPulseGeneration"); logger->set_level(spdlog::level::trace); auto detector = algorithms::GeoSvc::instance().detector(); - auto id_desc = detector->readout("MockTOFHits").idSpec(); + auto id_desc = detector->readout("MockLGADHits").idSpec(); SECTION("Pulse height linearlity test") { // check if max pulse height is linearly proportional to the initial Edep From 9fe2773237731ea557ed76f935806b6d872d00b8 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Wed, 18 Dec 2024 15:21:35 -0500 Subject: [PATCH 67/77] Make clang-tidy happy. --- src/algorithms/digi/LGADPulseGeneration.cc | 3 ++- src/algorithms/digi/LGADPulseGeneration.h | 5 +++++ .../algorithms_test/digi_LGADPulseDigitization.cc | 8 +++++--- src/tests/algorithms_test/digi_LGADPulseGeneration.cc | 11 +++++++---- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/algorithms/digi/LGADPulseGeneration.cc b/src/algorithms/digi/LGADPulseGeneration.cc index 0c5ae9e59f..e83e8d99db 100644 --- a/src/algorithms/digi/LGADPulseGeneration.cc +++ b/src/algorithms/digi/LGADPulseGeneration.cc @@ -8,12 +8,13 @@ #include #include #include +#include #include #include #include -#include "TMath.h" #include "LGADPulseGeneration.h" +#include "TMath.h" #include "algorithms/digi/LGADPulseGenerationConfig.h" namespace eicrecon { diff --git a/src/algorithms/digi/LGADPulseGeneration.h b/src/algorithms/digi/LGADPulseGeneration.h index 0917ad526f..e78e05ecb3 100644 --- a/src/algorithms/digi/LGADPulseGeneration.h +++ b/src/algorithms/digi/LGADPulseGeneration.h @@ -7,11 +7,16 @@ #pragma once +#include #include #include #include +#include #include #include +#include +#include +#include #include "algorithms/digi/LGADPulseGenerationConfig.h" #include "algorithms/interfaces/WithPodConfig.h" diff --git a/src/tests/algorithms_test/digi_LGADPulseDigitization.cc b/src/tests/algorithms_test/digi_LGADPulseDigitization.cc index 070f9c6b00..0270a0cfdc 100644 --- a/src/tests/algorithms_test/digi_LGADPulseDigitization.cc +++ b/src/tests/algorithms_test/digi_LGADPulseDigitization.cc @@ -4,21 +4,23 @@ #include #include #include +#include #include #include #include // for AssertionHandler, operator""_catch_sr, StringRef, REQUIRE, operator<, operator==, operator>, TEST_CASE -#include #include #include -#include -#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access #include // for level_enum #include // for logger #include // for default_logger +#include +#include +#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access #include #include #include "algorithms/digi/LGADPulseDigitization.h" +#include "algorithms/digi/LGADPulseDigitizationConfig.h" TEST_CASE("the LGAD charge sharing algorithm runs", "[LGADPulseDigitization]") { const float EPSILON = 1e-5; diff --git a/src/tests/algorithms_test/digi_LGADPulseGeneration.cc b/src/tests/algorithms_test/digi_LGADPulseGeneration.cc index bb77a1f3ca..14155016fa 100644 --- a/src/tests/algorithms_test/digi_LGADPulseGeneration.cc +++ b/src/tests/algorithms_test/digi_LGADPulseGeneration.cc @@ -4,19 +4,21 @@ #include #include #include -#include +#include #include #include // for AssertionHandler, operator""_catch_sr, StringRef, REQUIRE, operator<, operator==, operator>, TEST_CASE #include #include #include -#include -#include -#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access #include #include // for level_enum #include // for logger #include // for default_logger +#include +#include +#include +#include +#include // for allocator, unique_ptr, make_unique, shared_ptr, __shared_ptr_access #include #include #include @@ -24,6 +26,7 @@ #include "TF1.h" #include "TGraphErrors.h" #include "algorithms/digi/LGADPulseGeneration.h" +#include "algorithms/digi/LGADPulseGenerationConfig.h" TEST_CASE("the LGAD charge sharing algorithm runs", "[LGADPulseGeneration]") { const float EPSILON = 1e-5; From 2401f0abd45d045cb4889e6514c170224d3cda90 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Wed, 18 Dec 2024 15:39:53 -0500 Subject: [PATCH 68/77] Modified slightly so it works with negative global time. --- src/algorithms/digi/LGADPulseDigitization.cc | 2 +- src/algorithms/digi/LGADPulseGeneration.cc | 2 +- src/tests/algorithms_test/digi_LGADPulseDigitization.cc | 8 +++++--- src/tests/algorithms_test/digi_LGADPulseGeneration.cc | 6 ++++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/algorithms/digi/LGADPulseDigitization.cc b/src/algorithms/digi/LGADPulseDigitization.cc index 0df7210527..0eecb0032d 100644 --- a/src/algorithms/digi/LGADPulseDigitization.cc +++ b/src/algorithms/digi/LGADPulseDigitization.cc @@ -35,7 +35,7 @@ void LGADPulseDigitization::process(const LGADPulseDigitization::Input& input, double adc_prev = 0; double time_interval = pulse.getInterval(); auto adcs = pulse.getAdcCounts(); - double n_EICROC_cycle = int(pulse.getTime()/m_cfg.tMax + 1e-3); + double n_EICROC_cycle = static_cast(std::floor(pulse.getTime()/m_cfg.tMax + 1e-3)); for (const auto adc : adcs) { if (adc_prev >= thres && adc <= thres) { intersectionX = time_bin * time_interval + diff --git a/src/algorithms/digi/LGADPulseGeneration.cc b/src/algorithms/digi/LGADPulseGeneration.cc index e83e8d99db..63004822d7 100644 --- a/src/algorithms/digi/LGADPulseGeneration.cc +++ b/src/algorithms/digi/LGADPulseGeneration.cc @@ -84,7 +84,7 @@ void LGADPulseGeneration::process(const LGADPulseGeneration::Input& input, if (charge < m_cfg.ignore_thres) continue; - int n_EICROC_cycle = int(time/m_cfg.tMax + 1e-3); + int n_EICROC_cycle = static_cast(std::floor(time/m_cfg.tMax + 1e-3)); double time_in_cycle = time - n_EICROC_cycle * m_cfg.tMax; double mpv_analog = time_in_cycle + m_cfg.risetime; this -> _FillADCArray(adc_sum, charge, mpv_analog, n_EICROC_cycle, cellID); diff --git a/src/tests/algorithms_test/digi_LGADPulseDigitization.cc b/src/tests/algorithms_test/digi_LGADPulseDigitization.cc index 0270a0cfdc..35e5db5c0d 100644 --- a/src/tests/algorithms_test/digi_LGADPulseDigitization.cc +++ b/src/tests/algorithms_test/digi_LGADPulseDigitization.cc @@ -49,8 +49,9 @@ TEST_CASE("the LGAD charge sharing algorithm runs", "[LGADPulseDigitization]") { SECTION("TDC vs analytic solution scan") { logger->info("Begin TDC vs analytic solution scan"); - for(double time = 0; time <= cfg.tMax; time += cfg.tMax) { - if(time == 0) logger->info("Generation pulse at the first EICROC cycle"); + for(double time = -cfg.tMax; time <= cfg.tMax; time += cfg.tMax) { + if(time < 0) logger->info("Generation pulse at the negative time"); + else if(time == 0) logger->info("Generation pulse at the first EICROC cycle"); else logger->info("Generation pulse at the second EICROC cycle"); // test pulse with gaussian shape @@ -94,7 +95,8 @@ TEST_CASE("the LGAD charge sharing algorithm runs", "[LGADPulseDigitization]") { auto hit = (*rawhits_coll)[0]; REQUIRE(hit.getCellID() == cellID); REQUIRE(hit.getCharge() == test_peak); - if(time == 0) REQUIRE(hit.getTimeStamp() == analytic_TDC); + if(time < 0) REQUIRE(hit.getTimeStamp() == analytic_TDC - cfg.tdc_range); + else if(time == 0) REQUIRE(hit.getTimeStamp() == analytic_TDC); else REQUIRE(hit.getTimeStamp() == analytic_TDC + cfg.tdc_range); } } diff --git a/src/tests/algorithms_test/digi_LGADPulseGeneration.cc b/src/tests/algorithms_test/digi_LGADPulseGeneration.cc index 14155016fa..e4ff7d8f04 100644 --- a/src/tests/algorithms_test/digi_LGADPulseGeneration.cc +++ b/src/tests/algorithms_test/digi_LGADPulseGeneration.cc @@ -117,6 +117,8 @@ TEST_CASE("the LGAD charge sharing algorithm runs", "[LGADPulseGeneration]") { for (double time = 0; time < 12; time += 1.) times.push_back(time); // test multiple EICROC cycle for (double time = 10; time < 101; time += 25.) times.push_back(time); + // test negative time + times.push_back(-10); for (double time : times) { edm4hep::SimTrackerHitCollection rawhits_coll; @@ -139,7 +141,7 @@ TEST_CASE("the LGAD charge sharing algorithm runs", "[LGADPulseGeneration]") { REQUIRE(time_series_coll->size() == 1); auto min_adc = std::numeric_limits::max(); - unsigned int time_bin = 0; + int time_bin = 0; for(const auto& pulse: *time_series_coll) { //auto pulse = (*time_series_coll)[0]; REQUIRE(pulse.getCellID() == cellID); @@ -158,7 +160,7 @@ TEST_CASE("the LGAD charge sharing algorithm runs", "[LGADPulseGeneration]") { } // test linearlity - TF1 tf1("tf1", "pol1", 0, *std::max_element(times.begin(), times.end())); + TF1 tf1("tf1", "pol1", *std::min_element(times.begin(), times.end()), *std::max_element(times.begin(), times.end())); graph.Fit(&tf1, "R0"); // slope can't be consistent with zero REQUIRE(!(tf1.GetParameter(1) - tf1.GetParError(1) < 0 && 0 < tf1.GetParameter(1) + tf1.GetParError(1) )); From 01473d3c0e3d7d7486d9bccd2cdb9e3105aee126 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 20:40:08 +0000 Subject: [PATCH 69/77] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/tests/algorithms_test/digi_LGADPulseDigitization.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/algorithms_test/digi_LGADPulseDigitization.cc b/src/tests/algorithms_test/digi_LGADPulseDigitization.cc index 35e5db5c0d..5f11c0858c 100644 --- a/src/tests/algorithms_test/digi_LGADPulseDigitization.cc +++ b/src/tests/algorithms_test/digi_LGADPulseDigitization.cc @@ -95,8 +95,8 @@ TEST_CASE("the LGAD charge sharing algorithm runs", "[LGADPulseDigitization]") { auto hit = (*rawhits_coll)[0]; REQUIRE(hit.getCellID() == cellID); REQUIRE(hit.getCharge() == test_peak); - if(time < 0) REQUIRE(hit.getTimeStamp() == analytic_TDC - cfg.tdc_range); - else if(time == 0) REQUIRE(hit.getTimeStamp() == analytic_TDC); + if(time < 0) REQUIRE(hit.getTimeStamp() == analytic_TDC - cfg.tdc_range); + else if(time == 0) REQUIRE(hit.getTimeStamp() == analytic_TDC); else REQUIRE(hit.getTimeStamp() == analytic_TDC + cfg.tdc_range); } } From 2aab59bc23925fffdb7b4dfba3f605737b9af353 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Wed, 18 Dec 2024 16:55:34 -0500 Subject: [PATCH 70/77] Make clang-tidy happy. --- src/algorithms/digi/LGADPulseDigitization.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/algorithms/digi/LGADPulseDigitization.cc b/src/algorithms/digi/LGADPulseDigitization.cc index 0eecb0032d..ba426165df 100644 --- a/src/algorithms/digi/LGADPulseDigitization.cc +++ b/src/algorithms/digi/LGADPulseDigitization.cc @@ -4,12 +4,12 @@ // // Convert ADC pulses from LGADPulseGeneration into ADC and TDC values +#include +#include #include +#include #include #include -#include -#include -#include #include #include "LGADPulseDigitization.h" From 00936904681e4eaa1b1cf23acc17b6dff564aac1 Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Thu, 2 Jan 2025 17:37:14 -0500 Subject: [PATCH 71/77] Update src/algorithms/digi/LGADPulseGenerationConfig.h Co-authored-by: Derek M Anderson --- src/algorithms/digi/LGADPulseGenerationConfig.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/digi/LGADPulseGenerationConfig.h b/src/algorithms/digi/LGADPulseGenerationConfig.h index e46d6b85a1..5d4e5c008a 100644 --- a/src/algorithms/digi/LGADPulseGenerationConfig.h +++ b/src/algorithms/digi/LGADPulseGenerationConfig.h @@ -22,8 +22,8 @@ struct LGADPulseGenerationConfig { // total number of TDC/ADC values // Since digitizer starts at zero, max ADC value = adc_range - 1 // Similar for TDC - int adc_range = pow(2, adc_bit); - int tdc_range = pow(2, tdc_bit); + int adc_range = std::pow(2, adc_bit); + int tdc_range = std::pow(2, tdc_bit); // period of the sensor clock. Time internal to sensor will all be digitized to integer multiple // of tInterval From 6f852c0140c4009223209eac15da6e6d123547c2 Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Thu, 2 Jan 2025 17:37:24 -0500 Subject: [PATCH 72/77] Update src/algorithms/digi/LGADPulseDigitizationConfig.h Co-authored-by: Derek M Anderson --- src/algorithms/digi/LGADPulseDigitizationConfig.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/digi/LGADPulseDigitizationConfig.h b/src/algorithms/digi/LGADPulseDigitizationConfig.h index 498e907139..8df404629f 100644 --- a/src/algorithms/digi/LGADPulseDigitizationConfig.h +++ b/src/algorithms/digi/LGADPulseDigitizationConfig.h @@ -13,8 +13,8 @@ struct LGADPulseDigitizationConfig { // total number of TDC/ADC values // Since digitizer starts at zero, max ADC value = adc_range - 1 // Similar for TDC - int adc_range = pow(2, adc_bit); - int tdc_range = pow(2, tdc_bit); + int adc_range = std::pow(2, adc_bit); + int tdc_range = std::pow(2, tdc_bit); double t_thres = 0.1 * adc_range; // TDC value = time when pulse exceed t_thres From 231cb0a712cea6a01b05ef48283302eb16b60b1f Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Thu, 2 Jan 2025 17:37:37 -0500 Subject: [PATCH 73/77] Update src/algorithms/digi/LGADChargeSharingConfig.h Co-authored-by: Derek M Anderson --- src/algorithms/digi/LGADChargeSharingConfig.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/digi/LGADChargeSharingConfig.h b/src/algorithms/digi/LGADChargeSharingConfig.h index b7cb9f4641..5a09041c5e 100644 --- a/src/algorithms/digi/LGADChargeSharingConfig.h +++ b/src/algorithms/digi/LGADChargeSharingConfig.h @@ -25,8 +25,8 @@ struct TOFHitDigiConfig { // total number of TDC/ADC values // Since digitizer starts at zero, max ADC value = adc_range - 1 // Similar for TDC - int adc_range = pow(2, adc_bit); - int tdc_range = pow(2, tdc_bit); + int adc_range = std::pow(2, adc_bit); + int tdc_range = std::pow(2, tdc_bit); // period of the sensor clock. Time internal to sensor will all be digitized to integer multiple // of tInterval From 7f8a8e3c71026246a9ea940899ed4ed06cc04f67 Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Thu, 2 Jan 2025 17:38:07 -0500 Subject: [PATCH 74/77] Update src/algorithms/digi/LGADPulseGeneration.cc Co-authored-by: Derek M Anderson --- src/algorithms/digi/LGADPulseGeneration.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/algorithms/digi/LGADPulseGeneration.cc b/src/algorithms/digi/LGADPulseGeneration.cc index 63004822d7..f5673361db 100644 --- a/src/algorithms/digi/LGADPulseGeneration.cc +++ b/src/algorithms/digi/LGADPulseGeneration.cc @@ -68,8 +68,6 @@ void LGADPulseGeneration::process(const LGADPulseGeneration::Input& input, const auto [simhits] = input; auto [rawADCs] = output; - int tdc_range = m_cfg.tdc_range; - // signal sum // NOTE: we take the cellID of the most energetic hit in this group so it is a real cellID from an // MC hit From 8e652c9e5a6f01891a5bb164800be7b998658d00 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Thu, 2 Jan 2025 18:06:22 -0500 Subject: [PATCH 75/77] Removed legacy file LGADChargeSharingConfig.h --- src/algorithms/digi/LGADChargeSharingConfig.h | 39 ------------------- 1 file changed, 39 deletions(-) delete mode 100644 src/algorithms/digi/LGADChargeSharingConfig.h diff --git a/src/algorithms/digi/LGADChargeSharingConfig.h b/src/algorithms/digi/LGADChargeSharingConfig.h deleted file mode 100644 index 5a09041c5e..0000000000 --- a/src/algorithms/digi/LGADChargeSharingConfig.h +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2024 Souvik Paul - -#pragma once - -#include - -namespace eicrecon { - -struct TOFHitDigiConfig { - // Parameters of AC-LGAD signal generation - double gain = 113.755; - double risetime = 0.45 * dd4hep::ns; - double sigma_analog = 0.293951 * dd4hep::ns; - double sigma_sharingx = 0.1 * dd4hep::cm; - double sigma_sharingy = 0.5 * dd4hep::cm; - double Vm = -1e-4 * dd4hep::GeV; // Vm = voltage maximum. When EDep = 1e-4 GeV, voltage - // corresponds to ADC = adc_max - double t_thres = 0.1 * Vm; // TDC value = time when pulse exceed t_thres - double ignore_thres = 0.001 * Vm; // If EDep below this value, digitization for the cell will be - // ignored. Speed up calculation - int adc_bit = 8; - int tdc_bit = 10; - - // total number of TDC/ADC values - // Since digitizer starts at zero, max ADC value = adc_range - 1 - // Similar for TDC - int adc_range = std::pow(2, adc_bit); - int tdc_range = std::pow(2, tdc_bit); - - // period of the sensor clock. Time internal to sensor will all be digitized to integer multiple - // of tInterval - double tMax = 25 * dd4hep::ns; // 25 ns is the period of 40MHz EIC clock - double tInterval = tMax / (tdc_range - 1); - - std::string readout = "TOFBarrelHits"; -}; - -} // namespace eicrecon From e6956279658408ea960cfa069b34a3ee1f090083 Mon Sep 17 00:00:00 2001 From: Tommy Chun Yuen Tsang Date: Fri, 3 Jan 2025 16:16:13 -0500 Subject: [PATCH 76/77] Update src/algorithms/digi/BTOFChargeSharing.cc Co-authored-by: Derek M Anderson --- src/algorithms/digi/BTOFChargeSharing.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.cc b/src/algorithms/digi/BTOFChargeSharing.cc index 9210cf6334..749a2d4894 100644 --- a/src/algorithms/digi/BTOFChargeSharing.cc +++ b/src/algorithms/digi/BTOFChargeSharing.cc @@ -138,9 +138,7 @@ const dd4hep::rec::CellID BTOFChargeSharing::_getSensorID(const dd4hep::rec::CellID& hitCell) const { // fix x-y, what you left with are ids that corresponds to sensor info // cellID may change when position changes. - auto sensorID = hitCell; //_converter -> cellID(_converter -> position(hitCell)); - m_decoder->set(sensorID, "x", 0); - m_decoder->set(sensorID, "y", 0); + auto sensorID = m_decoder->get(hitCell, "sensor"); return sensorID; } From a1aa137b4d3c1cf4b4660ee0964eb3890a86bc36 Mon Sep 17 00:00:00 2001 From: ssedd1123 Date: Fri, 3 Jan 2025 16:17:54 -0500 Subject: [PATCH 77/77] use private rather than protected on BTOFChargeSharing --- src/algorithms/digi/BTOFChargeSharing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/BTOFChargeSharing.h b/src/algorithms/digi/BTOFChargeSharing.h index ff7c954249..64acda4f7a 100644 --- a/src/algorithms/digi/BTOFChargeSharing.h +++ b/src/algorithms/digi/BTOFChargeSharing.h @@ -36,7 +36,7 @@ class BTOFChargeSharing : public BTOFChargeSharingAlgorithm, void init() final; void process(const Input&, const Output&) const final; -protected: +private: void _findAllNeighborsInSensor(dd4hep::rec::CellID hitCell, std::shared_ptr>& answer, std::unordered_set& dp) const;