Skip to content

Commit f1af416

Browse files
author
Szymon Pulawski
committed
FT0: share PM lookup table across digitization
Extract the PM lookup table construction from the FT0 Digitizer into a reusable PMLookupTable class. The lookup is initialized only once and reused by the Digitizer, avoiding repeated LUT parsing and making the mapping available for other FT0 components. No functional changes are intended.
1 parent 5c63efa commit f1af416

2 files changed

Lines changed: 24 additions & 180 deletions

File tree

DataFormats/Detectors/FIT/FT0/src/PMLookupTable.cxx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,6 @@ PMLookupTable::PMLookupTable()
8585
}
8686
}
8787

88-
for (ChannelID channelID = 0; channelID < Constants::sNCHANNELS_PM; ++channelID) {
89-
if (!mChannelIsMapped[channelID]) {
90-
LOG(fatal) << "FT0 channel " << channelID << " is not mapped to a PM in the LUT";
91-
}
92-
}
9388
}
9489

9590
PMLookupTable::PMHash PMLookupTable::getPMHash(ChannelID channelID) const

Detectors/FIT/FT0/simulation/src/Digitizer.cxx

Lines changed: 24 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,9 @@
1616
#include "CommonConstants/PhysicsConstants.h"
1717
#include "CommonDataFormat/InteractionRecord.h"
1818

19-
#include "DataFormatsFT0/LookUpTable.h"
19+
#include "DataFormatsFT0/PMLookupTable.h"
2020
#include "FT0Base/Constants.h"
2121
#include <map>
22-
#include <array>
23-
#include <unordered_map>
24-
#include <regex>
25-
#include <string>
2622

2723
#include "TMath.h"
2824
#include "TRandom.h"
@@ -317,52 +313,7 @@ void Digitizer::storeBC(BCCache& bc,
317313
if (bc.hits.empty()) {
318314
return;
319315
}
320-
// Initialize mapping channelID -> PM hash and PM side (A/C) using FT0 LUT
321-
static bool pmLutInitialized = false;
322-
static std::array<uint8_t, o2::ft0::Constants::sNCHANNELS_PM> mChID2PMhash{};
323-
static std::map<uint8_t, bool> mMapPMhash2isAside; // hashed PM -> is A side
324-
325-
if (!pmLutInitialized) {
326-
std::map<std::string, uint8_t> mapFEE2hash; // module name -> hashed PM id
327-
uint8_t tcmHash = 0;
328-
329-
const auto& lut = o2::ft0::SingleLUT::Instance().getVecMetadataFEE();
330-
auto lutSorted = lut;
331-
std::sort(lutSorted.begin(), lutSorted.end(),
332-
[](const auto& first, const auto& second) { return first.mModuleName < second.mModuleName; });
333-
334-
uint8_t binPos = 0;
335-
for (const auto& lutEntry : lutSorted) {
336-
const auto& moduleName = lutEntry.mModuleName;
337-
const auto& moduleType = lutEntry.mModuleType;
338-
const auto& strChID = lutEntry.mChannelID;
339-
340-
auto [it, inserted] = mapFEE2hash.insert({moduleName, binPos});
341-
if (inserted) {
342-
if (moduleName.find("PMA") != std::string::npos) {
343-
mMapPMhash2isAside.insert({binPos, true});
344-
} else if (moduleName.find("PMC") != std::string::npos) {
345-
mMapPMhash2isAside.insert({binPos, false});
346-
}
347-
++binPos;
348-
}
349-
350-
if (std::regex_match(strChID, std::regex("^[0-9]{1,3}$"))) {
351-
int chID = std::stoi(strChID);
352-
if (chID < o2::ft0::Constants::sNCHANNELS_PM) {
353-
mChID2PMhash[chID] = mapFEE2hash[moduleName];
354-
} else {
355-
LOG(fatal) << "Incorrect LUT entry: chID " << strChID << " | " << moduleName;
356-
}
357-
} else if (moduleType != "TCM") {
358-
LOG(fatal) << "Non-TCM module w/o numerical chID: chID " << strChID << " | " << moduleName;
359-
} else { // TCM
360-
tcmHash = mapFEE2hash[moduleName];
361-
}
362-
}
363-
364-
pmLutInitialized = true;
365-
}
316+
const auto& pmLookupTable = PMLookupTable::Instance();
366317

367318
int n_hit_A = 0, n_hit_C = 0, mean_time_A = 0, mean_time_C = 0;
368319
int summ_ampl_A = 0, summ_ampl_C = 0;
@@ -371,57 +322,25 @@ void Digitizer::storeBC(BCCache& bc,
371322
std::vector<int> sum_ampl_ipmt(nPMTs, 0);
372323
// Per-PM summed charge (like in digits2trgFT0)
373324
std::map<uint8_t, int> mapPMhash2sumAmpl;
374-
for (const auto& entry : mMapPMhash2isAside) {
325+
for (const auto& entry : pmLookupTable.getPMs()) {
375326
mapPMhash2sumAmpl.insert({entry.first, 0});
376327
}
377328

378329
int vertex_time;
379330
const auto& params = FT0DigParam::Instance();
380-
381-
static bool pmGroupsInitialized = false;
382-
static std::vector<std::array<int, 4>> pmtChannelGroups;
383-
if (!pmGroupsInitialized) {
384-
std::unordered_map<uint8_t, std::vector<int>> tmpGroups;
385-
for (int ch = 0; ch < o2::ft0::Constants::sNCHANNELS_PM; ++ch) {
386-
tmpGroups[mChID2PMhash[static_cast<uint8_t>(ch)]].push_back(ch);
387-
}
388-
389-
for (auto& [pmHash, chVec] : tmpGroups) {
390-
std::sort(chVec.begin(), chVec.end());
391-
if (chVec.size() % 4 != 0) {
392-
LOG(fatal) << "PM hash " << int(pmHash) << " has " << chVec.size()
393-
<< " channels in LUT, expected multiplicity of 4";
394-
}
395-
for (size_t i = 0; i < chVec.size(); i += 4) {
396-
std::array<int, 4> arr = {chVec[i + 0], chVec[i + 1], chVec[i + 2], chVec[i + 3]};
397-
pmtChannelGroups.push_back(arr);
398-
}
399-
}
400-
pmGroupsInitialized = true;
401-
}
402-
403331
int first = digitsCh.size(), nStored = 0;
404332
auto& particles = bc.hits;
405333
std::sort(std::begin(particles), std::end(particles));
406334
auto channel_end = particles.begin();
407335
std::vector<float> channel_times;
408-
std::vector<float> baseAmp(params.mMCPs, 0.f);
409-
std::vector<float> finalAmp(params.mMCPs, 0.f);
410-
std::vector<int> chTime(params.mMCPs, -5000);
411-
std::vector<int> chChain(params.mMCPs, 0);
412-
std::vector<bool> chValid(params.mMCPs, false);
413-
414-
static const std::array<std::array<int, 3>, 4> localNeighbours = {{{{1, 2, 3}},
415-
{{0, 3, 2}},
416-
{{0, 3, 1}},
417-
{{1, 2, 0}}}};
418-
419-
// std::set<int> disabledChannels = {40, 41, 42, 43, 88, 89, 90, 91, 56, 57, 58, 59, 60, 61, 62, 63, 72, 73, 74, 75, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 164, 165, 166, 167, 184, 185, 186, 187, 160, 161, 162, 163, 188, 189, 190, 191, 156, 157, 158, 159, 192, 193, 194, 195, 152, 153, 154, 155, 196, 197, 198, 199, 148, 149, 150, 151, 144, 145, 146, 147, 204, 205, 206, 207, 200, 201, 202, 203}; // przykładowe kanały
336+
// std::set<int> disabledChannels = {40, 41, 42, 43, 88, 89, 90, 91, 56, 57, 58, 59, 60, 61, 62, 63, 72, 73, 74, 75, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 164, 165, 166, 167, 184, 185, 186, 187, 160, 161, 162, 163, 188, 189, 190, 191, 156, 157, 158, 159, 192, 193, 194, 195, 152, 153, 154, 155, 196, 197, 198, 199, 148, 149, 150, 151, 144, 145, 146, 147, 204, 205, 206, 207, 200, 201, 202, 203}; // przykładowe kanały
420337
for (Int_t ipmt = 0; ipmt < params.mMCPs; ++ipmt) {
421338
auto channel_begin = channel_end;
422339
channel_end = std::find_if(channel_begin, particles.end(),
423340
[ipmt](BCCache::particle const& p) { return p.hit_ch != ipmt; });
424341

342+
// The hits between 'channel_begin' and 'channel_end' now contains all hits for channel 'ipmt'
343+
425344
if (channel_end - channel_begin < params.mAmp_trsh) {
426345
continue;
427346
}
@@ -442,98 +361,31 @@ void Digitizer::storeBC(BCCache& bc,
442361
if (mCalibOffset) {
443362
miscalib = mCalibOffset->mTimeOffsets[ipmt];
444363
}
445-
int smeared_time = 1000. * (*cfd.particle - params.mCfdShift) * params.mChannelWidthInverse + miscalib;
364+
int smeared_time = 1000. * (*cfd.particle - params.mCfdShift) * params.mChannelWidthInverse + miscalib; // + int(1000. * mIntRecord.getTimeOffsetWrtBC() * params.mChannelWidthInverse);
446365
bool is_time_in_signal_gate = (smeared_time > -params.mTime_trg_gate && smeared_time < params.mTime_trg_gate);
447366
float charge = measure_amplitude(channel_times) * params.mCharge2amp;
448-
float amp = is_time_in_signal_gate ? params.mMV_2_Nchannels * charge : 0.f;
449-
if (amp > 4095.f) {
450-
amp = 4095.f;
367+
float amp = is_time_in_signal_gate ? params.mMV_2_Nchannels * charge : 0;
368+
if (amp > 4095) {
369+
amp = 4095;
451370
}
452-
// if (!disabledChannels.count(ipmt)) {
453-
// continue;
454-
// }
455-
456-
LOG(debug) << mEventID << " bc " << firstBCinDeque.bc << " orbit " << firstBCinDeque.orbit
457-
<< ", ipmt " << ipmt << ", smeared_time " << smeared_time
458-
<< " nStored " << nStored << " offset " << miscalib
459-
<< " base amp " << amp;
371+
// if (!disabledChannels.count(ipmt)) {
372+
// continue;
373+
// }
374+
375+
LOG(debug) << mEventID << " bc " << firstBCinDeque.bc << " orbit " << firstBCinDeque.orbit << ", ipmt " << ipmt << ", smeared_time " << smeared_time << " nStored " << nStored << " offset " << miscalib;
460376
if (is_time_in_signal_gate) {
461377
chain |= (1 << o2::ft0::ChannelData::EEventDataBit::kIsCFDinADCgate);
462378
chain |= (1 << o2::ft0::ChannelData::EEventDataBit::kIsEventInTVDC);
463-
}
464-
465-
baseAmp[ipmt] = amp;
466-
finalAmp[ipmt] = amp;
467-
chTime[ipmt] = smeared_time;
468-
chChain[ipmt] = chain;
469-
chValid[ipmt] = true;
470-
}
471-
472-
for (const auto& channels : pmtChannelGroups) {
473-
for (int localIdx = 0; localIdx < 4; ++localIdx) {
474-
const int src = channels[localIdx];
475-
if (!chValid[src] || baseAmp[src] <= 0.f) {
476-
continue;
477-
}
478-
479-
const int nb1 = channels[localNeighbours[localIdx][0]];
480-
const int nb2 = channels[localNeighbours[localIdx][1]];
481-
const int diag = channels[localNeighbours[localIdx][2]];
482-
483-
const float directXtalk = baseAmp[src] * params.Cross_Talk_Frac;
484-
const float diagXtalk = baseAmp[src] * (params.Cross_Talk_Frac / 3.f);
485-
486-
finalAmp[nb1] += directXtalk;
487-
finalAmp[nb2] += directXtalk;
488-
finalAmp[diag] += diagXtalk;
489-
490-
if (!chValid[nb1] && directXtalk >= params.mAmpThresholdForCrossTalkDigit) {
491-
chValid[nb1] = true;
492-
chTime[nb1] = chTime[src];
493-
chChain[nb1] = chChain[src];
494-
}
495-
496-
if (!chValid[nb2] && directXtalk >= params.mAmpThresholdForCrossTalkDigit) {
497-
chValid[nb2] = true;
498-
chTime[nb2] = chTime[src];
499-
chChain[nb2] = chChain[src];
500-
}
501-
502-
if (!chValid[diag] && diagXtalk >= params.mAmpThresholdForCrossTalkDigit) {
503-
chValid[diag] = true;
504-
chTime[diag] = chTime[src];
505-
chChain[diag] = chChain[src];
379+
// Sum channel charge per PM (similar logic as in digits2trgFT0)
380+
if (ipmt < o2::ft0::Constants::sNCHANNELS_PM) {
381+
mapPMhash2sumAmpl[pmLookupTable.getPMHash(static_cast<PMLookupTable::ChannelID>(ipmt))] += static_cast<int>(amp);
506382
}
507383
}
508-
}
509-
510-
for (Int_t ipmt = 0; ipmt < params.mMCPs; ++ipmt) {
511-
if (!chValid[ipmt]) {
512-
continue;
513-
}
514-
515-
float amp = finalAmp[ipmt];
516-
if (amp > 4095.f) {
517-
amp = 4095.f;
518-
}
519-
const bool hasPrimarySignal = (baseAmp[ipmt] > 0.f);
520-
const bool isCrossTalkOnly = (!hasPrimarySignal && amp > 0.f);
521-
522-
if (isCrossTalkOnly && amp < params.mAmpThresholdForCrossTalkDigit) {
523-
continue;
524-
}
525-
526-
const int smeared_time = chTime[ipmt];
527-
const int chain = chChain[ipmt];
528-
const bool is_time_in_signal_gate = (smeared_time > -params.mTime_trg_gate && smeared_time < params.mTime_trg_gate);
529-
530-
if (is_time_in_signal_gate && ipmt < o2::ft0::Constants::sNCHANNELS_PM) {
531-
mapPMhash2sumAmpl[mChID2PMhash[static_cast<uint8_t>(ipmt)]] += static_cast<int>(amp);
532-
}
533-
534384
digitsCh.emplace_back(ipmt, smeared_time, int(amp), chain);
535385
nStored++;
536386

387+
// fill triggers
388+
537389
Bool_t is_A_side = (ipmt < 4 * mGeometry.NCellsA);
538390
if (!is_time_in_signal_gate) {
539391
continue;
@@ -568,13 +420,10 @@ void Digitizer::storeBC(BCCache& bc,
568420
for (const auto& entry : mapPMhash2sumAmpl) {
569421
int pmAmpl = (entry.second >> 3);
570422
sum_PM_ampl_debug += pmAmpl;
571-
auto itSide = mMapPMhash2isAside.find(entry.first);
572-
if (itSide != mMapPMhash2isAside.end()) {
573-
if (itSide->second) {
574-
sum_PM_ampl_A_debug += pmAmpl;
575-
} else {
576-
sum_PM_ampl_C_debug += pmAmpl;
577-
}
423+
if (pmLookupTable.isASide(entry.first)) {
424+
sum_PM_ampl_A_debug += pmAmpl;
425+
} else {
426+
sum_PM_ampl_C_debug += pmAmpl;
578427
}
579428
}
580429
LOG(debug) << "Sum PM amplitude (LUT-based): total=" << sum_PM_ampl_debug

0 commit comments

Comments
 (0)