Project
Loading...
Searching...
No Matches
testClosureCoDec.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14#define BOOST_TEST_MODULE Test MCHRaw Closure
15#define BOOST_TEST_MAIN
16#define BOOST_TEST_DYN_LINK
17
18#include <boost/test/unit_test.hpp>
19#include <boost/property_tree/ptree.hpp>
22#include "Framework/Logger.h"
27#include <boost/mpl/list.hpp>
28#include <fmt/format.h>
29#include <iostream>
30
31using namespace o2::mch::raw;
32
33std::vector<std::string> chargeSumInput = {
34 "S728-J1-DS0-CH3-ts-24-bc-0-cs-14-q-13",
35 "S728-J1-DS0-CH13-ts-24-bc-0-cs-134-q-133",
36 "S728-J1-DS0-CH23-ts-24-bc-0-cs-164-q-163",
37
38 "S361-J0-DS4-CH0-ts-24-bc-0-cs-11-q-10",
39 "S361-J0-DS4-CH1-ts-24-bc-0-cs-21-q-20",
40 "S361-J0-DS4-CH2-ts-24-bc-0-cs-31-q-30",
41 "S361-J0-DS4-CH3-ts-24-bc-0-cs-41-q-40",
42
43 "S448-J6-DS2-CH22-ts-24-bc-0-cs-421-q-420",
44 "S448-J6-DS2-CH23-ts-24-bc-0-cs-431-q-430",
45 "S448-J6-DS2-CH24-ts-24-bc-0-cs-441-q-440",
46 "S448-J6-DS2-CH25-ts-24-bc-0-cs-451-q-450",
47 "S448-J6-DS2-CH26-ts-24-bc-0-cs-461-q-460",
48 "S448-J6-DS2-CH42-ts-24-bc-0-cs-421-q-420"};
49
50std::vector<std::string> sampleInput = {
51 "S728-J1-DS0-CH3-ts-24-bc-0-cs-3-q-13-15-17",
52 "S728-J1-DS0-CH13-ts-24-bc-0-cs-3-q-133-135-137",
53 "S728-J1-DS0-CH23-ts-24-bc-0-cs-2-q-163-165",
54
55 "S361-J0-DS4-CH0-ts-24-bc-0-cs-3-q-10-12-14",
56 "S361-J0-DS4-CH1-ts-24-bc-0-cs-3-q-20-22-24",
57 "S361-J0-DS4-CH2-ts-24-bc-0-cs-3-q-30-32-34",
58 "S361-J0-DS4-CH3-ts-24-bc-0-cs-3-q-40-42-44",
59
60 "S448-J6-DS2-CH22-ts-24-bc-0-cs-3-q-420-422-424",
61 "S448-J6-DS2-CH23-ts-24-bc-0-cs-3-q-430-432-434",
62 "S448-J6-DS2-CH24-ts-24-bc-0-cs-3-q-440-442-444",
63 "S448-J6-DS2-CH25-ts-24-bc-0-cs-3-q-450-452-454",
64 "S448-J6-DS2-CH26-ts-24-bc-0-cs-3-q-460-462-464",
65 "S448-J6-DS2-CH42-ts-24-bc-0-cs-5-q-420-422-424-426-428"};
66
67template <typename ELECMAP, typename FORMAT, typename CHARGESUM, int VERSION>
68std::vector<std::byte> paginate(gsl::span<const std::byte> buffer, const std::string& tmpbasename)
69{
70 fair::Logger::SetConsoleSeverity("nolog");
72
73 fw.setVerbosity(1);
74 fw.setDontFillEmptyHBF(true);
75
76 auto solar2LinkInfo = createSolar2LinkInfo<ELECMAP, FORMAT, CHARGESUM, VERSION>();
77
78 // only use the solarIds that are actually in this test buffer
79 // (to speed up the test)
80 std::set<LinkInfo> links;
81 for (auto solarId : {361, 448, 728}) {
82 links.insert(solar2LinkInfo(solarId).value());
83 }
84
85 registerLinks(fw, tmpbasename, links, false, false);
86
87 paginate(fw, buffer, links, solar2LinkInfo);
88
89 fw.close();
90
91 auto filename = fmt::format("{:s}.raw", tmpbasename);
92 std::ifstream in(filename, std::ifstream::binary);
93 if (in.fail()) {
94 throw std::runtime_error(fmt::format("could not open ", filename));
95 }
96 // get length of file:
97 in.seekg(0, in.end);
98 int length = in.tellg();
99 in.seekg(0, in.beg);
100 std::vector<std::byte> pages(length);
101
102 // read data as a block:
103 in.read(reinterpret_cast<char*>(&pages[0]), length);
104
105 return pages;
106}
107
108constexpr const char* sampaClusterFormat = "{}-CH{}-{}";
109
110// Create a vector of SampaCluster from a string d
111// where d is of the form ts-#-bc-#-cs-#-q-# or
112// ts-#-bc-#-cs-#-q-#-#-# ...
113// d is expected to be a valid SampaCluster string representation
114// see the asString function in SampaCluster
115std::vector<SampaCluster> getSampaClusters(const std::string& d)
116{
117 std::vector<SampaCluster> clusters;
118
119 //std::cout << "d: " << d << std::endl;
120
121 auto index = d.find("ts-");
122 auto ts = std::stoi(d.substr(index + 3));
123 index = d.find("bc-");
124 auto bc = std::stoi(d.substr(index + 3));
125 index = d.find("cs-");
126 auto cs = std::stoi(d.substr(index + 3));
127 index = d.find("q-");
128 auto q = d.substr(index + 2);
129 index = q.find("-");
130 if (index != std::string::npos) {
131 std::vector<uint10_t> charges;
132 std::istringstream ss(q);
133 std::string adc;
134 while (std::getline(ss, adc, '-')) {
135 charges.emplace_back(std::stoi(adc) & 0x3FF);
136 }
137 clusters.emplace_back(SampaCluster(ts, bc, charges));
138 } else {
139 clusters.emplace_back(SampaCluster(ts, bc, std::stoi(q), cs));
140 }
141 return clusters;
142}
143
144std::set<DsElecId> getDs(gsl::span<std::string> data)
145{
146 std::set<DsElecId> dsids;
147 for (auto d : data) {
148 auto dsElecId = decodeDsElecId(d);
149 if (!dsElecId) {
150 std::cout << "Could not get dsElecId for " << d << "\n";
151 continue;
152 }
153 dsids.insert(dsElecId.value());
154 }
155 return dsids;
156}
157
158// create a raw data buffer from a list of strings
159// where each string is of the form
160// S#-J#-DS#-CH#-ts-#-bc-#-q-#
161//
162// it's a two steps process :
163//
164// - first create a buffer of payloads using a PayloadEncoder
165// - then create the raw data itself (with proper RDHs) from the payload buffer
166//
167template <typename ELECMAP, typename FORMAT, typename CHARGESUM, int VERSION>
168std::vector<std::byte> createBuffer(gsl::span<std::string> data,
169 uint32_t orbit = 12345, uint16_t bc = 678)
170{
172 o2::conf::ConfigurableParam::setValue<uint32_t>("HBFUtils", "orbitFirst", orbit);
173 o2::conf::ConfigurableParam::setValue<uint32_t>("HBFUtils", "orbitFirstSampled", orbit);
174 auto encoder = createPayloadEncoder(createSolar2FeeLinkMapper<ELECMAP>(),
176 VERSION,
178 encoder->startHeartbeatFrame(orbit, bc);
179 std::set<DsElecId> dsElecIds = getDs(data);
180 encoder->addHeartbeatHeaders(dsElecIds);
181 for (auto d : data) {
182 auto dsElecId = decodeDsElecId(d);
183 if (!dsElecId) {
184 std::cout << "Could not get dsElecId for " << d << "\n";
185 }
186 auto channel = decodeChannelId(d);
187 if (!channel) {
188 std::cout << "Could not get channel for " << d << "\n";
189 }
190 auto sampaClusters = getSampaClusters(d);
191 encoder->addChannelData(dsElecId.value(), channel.value(), sampaClusters);
192 }
193 std::vector<std::byte> buffer;
194 encoder->moveToBuffer(buffer);
195
196 o2::conf::ConfigurableParam::setValue<uint32_t>("HBFUtils", "orbitFirst", orbit);
197 o2::conf::ConfigurableParam::setValue<uint32_t>("HBFUtils", "orbitFirstSampled", orbit);
198
199 std::vector<std::byte> out =
200 paginate<ELECMAP, FORMAT, CHARGESUM, VERSION>(buffer,
201 fmt::format("mch-closure-codec-{}-{}.raw",
202 orbit, bc));
203 return out;
204}
205
206// method that is called by the decoder each time a SampaCluster is decoded.
208{
209 return [&result](DsElecId dsId, DualSampaChannelId channel, SampaCluster sc) {
210 result.emplace_back(fmt::format(sampaClusterFormat, asString(dsId), channel, asString(sc)));
211 };
212}
213
214// decode the buffer and check its content against the expected vector of strings
215template <typename ELECMAP>
216bool testDecode(gsl::span<const std::byte> testBuffer, gsl::span<std::string> expected)
217{
218 std::vector<std::string> result;
219
220 DecodedDataHandlers handlers;
222 auto pageDecoder = createPageDecoder(testBuffer, handlers,
223 createFeeLink2SolarMapper<ELECMAP>());
224 auto parser = createPageParser();
225
226 parser(testBuffer, pageDecoder);
227
228 bool sameSize = result.size() == expected.size();
229 bool permutation = std::is_permutation(begin(result), end(result), begin(expected));
231 BOOST_CHECK_EQUAL(permutation, true);
232 if (!permutation || !sameSize) {
233 std::cout << "Got " << result.size() << " results:\n";
234 for (auto s : result) {
235 std::cout << s << "\n";
236 }
237 std::cout << "Expected " << expected.size() << ":\n";
238 for (auto s : expected) {
239 std::cout << s << "\n";
240 }
241 return false;
242 }
243
244 return true;
245}
246
247struct BareGen {
250 static constexpr int version = 0;
251};
252
253struct UserLogicGen {
256 static constexpr int version = 0;
257};
258
259struct UserLogicGen1 {
262 static constexpr int version = 1;
263};
264
265struct BareDummy {
268 static constexpr int version = 0;
269};
270
271struct UserLogicDummy {
274 static constexpr int version = 0;
275};
276
277struct UserLogicDummy1 {
280 static constexpr int version = 1;
281};
282
283typedef boost::mpl::list<BareGen, UserLogicGen, UserLogicGen1, BareDummy, UserLogicDummy, UserLogicDummy1> testTypes;
284
286{
287 auto buffer = createBuffer<typename T::elecmap,
288 typename T::format,
290 T::version>(chargeSumInput);
291 testDecode<typename T::elecmap>(buffer, chargeSumInput);
292}
293
295{
296 auto buffer = createBuffer<typename T::elecmap,
297 typename T::format,
299 T::version>(sampleInput);
300 testDecode<typename T::elecmap>(buffer, sampleInput);
301}
uint64_t orbit
Definition RawEventData.h:6
uint64_t bc
Definition RawEventData.h:5
Utility class to write detectors data to (multiple) raw data file(s) respecting CRU format.
void setDontFillEmptyHBF(bool v)
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint buffer
Definition glcorearb.h:655
GLuint GLuint end
Definition glcorearb.h:469
GLuint index
Definition glcorearb.h:781
GLboolean * data
Definition glcorearb.h:298
GLuint GLsizei GLsizei * length
Definition glcorearb.h:790
PageParser createPageParser()
void paginate(o2::raw::RawFileWriter &rawFileWriter, gsl::span< const std::byte > buffer, const std::set< LinkInfo > &links, Solar2LinkInfo solar2LinkInfo)
std::optional< uint8_t > decodeChannelId(std::string rep)
Definition DsElecId.cxx:84
void registerLinks(o2::raw::RawFileWriter &rawFileWriter, std::string outputBase, const std::set< LinkInfo > &links, bool filePerLink, bool filePerCru)
std::function< void(DsElecId dsId, DualSampaChannelId channel, SampaCluster)> SampaChannelHandler
uint6_t DualSampaChannelId
Definition DataFormats.h:65
PageDecoder createPageDecoder(RawBuffer rdhBuffer, DecodedDataHandlers decodedDataHandlers)
will be called for each decoded Sampa packet and in case of decoding errors
std::string asString(const SampaCluster &sc)
std::optional< DsElecId > decodeDsElecId(uint32_t code)
Definition DsElecId.cxx:37
std::unique_ptr< PayloadEncoder > createPayloadEncoder(Solar2FeeLinkMapper solar2feelink, bool userLogic, int version, bool chargeSumMode)
bool sameSize(T0 const &first, Ts const &... rest)
std::string filename()
static constexpr int version
static constexpr int version
static constexpr int version
static constexpr int version
static constexpr int version
static constexpr int version
Piece of data for one Sampa channel.
std::vector< std::string > chargeSumInput
constexpr const char * sampaClusterFormat
boost::mpl::list< BareGen, UserLogicGen, UserLogicGen1, BareDummy, UserLogicDummy, UserLogicDummy1 > testTypes
bool testDecode(gsl::span< const std::byte > testBuffer, gsl::span< std::string > expected)
std::vector< SampaCluster > getSampaClusters(const std::string &d)
std::vector< std::byte > createBuffer(gsl::span< std::string > data, uint32_t orbit=12345, uint16_t bc=678)
std::vector< std::string > sampleInput
SampaChannelHandler handlePacketStoreAsVec(std::vector< std::string > &result)
BOOST_AUTO_TEST_CASE_TEMPLATE(ClosureChargeSum, T, testTypes)
std::set< DsElecId > getDs(gsl::span< std::string > data)
std::map< std::string, ID > expected
boost::mpl::list< o2::dcs::DataPointIdentifier, o2::dcs::DataPointValue, o2::dcs::DataPointCompositeObject > testTypes
std::vector< Cluster > clusters
BOOST_CHECK_EQUAL(triggersD.size(), triggers.size())
ArrayADC adc