3#include <catch2/catch_test_macros.hpp>
4#include <catch2/matchers/catch_matchers_string.hpp>
8#include "Conditions/GeneralCSVLoader.h"
9#include "Conditions/SimpleCSVTableProvider.h"
10#include "Conditions/SimpleTableCondition.h"
11#include "Conditions/SimpleTableStreamers.h"
12#include "Conditions/URLStreamer.h"
15#include "Framework/Configure/Python.h"
18#include "Framework/RunHeader.h"
24void matchesMeta(
const T& a,
const T& b) {
25 REQUIRE(a.getColumnCount() == b.getColumnCount());
26 REQUIRE(a.getRowCount() == b.getRowCount());
27 REQUIRE(a.getColumnNames() == b.getColumnNames());
33 for (
unsigned int i = 0; i < a.
getRowCount(); i++) {
34 std::pair<unsigned int, std::vector<double>> ar = a.
getRow(i);
35 std::pair<unsigned int, std::vector<double>> br = b.
getRow(i);
36 REQUIRE(ar.first == br.first);
40 REQUIRE(fabs(ar.second[ic] - br.second[ic]) /
41 std::max(1e-5, (ar.second[ic] + br.second[ic]) / 2) <
54using Catch::Matchers::ContainsSubstring;
63TEST_CASE(
"Conditions",
"[Conditions]") {
66 std::vector<std::string> columns({
"A",
"Q",
"V"});
68 IntegerTableCondition itable(
"ITable", columns);
70 for (
int key = 100; key > 0; key -= 10) {
72 std::vector<int> vals;
73 vals.push_back(key * 2);
74 vals.push_back(key / 2);
75 vals.push_back(key * key);
76 itable.add(
id.raw(), vals);
79 std::vector<std::string> columnsd({
"SQRT",
"EXP",
"LOG"});
82 for (
int key = 1; key < 8; key += 2) {
84 std::vector<double> vals;
85 vals.push_back(sqrt(key));
86 vals.push_back(exp(key * 5));
87 vals.push_back(log(key));
88 dtable.add(
id.raw(), vals);
91 SECTION(
"Testing simple table construction") {
92 REQUIRE(itable.getRowCount() == 10);
94 REQUIRE(itable.getColumnCount() == 3);
97 REQUIRE(itable.get(
id.raw(), 1) == 10);
99 REQUIRE_THROWS_WITH(itable.add(2, std::vector<int>(2)),
100 ContainsSubstring(
"columns into a table"));
102 REQUIRE_THROWS_WITH(itable.add(
id.raw(), std::vector<int>(3)),
103 ContainsSubstring(
"existing id"));
105 std::pair<unsigned int, std::vector<int>> row = itable.getRow(4);
107 CHECK(row.first == 0x14021032);
109 CHECK(row.second.size() == 3);
111 CHECK(row.second.at(2) == (50 * 50));
115 CHECK(itable.getByName(id2.raw(),
"Q") == 30);
117 const char* expected =
118 "[ TableCondition: ITable\n"
119 " DetID,id:\"A\",id:\"Q\",id:\"V\"\n"
120 " 335679498,20,5,100\n"
121 " 335679508,40,10,400\n"
122 " 335679518,60,15,900\n"
123 " 335679528,80,20,1600\n"
124 " 335679538,100,25,2500\n"
125 " 335679548,120,30,3600\n"
126 " 335679558,140,35,4900\n"
127 " 335679568,160,40,6400\n"
128 " 335679578,180,45,8100\n"
129 " 335679588,200,50,10000\n"
131 std::stringstream ss;
133 std::string image = ss.str();
134 CHECK(image == expected);
137 SECTION(
"Testing CSV IO") {
138 std::stringstream ss;
141 std::string image1 = ss.str();
142 const char* expected1 =
143 "\"DetID\",id:\"subdetector\",id:\"layer\",id:\"module\",id:\"cell\","
144 "\"A\",\"Q\",\"V\"\n0x1402100a,5,1,1,10,20,5,100\n0x14021014,5,1,1,20,"
145 "40,10,400\n0x1402101e,5,1,1,30,60,15,900\n0x14021028,5,1,1,40,80,20,"
146 "1600\n0x14021032,5,1,1,50,100,25,2500\n0x1402103c,5,1,1,60,120,30,"
147 "3600\n0x14021046,5,1,1,70,140,35,4900\n0x14021050,5,1,1,80,160,40,"
148 "6400\n0x1402105a,5,1,1,90,180,45,8100\n0x14021064,5,1,1,100,200,50,"
151 CHECK(image1 == expected1);
155 std::stringstream ss_read1(image1);
156 IntegerTableCondition itable2(
"ITable", columns);
159 matchesAll(itable, itable2);
162 std::string image2(
"B,A,Q,V\n0,40,50,100\n0,60,70,90\n");
163 std::stringstream ss_read2(image2);
167 "Malformed CSV file with no DetId or subdetector column"));
171 "DetID,A,Q\n0x1402100a,20,5\n0x14021014,40,10\n0x1402101e,60,"
172 "15\n0x14021028,80,20\n0x14021032,100,25\n0x1402103c,120,"
173 "30\n0x14021046,140,35\n0x14021050,160,40\n0x1402105a,180,"
174 "45\n0x14021064,200,50\n");
175 std::stringstream ss_read3(image3);
178 ContainsSubstring(
"Missing column"));
182 "DetID,A,Q,V\n0x1402100a,20,5,100\n0x14021014,40,10\n0x1402101e,60,15,"
184 std::stringstream ss_read4(image4);
187 ContainsSubstring(
"Mismatched number of columns (3!=4) on line 3"));
190 SECTION(
"Testing python static") {
192 "#!/usr/bin/python3\n\nimport sys\n\nfrom LDMX.Framework import "
193 "ldmxcfg\nfrom LDMX.Conditions import "
194 "SimpleCSVTableProvider\n\np=ldmxcfg.Process('test')\np.testMode="
195 "True\ncolumns=['A','B','C']\ncop=SimpleCSVTableProvider."
196 "SimpleCSVIntegerTableProvider('test_table_python',columns)\ncop."
197 "validForAllRows([10,45,129])";
199 FILE* f = fopen(
"/tmp/test_cond.py",
"w");
204 "/tmp/test_cond.py", 0, 0)};
205 auto hp{std::make_unique<framework::Process>(cfg)};
207 hp->setEventHeader(&cxt);
210 const IntegerTableCondition& iTable =
211 hp->getConditions().getCondition<IntegerTableCondition>(
212 "test_table_python");
214 CHECK(iTable.getByName(292,
"A") == 10);
215 CHECK(iTable.getByName(2928184,
"B") == 45);
216 CHECK(iTable.getByName(82910,
"C") == 129);
219 SECTION(
"Testing file loading") {
220 std::ofstream fs(
"/tmp/dump_double.csv");
221 std::stringstream ss;
228 "#!/usr/bin/python3\n\nimport sys\n\nfrom LDMX.Framework import "
229 "ldmxcfg\nfrom LDMX.Conditions import "
230 "SimpleCSVTableProvider\n\np=ldmxcfg.Process('test')\np.testMode="
231 "True\ncolumns=['SQRT','EXP','LOG']\ncop=SimpleCSVTableProvider."
232 "SimpleCSVDoubleTableProvider('test_table_file',columns)\ncop."
233 "validForRuns('file:///tmp/dump_double.csv',0,100)\ncop.validForRuns('/"
234 "tmp/dump_double.csv',101,120)\n";
236 FILE* f = fopen(
"/tmp/test_cond.py",
"w");
241 "/tmp/test_cond.py", 0, 0)};
242 auto hp{std::make_unique<framework::Process>(cfg)};
244 hp->setEventHeader(&cxt);
254 matchesAll(dtable, fTable1);
255 matchesAll(dtable, fTable2);
258 SECTION(
"Testing HTTP loading") {
260 "#!/usr/bin/python3\n\nimport sys\n\nfrom LDMX.Framework "
261 "import ldmxcfg\nfrom LDMX.Conditions import SimpleCSVTableProvider\n"
262 "p=ldmxcfg.Process(\"test\")\n"
264 "columns=[\"A\",\"Q\",\"V\"]\n"
265 "cop=SimpleCSVTableProvider.SimpleCSVIntegerTableProvider(\"test_table_"
267 "cop.validForever(\"http://www-users.cse.umn.edu/~jmmans/"
268 "test_table.csv\")\n";
270 FILE* f = fopen(
"/tmp/test_cond.py",
"w");
275 "/tmp/test_cond.py", 0, 0)};
276 auto hp{std::make_unique<framework::Process>(cfg)};
278 hp->setEventHeader(&cxt);
280 const IntegerTableCondition& httpTable =
281 hp->getConditions().getCondition<IntegerTableCondition>(
283 matchesAll(httpTable, itable);
286 SECTION(
"Testing CSV metatable") {
288 "#!/usr/bin/python3\n\nimport sys\n\nfrom LDMX.Framework "
289 "import ldmxcfg\nfrom LDMX.Conditions import SimpleCSVTableProvider\n"
290 "p=ldmxcfg.Process(\"test\")\n"
292 "columns=[\"PEDESTAL_ADC\"]\n"
293 "cop=SimpleCSVTableProvider.SimpleCSVDoubleTableProvider(\"testbeam22_"
294 "pedestals\",columns)\n"
295 "cop.conditions_baseURL='http://www-users.cse.umn.edu/~jmmans/ldmx/"
297 "cop.entriesURL='${LDMX_CONDITION_BASEURL}/testbeam22_pedestals.csv'\n";
299 FILE* f = fopen(
"/tmp/test_cond.py",
"w");
304 "/tmp/test_cond.py", 0, 0)};
305 auto hp{std::make_unique<framework::Process>(cfg)};
308 hp->setEventHeader(&cxt);
310 unsigned int http_requests[2], http_failures[2];
312 conditions::urlstatistics(http_requests[0], http_failures[0]);
316 hp->getConditions().getCondition<DoubleTableCondition>(
317 "testbeam22_pedestals");
319 hp->getConditions().getCondition<DoubleTableCondition>(
320 "testbeam22_pedestals");
322 conditions::urlstatistics(http_requests[1], http_failures[1]);
323 REQUIRE(((http_requests[1] - http_requests[0]) == 1 &&
324 (http_failures[1] - http_failures[0]) == 0));
328 hp->getConditions().getCondition<DoubleTableCondition>(
329 "testbeam22_pedestals");
331 conditions::urlstatistics(http_requests[1], http_failures[1]);
332 REQUIRE(((http_requests[1] - http_requests[0]) == 1 &&
333 (http_failures[1] - http_failures[0]) == 0));
337 hp->getConditions().getCondition<DoubleTableCondition>(
338 "testbeam22_pedestals");
340 conditions::urlstatistics(http_requests[1], http_failures[1]);
341 REQUIRE(((http_requests[1] - http_requests[0]) == 2 &&
342 (http_failures[1] - http_failures[0]) == 0));
346 REQUIRE_THROWS(hp->getConditions().getCondition<DoubleTableCondition>(
347 "testbeam22_pedestals"));
357TEST_CASE(
"CSVLoader",
"[Conditions][CSVLoader]") {
358 std::string testA(
"A,B,C\n1,2,3\n5,\"6\",7\n");
360 StringCSVLoader loaderA(testA);
362 REQUIRE(loaderA.nextRow());
363 REQUIRE(loaderA.get(
"A") ==
"1");
364 REQUIRE(loaderA.getInteger(
"B") == 2);
365 REQUIRE(loaderA.get(
"C") ==
"3");
366 REQUIRE(loaderA.nextRow());
367 REQUIRE(loaderA.get(
"A") ==
"5");
368 REQUIRE(loaderA.getInteger(
"B") == 6);
369 REQUIRE(loaderA.get(
"C") ==
"7");
370 REQUIRE(!loaderA.nextRow());
372 std::string testB(
"#Ignore me, dude\nA,B,C\n\n1,2,3\n5,\"6\",7");
374 StringCSVLoader loaderB(testB);
376 REQUIRE(loaderB.nextRow());
377 REQUIRE(loaderB.get(
"A") ==
"1");
378 REQUIRE(loaderB.getInteger(
"B") == 2);
379 REQUIRE(loaderB.get(
"C") ==
"3");
380 REQUIRE(loaderB.nextRow());
381 REQUIRE(loaderB.get(
"A") ==
"5");
382 REQUIRE(loaderB.getInteger(
"B") == 6);
383 REQUIRE(loaderB.get(
"C") ==
"7");
384 REQUIRE(!loaderB.nextRow());
386 std::string testC(
"#Ignore me, dude\nA,B,C\n\n1,2,3\n5,\"6\",7,9");
388 StringCSVLoader loaderC(testC);
390 REQUIRE(loaderC.nextRow());
391 REQUIRE(loaderC.get(
"A") ==
"1");
392 REQUIRE(loaderC.getInteger(
"B") == 2);
393 REQUIRE(loaderC.get(
"C") ==
"3");
394 REQUIRE_THROWS(loaderC.nextRow());
396 std::ofstream fxB(
"test.csv");
400 StreamCSVLoader loaderB2(
"test.csv");
402 REQUIRE(loaderB2.nextRow());
403 REQUIRE(loaderB2.get(
"A") ==
"1");
404 REQUIRE(loaderB2.getInteger(
"B") == 2);
405 REQUIRE(loaderB2.get(
"C") ==
"3");
406 REQUIRE(loaderB2.nextRow());
407 REQUIRE(loaderB2.get(
"A") ==
"5");
408 REQUIRE(loaderB2.getInteger(
"B") == 6);
409 REQUIRE(loaderB2.get(
"C") ==
"7");
410 REQUIRE(!loaderB2.nextRow());
Class that defines an ECal detector ID with a cell number.
Class that defines an HCal sensitive detector.
Class which represents the process under execution.
unsigned int getColumnCount() const
Get the number of columns.
std::size_t getRowCount() const
Get the number of rows.
std::pair< unsigned int, std::vector< T > > getRow(unsigned int irow) const
Get a row by number Used primarily for persisting the SimpleTableCondition.
static void load(IntegerTableCondition &, std::istream &)
Load the table from a stream Columns must be defined by the user.
static void store(const IntegerTableCondition &, std::ostream &, bool expandIds=true)
Convert the table into a stream.
Extension of DetectorID providing access to ECal layers and cell numbers in a hex grid.
Implements detector ids for HCal subdetector.
Parameters run(const std::string &root_object, const std::string &pythonScript, char *args[], int nargs)
run the python script and extract the parameters