2020#include " FT0Base/Constants.h"
2121#include < map>
2222#include < array>
23+ #include < unordered_map>
2324#include < regex>
2425#include < string>
2526
@@ -376,19 +377,53 @@ void Digitizer::storeBC(BCCache& bc,
376377
377378 int vertex_time;
378379 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+
379403 int first = digitsCh.size (), nStored = 0 ;
380404 auto & particles = bc.hits ;
381405 std::sort (std::begin (particles), std::end (particles));
382406 auto channel_end = particles.begin ();
383407 std::vector<float > channel_times;
384- // 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
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 = {{
415+ {{1 , 2 , 3 }},
416+ {{0 , 3 , 2 }},
417+ {{0 , 3 , 1 }},
418+ {{1 , 2 , 0 }}
419+ }};
420+
421+ // 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
385422 for (Int_t ipmt = 0 ; ipmt < params.mMCPs ; ++ipmt) {
386423 auto channel_begin = channel_end;
387424 channel_end = std::find_if (channel_begin, particles.end (),
388425 [ipmt](BCCache::particle const & p) { return p.hit_ch != ipmt; });
389426
390- // The hits between 'channel_begin' and 'channel_end' now contains all hits for channel 'ipmt'
391-
392427 if (channel_end - channel_begin < params.mAmp_trsh ) {
393428 continue ;
394429 }
@@ -409,31 +444,86 @@ void Digitizer::storeBC(BCCache& bc,
409444 if (mCalibOffset ) {
410445 miscalib = mCalibOffset ->mTimeOffsets [ipmt];
411446 }
412- int smeared_time = 1000 . * (*cfd.particle - params.mCfdShift ) * params.mChannelWidthInverse + miscalib; // + int(1000. * mIntRecord.getTimeOffsetWrtBC() * params.mChannelWidthInverse);
447+ int smeared_time = 1000 . * (*cfd.particle - params.mCfdShift ) * params.mChannelWidthInverse + miscalib;
413448 bool is_time_in_signal_gate = (smeared_time > -params.mTime_trg_gate && smeared_time < params.mTime_trg_gate );
414449 float charge = measure_amplitude (channel_times) * params.mCharge2amp ;
415- float amp = is_time_in_signal_gate ? params.mMV_2_Nchannels * charge : 0 ;
416- if (amp > 4095 ) {
417- amp = 4095 ;
450+ float amp = is_time_in_signal_gate ? params.mMV_2_Nchannels * charge : 0 . f ;
451+ if (amp > 4095 . f ) {
452+ amp = 4095 . f ;
418453 }
419454// if (!disabledChannels.count(ipmt)) {
420455// continue;
421456// }
422457
423- LOG (debug) << mEventID << " bc " << firstBCinDeque.bc << " orbit " << firstBCinDeque.orbit << " , ipmt " << ipmt << " , smeared_time " << smeared_time << " nStored " << nStored << " offset " << miscalib;
458+ LOG (debug) << mEventID << " bc " << firstBCinDeque.bc << " orbit " << firstBCinDeque.orbit
459+ << " , ipmt " << ipmt << " , smeared_time " << smeared_time
460+ << " nStored " << nStored << " offset " << miscalib
461+ << " base amp " << amp;
424462 if (is_time_in_signal_gate) {
425463 chain |= (1 << o2::ft0::ChannelData::EEventDataBit::kIsCFDinADCgate );
426464 chain |= (1 << o2::ft0::ChannelData::EEventDataBit::kIsEventInTVDC );
427- // Sum channel charge per PM (similar logic as in digits2trgFT0)
428- if (ipmt < o2::ft0::Constants::sNCHANNELS_PM ) {
429- mapPMhash2sumAmpl[mChID2PMhash [static_cast <uint8_t >(ipmt)]] += static_cast <int >(amp);
465+ }
466+
467+ baseAmp[ipmt] = amp;
468+ finalAmp[ipmt] = amp;
469+ chTime[ipmt] = smeared_time;
470+ chChain[ipmt] = chain;
471+ chValid[ipmt] = true ;
472+ }
473+
474+ for (const auto & channels : pmtChannelGroups) {
475+ for (int localIdx = 0 ; localIdx < 4 ; ++localIdx) {
476+ const int src = channels[localIdx];
477+ if (!chValid[src] || baseAmp[src] <= 0 .f ) {
478+ continue ;
430479 }
480+
481+ const int nb1 = channels[localNeighbours[localIdx][0 ]];
482+ const int nb2 = channels[localNeighbours[localIdx][1 ]];
483+ const int diag = channels[localNeighbours[localIdx][2 ]];
484+
485+ const float directXtalk = baseAmp[src] * params.Cross_Talk_Frac ;
486+ const float diagXtalk = baseAmp[src] * (params.Cross_Talk_Frac / 3 .f );
487+
488+ finalAmp[nb1] += directXtalk;
489+ finalAmp[nb2] += directXtalk;
490+ finalAmp[diag] += diagXtalk;
491+
492+ auto propagateIfEmpty = [&](int dst) {
493+ if (!chValid[dst]) {
494+ chValid[dst] = true ;
495+ chTime[dst] = chTime[src];
496+ chChain[dst] = chChain[src];
497+ }
498+ };
499+
500+ propagateIfEmpty (nb1);
501+ propagateIfEmpty (nb2);
502+ propagateIfEmpty (diag);
503+ }
504+ }
505+
506+ for (Int_t ipmt = 0 ; ipmt < params.mMCPs ; ++ipmt) {
507+ if (!chValid[ipmt]) {
508+ continue ;
431509 }
510+
511+ float amp = finalAmp[ipmt];
512+ if (amp > 4095 .f ) {
513+ amp = 4095 .f ;
514+ }
515+
516+ const int smeared_time = chTime[ipmt];
517+ const int chain = chChain[ipmt];
518+ const bool is_time_in_signal_gate = (smeared_time > -params.mTime_trg_gate && smeared_time < params.mTime_trg_gate );
519+
520+ if (is_time_in_signal_gate && ipmt < o2::ft0::Constants::sNCHANNELS_PM ) {
521+ mapPMhash2sumAmpl[mChID2PMhash [static_cast <uint8_t >(ipmt)]] += static_cast <int >(amp);
522+ }
523+
432524 digitsCh.emplace_back (ipmt, smeared_time, int (amp), chain);
433525 nStored++;
434526
435- // fill triggers
436-
437527 Bool_t is_A_side = (ipmt < 4 * mGeometry .NCellsA );
438528 if (!is_time_in_signal_gate) {
439529 continue ;
0 commit comments