3#include <catch2/catch_test_macros.hpp>
4#include <catch2/matchers/catch_matchers_string.hpp>
9#include "Conditions/GeneralCSVLoader.h"
10#include "Conditions/SimpleTableCondition.h"
11#include "Conditions/SimpleTableStreamers.h"
12#include "Conditions/URLStreamer.h"
15#include "Framework/Configure/Python.h"
23void matchesMeta(
const T& a,
const T& b) {
24 REQUIRE(a.getColumnCount() == b.getColumnCount());
25 REQUIRE(a.getRowCount() == b.getRowCount());
26 REQUIRE(a.getColumnNames() == b.getColumnNames());
32 for (
unsigned int i = 0; i < a.
getRowCount(); i++) {
33 std::pair<unsigned int, std::vector<double>> ar = a.
getRow(i);
34 std::pair<unsigned int, std::vector<double>> br = b.
getRow(i);
35 REQUIRE(ar.first == br.first);
39 REQUIRE(fabs(ar.second[ic] - br.second[ic]) /
40 std::max(1e-5, (ar.second[ic] + br.second[ic]) / 2) <
53using Catch::Matchers::ContainsSubstring;
62TEST_CASE(
"Conditions",
"[Conditions]") {
65 std::vector<std::string> columns({
"A",
"Q",
"V"});
67 IntegerTableCondition itable(
"ITable", columns);
69 for (
int key = 100; key > 0; key -= 10) {
71 std::vector<int> vals;
72 vals.push_back(key * 2);
73 vals.push_back(key / 2);
74 vals.push_back(key * key);
75 itable.add(
id.raw(), vals);
78 std::vector<std::string> columnsd({
"SQRT",
"EXP",
"LOG"});
81 for (
int key = 1; key < 8; key += 2) {
83 std::vector<double> vals;
84 vals.push_back(sqrt(key));
85 vals.push_back(exp(key * 5));
86 vals.push_back(log(key));
87 dtable.add(
id.raw(), vals);
90 SECTION(
"Testing simple table construction") {
91 REQUIRE(itable.getRowCount() == 10);
93 REQUIRE(itable.getColumnCount() == 3);
96 REQUIRE(itable.get(
id.raw(), 1) == 10);
98 REQUIRE_THROWS_WITH(itable.add(2, std::vector<int>(2)),
99 ContainsSubstring(
"columns into a table"));
101 REQUIRE_THROWS_WITH(itable.add(
id.raw(), std::vector<int>(3)),
102 ContainsSubstring(
"existing id"));
104 std::pair<unsigned int, std::vector<int>> row = itable.getRow(4);
106 CHECK(row.first == 0x14021032);
108 CHECK(row.second.size() == 3);
110 CHECK(row.second.at(2) == (50 * 50));
114 CHECK(itable.getByName(id2.raw(),
"Q") == 30);
116 const char* expected =
117 "[ TableCondition: ITable\n"
118 " DetID,id:\"A\",id:\"Q\",id:\"V\"\n"
119 " 335679498,20,5,100\n"
120 " 335679508,40,10,400\n"
121 " 335679518,60,15,900\n"
122 " 335679528,80,20,1600\n"
123 " 335679538,100,25,2500\n"
124 " 335679548,120,30,3600\n"
125 " 335679558,140,35,4900\n"
126 " 335679568,160,40,6400\n"
127 " 335679578,180,45,8100\n"
128 " 335679588,200,50,10000\n"
130 std::stringstream ss;
132 std::string image = ss.str();
133 CHECK(image == expected);
136 SECTION(
"Testing CSV IO") {
137 std::stringstream ss;
140 std::string image1 = ss.str();
141 const char* expected1 =
142 "\"DetID\",id:\"subdetector\",id:\"layer\",id:\"module\",id:\"cell\","
143 "\"A\",\"Q\",\"V\"\n0x1402100a,5,1,1,10,20,5,100\n0x14021014,5,1,1,20,"
144 "40,10,400\n0x1402101e,5,1,1,30,60,15,900\n0x14021028,5,1,1,40,80,20,"
145 "1600\n0x14021032,5,1,1,50,100,25,2500\n0x1402103c,5,1,1,60,120,30,"
146 "3600\n0x14021046,5,1,1,70,140,35,4900\n0x14021050,5,1,1,80,160,40,"
147 "6400\n0x1402105a,5,1,1,90,180,45,8100\n0x14021064,5,1,1,100,200,50,"
150 CHECK(image1 == expected1);
154 std::stringstream ss_read1(image1);
155 IntegerTableCondition itable2(
"ITable", columns);
158 matchesAll(itable, itable2);
161 std::string image2(
"B,A,Q,V\n0,40,50,100\n0,60,70,90\n");
162 std::stringstream ss_read2(image2);
166 "Malformed CSV file with no DetId or subdetector column"));
170 "DetID,A,Q\n0x1402100a,20,5\n0x14021014,40,10\n0x1402101e,60,"
171 "15\n0x14021028,80,20\n0x14021032,100,25\n0x1402103c,120,"
172 "30\n0x14021046,140,35\n0x14021050,160,40\n0x1402105a,180,"
173 "45\n0x14021064,200,50\n");
174 std::stringstream ss_read3(image3);
177 ContainsSubstring(
"Missing column"));
181 "DetID,A,Q,V\n0x1402100a,20,5,100\n0x14021014,40,10\n0x1402101e,60,15,"
183 std::stringstream ss_read4(image4);
186 ContainsSubstring(
"Mismatched number of columns (3!=4) on line 3"));
189 SECTION(
"Testing python static") {
191 "#!/usr/bin/python3\n\nimport sys\n\nfrom LDMX.Framework import "
192 "ldmxcfg\nfrom LDMX.Conditions import "
193 "SimpleCSVTableProvider\n\np=ldmxcfg.Process('test')\n"
194 "columns=['A','B','C']\ncop=SimpleCSVTableProvider."
195 "simple_csv_integer_table_provider('test_table_python',columns)\ncop."
196 "valid_for_all_rows([10,45,129])";
198 FILE* f = fopen(
"/tmp/test_cond.py",
"w");
203 "/tmp/test_cond.py", 0, 0)};
204 auto hp{std::make_unique<framework::Process>(cfg)};
206 hp->setEventHeader(&cxt);
209 const IntegerTableCondition& i_table =
210 hp->getConditions().getCondition<IntegerTableCondition>(
211 "test_table_python");
213 CHECK(i_table.getByName(292,
"A") == 10);
214 CHECK(i_table.getByName(2928184,
"B") == 45);
215 CHECK(i_table.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')\n"
230 "columns=['SQRT','EXP','LOG']\ncop=SimpleCSVTableProvider."
231 "simple_csv_double_table_provider('test_table_file',columns)\ncop."
232 "valid_for_runs('file:///tmp/"
233 "dump_double.csv',0,100)\ncop.valid_for_runs('/"
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);
250 matchesAll(dtable, f_table1);
256 matchesAll(dtable, f_table2);
259 SECTION(
"Testing HTTP loading") {
261 "import sys\n\nfrom LDMX.Framework "
262 "import ldmxcfg\nfrom LDMX.Conditions import SimpleCSVTableProvider\n"
263 "p=ldmxcfg.Process(\"test\")\n"
264 "columns=[\"A\",\"Q\",\"V\"]\n"
265 "cop=SimpleCSVTableProvider.simple_csv_integer_table_provider(\"test_"
268 "cop.valid_forever(\"https://raw.githubusercontent.com/LDMX-Software/"
269 "ci-data/refs/heads/main/conditions-test/test_table.csv\")\n";
271 FILE* f = fopen(
"/tmp/test_cond.py",
"w");
276 "/tmp/test_cond.py", 0, 0)};
277 auto hp{std::make_unique<framework::Process>(cfg)};
279 hp->setEventHeader(&cxt);
281 const IntegerTableCondition& http_table =
282 hp->getConditions().getCondition<IntegerTableCondition>(
284 matchesAll(http_table, itable);
287 SECTION(
"Testing CSV metatable") {
290 "from LDMX.Framework import ldmxcfg\n"
291 "from LDMX.Conditions import SimpleCSVTableProvider\n"
292 "p=ldmxcfg.Process(\"test\")\n"
293 "columns=[\"PEDESTAL_ADC\"]\n"
294 "cop=SimpleCSVTableProvider.simple_csv_double_table_provider("
296 "pedestals\",columns)\n"
297 "cop.conditions_base_url='https://raw.githubusercontent.com/"
298 "LDMX-Software/conditions-data/refs/heads/main/'\n"
299 "cop.entries_url='${LDMX_CONDITION_BASEURL}/Hcal/testbeam04-2022/"
300 "pedestals/index_v1_0_0.csv'\n";
302 FILE* f = fopen(
"/tmp/test_cond.py",
"w");
307 "/tmp/test_cond.py", 0, 0)};
308 auto hp{std::make_unique<framework::Process>(cfg)};
311 hp->setEventHeader(&cxt);
313 unsigned int http_requests[2], http_failures[2];
315 conditions::urlstatistics(http_requests[0], http_failures[0]);
319 hp->getConditions().getCondition<DoubleTableCondition>(
320 "testbeam22_pedestals");
322 hp->getConditions().getCondition<DoubleTableCondition>(
323 "testbeam22_pedestals");
325 conditions::urlstatistics(http_requests[1], http_failures[1]);
326 REQUIRE(((http_requests[1] - http_requests[0]) == 1 &&
327 (http_failures[1] - http_failures[0]) == 0));
331 hp->getConditions().getCondition<DoubleTableCondition>(
332 "testbeam22_pedestals");
334 conditions::urlstatistics(http_requests[1], http_failures[1]);
335 REQUIRE(((http_requests[1] - http_requests[0]) == 1 &&
336 (http_failures[1] - http_failures[0]) == 0));
340 hp->getConditions().getCondition<DoubleTableCondition>(
341 "testbeam22_pedestals");
343 conditions::urlstatistics(http_requests[1], http_failures[1]);
344 REQUIRE(((http_requests[1] - http_requests[0]) == 2 &&
345 (http_failures[1] - http_failures[0]) == 0));
349 REQUIRE_THROWS(hp->getConditions().getCondition<DoubleTableCondition>(
350 "testbeam22_pedestals"));
360TEST_CASE(
"CSVLoader",
"[Conditions][CSVLoader]") {
361 std::string test_a(
"A,B,C\n1,2,3\n5,\"6\",7\n");
363 StringCSVLoader loader_a(test_a);
365 REQUIRE(loader_a.nextRow());
366 REQUIRE(loader_a.get(
"A") ==
"1");
367 REQUIRE(loader_a.getInteger(
"B") == 2);
368 REQUIRE(loader_a.get(
"C") ==
"3");
369 REQUIRE(loader_a.nextRow());
370 REQUIRE(loader_a.get(
"A") ==
"5");
371 REQUIRE(loader_a.getInteger(
"B") == 6);
372 REQUIRE(loader_a.get(
"C") ==
"7");
373 REQUIRE(!loader_a.nextRow());
375 std::string test_b(
"#Ignore me, dude\nA,B,C\n\n1,2,3\n5,\"6\",7");
377 StringCSVLoader loader_b(test_b);
379 REQUIRE(loader_b.nextRow());
380 REQUIRE(loader_b.get(
"A") ==
"1");
381 REQUIRE(loader_b.getInteger(
"B") == 2);
382 REQUIRE(loader_b.get(
"C") ==
"3");
383 REQUIRE(loader_b.nextRow());
384 REQUIRE(loader_b.get(
"A") ==
"5");
385 REQUIRE(loader_b.getInteger(
"B") == 6);
386 REQUIRE(loader_b.get(
"C") ==
"7");
387 REQUIRE(!loader_b.nextRow());
389 std::string test_c(
"#Ignore me, dude\nA,B,C\n\n1,2,3\n5,\"6\",7,9");
391 StringCSVLoader loader_c(test_c);
393 REQUIRE(loader_c.nextRow());
394 REQUIRE(loader_c.get(
"A") ==
"1");
395 REQUIRE(loader_c.getInteger(
"B") == 2);
396 REQUIRE(loader_c.get(
"C") ==
"3");
397 REQUIRE_THROWS(loader_c.nextRow());
399 std::ofstream fx_b(
"test.csv");
403 StreamCSVLoader loader_b2(
"test.csv");
405 REQUIRE(loader_b2.nextRow());
406 REQUIRE(loader_b2.get(
"A") ==
"1");
407 REQUIRE(loader_b2.getInteger(
"B") == 2);
408 REQUIRE(loader_b2.get(
"C") ==
"3");
409 REQUIRE(loader_b2.nextRow());
410 REQUIRE(loader_b2.get(
"A") ==
"5");
411 REQUIRE(loader_b2.getInteger(
"B") == 6);
412 REQUIRE(loader_b2.get(
"C") ==
"7");
413 REQUIRE(!loader_b2.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