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/ConfigurePython.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");
206 hp->setEventHeader(&cxt);
209 const IntegerTableCondition& iTable =
210 hp->getConditions().getCondition<IntegerTableCondition>(
211 "test_table_python");
213 CHECK(iTable.getByName(292,
"A") == 10);
214 CHECK(iTable.getByName(2928184,
"B") == 45);
215 CHECK(iTable.getByName(82910,
"C") == 129);
218 SECTION(
"Testing file loading") {
219 std::ofstream fs(
"/tmp/dump_double.csv");
220 std::stringstream ss;
227 "#!/usr/bin/python3\n\nimport sys\n\nfrom LDMX.Framework import "
228 "ldmxcfg\nfrom LDMX.Conditions import "
229 "SimpleCSVTableProvider\n\np=ldmxcfg.Process('test')\np.testMode="
230 "True\ncolumns=['SQRT','EXP','LOG']\ncop=SimpleCSVTableProvider."
231 "SimpleCSVDoubleTableProvider('test_table_file',columns)\ncop."
232 "validForRuns('file:///tmp/dump_double.csv',0,100)\ncop.validForRuns('/"
233 "tmp/dump_double.csv',101,120)\n";
235 FILE* f = fopen(
"/tmp/test_cond.py",
"w");
242 hp->setEventHeader(&cxt);
252 matchesAll(dtable, fTable1);
253 matchesAll(dtable, fTable2);
256 SECTION(
"Testing HTTP loading") {
258 "#!/usr/bin/python3\n\nimport sys\n\nfrom LDMX.Framework "
259 "import ldmxcfg\nfrom LDMX.Conditions import SimpleCSVTableProvider\n"
260 "p=ldmxcfg.Process(\"test\")\n"
262 "columns=[\"A\",\"Q\",\"V\"]\n"
263 "cop=SimpleCSVTableProvider.SimpleCSVIntegerTableProvider(\"test_table_"
265 "cop.validForever(\"http://www-users.cse.umn.edu/~jmmans/"
266 "test_table.csv\")\n";
268 FILE* f = fopen(
"/tmp/test_cond.py",
"w");
275 hp->setEventHeader(&cxt);
277 const IntegerTableCondition& httpTable =
278 hp->getConditions().getCondition<IntegerTableCondition>(
280 matchesAll(httpTable, itable);
283 SECTION(
"Testing CSV metatable") {
285 "#!/usr/bin/python3\n\nimport sys\n\nfrom LDMX.Framework "
286 "import ldmxcfg\nfrom LDMX.Conditions import SimpleCSVTableProvider\n"
287 "p=ldmxcfg.Process(\"test\")\n"
289 "columns=[\"PEDESTAL_ADC\"]\n"
290 "cop=SimpleCSVTableProvider.SimpleCSVDoubleTableProvider(\"testbeam22_"
291 "pedestals\",columns)\n"
292 "cop.conditions_baseURL='http://www-users.cse.umn.edu/~jmmans/ldmx/"
294 "cop.entriesURL='${LDMX_CONDITION_BASEURL}/testbeam22_pedestals.csv'\n";
296 FILE* f = fopen(
"/tmp/test_cond.py",
"w");
304 hp->setEventHeader(&cxt);
306 unsigned int http_requests[2], http_failures[2];
308 conditions::urlstatistics(http_requests[0], http_failures[0]);
312 hp->getConditions().getCondition<DoubleTableCondition>(
313 "testbeam22_pedestals");
315 hp->getConditions().getCondition<DoubleTableCondition>(
316 "testbeam22_pedestals");
318 conditions::urlstatistics(http_requests[1], http_failures[1]);
319 REQUIRE(((http_requests[1] - http_requests[0]) == 1 &&
320 (http_failures[1] - http_failures[0]) == 0));
324 hp->getConditions().getCondition<DoubleTableCondition>(
325 "testbeam22_pedestals");
327 conditions::urlstatistics(http_requests[1], http_failures[1]);
328 REQUIRE(((http_requests[1] - http_requests[0]) == 1 &&
329 (http_failures[1] - http_failures[0]) == 0));
333 hp->getConditions().getCondition<DoubleTableCondition>(
334 "testbeam22_pedestals");
336 conditions::urlstatistics(http_requests[1], http_failures[1]);
337 REQUIRE(((http_requests[1] - http_requests[0]) == 2 &&
338 (http_failures[1] - http_failures[0]) == 0));
342 REQUIRE_THROWS(hp->getConditions().getCondition<DoubleTableCondition>(
343 "testbeam22_pedestals"));
353TEST_CASE(
"CSVLoader",
"[Conditions][CSVLoader]") {
354 std::string testA(
"A,B,C\n1,2,3\n5,\"6\",7\n");
356 StringCSVLoader loaderA(testA);
358 REQUIRE(loaderA.nextRow());
359 REQUIRE(loaderA.get(
"A") ==
"1");
360 REQUIRE(loaderA.getInteger(
"B") == 2);
361 REQUIRE(loaderA.get(
"C") ==
"3");
362 REQUIRE(loaderA.nextRow());
363 REQUIRE(loaderA.get(
"A") ==
"5");
364 REQUIRE(loaderA.getInteger(
"B") == 6);
365 REQUIRE(loaderA.get(
"C") ==
"7");
366 REQUIRE(!loaderA.nextRow());
368 std::string testB(
"#Ignore me, dude\nA,B,C\n\n1,2,3\n5,\"6\",7");
370 StringCSVLoader loaderB(testB);
372 REQUIRE(loaderB.nextRow());
373 REQUIRE(loaderB.get(
"A") ==
"1");
374 REQUIRE(loaderB.getInteger(
"B") == 2);
375 REQUIRE(loaderB.get(
"C") ==
"3");
376 REQUIRE(loaderB.nextRow());
377 REQUIRE(loaderB.get(
"A") ==
"5");
378 REQUIRE(loaderB.getInteger(
"B") == 6);
379 REQUIRE(loaderB.get(
"C") ==
"7");
380 REQUIRE(!loaderB.nextRow());
382 std::string testC(
"#Ignore me, dude\nA,B,C\n\n1,2,3\n5,\"6\",7,9");
384 StringCSVLoader loaderC(testC);
386 REQUIRE(loaderC.nextRow());
387 REQUIRE(loaderC.get(
"A") ==
"1");
388 REQUIRE(loaderC.getInteger(
"B") == 2);
389 REQUIRE(loaderC.get(
"C") ==
"3");
390 REQUIRE_THROWS(loaderC.nextRow());
392 std::ofstream fxB(
"test.csv");
396 StreamCSVLoader loaderB2(
"test.csv");
398 REQUIRE(loaderB2.nextRow());
399 REQUIRE(loaderB2.get(
"A") ==
"1");
400 REQUIRE(loaderB2.getInteger(
"B") == 2);
401 REQUIRE(loaderB2.get(
"C") ==
"3");
402 REQUIRE(loaderB2.nextRow());
403 REQUIRE(loaderB2.get(
"A") ==
"5");
404 REQUIRE(loaderB2.getInteger(
"B") == 6);
405 REQUIRE(loaderB2.get(
"C") ==
"7");
406 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.
std::unique_ptr< Process > ProcessHandle
A handle to the current process Used to pass a process from ConfigurePython to fire....