Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:21:34

0001 #include "L1Trigger/Phase2L1ParticleFlow/interface/L1TCorrelatorLayer1PatternFileWriter.h"
0002 #include "FWCore/Utilities/interface/Exception.h"
0003 #include "FWCore/ParameterSet/interface/allowedValues.h"
0004 #include <iostream>
0005 
0006 L1TCorrelatorLayer1PatternFileWriter::L1TCorrelatorLayer1PatternFileWriter(const edm::ParameterSet& iConfig,
0007                                                                            const l1ct::Event& eventTemplate)
0008     : partition_(parsePartition(iConfig.getParameter<std::string>("partition"))),
0009       tmuxFactor_(iConfig.getParameter<uint32_t>("tmuxFactor")),
0010       writeInputs_(!iConfig.getParameter<std::string>("inputFileName").empty()),
0011       writeOutputs_(!iConfig.getParameter<std::string>("outputFileName").empty()),
0012       tfTimeslices_(std::max(1u, tfTmuxFactor_ / tmuxFactor_)),
0013       hgcTimeslices_(std::max(1u, hgcTmuxFactor_ / tmuxFactor_)),
0014       gctTimeslices_(std::max(1u, gctTmuxFactor_ / tmuxFactor_)),
0015       gmtTimeslices_(std::max(1u, gmtTmuxFactor_ / tmuxFactor_)),
0016       gttTimeslices_(std::max(1u, gttTmuxFactor_ / tmuxFactor_)),
0017       outputBoard_(-1),
0018       outputLinkEgamma_(-1),
0019       fileFormat_(iConfig.getParameter<std::string>("fileFormat")),
0020       eventsPerFile_(iConfig.getParameter<uint32_t>("eventsPerFile")),
0021       eventIndex_(0) {
0022   if (writeInputs_) {
0023     nInputFramesPerBX_ = iConfig.getParameter<uint32_t>("nInputFramesPerBX");
0024 
0025     if (partition_ == Partition::Barrel || partition_ == Partition::HGCal) {
0026       configTimeSlices(iConfig, "tf", eventTemplate.raw.track.size(), tfTimeslices_, tfLinksFactor_);
0027       channelSpecsInput_["tf"] = {tfTmuxFactor_, tfTimeslices_};
0028     }
0029     if (partition_ == Partition::Barrel) {
0030       auto sectorConfig = iConfig.getParameter<std::vector<edm::ParameterSet>>("gctSectors");
0031       if (sectorConfig.size() != gctSectors_)
0032         throw cms::Exception("Configuration", "Bad number of GCT sectors");
0033       for (unsigned int iS = 0; iS < gctSectors_; ++iS) {
0034         auto linksEcal = sectorConfig[iS].getParameter<std::vector<int32_t>>("gctLinksEcal");
0035         auto linksHad = sectorConfig[iS].getParameter<std::vector<int32_t>>("gctLinksHad");
0036         if (linksEcal.size() != gctLinksEcal_ || linksHad.size() != gctLinksHad_)
0037           throw cms::Exception("Configuration", "Bad number of GCT links");
0038         unsigned int iLink = 0;
0039         for (unsigned int i = 0; i < gctLinksHad_; ++i, ++iLink) {
0040           if (linksHad[i] != -1)
0041             channelIdsInput_[l1t::demo::LinkId{"gct", iLink + 10 * iS}].push_back(linksHad[i]);
0042         }
0043         for (unsigned int i = 0; i < gctLinksEcal_; ++i) {
0044           if (linksEcal[i] != -1)
0045             channelIdsInput_[l1t::demo::LinkId{"gct", iLink + 10 * iS}].push_back(linksEcal[i]);
0046         }
0047         channelSpecsInput_["gct"] = {tmuxFactor_ * gctTimeslices_, 0};
0048       }
0049     }
0050     if (partition_ == Partition::HGCal || partition_ == Partition::HGCalNoTk) {
0051       configTimeSlices(iConfig, "hgc", eventTemplate.raw.hgcalcluster.size(), hgcTimeslices_, hgcLinksFactor_);
0052       channelSpecsInput_["hgc"] = {tmuxFactor_ * hgcTimeslices_, hgcTimeslices_};
0053     }
0054     if (partition_ == Partition::Barrel || partition_ == Partition::HGCal || partition_ == Partition::HGCalNoTk) {
0055       configTimeSlices(iConfig, "gmt", 1, gmtTimeslices_, gmtLinksFactor_);
0056       gmtNumberOfMuons_ = iConfig.getParameter<uint32_t>("gmtNumberOfMuons");
0057       channelSpecsInput_["gmt"] = {tmuxFactor_ * gmtTimeslices_,
0058                                    gmtTimeslices_ * nInputFramesPerBX_ * tmuxFactor_ - gmtNumberOfMuons_};
0059     }
0060     if (partition_ == Partition::Barrel || partition_ == Partition::HGCal) {
0061       configTimeSlices(iConfig, "gtt", 1, gttTimeslices_, gttLinksFactor_);
0062       gttLatency_ = iConfig.getParameter<uint32_t>("gttLatency");
0063       gttNumberOfPVs_ = iConfig.getParameter<uint32_t>("gttNumberOfPVs");
0064       channelSpecsInput_["gtt"] = l1t::demo::ChannelSpec{tmuxFactor_ * gttTimeslices_, 1, gttLatency_};
0065     }
0066     inputFileWriter_ =
0067         std::make_unique<l1t::demo::BoardDataWriter>(l1t::demo::parseFileFormat(fileFormat_),
0068                                                      iConfig.getParameter<std::string>("inputFileName"),
0069                                                      iConfig.getParameter<std::string>("inputFileExtension"),
0070                                                      nInputFramesPerBX_,
0071                                                      tmuxFactor_,
0072                                                      iConfig.getParameter<uint32_t>("maxLinesPerInputFile"),
0073                                                      channelIdsInput_,
0074                                                      channelSpecsInput_);
0075   }
0076 
0077   if (writeOutputs_) {
0078     nOutputFramesPerBX_ = iConfig.getParameter<uint32_t>("nOutputFramesPerBX");
0079 
0080     outputRegions_ = iConfig.getParameter<std::vector<uint32_t>>("outputRegions");
0081     outputLinksPuppi_ = iConfig.getParameter<std::vector<uint32_t>>("outputLinksPuppi");
0082     for (unsigned int i = 0; i < outputLinksPuppi_.size(); ++i) {
0083       channelIdsOutput_[l1t::demo::LinkId{"puppi", i}].push_back(outputLinksPuppi_[i]);
0084     }
0085     channelSpecsOutput_["puppi"] = {tmuxFactor_, 0};
0086     nPuppiFramesPerRegion_ = (nOutputFramesPerBX_ * tmuxFactor_) / outputRegions_.size();
0087     if (partition_ == Partition::Barrel || partition_ == Partition::HGCal) {
0088       outputLinkEgamma_ = iConfig.getParameter<int32_t>("outputLinkEgamma");
0089       nEgammaObjectsOut_ = iConfig.getParameter<uint32_t>("nEgammaObjectsOut");
0090       if (outputLinkEgamma_ != -1) {
0091         channelIdsOutput_[l1t::demo::LinkId{"egamma", 0}].push_back(outputLinkEgamma_);
0092         if (partition_ == Partition::HGCal && tmuxFactor_ == 18) {
0093           // the format is different, as we put together both endcaps
0094           channelSpecsOutput_["egamma"] = {tmuxFactor_, nOutputFramesPerBX_ * tmuxFactor_ / 2 - 3 * nEgammaObjectsOut_};
0095         } else {
0096           outputBoard_ = iConfig.getParameter<int32_t>("outputBoard");
0097           channelSpecsOutput_["egamma"] = {tmuxFactor_, nOutputFramesPerBX_ * tmuxFactor_ - 3 * nEgammaObjectsOut_};
0098         }
0099       }
0100     }
0101     outputFileWriter_ =
0102         std::make_unique<l1t::demo::BoardDataWriter>(l1t::demo::parseFileFormat(fileFormat_),
0103                                                      iConfig.getParameter<std::string>("outputFileName"),
0104                                                      iConfig.getParameter<std::string>("outputFileExtension"),
0105                                                      nOutputFramesPerBX_,
0106                                                      tmuxFactor_,
0107                                                      iConfig.getParameter<uint32_t>("maxLinesPerOutputFile"),
0108                                                      channelIdsOutput_,
0109                                                      channelSpecsOutput_);
0110   }
0111 }
0112 
0113 L1TCorrelatorLayer1PatternFileWriter::~L1TCorrelatorLayer1PatternFileWriter() {}
0114 
0115 edm::ParameterSetDescription L1TCorrelatorLayer1PatternFileWriter::getParameterSetDescription() {
0116   edm::ParameterSetDescription description;
0117   description.add<std::string>("inputFileName", "");
0118   description.add<std::string>("inputFileExtension", "txt.gz");
0119   description.add<uint32_t>("maxLinesPerInputFile", 1024u);
0120   description.add<uint32_t>("nInputFramesPerBX", 9u);
0121   description.add<std::string>("outputFileName", "");
0122   description.add<std::string>("outputFileExtension", "txt.gz");
0123   description.add<uint32_t>("maxLinesPerOutputFile", 1024u);
0124   description.add<uint32_t>("nOutputFramesPerBX", 9u);
0125   description.add<uint32_t>("tmuxFactor", 6u);
0126   description.add<uint32_t>("eventsPerFile", 12u);
0127   description.add<std::string>("fileFormat");
0128 
0129   description.ifValue(edm::ParameterDescription<std::string>("partition", "Barrel", true),
0130                       "Barrel" >> (describeTF() and describeGCT() and describeGTT() and describeGMT() and
0131                                    describePuppi() and describeEG()) or
0132                           "HGCal" >> (describeTF() and describeHGC() and describeGTT() and describeGMT() and
0133                                       describePuppi() and describeEG()) or
0134                           "HGCalNoTk" >> (describeHGC() and describeGMT() and describePuppi()) or
0135                           "HF" >> (describePuppi()));
0136   return description;
0137 }
0138 
0139 std::unique_ptr<edm::ParameterDescriptionNode> L1TCorrelatorLayer1PatternFileWriter::describeTF() {
0140   return describeTimeSlices("tf");
0141 }
0142 std::unique_ptr<edm::ParameterDescriptionNode> L1TCorrelatorLayer1PatternFileWriter::describeGCT() {
0143   edm::ParameterSetDescription gctSectorPSD;
0144   gctSectorPSD.add<std::vector<int32_t>>("gctLinksEcal");
0145   gctSectorPSD.add<std::vector<int32_t>>("gctLinksHad");
0146   return std::make_unique<edm::ParameterDescription<std::vector<edm::ParameterSet>>>("gctSectors", gctSectorPSD, true);
0147 }
0148 std::unique_ptr<edm::ParameterDescriptionNode> L1TCorrelatorLayer1PatternFileWriter::describeHGC() {
0149   return describeTimeSlices("hgc");
0150 }
0151 std::unique_ptr<edm::ParameterDescriptionNode> L1TCorrelatorLayer1PatternFileWriter::describeGMT() {
0152   return describeTimeSlices("gmt") and edm::ParameterDescription<uint32_t>("gmtNumberOfMuons", 12, true);
0153 }
0154 std::unique_ptr<edm::ParameterDescriptionNode> L1TCorrelatorLayer1PatternFileWriter::describeGTT() {
0155   return describeTimeSlices("gtt") and
0156          edm::ParameterDescription<uint32_t>("gttLatency", 162, true) and  // minimal latency is 18 BX
0157          edm::ParameterDescription<uint32_t>("gttNumberOfPVs", 10, true);
0158 }
0159 std::unique_ptr<edm::ParameterDescriptionNode> L1TCorrelatorLayer1PatternFileWriter::describePuppi() {
0160   return edm::ParameterDescription<std::vector<uint32_t>>("outputRegions", std::vector<uint32_t>(), true) and
0161          edm::ParameterDescription<std::vector<uint32_t>>("outputLinksPuppi", std::vector<uint32_t>(), true);
0162 }
0163 std::unique_ptr<edm::ParameterDescriptionNode> L1TCorrelatorLayer1PatternFileWriter::describeEG() {
0164   return edm::ParameterDescription<int32_t>("outputLinkEgamma", -1, true) and
0165          edm::ParameterDescription<uint32_t>("nEgammaObjectsOut", 16, true) and
0166          edm::ParameterDescription<int32_t>("outputBoard", -1, true);
0167 }
0168 
0169 void L1TCorrelatorLayer1PatternFileWriter::write(const l1ct::Event& event) {
0170   if (writeInputs_) {
0171     l1t::demo::EventData inputs;
0172     if (partition_ == Partition::Barrel || partition_ == Partition::HGCal) {
0173       writeTF(event, inputs);
0174     }
0175     if (partition_ == Partition::Barrel) {
0176       writeBarrelGCT(event, inputs);
0177     }
0178     if (partition_ == Partition::HGCal || partition_ == Partition::HGCalNoTk) {
0179       writeHGC(event, inputs);
0180     }
0181     if (partition_ == Partition::Barrel || partition_ == Partition::HGCal || partition_ == Partition::HGCalNoTk) {
0182       writeGMT(event, inputs);
0183     }
0184     if (partition_ == Partition::Barrel || partition_ == Partition::HGCal) {
0185       writeGTT(event, inputs);
0186     }
0187     inputFileWriter_->addEvent(inputs);
0188   }
0189 
0190   if (writeOutputs_) {
0191     l1t::demo::EventData outputs;
0192     writePuppi(event, outputs);
0193     if (outputLinkEgamma_ != -1)
0194       writeEgamma(event, outputs);
0195     outputFileWriter_->addEvent(outputs);
0196   }
0197 
0198   eventIndex_++;
0199   if (eventIndex_ % eventsPerFile_ == 0) {
0200     if (writeInputs_)
0201       inputFileWriter_->flush();
0202     if (writeOutputs_)
0203       outputFileWriter_->flush();
0204   }
0205 }
0206 
0207 L1TCorrelatorLayer1PatternFileWriter::Partition L1TCorrelatorLayer1PatternFileWriter::parsePartition(
0208     const std::string& partition) {
0209   if (partition == "Barrel")
0210     return Partition::Barrel;
0211   if (partition == "HGCal")
0212     return Partition::HGCal;
0213   if (partition == "HGCalNoTk")
0214     return Partition::HGCalNoTk;
0215   if (partition == "HF")
0216     return Partition::HF;
0217   throw cms::Exception("Configuration", "Unsupported partition_ '" + partition + "'\n");
0218 }
0219 
0220 void L1TCorrelatorLayer1PatternFileWriter::configTimeSlices(const edm::ParameterSet& iConfig,
0221                                                             const std::string& prefix,
0222                                                             unsigned int nSectors,
0223                                                             unsigned int nTimeSlices,
0224                                                             unsigned int linksFactor) {
0225   if (nTimeSlices > 1) {
0226     auto timeSliceConfig = iConfig.getParameter<std::vector<edm::ParameterSet>>(prefix + "TimeSlices");
0227     if (timeSliceConfig.size() != nTimeSlices)
0228       throw cms::Exception("Configuration")
0229           << "Mismatched number of " << prefix << "TimeSlices, expected " << nTimeSlices << std::endl;
0230     for (unsigned int iT = 0; iT < nTimeSlices; ++iT) {
0231       configSectors(timeSliceConfig[iT], prefix, nSectors, linksFactor);
0232     }
0233   } else {
0234     configSectors(iConfig, prefix, nSectors, linksFactor);
0235   }
0236 }
0237 
0238 std::unique_ptr<edm::ParameterDescriptionNode> L1TCorrelatorLayer1PatternFileWriter::describeTimeSlices(
0239     const std::string& prefix) {
0240   edm::ParameterSetDescription timeslicesPSD;
0241   timeslicesPSD.addNode(describeSectors(prefix));
0242   return edm::ParameterDescription<std::vector<edm::ParameterSet>>(prefix + "TimeSlices", timeslicesPSD, true) xor
0243          describeSectors(prefix);
0244 }
0245 
0246 void L1TCorrelatorLayer1PatternFileWriter::configSectors(const edm::ParameterSet& iConfig,
0247                                                          const std::string& prefix,
0248                                                          unsigned int nSectors,
0249                                                          unsigned int linksFactor) {
0250   if (nSectors > 1) {
0251     auto sectorConfig = iConfig.getParameter<std::vector<edm::ParameterSet>>(prefix + "Sectors");
0252     if (sectorConfig.size() != nSectors)
0253       throw cms::Exception("Configuration")
0254           << "Mismatched number of " << prefix << "Sectors, expected " << nSectors << std::endl;
0255     for (unsigned int iS = 0; iS < nSectors; ++iS) {
0256       configLinks(sectorConfig[iS], prefix, linksFactor, linksFactor > 1 ? iS * 10 : iS);
0257     }
0258   } else {
0259     configLinks(iConfig, prefix, linksFactor, 0);
0260   }
0261 }
0262 
0263 std::unique_ptr<edm::ParameterDescriptionNode> L1TCorrelatorLayer1PatternFileWriter::describeSectors(
0264     const std::string& prefix) {
0265   edm::ParameterSetDescription sectorsPSD;
0266   sectorsPSD.addNode(describeLinks(prefix));
0267   return edm::ParameterDescription<std::vector<edm::ParameterSet>>(prefix + "Sectors", sectorsPSD, true) xor
0268          describeLinks(prefix);
0269 }
0270 
0271 void L1TCorrelatorLayer1PatternFileWriter::configLinks(const edm::ParameterSet& iConfig,
0272                                                        const std::string& prefix,
0273                                                        unsigned int linksFactor,
0274                                                        unsigned int offset) {
0275   if (linksFactor > 1) {
0276     auto links = iConfig.getParameter<std::vector<int32_t>>(prefix + "Links");
0277     if (links.size() != linksFactor)
0278       throw cms::Exception("Configuration")
0279           << "Mismatched number of " << prefix << "Links, expected " << linksFactor << std::endl;
0280     for (unsigned int i = 0; i < linksFactor; ++i) {
0281       if (links[i] != -1) {
0282         channelIdsInput_[l1t::demo::LinkId{prefix, i + offset}].push_back(links[i]);
0283       }
0284     }
0285   } else {
0286     auto link = iConfig.getParameter<int32_t>(prefix + "Link");
0287     if (link != -1) {
0288       channelIdsInput_[l1t::demo::LinkId{prefix, offset}].push_back(link);
0289     }
0290   }
0291 }
0292 
0293 std::unique_ptr<edm::ParameterDescriptionNode> L1TCorrelatorLayer1PatternFileWriter::describeLinks(
0294     const std::string& prefix) {
0295   return edm::ParameterDescription<int32_t>(prefix + "Link", true) xor
0296          edm::ParameterDescription<std::vector<int32_t>>(prefix + "Links", true);
0297 }
0298 
0299 void L1TCorrelatorLayer1PatternFileWriter::writeTF(const l1ct::Event& event, l1t::demo::EventData& out) {
0300   for (unsigned int iS = 0, nS = event.raw.track.size(); iS < nS; ++iS) {
0301     l1t::demo::LinkId key{"tf", iS};
0302     if (channelIdsInput_.count(key) == 0)
0303       continue;
0304     std::vector<ap_uint<64>> ret;
0305     std::vector<ap_uint<96>> tracks = event.raw.track[iS].obj;
0306     if (tracks.empty())
0307       tracks.emplace_back(0);
0308     for (unsigned int i = 0, n = tracks.size(); i < n; ++i) {
0309       const ap_uint<96>& packedtk = tracks[i];
0310       if (i % 2 == 0) {
0311         ret.emplace_back(packedtk(63, 0));
0312         ret.emplace_back(0);
0313         ret.back()(31, 0) = packedtk(95, 64);
0314       } else {
0315         ret.back()(63, 32) = packedtk(31, 0);
0316         ret.emplace_back(packedtk(95, 32));
0317       }
0318     }
0319     out.add(key, ret);
0320   }
0321 }
0322 
0323 void L1TCorrelatorLayer1PatternFileWriter::writeHGC(const l1ct::Event& event, l1t::demo::EventData& out) {
0324   assert(hgcLinksFactor_ == 4);  // this piece of code won't really work otherwise
0325   std::vector<ap_uint<64>> ret[hgcLinksFactor_];
0326   for (unsigned int iS = 0, nS = event.raw.hgcalcluster.size(); iS < nS; ++iS) {
0327     l1t::demo::LinkId key0{"hgc", iS * 10};
0328     if (channelIdsInput_.count(key0) == 0)
0329       continue;
0330     for (unsigned int il = 0; il < hgcLinksFactor_; ++il) {
0331       // put header word and (dummy) towers
0332       ret[il].resize(31);
0333       ap_uint<64>& head64 = ret[il][0];
0334       head64(63, 48) = 0xABC0;                                        // Magic
0335       head64(47, 38) = 0;                                             // Opaque
0336       head64(39, 32) = (eventIndex_ % hgcTimeslices_) * tmuxFactor_;  // TM slice
0337       head64(31, 24) = iS;                                            // Sector
0338       head64(23, 16) = il;                                            // link
0339       head64(15, 0) = eventIndex_ % 3564;                             // BX
0340       for (unsigned int j = 0; j < 30; ++j) {
0341         ret[il][j + 1] = 4 * j + il;
0342       }
0343     }
0344     for (auto clust : event.raw.hgcalcluster[iS].obj) {
0345       for (unsigned int il = 0; il < hgcLinksFactor_; ++il) {
0346         ret[il].push_back(clust(64 * il + 63, 64 * il));
0347       }
0348     }
0349     for (unsigned int il = 0; il < hgcLinksFactor_; ++il) {
0350       out.add(l1t::demo::LinkId{"hgc", iS * 10 + il}, ret[il]);
0351     }
0352   }
0353 }
0354 
0355 void L1TCorrelatorLayer1PatternFileWriter::writeBarrelGCT(const l1ct::Event& event, l1t::demo::EventData& out) {
0356   std::vector<ap_uint<64>> ret;
0357   for (unsigned int iS = 0; iS < gctSectors_; ++iS) {
0358     l1t::demo::LinkId key0{"gct", iS * 10};
0359     if (channelIdsInput_.count(key0) == 0)
0360       continue;
0361     const auto& had = event.decoded.hadcalo[iS];
0362     const auto& ecal = event.decoded.emcalo[iS];
0363     unsigned int iLink = 0, nHad = had.size(), nEcal = ecal.size();
0364     for (unsigned int i = 0; i < gctLinksHad_; ++i, ++iLink) {
0365       ret.clear();
0366       for (unsigned int iHad = i; iHad < nHad; iHad += gctLinksHad_) {
0367         ret.emplace_back(had[iHad].pack());
0368       }
0369       if (ret.empty())
0370         ret.emplace_back(0);
0371       out.add(l1t::demo::LinkId{"gct", iS * 10 + iLink}, ret);
0372     }
0373     for (unsigned int i = 0; i < gctLinksEcal_; ++i, ++iLink) {
0374       ret.clear();
0375       for (unsigned int iEcal = i; iEcal < nEcal; iEcal += gctLinksEcal_) {
0376         ret.emplace_back(ecal[iEcal].pack());
0377       }
0378       if (ret.empty())
0379         ret.emplace_back(0);
0380       out.add(l1t::demo::LinkId{"gct", iS * 10 + iLink}, ret);
0381     }
0382   }
0383 }
0384 
0385 void L1TCorrelatorLayer1PatternFileWriter::writeGMT(const l1ct::Event& event, l1t::demo::EventData& out) {
0386   l1t::demo::LinkId key{"gmt", 0};
0387   if (channelIdsInput_.count(key) == 0)
0388     return;
0389   std::vector<ap_uint<64>> muons = event.raw.muon.obj;
0390   muons.resize(gmtNumberOfMuons_, ap_uint<64>(0));
0391   out.add(key, muons);
0392 }
0393 
0394 void L1TCorrelatorLayer1PatternFileWriter::writeGTT(const l1ct::Event& event, l1t::demo::EventData& out) {
0395   l1t::demo::LinkId key{"gtt", 0};
0396   if (channelIdsInput_.count(key) == 0)
0397     return;
0398   std::vector<ap_uint<64>> pvs = event.pvs_emu;
0399   pvs.resize(gttNumberOfPVs_, ap_uint<64>(0));
0400   out.add(key, pvs);
0401 }
0402 
0403 void L1TCorrelatorLayer1PatternFileWriter::writePuppi(const l1ct::Event& event, l1t::demo::EventData& out) {
0404   unsigned int n = outputLinksPuppi_.size();
0405   std::vector<std::vector<ap_uint<64>>> links(n);
0406   for (auto ir : outputRegions_) {
0407     auto puppi = event.out[ir].puppi;
0408     unsigned int npuppi = puppi.size();
0409     for (unsigned int i = 0; i < n * nPuppiFramesPerRegion_; ++i) {
0410       links[i / nPuppiFramesPerRegion_].push_back(i < npuppi ? puppi[i].pack() : ap_uint<l1ct::PuppiObj::BITWIDTH>(0));
0411     }
0412   }
0413   for (unsigned int i = 0; i < n; ++i) {
0414     out.add(l1t::demo::LinkId{"puppi", i}, links[i]);
0415   }
0416 }
0417 
0418 void L1TCorrelatorLayer1PatternFileWriter::writeEgamma(const l1ct::OutputBoard& egboard,
0419                                                        std::vector<ap_uint<64>>& ret) {
0420   unsigned int s0 = ret.size();
0421   const auto& pho = egboard.egphoton;
0422   const auto& ele = egboard.egelectron;
0423   ret.reserve(s0 + 3 * nEgammaObjectsOut_);
0424   for (const auto& p : pho) {
0425     ret.emplace_back(p.pack());
0426   }
0427   ret.resize(s0 + nEgammaObjectsOut_, ap_uint<64>(0));
0428   for (const auto& p : ele) {
0429     ap_uint<128> dword = p.pack();
0430     ret.push_back(dword(63, 0));
0431     ret.push_back(dword(127, 64));
0432   }
0433   ret.resize(s0 + 3 * nEgammaObjectsOut_, ap_uint<64>(0));
0434 }
0435 
0436 void L1TCorrelatorLayer1PatternFileWriter::writeEgamma(const l1ct::Event& event, l1t::demo::EventData& out) {
0437   std::vector<ap_uint<64>> ret;
0438   if (partition_ == Partition::HGCal && tmuxFactor_ == 18) {
0439     // the format is different, as we put together both endcaps
0440     writeEgamma(event.board_out[0], ret);
0441     ret.resize(nOutputFramesPerBX_ * tmuxFactor_ / 2, ap_uint<64>(0));
0442     writeEgamma(event.board_out[1], ret);
0443   } else {
0444     writeEgamma(event.board_out[outputBoard_], ret);
0445   }
0446   out.add(l1t::demo::LinkId{"egamma", 0}, ret);
0447 }
0448 
0449 void L1TCorrelatorLayer1PatternFileWriter::flush() {
0450   if (inputFileWriter_)
0451     inputFileWriter_->flush();
0452   if (outputFileWriter_)
0453     outputFileWriter_->flush();
0454 }