Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:16:17

0001 #include "SingleTriggeredInput.h"
0002 #include "SingleGl1TriggeredInput.h"
0003 
0004 #include <frog/FROG.h>
0005 
0006 #include <ffarawobjects/CaloPacketContainerv1.h>
0007 #include <ffarawobjects/CaloPacketv1.h>
0008 
0009 #include <fun4all/Fun4AllReturnCodes.h>
0010 
0011 #include <phool/PHCompositeNode.h>
0012 #include <phool/PHIODataNode.h>    // for PHIODataNode
0013 #include <phool/PHNode.h>          // for PHNode
0014 #include <phool/PHNodeIterator.h>  // for PHNodeIterator
0015 #include <phool/PHObject.h>        // for PHObject
0016 #include <phool/getClass.h>
0017 #include <phool/phool.h>
0018 
0019 #include <TSystem.h>
0020 
0021 #include <cstdint>   // for uint64_t
0022 #include <iostream>  // for operator<<, basic_ostream, endl
0023 #include <ranges>
0024 #include <set>
0025 #include <unordered_set>
0026 #include <utility>  // for pair
0027 #include <vector>
0028 
0029 SingleTriggeredInput::SingleTriggeredInput(const std::string &name)
0030   : Fun4AllBase(name)
0031 {
0032   m_bclkarray.fill(std::numeric_limits<uint64_t>::max());
0033   m_bclkdiffarray.fill(std::numeric_limits<uint64_t>::max());
0034 }
0035 
0036 SingleTriggeredInput::~SingleTriggeredInput()
0037 {
0038   for (auto& [pid, dq] : m_PacketEventDeque)
0039   {
0040     while (!dq.empty())
0041     {
0042       delete dq.front();
0043       dq.pop_front();
0044     }
0045   }
0046 
0047   for (auto& [pid, evt] : m_PacketEventBackup)
0048   {
0049     delete evt;
0050   }
0051 
0052   delete m_EventIterator;
0053 }
0054 
0055 bool SingleTriggeredInput::CheckFemDiffIdx(int pid, size_t index, const std::deque<Event*>& events, uint64_t gl1diffidx)
0056 {
0057   if (index >= events.size())
0058   {
0059     return false;
0060   }
0061 
0062   Packet* pkt_prev = events[index-1]->getPacket(pid);
0063   Packet* pkt_curr = events[index]->getPacket(pid);
0064   if (!pkt_prev || !pkt_curr)
0065   {
0066     delete pkt_prev;
0067     delete pkt_curr;
0068     return false;
0069   }
0070 
0071   auto get_majority_femclk = [](Packet* pkt) -> uint16_t {
0072     int nmod = pkt->iValue(0, "NRMODULES");
0073     std::map<uint16_t, int> counts;
0074     for (int j = 0; j < nmod; ++j)
0075     {
0076       uint16_t clk = static_cast<uint16_t>(pkt->iValue(j, "FEMCLOCK"));
0077       counts[clk]++;
0078     }
0079     if (counts.empty())
0080     {
0081       return std::numeric_limits<uint16_t>::max();
0082     }
0083     return std::max_element(counts.begin(), counts.end(), [](const auto& a, const auto& b) { return a.second < b.second; })->first;
0084   };
0085 
0086   uint16_t clk_prev = get_majority_femclk(pkt_prev);
0087   uint16_t clk_curr = get_majority_femclk(pkt_curr);
0088 
0089   delete pkt_prev;
0090   delete pkt_curr;
0091 
0092   if (clk_prev == std::numeric_limits<uint16_t>::max() || clk_curr == std::numeric_limits<uint16_t>::max())
0093   {
0094     return false;
0095   }
0096 
0097   uint16_t femdiff = static_cast<uint16_t>(clk_curr - clk_prev);
0098   gl1diffidx = static_cast<uint16_t>(gl1diffidx & 0xFFFFU);
0099   return (femdiff == gl1diffidx);
0100 }
0101 
0102 bool SingleTriggeredInput::CheckPoolAlignment(int pid, const std::array<uint64_t, pooldepth>& sebdiff, const std::array<uint64_t, pooldepth>& gl1diff, std::vector<int>& bad_indices, int& shift, bool& CurrentPoolLastDiffBad, bool PrevPoolLastDiffBad)
0103 {
0104   bad_indices.clear();
0105   shift = 0;
0106   CurrentPoolLastDiffBad=false;
0107 
0108   if (std::equal(sebdiff.begin(), sebdiff.end(), gl1diff.begin()))
0109   {
0110     return true;
0111   }
0112 
0113   //Finding intermittent corrupted data
0114   size_t n = sebdiff.size();
0115   std::vector<int> bad_diff_indices;
0116   for (size_t i = 0; i < n; ++i)
0117   {
0118     if ( sebdiff[i] != gl1diff[i] )
0119     {
0120       if ( !m_packetclk_copy_runs )
0121       {
0122         //backup procedure to recover stuck 16bit XMIT clock
0123         size_t idxcheck =  i == 0  ? i+1 : i;
0124         bool passFemDiffCheckIdx = CheckFemDiffIdx(pid, idxcheck, m_PacketEventDeque[pid], gl1diff[idxcheck]);
0125         if ( passFemDiffCheckIdx )
0126         {
0127           m_OverrideWithRepClock.insert(pid);
0128           continue;
0129         }
0130       } 
0131       bad_diff_indices.push_back(i);
0132     }
0133   }
0134 
0135   if (bad_diff_indices.empty())
0136   {
0137     if ( Verbosity() > 0 )
0138     {
0139       std::cout << Name() << " recovered from bad XMIT clocks. Merging pool" << std::endl;
0140     }
0141     return true;
0142   }
0143 
0144   bool move_to_shift_algo = false;
0145   if(bad_diff_indices.size() >=5)
0146   {
0147     std::cout << std::endl;
0148     std::cout << "----------------- " << Name() << " -----------------" << std::endl;
0149     std::cout << "More than 5 diffs are bad.. try shifting algorithm" << std::endl;
0150     move_to_shift_algo = true;
0151   }
0152   if(!move_to_shift_algo)
0153   {
0154     std::cout << std::endl;
0155     std::cout << "----------------- " << Name() << " -----------------" << std::endl;
0156   }
0157 
0158   size_t idx = 0;
0159   while (idx < bad_diff_indices.size() && !move_to_shift_algo)
0160   {
0161     int start = bad_diff_indices[idx];
0162     int end = start;
0163     while ((idx+1) < bad_diff_indices.size() && bad_diff_indices[idx+1] == end + 1)
0164     {
0165       ++idx;
0166       ++end;
0167     }
0168 
0169     int length = end - start + 1;
0170     if(length<=0)
0171     {
0172       std::cout << Name() << ": length of bad diffs is <=0. This should not happen... something very wrong. rejecting the pool" << std::endl;
0173       return false;
0174     }
0175     if(length>=5)
0176     {
0177       std::cout << Name() << ": length of bad diffs >=5 with bad_diff_indices.size() " << bad_diff_indices.size() << ". This should not have happened.. rejecting pool" << std::endl;
0178       return false;
0179     }
0180 
0181     if(start==static_cast<int>(pooldepth - 1))
0182     {
0183       bad_indices.push_back(start);
0184       CurrentPoolLastDiffBad= true;
0185     }
0186     else if (start==0)
0187     {
0188       if (PrevPoolLastDiffBad)
0189       {
0190         for (int j = start; j < end; ++j)
0191         {
0192           bad_indices.push_back(j);
0193         }
0194       }
0195       else
0196       {
0197         if (length == 1)
0198         {
0199           std::cout << Name() << ": diff[0] alone bad. isolated bad diff which should not happen.. rejecting pool" << std::endl;
0200           return false;
0201         }
0202         for (int j = start; j < end; ++j)
0203         {
0204           bad_indices.push_back(j);
0205         }
0206       }
0207     }
0208     else if (start < static_cast<int>(pooldepth - 1) && start >0)
0209     {
0210       if(length==1)
0211       {
0212         std::cout << Name() << ": Isolated bad diff[" << start << "] - rejecting pool" << std::endl;
0213         return false;
0214       }
0215       if(length>=2)
0216       {
0217         for (int j = start; j < end; ++j)
0218         {
0219           bad_indices.push_back(j);
0220         }
0221       }
0222     }
0223     else
0224     {
0225       std::cout << Name() << ": no categories assigned for length " << length << " and start / end " << start << " / " << end << " rejecting pool" << std::endl; 
0226       return false;
0227     }
0228     ++idx;
0229   }
0230 
0231   if (!move_to_shift_algo)
0232   {
0233     size_t nbads = bad_indices.size();
0234 
0235     if (nbads == 0 || nbads >= 4)
0236     {
0237       std::cout << Name() << ": unexpected number of bad events = " << nbads << " – rejecting pool" << std::endl;
0238       return false;
0239     }
0240 
0241     std::cout << Name() << ": intermittent bad events = " << nbads << " – do not try shifting algorithm" << std::endl;
0242     return true;
0243   }
0244 
0245 
0246   //Try shift 
0247   if(!move_to_shift_algo)
0248   {
0249     std::cout << Name() << ": Unexpected shift flag = " << move_to_shift_algo << ". Something went wrong - rejecting pool" << std::endl;
0250     return false;
0251   }
0252   
0253   if(move_to_shift_algo)
0254   {
0255     std::cout << Name() << ": Inconsistent diffs of " << bad_diff_indices.size() << ". Trying now shifting events to resynchronize" << std::endl;
0256   }
0257 
0258   bool match = true;
0259   bool first_pool = (gl1diff[0] == std::numeric_limits<uint64_t>::max());
0260   size_t start = first_pool ? 2 : 1;
0261 
0262   for (size_t i = start; i < pooldepth; ++i)
0263   {
0264     if (sebdiff[i] != gl1diff[i - 1])
0265     {
0266       match= false;
0267       break;
0268     }
0269   }
0270   if (match)
0271   {
0272     shift = -1;
0273     return true;
0274   }
0275 
0276   match = true;
0277   start = first_pool ? 1 : 0;
0278   for (size_t i = start; i < pooldepth - 1; ++i)
0279   {
0280     if (sebdiff[i] != gl1diff[i + 1])
0281     {
0282       match= false;
0283       break;
0284     }
0285   }
0286   if (match)
0287   {
0288     shift = 1;
0289     return true;
0290   }
0291 
0292   return false;
0293 }
0294 
0295 int SingleTriggeredInput::fileopen(const std::string &filenam)
0296 {
0297   std::cout << PHWHERE << "trying to open " << filenam << std::endl;
0298   if (IsOpen())
0299   {
0300     std::cout << "Closing currently open file "
0301               << FileName()
0302               << " and opening " << filenam << std::endl;
0303     fileclose();
0304   }
0305   FileName(filenam);
0306   FROG frog;
0307   std::string fname = frog.location(FileName());
0308   if (Verbosity() > 0)
0309   {
0310     std::cout << Name() << ": opening file " << FileName() << std::endl;
0311   }
0312   int status = 0;
0313   m_EventIterator = new fileEventiterator(fname.c_str(), status);
0314   if (status)
0315   {
0316     delete m_EventIterator;
0317     m_EventIterator = nullptr;
0318     std::cout << PHWHERE << Name() << ": could not open file " << fname << std::endl;
0319     return -1;
0320   }
0321   IsOpen(1);
0322   AddToFileOpened(fname);  // add file to the list of files which were opened
0323   return 0;
0324 }
0325 
0326 int SingleTriggeredInput::fileclose()
0327 {
0328   if (!IsOpen())
0329   {
0330     std::cout << Name() << ": fileclose: No Input file open" << std::endl;
0331     return -1;
0332   }
0333   delete m_EventIterator;
0334   m_EventIterator = nullptr;
0335   IsOpen(0);
0336   UpdateFileList();
0337   return 0;
0338 }
0339 
0340 int SingleTriggeredInput::FillEventVector()
0341 {
0342   while (GetEventIterator() == nullptr)  // at startup this is a null pointer
0343   {
0344     if (!OpenNextFile())
0345     {
0346       AllDone(1);
0347       return -1;
0348     }
0349   }
0350 
0351   bool allPacketEventDequeEmpty = true;
0352   int representative_pid = -1;
0353   for (int pid : m_PacketSet)
0354   {
0355     if ( !m_PacketEventDeque[pid].empty() )
0356     {
0357       allPacketEventDequeEmpty = false;
0358       break;
0359     }
0360     uint64_t tmp = m_bclkarray_map[pid][pooldepth];
0361     m_bclkarray_map[pid].fill(std::numeric_limits<uint64_t>::max());
0362     m_bclkarray_map[pid][0] = tmp;
0363     m_bclkdiffarray_map[pid].fill(std::numeric_limits<uint64_t>::max());
0364 
0365     if ( representative_pid == -1 ) 
0366     {
0367       representative_pid = pid;
0368     }
0369   }
0370   if ( !allPacketEventDequeEmpty )
0371   {
0372     return 0;
0373   }
0374 
0375   size_t i{0};
0376   std::map<int, Event*> m_ShiftedEvents;
0377 
0378   while (i < pooldepth)
0379   {
0380     Event* evt{nullptr};
0381     if (this != Gl1Input())
0382     {
0383       auto* gl1 = dynamic_cast<SingleGl1TriggeredInput*>(Gl1Input());
0384       if (gl1)
0385       {
0386         int nskip = gl1->GetGl1SkipArray()[i];
0387         if (m_Gl1PacketOneSkipActiveTrace)
0388         {
0389           int gl1packetcountdiff = static_cast<int>(gl1->GetPacketNumbers()[i] - m_Gl1PacketNumberOneSkip);
0390           if ( nskip == -1 && gl1packetcountdiff < m_Gl1PacketOneSkipCount )
0391           {
0392             m_Gl1PacketOneSkipActiveTrace = false;
0393             if (Verbosity() > 0)
0394             {
0395               std::cout << Name() << ": GL1 stuck detected at " << gl1->GetPacketNumbers()[i] << " after skipping " << gl1packetcountdiff << ". Clearing trace." << std::endl;
0396             }
0397           }
0398           else if ( gl1packetcountdiff >= m_Gl1PacketOneSkipCount )
0399           {
0400             m_Gl1PacketOneSkipActiveTrace = false;
0401             if (Verbosity() > 0)
0402             {
0403               std::cout <<  Name() << ": No stuck found before " << m_Gl1PacketOneSkipCount << " events. Skipping one SEB event now." << std::endl;
0404             }
0405             Event* skip_evt = GetEventIterator()->getNextEvent();
0406             while (!skip_evt)
0407             {
0408               fileclose();
0409               if (!OpenNextFile())
0410               {
0411                 FilesDone(1);
0412                 return -1;
0413               }
0414               skip_evt = GetEventIterator()->getNextEvent();
0415             }
0416           }
0417         }
0418         if (nskip == 1 && m_packetclk_copy_runs == true)
0419         {
0420           m_Gl1PacketOneSkipActiveTrace = true;
0421           m_Gl1PacketNumberOneSkip = gl1->GetPacketNumbers()[i];
0422           if (Verbosity() > 0)
0423           {
0424             std::cout << Name() << ": GL1 packet skip for " << m_Gl1PacketNumberOneSkip << ". Start tracing Gl1 packet number." << std::endl;
0425           }
0426           nskip = 0;
0427         }
0428 
0429         while (nskip > 0)
0430         {
0431           Event* skip_evt = GetEventIterator()->getNextEvent();
0432           while (!skip_evt)
0433           {
0434             fileclose();
0435             if (!OpenNextFile())
0436             {
0437               FilesDone(1);
0438               return -1;
0439             }
0440             skip_evt = GetEventIterator()->getNextEvent();
0441           }
0442           if (Verbosity() > 0)
0443           {
0444             std::cout << Name() << ": Skipping SEB events because of GL1 packet number diff : " << nskip
0445               << ", with event sequence number " << skip_evt->getEvtSequence() << std::endl;
0446           }
0447 
0448           Packet* pkt = skip_evt->getPacket(representative_pid);
0449           if (!pkt)
0450           {
0451             delete skip_evt;
0452             continue;
0453           }
0454 
0455           FillPacketClock(skip_evt, pkt, i);
0456           delete pkt;
0457 
0458           uint64_t seb_diff = m_bclkdiffarray_map[representative_pid][i];
0459           int gl1pid = Gl1Input()->m_bclkdiffarray_map.begin()->first;
0460           uint64_t gl1_diff = Gl1Input()->m_bclkdiffarray_map[gl1pid][i];
0461 
0462           if (seb_diff == gl1_diff)
0463           {
0464             if (Verbosity() > 0)
0465             {
0466               std::cout << Name() << ": Early stop of SEB skip after " << (gl1->GetGl1SkipArray()[i] - nskip)
0467                 << " from intial " << gl1->GetGl1SkipArray()[i] << " events." << std::endl;
0468             }
0469             evt = skip_evt;
0470             break;
0471           }
0472           delete skip_evt;
0473           nskip--;
0474         }
0475       }
0476     }
0477 
0478     if (!evt)
0479     {
0480       evt = GetEventIterator()->getNextEvent();
0481       while (!evt)
0482       {
0483         fileclose();
0484         if (!OpenNextFile())
0485         {
0486           FilesDone(1);
0487           return -1;
0488         }
0489         evt = GetEventIterator()->getNextEvent();
0490       }
0491     }
0492     if (evt->getEvtType() != DATAEVENT)
0493     {
0494       if (Verbosity() > 0)
0495       {
0496         std::cout << Name() << " dropping non data event: " << evt->getEvtSequence() << std::endl;
0497       }
0498       delete evt;
0499       continue;
0500     }
0501     evt->convert();
0502     
0503     if (firstcall)
0504     {
0505       std::cout << "Creating DSTs first call" << std::endl;
0506       CreateDSTNodes(evt);
0507       int run = evt->getRunNumber();
0508       m_packetclk_copy_runs = (run >= 44000 && run < 56079); 
0509       firstcall = false;
0510     }
0511 
0512     for (int pid : m_PacketSet)
0513     {
0514       Event *thisevt = evt;
0515       if (m_PacketShiftOffset[pid] == 1)
0516       {
0517         if (i==0)
0518         {
0519           thisevt = m_PacketEventBackup[pid];
0520           m_ShiftedEvents[pid] = evt;
0521         }
0522         else if (i > 0)
0523         {
0524           thisevt = m_ShiftedEvents[pid];
0525           m_ShiftedEvents[pid] = evt;
0526           if (i == pooldepth -1)
0527           {
0528             m_PacketEventBackup[pid] = evt;
0529           }
0530         }
0531       }
0532       
0533       Packet* pkt = thisevt->getPacket(pid);
0534       if (!pkt)
0535       {
0536         continue;
0537       }
0538       FillPacketClock(thisevt, pkt, i);
0539       m_PacketEventDeque[pid].push_back(thisevt);
0540       delete pkt;
0541     
0542       if (representative_pid == -1 && m_PacketShiftOffset[pid] == 0)
0543       {
0544         representative_pid = pid;
0545       }
0546     }
0547     i++;
0548   }
0549 
0550   size_t minSize = pooldepth;
0551   for (const auto& [pid, dq] : m_PacketEventDeque)
0552   {
0553     minSize = std::min(dq.size(), minSize);
0554   }
0555   return minSize;
0556 }
0557 
0558 uint64_t SingleTriggeredInput::GetClock(Event *evt, int pid)
0559 {
0560   Packet* packet = evt->getPacket(pid);
0561   if (!packet)
0562   {
0563     std::cout << Name() << ": Missing packet " << pid << " in event " << evt->getEvtSequence() << std::endl;
0564     return std::numeric_limits<uint64_t>::max();
0565   }
0566   uint64_t clkval = static_cast<uint64_t>(packet->lValue(0, "CLOCK"));
0567   uint64_t clk = clkval & 0xFFFFFFFFU;
0568   delete packet;
0569   return clk;
0570 }
0571 
0572 void SingleTriggeredInput::FillPacketClock(Event* evt, Packet* pkt, size_t event_index)
0573 {
0574   if (!pkt)
0575   {
0576     return;
0577   }
0578   int pid = pkt->getIdentifier();
0579 
0580   if (m_bclkarray_map.find(pid) == m_bclkarray_map.end())
0581   {
0582     m_bclkarray_map[pid].fill(std::numeric_limits<uint64_t>::max());
0583     m_bclkdiffarray_map[pid].fill(std::numeric_limits<uint64_t>::max());
0584   }
0585 
0586   auto& clkarray = m_bclkarray_map[pid];
0587   auto& diffarray = m_bclkdiffarray_map[pid];
0588 
0589 
0590   // Special handling for FEM-copied clocks
0591   if (m_packetclk_copy_runs && m_CorrectCopiedClockPackets.count(pid))
0592   {
0593     if (event_index == 0)
0594     {
0595       clkarray[event_index+1] = m_PreviousValidBCOMap[pid];
0596     }
0597     else if (event_index >=1) 
0598     {
0599       Event* shifted_evt = m_PacketEventDeque[pid][event_index - 1];
0600       clkarray[event_index+1] = GetClock(shifted_evt, pid);
0601     }
0602     
0603     uint64_t prev = clkarray[event_index];
0604     uint64_t curr = clkarray[event_index + 1];
0605 
0606     if (prev == std::numeric_limits<uint64_t>::max() || curr == std::numeric_limits<uint64_t>::max())
0607     {
0608       diffarray[event_index] = std::numeric_limits<uint64_t>::max();
0609     }
0610     else
0611     {
0612       diffarray[event_index] = ComputeClockDiff(curr, prev);
0613     }
0614 
0615     return;
0616   }
0617 
0618 
0619   uint64_t clk = GetClock(evt, pid);
0620   if (clk == std::numeric_limits<uint64_t>::max())
0621   {
0622     std::cout << Name() << ": Bad clock for packet " << pid << " at event index " << event_index << std::endl;
0623     return;
0624   }
0625 
0626   clkarray[event_index + 1] = clk;
0627 
0628   uint64_t prev = clkarray[event_index];
0629   if(prev == std::numeric_limits<uint64_t>::max())
0630   {
0631     static std::unordered_set<int> warned;
0632 
0633     if (warned.find(pid) == warned.end())
0634     {
0635       std::cout << Name() << ": First pool for pacekt " << pid << " – skipping first diff because of no previous clock" << std::endl;
0636       warned.insert(pid);
0637     }
0638     else
0639     {
0640       std::cout << "prev clock is max something is wrong... : " << event_index << std::endl;
0641     }
0642     diffarray[event_index] = std::numeric_limits<uint64_t>::max();
0643   }
0644   else
0645   {
0646     diffarray[event_index] = ComputeClockDiff(clk, prev);
0647   }
0648 
0649   if (auto* gl1 = dynamic_cast<SingleGl1TriggeredInput*>(this))
0650   {
0651     int packet_number = pkt->iValue(0);
0652     gl1->SetPacketNumbers(gl1->GetCurrentPacketNumber(), packet_number);
0653     if ( event_index < pooldepth )
0654     {
0655       gl1->SetGl1PacketNumber(event_index, packet_number);
0656     }
0657 
0658     int skip_count = 0;
0659     if (gl1->GetLastPacketNumber() != 0)
0660     {
0661       int diff = gl1->GetCurrentPacketNumber() - gl1->GetLastPacketNumber() ;
0662       skip_count = diff - 1;
0663     }
0664 
0665     if (event_index < pooldepth)
0666     {
0667       gl1->SetGl1SkipAtIndex(event_index, skip_count);
0668     }
0669   }
0670 }
0671 
0672 void SingleTriggeredInput::FillPool()
0673 {
0674   if (AllDone() || EventAlignmentProblem())
0675   {
0676     return;
0677   }
0678 
0679   bool all_packets_bad = !m_PacketAlignmentProblem.empty() && std::all_of(m_PacketAlignmentProblem.begin(), m_PacketAlignmentProblem.end(), [](const std::pair<const int, bool> &entry) -> bool { return entry.second;});
0680   if (all_packets_bad)
0681   {
0682     std::cout << Name() << ": ALL packets are marked as bad. Stop combining for this SEB." << std::endl;
0683     EventAlignmentProblem(1);
0684     return;
0685   }
0686 
0687   if (!FilesDone())
0688   {
0689     int eventvectorsize = FillEventVector();
0690     if (eventvectorsize != 0)
0691     {
0692       if (Gl1Input()->m_bclkdiffarray_map.empty())
0693       {
0694         std::cout << Name() << " : GL1 clock map is empty!" << std::endl;
0695         return;
0696       }
0697       m_OverrideWithRepClock.clear();
0698 
0699       int gl1pid = Gl1Input()->m_bclkdiffarray_map.begin()->first;
0700       const auto& gl1diff = Gl1Input()->m_bclkdiffarray_map.at(gl1pid);
0701 
0702       bool allgl1max = std::all_of(gl1diff.begin(), gl1diff.end(), [](uint64_t val) {
0703           return val == std::numeric_limits<uint64_t>::max();
0704         });
0705       if (allgl1max)
0706       {
0707         std::cout << Name() << " : GL1 clock diffs all filled with max 64 bit values for PID " << gl1pid << " return and try next pool" << std::endl;
0708         return;
0709       }
0710       m_DitchPackets.clear();
0711 
0712       for (auto& [pid, _] : m_PrevPoolLastDiffBad)
0713       {
0714         m_PrevPoolLastDiffBad[pid] = false;
0715       }
0716 
0717       for (const auto& [pid, sebdiff] : m_bclkdiffarray_map)
0718       {
0719         size_t packetpoolsize = m_PacketEventDeque[pid].size();
0720         if(packetpoolsize==0)
0721         {
0722           std::cout << Name() << ": packet pool size is zero.... something is wrong" << std::endl;
0723           return;
0724         }
0725 
0726         if(m_PacketAlignmentProblem[pid])
0727         {
0728           continue;
0729         }
0730         std::vector<int> bad_indices;
0731         int shift = 0;
0732 
0733         bool CurrentPoolLastDiffBad = false;
0734         bool PrevPoolLastDiffBad = m_PrevPoolLastDiffBad[pid];
0735 
0736         bool aligned = CheckPoolAlignment(pid, sebdiff, gl1diff, bad_indices, shift, CurrentPoolLastDiffBad, PrevPoolLastDiffBad);
0737         
0738         if (aligned)
0739         {
0740           m_PrevPoolLastDiffBad[pid] = CurrentPoolLastDiffBad;
0741           if (!bad_indices.empty())
0742           {
0743             std::cout << Name() << ": Packet " << pid << " has bad indices: ";
0744             for (int bi : bad_indices){
0745               std::cout << bi << " ";
0746               m_DitchPackets[pid].insert(bi);
0747             }
0748             std::cout << std::endl;
0749 
0750             std::cout << "full print out of gl1 vs seb clocks " << std::endl;
0751             for (size_t i = 0; i <= pooldepth; ++i)
0752             {
0753               uint64_t gl1_clk = Gl1Input()->m_bclkarray_map[gl1pid][i];
0754               uint64_t seb_clk = m_bclkarray_map[pid][i];
0755               std::cout << "pool index i " << i << ", gl1 / seb : " << gl1_clk << " / " << seb_clk;
0756               if(i<pooldepth){
0757                 uint64_t gl1_diff = Gl1Input()->m_bclkdiffarray_map[gl1pid][i];
0758                 uint64_t seb_diff = m_bclkdiffarray_map[pid][i];
0759                 std::cout << " -> diff of gl1 vs seb : " << gl1_diff << " " << seb_diff << std::endl;
0760               }
0761               else if(i==pooldepth)
0762               {
0763                 std::cout << std::endl;
0764               }
0765             }
0766           }
0767 
0768           if (shift == -1)
0769           {
0770             std::cout << Name() << ": Packet " << pid << " shifted by -1 with dropping the first seb event" << std::endl;
0771             if(m_PacketShiftOffset[pid] == -1)
0772             {
0773               std::cout << "Packet " << pid << " requires an additional shift -1. Lets not handle this for the moment.. stop combining" << std::endl;
0774               m_PacketAlignmentProblem[pid] = true;
0775             } 
0776 
0777             if (!m_PacketEventDeque[pid].empty())
0778             {
0779               m_PacketEventDeque[pid].pop_front();
0780             }
0781             else
0782             {
0783               std::cout << Name() << ": ERROR — shift -1 requested but packet deque is empty!" << std::endl;
0784               continue;
0785             }
0786 
0787             for (size_t i = 0; i < packetpoolsize - 1; ++i)
0788             {
0789               m_bclkarray_map[pid][i] = m_bclkarray_map[pid][i+1];
0790             }
0791 
0792             for (size_t i = 0; i < packetpoolsize; ++i)
0793             {
0794               m_bclkdiffarray_map[pid][i] = ComputeClockDiff(m_bclkarray_map[pid][i+1], m_bclkarray_map[pid][i]);
0795             }
0796             Event* evt = GetEventIterator()->getNextEvent();
0797             if (evt)
0798             {
0799               evt->convert();
0800               std::vector<Packet*> pktvec = evt->getPacketVector();
0801               for (Packet* pkt : pktvec)
0802               {
0803                 if (pkt->getIdentifier() == pid)
0804                 {
0805                   FillPacketClock(evt, pkt, packetpoolsize - 1);
0806                   m_PacketEventDeque[pid].push_back(evt);
0807                 }
0808                 delete pkt;
0809               }
0810             }
0811             else
0812             {
0813               std::cout << Name() << ": Cannot refill after shift -1" << std::endl;
0814               FilesDone(1);
0815               return;
0816             }
0817             m_PacketShiftOffset[pid] -= 1;
0818           }
0819           else if (shift == 1)
0820           {
0821             std::cout << Name() << ": Packet " << pid << " requires shift +1 (insert dummy at front)" << std::endl;
0822             
0823             if (m_packetclk_copy_runs)
0824             {
0825               std::cout << Name() << " : runs where clocks are copied from the first XMIT. Checking FEM clock diff" << std::endl;
0826               if (FemClockAlignment(pid, m_PacketEventDeque[pid], gl1diff))
0827               {
0828                 std::cout << Name() << " : Packet identified as aligned with FEM clocks. Apply shift only on packet clocks." << std::endl;
0829                 m_CorrectCopiedClockPackets.insert(pid);
0830                 m_DitchPackets[pid].insert(0);
0831 
0832                 Event* evt0 = m_PacketEventDeque[pid].front();
0833                 m_PreviousValidBCOMap[pid] = GetClock(evt0, pid);
0834                 m_bclkarray_map[pid][pooldepth] = m_bclkarray_map[pid][pooldepth - 1];
0835                 continue;
0836               }
0837               std::cout << Name() << " : Packet identified as misaligned also with FEMs. Do normal recovery process" << std::endl;
0838             }
0839 
0840             if(m_PacketShiftOffset[pid] == 1)
0841             {
0842               std::cout << "Packet " << pid << " requires an additional shift +1. Lets not handle this for the moment.. stop combining" << std::endl;
0843               m_PacketAlignmentProblem[pid] = true;
0844             }
0845 
0846             for (size_t i = pooldepth; i > 0; --i)
0847             {
0848               m_bclkarray_map[pid][i] = m_bclkarray_map[pid][i-1];
0849             }
0850             for (size_t i = 1 ; i < pooldepth; ++i)
0851             {
0852               m_bclkdiffarray_map[pid][i] = ComputeClockDiff(m_bclkarray_map[pid][i+1], m_bclkarray_map[pid][i]);
0853             }
0854 
0855             m_bclkarray_map[pid][0] = 0;
0856             m_bclkdiffarray_map[pid][0] = 0;
0857             m_DitchPackets[pid].insert(0);
0858 
0859             if (!m_PacketEventDeque[pid].empty())
0860             {
0861               m_PacketEventBackup[pid] = m_PacketEventDeque[pid].back();
0862               Event* dummy_event = m_PacketEventDeque[pid][0]; 
0863               m_PacketEventDeque[pid].push_front(dummy_event);
0864               m_PacketEventDeque[pid].pop_back();
0865             }
0866             else
0867             {
0868               std::cout << Name() << ": m_PacketEventDeque is empty, cannot insert dummy event!" << std::endl;
0869               return;
0870             }
0871 
0872             m_PacketShiftOffset[pid] += 1;
0873             std::cout << std::endl;
0874           }
0875         }
0876         else
0877         {
0878           std::cout << Name() << ": Alignment failed for packet " << pid
0879             << " (retry count = " << m_PacketAlignmentFailCount[pid] << ")" << std::endl;
0880           std::cout << "full print out of gl1 vs seb clocks " << std::endl;
0881           for (size_t i = 0; i <= pooldepth; ++i)
0882           {
0883             uint64_t gl1_clk = Gl1Input()->m_bclkarray_map[gl1pid][i];
0884             uint64_t seb_clk = m_bclkarray_map[pid][i];
0885             std::cout << "pool index i " << i << ", gl1 / seb : " << gl1_clk << " / " << seb_clk;
0886             if(i<pooldepth){
0887               uint64_t gl1_diff = Gl1Input()->m_bclkdiffarray_map[gl1pid][i];
0888               uint64_t seb_diff = m_bclkdiffarray_map[pid][i];
0889               std::cout << " -- diff of gl1 vs seb : " << gl1_diff << " " << seb_diff << std::endl;
0890             }
0891             else if(i==pooldepth)
0892             {
0893               std::cout << std::endl;
0894             }
0895           }
0896 
0897           m_PacketAlignmentFailCount[pid]++;
0898           for (size_t i = 0; i < pooldepth; ++i)
0899           {
0900             m_DitchPackets[pid].insert(i);
0901           }
0902 
0903           if (m_PacketAlignmentFailCount[pid] >= m_max_alignment_retries)
0904           {
0905             std::cout << Name() << ": Max retries reached — permanently ditching packet " << pid << std::endl;
0906             m_PacketAlignmentFailCount[pid] = 0; 
0907             m_PacketAlignmentProblem[pid] = true;
0908           }
0909         }
0910       }
0911     }
0912   }
0913   return;
0914 }
0915 
0916 void SingleTriggeredInput::CreateDSTNodes(Event *evt)
0917 {
0918   std::string CompositeNodeName = "Packets";
0919   if (KeepMyPackets())
0920   {
0921     CompositeNodeName = "PacketsKeep";
0922   }
0923   PHNodeIterator iter(m_topNode);
0924   PHCompositeNode *dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
0925   if (!dstNode)
0926   {
0927     dstNode = new PHCompositeNode("DST");
0928     m_topNode->addNode(dstNode);
0929   }
0930   PHNodeIterator iterDst(dstNode);
0931   PHCompositeNode *detNode = dynamic_cast<PHCompositeNode *>(iterDst.findFirst("PHCompositeNode", CompositeNodeName));
0932   if (!detNode)
0933   {
0934     detNode = new PHCompositeNode(CompositeNodeName);
0935     dstNode->addNode(detNode);
0936   }
0937   std::vector<Packet *> pktvec = evt->getPacketVector();
0938   for (auto *piter : pktvec)
0939   {
0940     int packet_id = piter->getIdentifier();
0941     m_PacketSet.insert(packet_id);
0942     std::string PacketNodeName = std::to_string(packet_id);
0943     CaloPacket *calopacket = findNode::getClass<CaloPacket>(detNode, PacketNodeName);
0944     if (!calopacket)
0945     {
0946       calopacket = new CaloPacketv1();
0947       PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(calopacket, PacketNodeName, "PHObject");
0948       detNode->addNode(newNode);
0949     }
0950     m_PacketShiftOffset.try_emplace(packet_id, 0);
0951     delete piter;
0952   }
0953 }
0954 
0955 bool SingleTriggeredInput::FemClockAlignment(int pid, const std::deque<Event*>& events, const std::array<uint64_t, pooldepth>& gl1diff)
0956 {
0957   if (events.size() < pooldepth)
0958   {
0959     std::cout << Name() << ": Not enough events for FEMClockAlignment check for packet " << pid << std::endl;
0960     return false;
0961   }
0962 
0963   uint64_t prev_clk = std::numeric_limits<uint64_t>::max();
0964 
0965   for (size_t i = 0; i < pooldepth; ++i)
0966   {
0967     Event* evt = events[i];
0968     Packet* pkt = evt->getPacket(pid);
0969     if (!pkt)
0970     {
0971       continue;
0972     }
0973 
0974     int nmod = pkt->iValue(0, "NRMODULES");
0975     std::map<int, int> clk_count;
0976 
0977     for (int j = 0; j < nmod; ++j)
0978     {
0979       int femclk = static_cast<uint16_t>(pkt->iValue(j, "FEMCLOCK"));
0980       clk_count[femclk]++;
0981     }
0982 
0983     delete pkt;
0984 
0985     if (clk_count.empty())
0986     {
0987       continue;
0988     }
0989 
0990     int majority_clk = std::max_element(
0991         clk_count.begin(), clk_count.end(),
0992         [](const auto& a, const auto& b) { return a.second < b.second; })->first;
0993 
0994     if (clk_count[majority_clk] < 2)
0995     {
0996       std::cout << Name() << ": FemClockAlignment — no majority FEM clocks for packet " << pid << " at pool index " << i << std::endl;
0997       return false;
0998     }
0999 
1000 
1001     if (i >= 1 && prev_clk != std::numeric_limits<uint64_t>::max() && gl1diff[i] != std::numeric_limits<uint64_t>::max())
1002     {
1003       uint16_t fem_diff = static_cast<uint16_t>(ComputeClockDiff(majority_clk, prev_clk) & 0xFFFFU);
1004       uint16_t gl1_diff = static_cast<uint16_t>(gl1diff[i] & 0xFFFFU);
1005 
1006       std::cout << "i " << i << " curr_fem_clk / prev_fem_clk " << majority_clk << " " << prev_clk << " , fem_diff / gl1_diff " << fem_diff << " " << gl1_diff << std::endl;
1007       if (fem_diff != gl1_diff)
1008       {
1009         return false;
1010       }
1011     }
1012 
1013     prev_clk = majority_clk;
1014   }
1015 
1016   return true;
1017 }
1018 
1019 int SingleTriggeredInput::FemEventNrClockCheck(OfflinePacket *pkt)
1020 {
1021   CaloPacket *calopkt = dynamic_cast<CaloPacket *>(pkt);
1022   if (!calopkt)
1023   {
1024     return 0;
1025   }
1026   // make sure all clocks of the FEM are fine,
1027   int nrModules = calopkt->iValue(0, "NRMODULES");
1028   std::set<int> EventNoSet;
1029   for (int j = 0; j < nrModules; j++)
1030   {
1031     EventNoSet.insert(calopkt->iValue(j, "FEMEVTNR"));
1032   }
1033   size_t femeventnumbers = EventNoSet.size();
1034   if (femeventnumbers > 1)
1035   {
1036     int goodfemevent = 0;  // store the good event number so we can insert it in the set, but only if the clock counters agree
1037     if (femeventnumbers == 2)
1038     {
1039       // find the outlier if we have a 2:1 decision
1040       std::map<int, int> EventMap;
1041       std::map<int, int> BadModuleMap;
1042       for (int j = 0; j < nrModules; j++)
1043       {
1044         EventMap[calopkt->iValue(j, "FEMEVTNR")]++;
1045         BadModuleMap[calopkt->iValue(j, "FEMEVTNR")] = j;
1046       }
1047       for (const auto iter : EventMap)
1048       {
1049         if (iter.second == 1)
1050         {
1051           calopkt->setFemStatus(BadModuleMap[iter.first], CaloPacket::BAD_EVENTNR);
1052         }
1053         else
1054         {
1055           goodfemevent = iter.first;
1056         }
1057       }
1058     }
1059     else 
1060     {
1061       for (int j = 0; j < nrModules; j++)
1062       {
1063         calopkt->setFemStatus(j, CaloPacket::BAD_EVENTNR);
1064       }
1065     }
1066     std::set<int> FemClockSet;
1067     for (int j = 0; j < nrModules; j++)
1068     {
1069       FemClockSet.insert(calopkt->iValue(j, "FEMCLOCK"));
1070     }
1071     if (FemClockSet.size() == 1)
1072     {
1073       static int icnt = 0;
1074       if (icnt < 10)
1075       {
1076         icnt++;
1077         std::cout << "Packet " << calopkt->getIdentifier() << " has not unique event numbers"
1078                   << " but FEM Clock counters are identical" << std::endl;
1079       }
1080       if (goodfemevent > 0)
1081       {
1082         m_FEMEventNrSet.insert(goodfemevent);
1083       }
1084       return 1;
1085     }
1086     static int icnt = 0;
1087     if (icnt < 1000)
1088     {
1089       icnt++;
1090       std::cout << "resetting packet " << calopkt->getIdentifier()
1091                 << " with fem event and clock mismatch" << std::endl;
1092       std::map<int, int> ClockMap;
1093       std::map<int, int> EventMap;
1094       for (int j = 0; j < nrModules; j++)
1095       {
1096         EventMap[calopkt->iValue(j, "FEMEVTNR")]++;
1097         ClockMap[calopkt->iValue(j, "FEMCLOCK")]++;
1098       }
1099       for (const auto iterA : EventMap)
1100       {
1101         std::cout << "Event Nr : " << iterA.first << " shows up " << iterA.second << " times"
1102                   << std::hex << ", Event Nr 0x" << iterA.first << std::dec << std::endl;
1103       }
1104       for (const auto iterA : ClockMap)
1105       {
1106         std::cout << "Clock : 0x" << std::hex << iterA.first << std::dec
1107                  << " shows up " << iterA.second << " times" << std::endl;
1108       }
1109     }
1110     return -1;
1111   }
1112   m_FEMEventNrSet.insert(*(EventNoSet.begin()));
1113   return 0;
1114 }
1115 
1116 void SingleTriggeredInput::dumpdeque()
1117 {
1118   const auto *iter1 = clkdiffbegin();
1119   const auto *iter2 = Gl1Input()->clkdiffbegin();
1120   while (iter1 != clkdiffend())
1121   {
1122     std::cout << Name() << " clk: 0x" << std::hex << *iter1
1123               << " Gl1 clk: 0x" << *iter2 << std::dec << std::endl;
1124     iter1++;
1125     iter2++;
1126   }
1127   return;
1128 }
1129 
1130 int SingleTriggeredInput::ReadEvent()
1131 {
1132   for (const auto& [pid, dq] : m_PacketEventDeque)
1133   {
1134     if (dq.empty())
1135     {
1136       if (!EventAlignmentProblem())
1137       {
1138         std::cout << Name() << ": Packet " << pid << " has empty deque — all events done" << std::endl;
1139         AllDone(1);
1140       }
1141       return -1;
1142     }
1143   }
1144 
1145   if (Verbosity() > 1)
1146   {
1147     size_t size = m_PacketEventDeque.begin()->second.size();
1148     std::cout << "deque size: " << size << std::endl;
1149   }
1150 
1151   auto *ref_evt = m_PacketEventDeque.begin()->second.front();
1152   RunNumber(ref_evt->getRunNumber());
1153 
1154   uint64_t event_number = ref_evt->getEvtSequence();
1155   if(event_number % 10000==0)
1156   {
1157     std::cout << "processed events : " << event_number << std::endl;
1158   }
1159 
1160   m_FEMEventNrSet.clear();
1161 
1162   bool all_packets_unshifted = std::all_of(
1163       m_PacketShiftOffset.begin(), m_PacketShiftOffset.end(),
1164       [](const std::pair<int, int>& p) { return p.second == 0; });
1165 
1166   std::set<Event*> events_to_delete;
1167 
1168   for (auto& [pid, dq] : m_PacketEventDeque)
1169   {
1170     if(m_PacketAlignmentProblem[pid]) 
1171     {
1172       continue;
1173     }
1174     Event* evt = dq.front();
1175     Packet* packet = evt->getPacket(pid);
1176 
1177     int packet_id = packet->getIdentifier();
1178     if (packet_id != pid)
1179     {
1180       std::cout << Name() << ": packet id mismatch... Should never happen. Abort combining" << std::endl;
1181       EventAlignmentProblem(1);
1182       delete packet;
1183       return -1;
1184     }
1185 
1186     CaloPacket *newhit = findNode::getClass<CaloPacket>(m_topNode, packet_id);
1187     newhit->Reset();
1188 
1189     if (m_DitchPackets.count(packet_id) && m_DitchPackets[packet_id].count(0))
1190     {
1191       newhit->setStatus(OfflinePacket::PACKET_DROPPED);
1192       newhit->setIdentifier(packet_id);
1193       std::cout << "ditching packet " << packet_id << " from prdf event " << evt->getEvtSequence() << std::endl;
1194       delete packet;
1195       continue;
1196     }
1197 
1198     newhit->setStatus(OfflinePacket::PACKET_OK);
1199     if (m_OverrideWithRepClock.count(packet_id))
1200     {
1201       newhit->setStatus(OfflinePacket::PACKET_CORRUPT);
1202     }
1203     newhit->setPacketEvtSequence(packet->iValue(0, "EVTNR"));
1204     int nr_modules = packet->iValue(0, "NRMODULES");
1205     int nr_channels = packet->iValue(0, "CHANNELS");
1206     int nr_samples = packet->iValue(0, "SAMPLES");
1207     newhit->setNrModules(nr_modules);
1208     newhit->setNrChannels(nr_channels);
1209     newhit->setNrSamples(nr_samples);
1210     newhit->setIdentifier(packet_id);
1211     if (m_packetclk_copy_runs && m_CorrectCopiedClockPackets.count(packet_id))
1212     {
1213       uint64_t prev_packet_clock = m_PreviousValidBCOMap[packet_id];
1214       newhit->setBCO(prev_packet_clock);
1215       m_PreviousValidBCOMap[packet_id] = GetClock(evt,packet_id);
1216     }
1217     else
1218     {
1219       newhit->setBCO(packet->lValue(0, "CLOCK"));
1220     }
1221 
1222     for (int ifem = 0; ifem < nr_modules; ifem++)
1223     {
1224       newhit->setFemClock(ifem, packet->iValue(ifem, "FEMCLOCK"));
1225       newhit->setFemEvtSequence(ifem, packet->iValue(ifem, "FEMEVTNR"));
1226       newhit->setFemSlot(ifem, packet->iValue(ifem, "FEMSLOT"));
1227       newhit->setChecksumLsb(ifem, packet->iValue(ifem, "CHECKSUMLSB"));
1228       newhit->setChecksumMsb(ifem, packet->iValue(ifem, "CHECKSUMMSB"));
1229       newhit->setCalcChecksumLsb(ifem, packet->iValue(ifem, "CALCCHECKSUMLSB"));
1230       newhit->setCalcChecksumMsb(ifem, packet->iValue(ifem, "CALCCHECKSUMMSB"));
1231       newhit->setFemStatus(ifem, CaloPacket::FEM_OK);
1232     }
1233     for (int ipmt = 0; ipmt < nr_channels; ipmt++)
1234     {
1235       bool isSuppressed = packet->iValue(ipmt, "SUPPRESSED");
1236       newhit->setSuppressed(ipmt, isSuppressed);
1237       if (isSuppressed)
1238       {
1239         newhit->setPre(ipmt, packet->iValue(ipmt, "PRE"));
1240         newhit->setPost(ipmt, packet->iValue(ipmt, "POST"));
1241       }
1242       else
1243       {
1244         for (int isamp = 0; isamp < nr_samples; isamp++)
1245         {
1246           newhit->setSample(ipmt, isamp, packet->iValue(isamp, ipmt));
1247         }
1248       }
1249     }
1250     delete packet;
1251     int iret = FemEventNrClockCheck(newhit);
1252     if (iret < 0)
1253     {
1254       std::cout << Name() <<" : failed on FemEventNrClockCheck reset calo packet " << std::endl;
1255       newhit->Reset();
1256     }
1257 
1258     if (all_packets_unshifted || m_PacketShiftOffset[pid] == 1)
1259     {
1260       events_to_delete.insert(evt);
1261     }
1262   }
1263 
1264   for(Event *evtdelete : events_to_delete)
1265   {
1266     delete evtdelete;
1267   }
1268 
1269   for (auto& [pid, idx_set] : m_DitchPackets)
1270   {
1271     std::set<int> new_set;
1272     for (int idx : idx_set)
1273     {
1274       if (idx > 0)
1275       {
1276         new_set.insert(idx - 1);
1277       }
1278     }
1279     idx_set = std::move(new_set);
1280   }
1281 
1282   for (auto& [pid, dq] : m_PacketEventDeque)
1283   {
1284     if (!dq.empty())
1285     {
1286       dq.pop_front();
1287     }
1288   }
1289 
1290   return Fun4AllReturnCodes::EVENT_OK;
1291 }
1292