Skip to content

Commit 6577bc3

Browse files
author
Szymon Pulawski
committed
FT0: tune signal shape and trigger tunning for MC
1 parent cfb2c3a commit 6577bc3

File tree

2 files changed

+167
-6
lines changed

2 files changed

+167
-6
lines changed

Detectors/FIT/FT0/base/include/FT0Base/FT0DigParam.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ struct FT0DigParam : o2::conf::ConfigurableParamHelper<FT0DigParam> {
3131
float mAmpRecordUp = 15; // to [ns]
3232
float hitTimeOffsetA = 0; ///< hit time offset on the A side [ns]
3333
float hitTimeOffsetC = 0; ///< hit time offset on the C side [ns]
34-
int mtrg_central_trh = 600.; // channels
35-
int mtrg_semicentral_trh = 300.; // channels
34+
int mtrg_central_trh = 1433.; // Tclu
35+
int mtrg_semicentral_trh = 35.; // Tclu units = TCM charge level unit = 16 ADCunits
3636

3737
float mMip_in_V = 7; // MIP to mV
3838
float mPe_in_mip = 0.004; // invserse Np.e. in MIP 1./250.
@@ -43,6 +43,7 @@ struct FT0DigParam : o2::conf::ConfigurableParamHelper<FT0DigParam> {
4343
float mNoiseVar = 0.1; // noise level
4444
float mNoisePeriod = 1 / 0.9; // GHz low frequency noise period;
4545
short mTime_trg_gate = 153; // #channels as in TCM as in Pilot beams ('OR gate' setting in TCM tab in ControlServer)
46+
short mTime_trg_vertex_gate = 100; // #channels as in TCM as in Pilot beams ('OR gate' setting in TCM tab in ControlServer)
4647
float mAmpThresholdForReco = 5; // only channels with amplitude higher will participate in calibration and collision time: 0.3 MIP
4748
short mTimeThresholdForReco = 1000; // only channels with time below will participate in calibration and collision time
4849

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

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

19+
#include "DataFormatsFT0/LookUpTable.h"
20+
#include "FT0Base/Constants.h"
21+
#include <map>
22+
#include <array>
23+
#include <regex>
24+
#include <string>
25+
1926
#include "TMath.h"
2027
#include "TRandom.h"
2128
#include <TH1F.h>
@@ -34,6 +41,66 @@ namespace o2::ft0
3441
// signal shape function
3542
template <typename Float>
3643
Float signalForm_i(Float x)
44+
{
45+
float p0, p1, p2, p3, p4, p5, p6, p7;
46+
p0 = 1.30853;
47+
p1 = 0.516807;
48+
p2 = 3.36714;
49+
p3 = -1.01206;
50+
p4 = 1.42832;
51+
p5 = 1.1589;
52+
p6 = 1.22019;
53+
p7 = 0.426818;
54+
55+
Double_t val = 0;
56+
57+
if (x > p3) {
58+
Double_t x1 = x - p3;
59+
Double_t arg1 = (log(x1) - p0) / p1;
60+
val += p2 * (1.0 / (x1 * p1 * sqrt(2 * TMath::Pi()))) * exp(-0.5 * arg1 * arg1);
61+
}
62+
63+
if (x > p7) {
64+
Double_t x2 = x - p7;
65+
Double_t arg2 = (log(x2) - p4) / p5;
66+
val += p6 * (1.0 / (x2 * p5 * sqrt(2 * TMath::Pi()))) * exp(-0.5 * arg2 * arg2);
67+
}
68+
69+
return val;
70+
};
71+
72+
// integrated signal shape function
73+
inline float signalForm_integral(float x)
74+
{
75+
float p0, p1, p2, p3, p4, p5, p6, p7;
76+
p0 = 1.30853;
77+
p1 = 0.516807;
78+
p2 = 3.36714;
79+
p3 = -1.01206;
80+
p4 = 1.42832;
81+
p5 = 1.1589;
82+
p6 = 1.22019;
83+
p7 = 0.426818;
84+
Double_t val = 0;
85+
86+
if (x > p3) {
87+
Double_t x1 = x - p3;
88+
Double_t z1 = (log(x1) - p0) / (sqrt(2) * p1);
89+
val += p2 * 0.5 * (1 + TMath::Erf(z1)); // norm1 * CDF1
90+
}
91+
92+
if (x > p7) {
93+
Double_t x2 = x - p7;
94+
Double_t z2 = (log(x2) - p4) / (sqrt(2) * p5);
95+
val += p6 * 0.5 * (1 + TMath::Erf(z2)); // norm2 * CDF2
96+
}
97+
98+
return val;
99+
};
100+
/*
101+
// signal shape function
102+
template <typename Float>
103+
Float signalForm_i(Float x)
37104
{
38105
using namespace std;
39106
Float const a = -0.45458;
@@ -52,7 +119,7 @@ inline float signalForm_integral(float x)
52119
}
53120
return -(exp(b * x) / b - exp(a * x) / a) / 7.8446501;
54121
};
55-
122+
*/
56123
// SIMD version of the integrated signal shape function
57124
inline Vc::float_v signalForm_integralVc(Vc::float_v x)
58125
{
@@ -249,8 +316,64 @@ void Digitizer::storeBC(BCCache& bc,
249316
if (bc.hits.empty()) {
250317
return;
251318
}
319+
// Initialize mapping channelID -> PM hash and PM side (A/C) using FT0 LUT
320+
static bool pmLutInitialized = false;
321+
static std::array<uint8_t, o2::ft0::Constants::sNCHANNELS_PM> mChID2PMhash{};
322+
static std::map<uint8_t, bool> mMapPMhash2isAside; // hashed PM -> is A side
323+
324+
if (!pmLutInitialized) {
325+
std::map<std::string, uint8_t> mapFEE2hash; // module name -> hashed PM id
326+
uint8_t tcmHash = 0;
327+
328+
const auto& lut = o2::ft0::SingleLUT::Instance().getVecMetadataFEE();
329+
auto lutSorted = lut;
330+
std::sort(lutSorted.begin(), lutSorted.end(),
331+
[](const auto& first, const auto& second) { return first.mModuleName < second.mModuleName; });
332+
333+
uint8_t binPos = 0;
334+
for (const auto& lutEntry : lutSorted) {
335+
const auto& moduleName = lutEntry.mModuleName;
336+
const auto& moduleType = lutEntry.mModuleType;
337+
const auto& strChID = lutEntry.mChannelID;
338+
339+
auto [it, inserted] = mapFEE2hash.insert({moduleName, binPos});
340+
if (inserted) {
341+
if (moduleName.find("PMA") != std::string::npos) {
342+
mMapPMhash2isAside.insert({binPos, true});
343+
} else if (moduleName.find("PMC") != std::string::npos) {
344+
mMapPMhash2isAside.insert({binPos, false});
345+
}
346+
++binPos;
347+
}
348+
349+
if (std::regex_match(strChID, std::regex("^[0-9]{1,3}$"))) {
350+
int chID = std::stoi(strChID);
351+
if (chID < o2::ft0::Constants::sNCHANNELS_PM) {
352+
mChID2PMhash[chID] = mapFEE2hash[moduleName];
353+
} else {
354+
LOG(fatal) << "Incorrect LUT entry: chID " << strChID << " | " << moduleName;
355+
}
356+
} else if (moduleType != "TCM") {
357+
LOG(fatal) << "Non-TCM module w/o numerical chID: chID " << strChID << " | " << moduleName;
358+
} else { // TCM
359+
tcmHash = mapFEE2hash[moduleName];
360+
}
361+
}
362+
363+
pmLutInitialized = true;
364+
}
365+
252366
int n_hit_A = 0, n_hit_C = 0, mean_time_A = 0, mean_time_C = 0;
253367
int summ_ampl_A = 0, summ_ampl_C = 0;
368+
int sum_A_ampl = 0, sum_C_ampl = 0;
369+
int nPMTs = mGeometry.NCellsA * 4 + mGeometry.NCellsC * 4;
370+
std::vector<int> sum_ampl_ipmt(nPMTs, 0);
371+
// Per-PM summed charge (like in digits2trgFT0)
372+
std::map<uint8_t, int> mapPMhash2sumAmpl;
373+
for (const auto& entry : mMapPMhash2isAside) {
374+
mapPMhash2sumAmpl.insert({entry.first, 0});
375+
}
376+
254377
int vertex_time;
255378
const auto& params = FT0DigParam::Instance();
256379
int first = digitsCh.size(), nStored = 0;
@@ -297,6 +420,10 @@ void Digitizer::storeBC(BCCache& bc,
297420
if (is_time_in_signal_gate) {
298421
chain |= (1 << o2::ft0::ChannelData::EEventDataBit::kIsCFDinADCgate);
299422
chain |= (1 << o2::ft0::ChannelData::EEventDataBit::kIsEventInTVDC);
423+
// Sum channel charge per PM (similar logic as in digits2trgFT0)
424+
if (ipmt < o2::ft0::Constants::sNCHANNELS_PM) {
425+
mapPMhash2sumAmpl[mChID2PMhash[static_cast<uint8_t>(ipmt)]] += static_cast<int>(amp);
426+
}
300427
}
301428
digitsCh.emplace_back(ipmt, smeared_time, int(amp), chain);
302429
nStored++;
@@ -308,6 +435,8 @@ void Digitizer::storeBC(BCCache& bc,
308435
continue;
309436
}
310437

438+
sum_ampl_ipmt[ipmt] += amp;
439+
311440
if (is_A_side) {
312441
n_hit_A++;
313442
summ_ampl_A += amp;
@@ -318,17 +447,48 @@ void Digitizer::storeBC(BCCache& bc,
318447
mean_time_C += smeared_time;
319448
}
320449
}
450+
451+
for (size_t i = 0; i < sum_ampl_ipmt.size(); i++) {
452+
sum_ampl_ipmt[i] = sum_ampl_ipmt[i] >> 3;
453+
if (i < 4 * mGeometry.NCellsA) {
454+
sum_A_ampl += sum_ampl_ipmt[i];
455+
} else {
456+
sum_C_ampl += sum_ampl_ipmt[i];
457+
}
458+
}
459+
460+
// Sum over PMs (using per-PM map) for debug/monitoring
461+
int sum_PM_ampl_debug = 0;
462+
int sum_PM_ampl_A_debug = 0;
463+
int sum_PM_ampl_C_debug = 0;
464+
for (const auto& entry : mapPMhash2sumAmpl) {
465+
int pmAmpl = (entry.second >> 3);
466+
sum_PM_ampl_debug += pmAmpl;
467+
auto itSide = mMapPMhash2isAside.find(entry.first);
468+
if (itSide != mMapPMhash2isAside.end()) {
469+
if (itSide->second) {
470+
sum_PM_ampl_A_debug += pmAmpl;
471+
} else {
472+
sum_PM_ampl_C_debug += pmAmpl;
473+
}
474+
}
475+
}
476+
LOG(debug) << "Sum PM amplitude (LUT-based): total=" << sum_PM_ampl_debug
477+
<< " A-side=" << sum_PM_ampl_A_debug
478+
<< " C-side=" << sum_PM_ampl_C_debug;
479+
480+
321481
Bool_t is_A, is_C, isVertex, is_Central, is_SemiCentral = 0;
322482
is_A = n_hit_A > 0;
323483
is_C = n_hit_C > 0;
324-
is_Central = summ_ampl_A + summ_ampl_C >= params.mtrg_central_trh;
325-
is_SemiCentral = summ_ampl_A + summ_ampl_C >= params.mtrg_semicentral_trh;
484+
is_Central = sum_PM_ampl_A_debug + sum_PM_ampl_C_debug >= 2*params.mtrg_central_trh;
485+
is_SemiCentral = sum_PM_ampl_A_debug + sum_PM_ampl_C_debug >= 2*params.mtrg_semicentral_trh && !is_Central;
326486
uint32_t amplA = is_A ? summ_ampl_A * 0.125 : -5000; // sum amplitude A side / 8 (hardware)
327487
uint32_t amplC = is_C ? summ_ampl_C * 0.125 : -5000; // sum amplitude C side / 8 (hardware)
328488
int timeA = is_A ? mean_time_A / n_hit_A : -5000; // average time A side
329489
int timeC = is_C ? mean_time_C / n_hit_C : -5000; // average time C side
330490
vertex_time = (timeC - timeA) * 0.5;
331-
isVertex = is_A && is_C && (vertex_time > -params.mTime_trg_gate && vertex_time < params.mTime_trg_gate);
491+
isVertex = is_A && is_C && (vertex_time > -params.mTime_trg_vertex_gate && vertex_time < params.mTime_trg_vertex_gate);
332492
LOG(debug) << " A " << is_A << " timeA " << timeA << " mean_time_A " << mean_time_A << " n_hit_A " << n_hit_A << " C " << is_C << " timeC " << timeC << " mean_time_C " << mean_time_C << " n_hit_C " << n_hit_C << " vertex_time " << vertex_time;
333493
Triggers triggers;
334494
bool isLaser = false;

0 commit comments

Comments
 (0)