Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:19:39

0001 #include "L1Trigger/DemonstratorTools/interface/BoardDataWriter.h"
0002 
0003 #include <fstream>
0004 
0005 #include "L1Trigger/DemonstratorTools/interface/Frame.h"
0006 #include "L1Trigger/DemonstratorTools/interface/utilities.h"
0007 
0008 namespace l1t::demo {
0009 
0010   BoardDataWriter::BoardDataWriter(FileFormat format,
0011                                    const std::string& path,
0012                                    const std::string& fileExt,
0013                                    const size_t framesPerBX,
0014                                    const size_t tmux,
0015                                    const size_t maxFramesPerFile,
0016                                    const ChannelMap_t& channelSpecs)
0017       : fileFormat_(format),
0018         boardDataFileID_("CMSSW"),
0019         filePathGen_([=](const size_t i) { return path + "_" + std::to_string(i) + "." + fileExt; }),
0020         framesPerBX_(framesPerBX),
0021         boardTMUX_(tmux),
0022         maxFramesPerFile_(maxFramesPerFile),
0023         maxEventsPerFile_(maxFramesPerFile_),
0024         eventIndex_(0),
0025         pendingEvents_(0),
0026         channelMap_(channelSpecs) {
0027     if (channelMap_.empty())
0028       throw std::runtime_error("BoardDataWriter channel map cannnot be empty");
0029     if (fileExt != "txt" && fileExt != "txt.gz" && fileExt != "txt.xz")
0030       throw std::runtime_error("BoardDataWriter fileExt must be one of txt, txt.gz, txt.xz");
0031 
0032     for (const auto& [id, value] : channelMap_) {
0033       const auto& [spec, indices] = value;
0034       for (const auto i : indices)
0035         boardData_.add(i);
0036 
0037       if ((spec.tmux % boardTMUX_) != 0)
0038         throw std::runtime_error("BoardDataWriter, link [" + id.interface + ", " + std::to_string(id.channel) +
0039                                  "]: Specified TMUX period, " + std::to_string(spec.tmux) +
0040                                  ", is not a multiple of the board TMUX, " + std::to_string(boardTMUX_));
0041 
0042       const size_t tmuxRatio(spec.tmux / boardTMUX_);
0043       if (indices.size() != tmuxRatio)
0044         throw std::runtime_error("BoardDataWriter, link [" + id.interface + ", " + std::to_string(id.channel) +
0045                                  "]: Number of channel indices specified, " + std::to_string(indices.size()) +
0046                                  ", does not match link:board TMUX ratio, " + std::to_string(tmuxRatio));
0047 
0048       maxEventsPerFile_ = std::min(maxEventsPerFile_,
0049                                    ((maxFramesPerFile_ - spec.offset) / (framesPerBX_ * boardTMUX_)) - (tmuxRatio - 1));
0050     }
0051 
0052     resetBoardData();
0053   }
0054 
0055   BoardDataWriter::BoardDataWriter(FileFormat format,
0056                                    const std::string& path,
0057                                    const std::string& fileExt,
0058                                    const size_t framesPerBX,
0059                                    const size_t tmux,
0060                                    const size_t maxFramesPerFile,
0061                                    const std::map<LinkId, std::vector<size_t>>& channelMap,
0062                                    const std::map<std::string, ChannelSpec>& channelSpecs)
0063       : BoardDataWriter(
0064             format, path, fileExt, framesPerBX, tmux, maxFramesPerFile, mergeMaps(channelMap, channelSpecs)) {}
0065 
0066   void BoardDataWriter::setBoardDataFileID(const std::string& aId) { boardDataFileID_ = aId; }
0067 
0068   void BoardDataWriter::addEvent(const EventData& eventData) {
0069     // Check that data is supplied for each channel
0070     for (const auto& [id, info] : channelMap_) {
0071       if (not eventData.has(id))
0072         throw std::runtime_error("Event data for link [" + id.interface + ", " + std::to_string(id.channel) +
0073                                  "] is missing.");
0074     }
0075 
0076     for (const auto& [id, channelData] : eventData) {
0077       // Check that each channel was declared to constructor
0078       if (channelMap_.count(id) == 0)
0079         throw std::runtime_error("Event data for link [" + id.interface + ", " + std::to_string(id.channel) +
0080                                  "] was given to BoardDataWriter, but its structure was not defined");
0081 
0082       const auto& [spec, indices] = channelMap_.at(id);
0083       const size_t chanIndex(indices.at(pendingEvents_ % (spec.tmux / boardTMUX_)));
0084 
0085       // Check that that expected amount of data has been provided
0086       if (channelData.size() > (spec.tmux * framesPerBX_ - spec.interpacketGap))
0087         throw std::runtime_error("Event data for link [" + id.interface + ", " + std::to_string(id.channel) +
0088                                  "] (TMUX " + std::to_string(spec.tmux) + ", " + std::to_string(spec.interpacketGap) +
0089                                  " cycles between packets) is too long (" + std::to_string(channelData.size()) +
0090                                  " 64-bit words)");
0091 
0092       if (channelData.empty())
0093         throw std::runtime_error("Event data for link [" + id.interface + ", " + std::to_string(id.channel) +
0094                                  "] is empty");
0095 
0096       // Copy event data for this channel to board data object
0097       boardData_.at(chanIndex).insert(boardData_.at(chanIndex).end(), channelData.begin(), channelData.end());
0098 
0099       // Override flags for start & end of event
0100       BoardData::Channel::iterator it(boardData_.at(chanIndex).end() - 1);
0101       it->endOfPacket = true;
0102       it -= (channelData.size() - 1);
0103       it->startOfPacket = true;
0104 
0105       // Pad link with non-valid frames
0106       boardData_.at(chanIndex).insert(
0107           boardData_.at(chanIndex).end(), spec.tmux * framesPerBX_ - channelData.size(), Frame());
0108     }
0109 
0110     eventIndex_++;
0111     pendingEvents_++;
0112 
0113     if (pendingEvents_ == maxEventsPerFile_)
0114       flush();
0115   }
0116 
0117   void BoardDataWriter::flush() {
0118     if (pendingEvents_ == 0)
0119       return;
0120 
0121     // Pad any channels that aren't full with invalid frames
0122     for (auto& x : boardData_)
0123       x.second.resize(maxFramesPerFile_);
0124 
0125     // For each channel: Assert start_of_orbit for first clock cycle that start is asserted
0126     for (auto& x : boardData_) {
0127       for (auto& frame : x.second) {
0128         if (frame.startOfPacket) {
0129           frame.startOfOrbit = true;
0130           break;
0131         }
0132       }
0133     }
0134 
0135     // Set ID field for board data files
0136     boardData_.name(boardDataFileID_);
0137 
0138     // Write board data object to file
0139     const std::string filePath = filePathGen_(fileNames_.size());
0140     write(boardData_, filePath, fileFormat_);
0141     fileNames_.push_back(filePath);
0142 
0143     // Clear board data to be ready for next event
0144     resetBoardData();
0145   }
0146 
0147   BoardDataWriter::ChannelMap_t BoardDataWriter::mergeMaps(const std::map<LinkId, std::vector<size_t>>& indexMap,
0148                                                            const std::map<std::string, ChannelSpec>& specMap) {
0149     ChannelMap_t channelMap;
0150     for (const auto& x : indexMap)
0151       channelMap[x.first] = {specMap.at(x.first.interface), x.second};
0152     return channelMap;
0153   }
0154 
0155   void BoardDataWriter::resetBoardData() {
0156     for (auto& x : boardData_)
0157       x.second.clear();
0158 
0159     for (const auto& [id, value] : channelMap_) {
0160       const auto& [spec, indices] = value;
0161       for (size_t tmuxIndex = 0; tmuxIndex < indices.size(); tmuxIndex++)
0162         boardData_.at(indices.at(tmuxIndex)).resize(tmuxIndex * boardTMUX_ * framesPerBX_ + spec.offset);
0163     }
0164 
0165     pendingEvents_ = 0;
0166   }
0167 
0168 }  // namespace l1t::demo