Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-17 09:19:49

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