Skip to content

Commit aa5d3c6

Browse files
spulawskSzymon Pulawski
andauthored
FT0: update Digitizer signal shape and trigger logic; FV0: update trigger logic in digitizer (#15209)
* FT0: tune signal shape and trigger tunning for MC * apply clang-format * Update FV0 trigger settings and digitizer logic * FV0: update Digitizer trigger handling * Update parameter comments and default settings for Run 3 * Clang formating * Default trigger settings set for pp. PbPb will be sent via parameters * Default trigger settings set for pp. PbPb will be sent via parameters --------- Co-authored-by: Szymon Pulawski <spulawsk@h010.nuph.us.edu.pl>
1 parent d87ad11 commit aa5d3c6

File tree

4 files changed

+203
-33
lines changed

4 files changed

+203
-33
lines changed

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

Lines changed: 5 additions & 4 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 = 40; // Tclu units (40 for pp and 1433 for PbPb in Run3)
35+
int mtrg_semicentral_trh = 20; // Tclu units (20 for pp and 35 for PbPb in Run3)
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,11 +43,12 @@ 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

49-
float mMV_2_Nchannels = 2.2857143; // amplitude channel 7 mV ->16channels
50-
float mMV_2_NchannelsInverse = 0.437499997; // inverse amplitude channel 7 mV ->16channels
50+
float mMV_2_Nchannels = 2.; // amplitude channel 7 mV ->14channels
51+
float mMV_2_NchannelsInverse = 0.5; // inverse amplitude channel 7 mV ->14channels (nowhere used)
5152

5253
O2ParamDef(FT0DigParam, "FT0DigParam");
5354
};

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

Lines changed: 172 additions & 13 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>
@@ -35,24 +42,84 @@ namespace o2::ft0
3542
template <typename Float>
3643
Float signalForm_i(Float x)
3744
{
38-
using namespace std;
39-
Float const a = -0.45458;
40-
Float const b = -0.83344945;
41-
return x > Float(0) ? -(exp(b * x) - exp(a * x)) / Float(7.8446501) : Float(0);
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;
4270
};
4371

4472
// integrated signal shape function
4573
inline float signalForm_integral(float x)
4674
{
47-
using namespace std;
48-
double const a = -0.45458;
49-
double const b = -0.83344945;
50-
if (x < 0) {
51-
x = 0;
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
5290
}
53-
return -(exp(b * x) / b - exp(a * x) / a) / 7.8446501;
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)
104+
{
105+
using namespace std;
106+
Float const a = -0.45458;
107+
Float const b = -0.83344945;
108+
return x > Float(0) ? -(exp(b * x) - exp(a * x)) / Float(7.8446501) : Float(0);
54109
};
55110
111+
// integrated signal shape function
112+
inline float signalForm_integral(float x)
113+
{
114+
using namespace std;
115+
double const a = -0.45458;
116+
double const b = -0.83344945;
117+
if (x < 0) {
118+
x = 0;
119+
}
120+
return -(exp(b * x) / b - exp(a * x) / a) / 7.8446501;
121+
};
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,47 @@ 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+
321480
Bool_t is_A, is_C, isVertex, is_Central, is_SemiCentral = 0;
322481
is_A = n_hit_A > 0;
323482
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;
483+
is_Central = sum_PM_ampl_A_debug + sum_PM_ampl_C_debug >= 2 * params.mtrg_central_trh;
484+
is_SemiCentral = sum_PM_ampl_A_debug + sum_PM_ampl_C_debug >= 2 * params.mtrg_semicentral_trh && !is_Central;
326485
uint32_t amplA = is_A ? summ_ampl_A * 0.125 : -5000; // sum amplitude A side / 8 (hardware)
327486
uint32_t amplC = is_C ? summ_ampl_C * 0.125 : -5000; // sum amplitude C side / 8 (hardware)
328487
int timeA = is_A ? mean_time_A / n_hit_A : -5000; // average time A side
329488
int timeC = is_C ? mean_time_C / n_hit_C : -5000; // average time C side
330489
vertex_time = (timeC - timeA) * 0.5;
331-
isVertex = is_A && is_C && (vertex_time > -params.mTime_trg_gate && vertex_time < params.mTime_trg_gate);
490+
isVertex = is_A && is_C && (vertex_time > -params.mTime_trg_vertex_gate && vertex_time < params.mTime_trg_vertex_gate);
332491
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;
333492
Triggers triggers;
334493
bool isLaser = false;

Detectors/FIT/FV0/simulation/include/FV0Simulation/FV0DigParam.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ struct FV0DigParam : o2::conf::ConfigurableParamHelper<FV0DigParam> {
6969
uint8_t defaultChainQtc = 0x48; // only 2 flags are set by default in simulation: kIsCFDinADCgate and kIsEventInTVDC
7070
float mAmpThresholdForReco = 24; // only channels with amplitude higher will participate in calibration and collision time
7171
short mTimeThresholdForReco = 1000; // only channels with time below will participate in calibration and collision time
72+
int NchannelsLevel = 2; // trigger Nchannels
73+
float InnerChargeLevel = 4; // InnerRingsChargeLevel
74+
float OuterChargeLevel = 4; // OuterRingsChargeLevel
75+
float ChargeLevel = 8; // ChargeLevel
7276

7377
O2ParamDef(FV0DigParam, "FV0DigParam");
7478
};

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

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ void Digitizer::clear()
3838
void Digitizer::init()
3939
{
4040
LOG(info) << "init";
41-
mNBins = FV0DigParam::Instance().waveformNbins; //Will be computed using detector set-up from CDB
42-
mBinSize = FV0DigParam::Instance().waveformBinWidth; //Will be set-up from CDB
41+
mNBins = FV0DigParam::Instance().waveformNbins; // Will be computed using detector set-up from CDB
42+
mBinSize = FV0DigParam::Instance().waveformBinWidth; // Will be set-up from CDB
4343
mNTimeBinsPerBC = std::lround(o2::constants::lhc::LHCBunchSpacingNS / mBinSize); // 1920 bins/BC
4444

4545
for (Int_t detID = 0; detID < Constants::nFv0Channels; detID++) {
@@ -149,8 +149,8 @@ void Digitizer::process(const std::vector<o2::fv0::Hit>& hits,
149149

150150
createPulse(mipFraction, hit.GetTrackID(), hitTime, hit.GetPos().R(), cachedIR, nCachedIR, detId);
151151

152-
} //while loop
153-
} //hitloop
152+
} // while loop
153+
} // hitloop
154154
}
155155

156156
void Digitizer::createPulse(float mipFraction, int parID, const double hitTime, const float hitR,
@@ -200,7 +200,7 @@ void Digitizer::createPulse(float mipFraction, int parID, const double hitTime,
200200
}
201201
added[ir] = true;
202202
}
203-
///Add MC labels to BCs for those contributed to the PMT signal
203+
/// Add MC labels to BCs for those contributed to the PMT signal
204204
for (int ir = 0; ir < nCachedIR; ir++) {
205205
if (added[ir]) {
206206
auto bcCache = getBCCache(cachedIR[ir]);
@@ -238,6 +238,8 @@ void Digitizer::storeBC(const BCCache& bc,
238238
int8_t nTotFiredCells = 0;
239239
int8_t nTrgFiredCells = 0; // number of fired cells, that follow additional trigger conditions (time gate)
240240
int totalChargeAllRing = 0;
241+
int totalChargeInnerRing = 0;
242+
int totalChargeOuterRing = 0;
241243
int32_t avgTime = 0;
242244
double nSignalInner = 0;
243245
double nSignalOuter = 0;
@@ -285,8 +287,10 @@ void Digitizer::storeBC(const BCCache& bc,
285287
avgTime += iCfdZero;
286288
if (iPmt < 24) {
287289
nSignalInner++;
290+
totalChargeInnerRing += iTotalCharge;
288291
} else {
289292
nSignalOuter++;
293+
totalChargeOuterRing += iTotalCharge;
290294
}
291295
}
292296
}
@@ -300,24 +304,26 @@ void Digitizer::storeBC(const BCCache& bc,
300304
} else {
301305
avgTime = o2::fit::Triggers::DEFAULT_TIME;
302306
}
303-
///Triggers for FV0
304-
bool isA, isAIn, isAOut, isCen, isSCen;
307+
/// Triggers for FV0
308+
bool isA, isNchannels, isAIn, isAOut, isTotalCharge;
305309
isA = nTrgFiredCells > 0;
306-
isAIn = nSignalInner > 0; // ring 1,2 and 3
307-
isAOut = nSignalOuter > 0; // ring 4 and 5
308-
isCen = totalChargeAllRing > FV0DigParam::Instance().adcChargeCenThr;
309-
isSCen = totalChargeAllRing > FV0DigParam::Instance().adcChargeSCenThr;
310+
isNchannels = nTrgFiredCells > FV0DigParam::Instance().NchannelsLevel;
311+
// isAIn = nSignalInner > FV0DigParam::Instance().NchannelsLevel; // ring 1,2 and 3
312+
isAIn = 0.125 * totalChargeInnerRing > 2 * FV0DigParam::Instance().InnerChargeLevel; // ring 1,2 and 3
313+
// isAOut = nSignalOuter > FV0DigParam::Instance().NchannelsLevel; // ring 4 and 5
314+
isAOut = 0.125 * totalChargeOuterRing > 2 * FV0DigParam::Instance().OuterChargeLevel; // ring 4 and 5
315+
isTotalCharge = 0.125 * totalChargeAllRing > 2 * FV0DigParam::Instance().ChargeLevel;
310316

311317
Triggers triggers;
312318
const int unusedCharge = o2::fit::Triggers::DEFAULT_AMP;
313319
const int unusedTime = o2::fit::Triggers::DEFAULT_TIME;
314320
const int unusedZero = o2::fit::Triggers::DEFAULT_ZERO;
315321
const bool unusedBitsInSim = false; // bits related to laser and data validity
316322
const bool bitDataIsValid = true;
317-
triggers.setTriggers(isA, isAIn, isAOut, isCen, isSCen, nTrgFiredCells, (int8_t)unusedZero,
323+
triggers.setTriggers(isA, isAIn, isAOut, isTotalCharge, isNchannels, nTrgFiredCells, (int8_t)unusedZero,
318324
(int32_t)(0.125 * totalChargeAllRing), (int32_t)unusedCharge, (int16_t)avgTime, (int16_t)unusedTime, unusedBitsInSim, unusedBitsInSim, bitDataIsValid);
319325
digitsBC.emplace_back(first, nTotFiredCells, bc, triggers, mEventId - 1);
320-
digitsTrig.emplace_back(bc, isA, isAIn, isAOut, isCen, isSCen);
326+
digitsTrig.emplace_back(bc, isA, isAIn, isAOut, isTotalCharge, isNchannels);
321327
for (auto const& lbl : bc.labels) {
322328
labels.addElement(nBC, lbl);
323329
}
@@ -342,8 +348,8 @@ Int_t Digitizer::SimulateLightYield(Int_t pmt, Int_t nPhot) const
342348
//---------------------------------------------------------------------------
343349
Float_t Digitizer::IntegrateCharge(const ChannelDigitF& pulse) const
344350
{
345-
int const chargeIntMin = FV0DigParam::Instance().isIntegrateFull ? 0 : (FV0DigParam::Instance().avgCfdTimeForMip - 6.0) / mBinSize; //Charge integration offset (cfd mean time - 6 ns)
346-
int const chargeIntMax = FV0DigParam::Instance().isIntegrateFull ? mNTimeBinsPerBC : (FV0DigParam::Instance().avgCfdTimeForMip + 14.0) / mBinSize; //Charge integration offset (cfd mean time + 14 ns)
351+
int const chargeIntMin = FV0DigParam::Instance().isIntegrateFull ? 0 : (FV0DigParam::Instance().avgCfdTimeForMip - 6.0) / mBinSize; // Charge integration offset (cfd mean time - 6 ns)
352+
int const chargeIntMax = FV0DigParam::Instance().isIntegrateFull ? mNTimeBinsPerBC : (FV0DigParam::Instance().avgCfdTimeForMip + 14.0) / mBinSize; // Charge integration offset (cfd mean time + 14 ns)
347353
if (chargeIntMin < 0 || chargeIntMin > mNTimeBinsPerBC || chargeIntMax > mNTimeBinsPerBC) {
348354
LOG(fatal) << "invalid indicess: chargeInMin=" << chargeIntMin << " chargeIntMax=" << chargeIntMax;
349355
}
@@ -400,7 +406,7 @@ float Digitizer::getDistFromCellCenter(UInt_t cellId, double hitx, double hity)
400406
double a = -(y0 - pCell->y) / (x0 - pCell->x);
401407
double b = 1;
402408
double c = -(y0 - a * x0);
403-
//Return the distance from hit to this line
409+
// Return the distance from hit to this line
404410
return (a * hitx + b * hity + c) / TMath::Sqrt(a * a + b * b);
405411
}
406412

0 commit comments

Comments
 (0)