Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Realistic BTOF digitization #1635

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
8123783
First commit of BTOF digitization code!
ssedd1123 Jul 18, 2024
2332d18
Update BTOFHitDigi.cc
eicsouvik Jul 19, 2024
4b907cb
Update BTOFHitDigi.h
eicsouvik Jul 19, 2024
204d472
Update BTOFHitDigi.cc
eicsouvik Jul 19, 2024
1b08022
Merge pull request #3 from eicsouvik/patch-1
ssedd1123 Jul 19, 2024
5e011e1
Merge pull request #2 from eicsouvik/patch-2
ssedd1123 Jul 19, 2024
5e17954
Merge pull request #1 from eicsouvik/patch-3
ssedd1123 Jul 19, 2024
9fbe640
Changed the algorithm of BarrelTOFNeighborFinder so it's more intuita…
Jul 19, 2024
171ffd4
Merge branch 'main' of https://github.com/ssedd1123/EICrecon
Jul 19, 2024
52a9b33
Changed spread calculation. Originally the spread were estimated with…
Jul 19, 2024
54024b6
Fixed bugs when sensor ID from barrelTOFNeighborFinder gives wrong ne…
ssedd1123 Jul 25, 2024
5e1cec4
Merge branch 'eic:main' into main
ssedd1123 Aug 3, 2024
40abca0
Updated BTOF neighbor finder. To be used with updated epic geometry w…
ssedd1123 Aug 3, 2024
72edf8b
Merge branch 'eic:main' into main
ssedd1123 Aug 26, 2024
df48d16
Merge branch 'eic:main' into main
ssedd1123 Aug 26, 2024
1d3c040
Merge branch 'eic:main' into main
ssedd1123 Aug 26, 2024
1adfd02
Sync fork.
ssedd1123 Sep 24, 2024
f373972
Added missing closing parenthesis.
ssedd1123 Sep 24, 2024
0725492
Use more realistic charge sharing parameters and bug fix on ADC heights.
ssedd1123 Sep 27, 2024
a451aed
Merge branch 'main' of https://github.com/ssedd1123/EICrecon
ssedd1123 Sep 27, 2024
ce9122d
Fixed incorrect threshold for ADC TDC.
ssedd1123 Oct 8, 2024
08c83e6
Merge branch 'eic:main' into main
ssedd1123 Oct 14, 2024
350ca3b
Move digitization code to the main branch.
ssedd1123 Oct 15, 2024
4f892ee
Formated files.
ssedd1123 Oct 15, 2024
8d8a12a
Included config content in parameter ref.
ssedd1123 Oct 15, 2024
d260635
Merge remote-tracking branch 'new-origin/main' into pr/BTOF-digitizat…
ssedd1123 Oct 15, 2024
875f0f4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 15, 2024
b12ee38
Fixed BTOF reco uncertainty estimation bug.
ssedd1123 Oct 15, 2024
0d91db5
Merge branch 'main' into pr/BTOF-digitization-clusterization
ssedd1123 Oct 21, 2024
34f4daa
Removed reconstruction for later pull request. Breaks TOF digi into t…
ssedd1123 Oct 23, 2024
9ab01c9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 23, 2024
4cf1216
Removed legacy modification to JEventProcessorPODIO.cc
ssedd1123 Oct 23, 2024
83c9b88
Merge branch 'pr/BTOF-digitization-clusterization' of https://github.…
ssedd1123 Oct 23, 2024
deaf63c
Merge branch 'main' into pr/BTOF-digitization-clusterization
ssedd1123 Oct 23, 2024
14889de
Fixed bugs on charge sharing calculation. It was assumed that all gea…
ssedd1123 Oct 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions src/algorithms/digi/TOFHitDigiConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright (C) 2024 Souvik Paul

#pragma once

#include <DD4hep/DD4hepUnits.h>

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
// 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; // 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
131 changes: 74 additions & 57 deletions src/detectors/BTOF/BTOF.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,29 @@
#include "extensions/jana/JOmniFactoryGeneratorT.h"
#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 "global/pid_lut/PIDLookup_factory.h"
#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<SiliconTrackerDigi_factory>(
"TOFBarrelRawHit",
{
"TOFBarrelHits"
},
{
"TOFBarrelRawHit",
"TOFBarrelRawHitAssociations"
},
{
.threshold = 6.0 * dd4hep::keV,
.timeResolution = 0.025, // [ns]
},
app
));
// Digitization
app->Add(new JOmniFactoryGeneratorT<SiliconTrackerDigi_factory>(
"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<TrackerHitReconstruction_factory>(
// Convert raw digitized hits into hits with geometry info (ready for tracking)
app->Add(new JOmniFactoryGeneratorT<TrackerHitReconstruction_factory>(
"TOFBarrelRecHit",
{"TOFBarrelRawHit"}, // Input data collection tags
{"TOFBarrelRecHit"}, // Output data tag
Expand All @@ -55,53 +50,75 @@ void InitPlugin(JApplication *app) {
app
)); // Hit reco default config for factories

int BarrelTOF_ID = 0;
try {
auto detector = app->GetService<DD4hep_service>()->detector();
BarrelTOF_ID = detector->constant<int>("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<BTOFChargeSharing_factory>(
"BTOFChargeSharing",
{"TOFBarrelHits"},
{"TOFBarrelSharedHits"},
{},
app
));

app->Add(new JOmniFactoryGeneratorT<TOFPulseGeneration_factory>(
"BTOFPulseGeneration",
{"TOFBarrelSharedHits"},
{"TOFBarrelPulse"},
{},
app
));

app->Add(new JOmniFactoryGeneratorT<TOFPulseDigitization_factory>(
"BTOFPulseDigitization",
{"TOFBarrelPulse"},
{"TOFBarrelADCTDC"},
{},
app
));

int BarrelTOF_ID = 0;
try {
auto detector = app->GetService<DD4hep_service>()->detector();
BarrelTOF_ID = detector->constant<int>("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<PIDLookup_factory>(
"CombinedTOFTruthSeededLUTPID",
{
app->Add(new JOmniFactoryGeneratorT<PIDLookup_factory>(
"CombinedTOFTruthSeededLUTPID",
{
"ReconstructedTruthSeededChargedWithPFRICHPIDParticles",
"ReconstructedTruthSeededChargedWithPFRICHPIDParticleAssociations",
},
{
},
{
"ReconstructedTruthSeededChargedWithPFRICHTOFPIDParticles",
"ReconstructedTruthSeededChargedWithPFRICHTOFPIDParticleAssociations",
"CombinedTOFTruthSeededParticleIDs",
},
pid_cfg,
app
));
},
pid_cfg, app));

app->Add(new JOmniFactoryGeneratorT<PIDLookup_factory>(
"CombinedTOFLUTPID",
{
app->Add(new JOmniFactoryGeneratorT<PIDLookup_factory>(
"CombinedTOFLUTPID",
{
"ReconstructedChargedWithPFRICHPIDParticles",
"ReconstructedChargedWithPFRICHPIDParticleAssociations",
},
{
},
{
"ReconstructedChargedWithPFRICHTOFPIDParticles",
"ReconstructedChargedWithPFRICHTOFPIDParticleAssociations",
"CombinedTOFParticleIDs",
},
pid_cfg,
app
));
},
pid_cfg, app));
}
} // extern "C"
182 changes: 182 additions & 0 deletions src/detectors/BTOF/BTOFChargeSharing.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// 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 <Evaluator/DD4hepUnits.h>
#include <TGraph.h>
#include <bitset>
#include <fmt/format.h>
#include <iostream>
#include <vector>

#include "BTOFChargeSharing.h"
#include "Math/SpecFunc.h"
#include "algorithms/digi/TOFHitDigiConfig.h"
#include <algorithms/geo.h>

// 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<std::vector<dd4hep::rec::CellID>>& ans,
std::unordered_set<dd4hep::rec::CellID>& 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<std::pair<int, int>> 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 position = m_converter -> position(cell); // global position
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];
pos.GetCoordinates(g);
currMatrix->MasterToLocal(g, l);
dd4hep::Position position;
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<std::vector<dd4hep::rec::CellID>> 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<dd4hep::rec::CellID> dp;
neighbors = std::make_shared<std::vector<dd4hep::rec::CellID>>();
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 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
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
Loading
Loading