File indexing completed on 2022-04-01 23:54:04
0001 #include "L1Trigger/DemonstratorTools/interface/utilities.h"
0002
0003 #include <algorithm>
0004 #include <fstream>
0005 #include <regex>
0006 #include <unordered_map>
0007
0008 #ifdef CMSSW_GIT_HASH
0009 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0010 #endif
0011 #include "L1Trigger/DemonstratorTools/interface/BoardData.h"
0012
0013 namespace {
0014
0015 l1t::demo::BoardData createBoardDataFromRows(const std::string& id,
0016 const std::vector<size_t>& channels,
0017 const std::vector<std::vector<l1t::demo::Frame>>& dataRows) {
0018 l1t::demo::BoardData boardData(id);
0019
0020 for (size_t i = 0; i < channels.size(); i++) {
0021 std::vector<l1t::demo::Frame> channelData(dataRows.size());
0022 for (size_t j = 0; j < dataRows.size(); j++)
0023 channelData.at(j) = dataRows.at(j).at(i);
0024 boardData.add(channels.at(i), channelData);
0025 }
0026
0027 return boardData;
0028 }
0029
0030 std::vector<std::string> searchAndTokenize(std::istream& file, const std::string& linePrefix) {
0031 std::string line;
0032
0033 while (getline(file, line)) {
0034
0035 size_t startIndex = line.find_first_not_of(" \t");
0036 if (startIndex != std::string::npos)
0037 line = line.substr(startIndex);
0038
0039 if (line.empty())
0040 continue;
0041 if (line[0] == '#')
0042 continue;
0043
0044 if (line.rfind(linePrefix, 0) != std::string::npos) {
0045 std::vector<std::string> tokens;
0046
0047
0048 const std::regex delimiterRegex("\\s+");
0049 std::sregex_token_iterator it(line.begin() + linePrefix.size(), line.end(), delimiterRegex, -1);
0050
0051 for (; it != std::sregex_token_iterator(); it++) {
0052 const std::string token(it->str());
0053 if (token.empty())
0054 continue;
0055 tokens.push_back(token);
0056 }
0057
0058 return tokens;
0059 } else
0060 throw std::logic_error("Found unexpected line found when searching for \"" + linePrefix + "\": \"" + line +
0061 "\"");
0062 }
0063 throw std::logic_error("Couldn't find any line starting with \"" + linePrefix + "\"");
0064 }
0065
0066 }
0067
0068 namespace l1t::demo {
0069
0070 FileFormat parseFileFormat(const std::string& s) {
0071 static const std::unordered_map<std::string, FileFormat> kFormatStringMap({{"EMP", FileFormat::EMP},
0072 {"emp", FileFormat::EMP},
0073 {"APx", FileFormat::APx},
0074 {"apx", FileFormat::APx},
0075 {"X20", FileFormat::X20},
0076 {"x20", FileFormat::X20}});
0077
0078 const auto it = kFormatStringMap.find(s);
0079 if (it == kFormatStringMap.end())
0080 throw std::runtime_error("Could not convert '" + s + "' to FileFormat enum value");
0081
0082 return it->second;
0083 }
0084
0085 BoardData readAPxFile(std::istream&, const FileFormat);
0086
0087 BoardData readEMPFile(std::istream&, const FileFormat);
0088
0089 BoardData readX20File(std::istream&, const FileFormat);
0090
0091 BoardData read(const std::string& filePath, const FileFormat format) {
0092 std::ifstream file(filePath);
0093
0094 if (not file.is_open())
0095 throw std::runtime_error("Could not open file '" + filePath + "'");
0096
0097 return read(file, format);
0098 }
0099
0100 BoardData read(std::istream& file, const FileFormat format) {
0101 if (format == FileFormat::APx)
0102 return readAPxFile(file, format);
0103 else if (format == FileFormat::EMP)
0104 return readEMPFile(file, format);
0105 else
0106 return readX20File(file, format);
0107 }
0108
0109 BoardData readAPxFile(std::istream& file, const FileFormat format) {
0110 std::string line;
0111
0112
0113 if (not std::getline(file, line))
0114 throw std::runtime_error("Specified file is empty!");
0115
0116
0117 if (line.find("#Sideband") == 0) {
0118 if (not std::getline(file, line))
0119 throw std::runtime_error("APx file has incorrect format: Link labels and data missing!");
0120 }
0121
0122
0123 if (line.find("#LinkLabel") != 0)
0124 throw std::runtime_error(
0125 "APx file has incorrect format: Link header does not start with '#LinkLabel' (line is '" + line + "')");
0126
0127 std::vector<size_t> indices;
0128 const std::regex delimiterRegex("\\s+");
0129 std::sregex_token_iterator it(line.begin() + 10, line.end(), delimiterRegex, -1);
0130 for (; it != std::sregex_token_iterator(); it++) {
0131 const std::string token(it->str());
0132 if (token.empty())
0133 continue;
0134
0135 if (token.find("LINK_") != 0)
0136 throw std::runtime_error("Link column name '" + token + "' (does not start with 'LINK_')");
0137 if (token.size() == 5)
0138 throw std::runtime_error("Link column name '" + token + "' is too short");
0139 if (not std::all_of(token.begin() + 5, token.end(), ::isdigit))
0140 throw std::runtime_error("Link column name '" + token + "' does not end with a number");
0141
0142 indices.push_back(std::stoul(token.substr(5)));
0143 }
0144
0145
0146 if (not std::getline(file, line))
0147 throw std::runtime_error("APx file has incorrect format: Data missing!");
0148 if (line != "#BeginData")
0149 throw std::runtime_error("APx file has incorrect format: '#BeginData' line missing (found '" + line + "')");
0150
0151
0152 std::vector<std::vector<l1t::demo::Frame>> dataRows;
0153 while (std::getline(file, line)) {
0154 it = std::sregex_token_iterator(line.begin(), line.end(), delimiterRegex, -1);
0155 size_t count = 0;
0156 for (; it != std::sregex_token_iterator(); it++, count++) {
0157 const std::string token(it->str());
0158
0159 if ((token.find("0x") != 0) or (not std::all_of(token.begin() + 2, token.end(), ::isxdigit)))
0160 throw std::runtime_error("APx file has incorrect format: Data token '" + token +
0161 "' is not hexadecimal number");
0162
0163 if (count == 0) {
0164 size_t rowIndex = std::stoul(token, nullptr, 16);
0165 if (rowIndex != dataRows.size())
0166 throw std::runtime_error("APx file has incorrect format: Expected data row " +
0167 std::to_string(dataRows.size()) + ", but found row " + std::to_string(rowIndex));
0168 dataRows.push_back(std::vector<l1t::demo::Frame>(indices.size()));
0169 }
0170
0171 else if ((count % 2) == 1) {
0172 uint16_t sbValue = std::stoul(token, nullptr, 16);
0173 dataRows.back().at((count - 1) / 2).valid = (sbValue & 0x1);
0174 dataRows.back().at((count - 1) / 2).start = ((sbValue >> 1) & 0x1);
0175 dataRows.back().at((count - 1) / 2).end = ((sbValue >> 3) & 0x1);
0176 }
0177
0178 else
0179 dataRows.back().at((count - 1) / 2).data = ap_uint<64>(std::stoull(token, nullptr, 16));
0180 }
0181
0182 if (count != (2 * indices.size() + 1))
0183 throw std::runtime_error("APx file has incorrect format: Line has incorrect number of tokens (expected " +
0184 std::to_string(2 * indices.size() + 1) + ", found " + std::to_string(count) + "!");
0185 }
0186
0187 return createBoardDataFromRows("", indices, dataRows);
0188 }
0189
0190 BoardData readEMPFile(std::istream& file, const FileFormat format) {
0191
0192 std::string id, line;
0193 while (getline(file, line)) {
0194 if (line.empty())
0195 continue;
0196 if (line[0] == '#')
0197 continue;
0198
0199 if (line.rfind("Board ", 0) != std::string::npos) {
0200 id = line.substr(6);
0201 break;
0202 } else
0203 throw std::logic_error("Found unexpected line found when searching for board ID: \"" + line + "\"");
0204 }
0205
0206
0207 searchAndTokenize(file, "Quad/Chan :");
0208 const auto tokens = searchAndTokenize(file, "Link :");
0209 std::vector<size_t> channels;
0210 std::transform(tokens.begin(), tokens.end(), std::back_inserter(channels), [](const std::string& s) {
0211 return std::stoull(s);
0212 });
0213
0214
0215 const std::regex delimiterRegex("\\s+");
0216 static const std::regex frameRegex("([01]s)?([01]v)([0-9a-fA-F]{16})");
0217 std::vector<std::vector<Frame>> dataRows;
0218 while (file.good() and getline(file, line)) {
0219 if (line.empty() or line[0] == '#')
0220 continue;
0221
0222 std::ostringstream prefixStream;
0223 prefixStream << "Frame ";
0224 prefixStream << std::setw(4) << std::setfill('0') << dataRows.size();
0225 prefixStream << " :";
0226
0227 const std::string prefix(prefixStream.str());
0228 if (line.rfind(prefix, 0) == std::string::npos)
0229 throw std::logic_error("Found unexpected line found when searching for \"" + prefix + "\": \"" + line + "\"");
0230
0231 std::vector<l1t::demo::Frame> row;
0232 std::sregex_token_iterator it(line.begin() + prefix.size(), line.end(), delimiterRegex, -1);
0233 for (; it != std::sregex_token_iterator(); it++) {
0234 const std::string token(it->str());
0235 if (token.empty())
0236 continue;
0237
0238 std::smatch what;
0239 if (not std::regex_match(token, what, frameRegex))
0240 throw std::logic_error("Token '" + token + "' doesn't match the valid format");
0241
0242 l1t::demo::Frame value;
0243
0244 if (what[1].matched) {
0245 value.strobe = (what[1] == "1s");
0246 }
0247
0248 value.valid = (what[2] == "1v");
0249 value.data = ap_uint<64>(std::stoull(what[3].str(), nullptr, 16));
0250
0251 row.push_back(value);
0252 }
0253
0254 dataRows.push_back(row);
0255 }
0256
0257 return createBoardDataFromRows(id, channels, dataRows);
0258 }
0259
0260 BoardData readX20File(std::istream& file, const FileFormat format) {
0261 throw std::runtime_error("Reading X20 file format not yet implemented. Will be done ASAP.");
0262 }
0263
0264 void writeAPxFile(const BoardData&, std::ostream&, const FileFormat);
0265
0266 void writeEMPFile(const BoardData&, std::ostream&, const FileFormat);
0267
0268 void writeX20File(const BoardData&, std::ostream&, const FileFormat);
0269
0270 void write(const BoardData& data, const std::string& filePath, const FileFormat format) {
0271
0272 #ifdef CMSSW_GIT_HASH
0273 edm::LogInfo("L1TDemonstratorTools")
0274 #else
0275 std::cout
0276 #endif
0277 << "Writing board data (" << std::distance(data.begin(), data.end()) << " channels, "
0278 << data.begin()->second.size() << " frames) to file '" << filePath << "' (format: " << format << ")"
0279 << std::endl;
0280 std::ofstream file(filePath);
0281
0282 if (not file.is_open())
0283 throw std::runtime_error("Could not open file '" + filePath + "'");
0284
0285 write(data, file, format);
0286 }
0287
0288 void write(const BoardData& data, std::ostream& file, const FileFormat format) {
0289
0290 const auto firstChannel = data.begin();
0291
0292 for (const auto& channel : data) {
0293 const auto i = channel.first;
0294 const auto channelData = channel.second;
0295 if (channelData.size() != firstChannel->second.size())
0296 throw std::runtime_error("Cannot write board data to file - channels do not all have the same length (" +
0297 std::to_string(channelData.size()) + " words on channel " + std::to_string(i) +
0298 ", but " + std::to_string(firstChannel->second.size()) + " words on channel " +
0299 std::to_string(firstChannel->first) + ")");
0300 }
0301
0302
0303 switch (format) {
0304 case FileFormat::APx:
0305 writeAPxFile(data, file, format);
0306 return;
0307 case FileFormat::EMP:
0308 writeEMPFile(data, file, format);
0309 return;
0310 case FileFormat::X20:
0311 writeX20File(data, file, format);
0312 return;
0313 }
0314 }
0315
0316 void writeAPxFile(const BoardData& data, std::ostream& file, const FileFormat format) {
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331 file << std::setfill('0');
0332 file << "#Sideband ON" << std::endl;
0333
0334
0335 file << "#LinkLabel";
0336 for (const auto& channel : data) {
0337 const auto i = channel.first;
0338 file << " LINK_" << std::setw(2) << i << " ";
0339 }
0340 file << std::endl;
0341
0342 file << "#BeginData" << std::endl;
0343
0344
0345 file << std::hex;
0346 const auto firstChannel = data.begin();
0347 for (size_t i = 0; i < firstChannel->second.size(); i++) {
0348 file << "0x" << std::setw(4) << i;
0349 for (const auto& channel : data) {
0350
0351 const auto channelData = channel.second;
0352 uint16_t sideband = channelData.at(i).valid;
0353 sideband |= channelData.at(i).start << 1;
0354 sideband |= channelData.at(i).end << 3;
0355 file << " 0x" << std::setw(2) << sideband;
0356 file << " 0x" << std::setw(16) << uint64_t(channelData.at(i).data);
0357 }
0358 file << std::endl;
0359 }
0360 }
0361
0362 void writeEMPFile(const BoardData& data, std::ostream& file, const FileFormat format) {
0363 file << std::setfill('0');
0364
0365
0366 file << "Board CMSSW" << std::endl;
0367
0368
0369 file << " Quad/Chan :";
0370 for (const auto& channel : data) {
0371 const auto i = channel.first;
0372 file << " q" << std::setw(2) << i / 4 << 'c' << std::setw(1) << i % 4 << " ";
0373 }
0374 file << std::endl;
0375
0376
0377 file << " Link :";
0378 for (const auto& channel : data) {
0379 const auto i = channel.first;
0380 file << " " << std::setw(3) << i << " ";
0381 }
0382 file << std::endl;
0383
0384
0385 const auto firstChannel = data.begin();
0386 for (size_t i = 0; i < firstChannel->second.size(); i++) {
0387 file << "Frame " << std::setw(4) << i << " :";
0388 for (const auto& channel : data) {
0389
0390 const auto channelData = channel.second;
0391 file << " ";
0392
0393 file << " ";
0394 file << std::setw(1) << channelData.at(i).valid << "v" << std::setw(16) << std::hex
0395 << uint64_t(channelData.at(i).data);
0396 }
0397 file << std::endl << std::dec;
0398 }
0399 }
0400
0401 void writeX20File(const BoardData& data, std::ostream& file, const FileFormat format) {
0402 throw std::runtime_error("Writing X20 file format not yet implemented. Will be done ASAP.");
0403 }
0404
0405 }