PODIO v00-16-03
An Event-Data-Model Toolkit for High Energy Physics Experiments
Loading...
Searching...
No Matches
read_test.h
Go to the documentation of this file.
1#ifndef PODIO_TESTS_READ_TEST_H // NOLINT(llvm-header-guard): folder structure not suitable
2#define PODIO_TESTS_READ_TEST_H // NOLINT(llvm-header-guard): folder structure not suitable
3// test data model
4#include "datamodel/ExampleClusterCollection.h"
5#include "datamodel/ExampleHitCollection.h"
6#include "datamodel/ExampleMCCollection.h"
7#include "datamodel/ExampleReferencingTypeCollection.h"
8#include "datamodel/ExampleWithARelationCollection.h"
9#include "datamodel/ExampleWithArrayCollection.h"
10#include "datamodel/ExampleWithComponentCollection.h"
11#include "datamodel/ExampleWithFixedWidthIntegersCollection.h"
12#include "datamodel/ExampleWithNamespace.h"
13#include "datamodel/ExampleWithOneRelationCollection.h"
14#include "datamodel/ExampleWithVectorMemberCollection.h"
15
16// podio specific includes
17#include "podio/EventStore.h"
18#include "podio/IReader.h"
20#include "podio/podioVersion.h"
21
22// STL
23#include <cassert>
24#include <exception>
25#include <iostream>
26#include <limits>
27#include <sstream>
28#include <stdexcept>
29#include <type_traits>
30#include <vector>
31
32template <typename FixedWidthT>
33bool check_fixed_width_value(FixedWidthT actual, FixedWidthT expected, const std::string& type) {
34 if (actual != expected) {
35 std::stringstream msg{};
36 msg << "fixed width integer (" << type << ") value is not as expected: " << actual << " vs " << expected;
37 throw std::runtime_error(msg.str());
38 }
39 return true;
40}
41
42template <typename StoreT>
43static constexpr bool isEventStore = std::is_same_v<podio::EventStore, StoreT>;
44
45template <typename StoreT = podio::EventStore>
46void processEvent(StoreT& store, int eventNum, podio::version::Version fileVersion) {
47
48 float evtWeight = -1;
49 if constexpr (isEventStore<StoreT>) {
50 const auto& evtMD = store.getEventMetaData();
51 evtWeight = evtMD.template getValue<float>("UserEventWeight");
52 } else {
53 evtWeight = store.template getParameter<float>("UserEventWeight");
54 }
55 if (evtWeight != (float)100. * eventNum) {
56 std::cout << " read UserEventWeight: " << evtWeight << " - expected : " << (float)100. * eventNum << std::endl;
57 throw std::runtime_error("Couldn't read event meta data parameters 'UserEventWeight'");
58 }
59
60 std::stringstream ss;
61 ss << " event_number_" << eventNum;
62 std::string evtName = "";
63 if constexpr (isEventStore<StoreT>) {
64 const auto& evtMD = store.getEventMetaData();
65 evtName = evtMD.template getValue<std::string>("UserEventName");
66 } else {
67 evtName = store.template getParameter<std::string>("UserEventName");
68 }
69
70 if (evtName != ss.str()) {
71 std::cout << " read UserEventName: " << evtName << " - expected : " << ss.str() << std::endl;
72 throw std::runtime_error("Couldn't read event meta data parameters 'UserEventName'");
73 }
74
75 if (fileVersion > podio::version::Version{0, 14, 1}) {
76 std::vector<int> someVectorData{};
77 if constexpr (isEventStore<StoreT>) {
78 const auto& evtMD = store.getEventMetaData();
79 someVectorData = evtMD.template getValue<std::vector<int>>("SomeVectorData");
80 } else {
81 someVectorData = store.template getParameter<std::vector<int>>("SomeVectorData");
82 }
83 if (someVectorData.size() != 4) {
84 throw std::runtime_error("Couldn't read event meta data parameters: 'SomeVectorData'");
85 }
86 for (int i = 0; i < 4; ++i) {
87 if (someVectorData[i] != i + 1) {
88 throw std::runtime_error("Couldn't read event meta data parameters: 'SomeVectorData'");
89 }
90 }
91 }
92
93 if constexpr (!isEventStore<StoreT>) {
94 if (fileVersion > podio::version::Version{0, 16, 2}) {
95 const auto doubleParams = store.template getParameter<std::vector<double>>("SomeVectorData");
96 if (doubleParams.size() != 2 || doubleParams[0] != eventNum * 1.1 || doubleParams[1] != eventNum * 2.2) {
97 throw std::runtime_error("Could not read event parameter: 'SomeDoubleValues' correctly");
98 }
99 }
100 }
101
102 try {
103 // not assigning to a variable, because it will remain unused, we just want
104 // the exception here
105 store.template get<ExampleClusterCollection>("notthere");
106 } catch (const std::runtime_error& err) {
107 if (std::string(err.what()) != "No collection \'notthere\' is present in the EventStore") {
108 throw std::runtime_error("Trying to get non present collection \'notthere' should throw an exception");
109 }
110 }
111
112 // read collection meta data
113 auto& hits = store.template get<ExampleHitCollection>("hits");
114 if constexpr (isEventStore<StoreT>) {
115 const auto& colMD = store.getCollectionMetaData(hits.getID());
116 const auto& es = colMD.template getValue<std::string>("CellIDEncodingString");
117 if (es != std::string("system:8,barrel:3,layer:6,slice:5,x:-16,y:-16")) {
118 std::cout << " meta data from collection 'hits' with id = " << hits.getID()
119 << " read CellIDEncodingString: " << es << " - expected : system:8,barrel:3,layer:6,slice:5,x:-16,y:-16"
120 << std::endl;
121 throw std::runtime_error("Couldn't read event meta data parameters 'CellIDEncodingString'");
122 }
123
124 } else {
125 // TODO: Integrate this into the frame workflow somehow
126 }
127
128 if (fileVersion > podio::version::Version{0, 14, 0}) {
129 auto& hitRefs = store.template get<ExampleHitCollection>("hitRefs");
130 if (hitRefs.size() != hits.size()) {
131 throw std::runtime_error("hit and subset hit collection do not have the same size");
132 }
133 if (!(hits[1] == hitRefs[0] && hits[0] == hitRefs[1])) {
134 throw std::runtime_error("hit subset collections do not have the expected contents");
135 }
136 }
137
138 auto& clusters = store.template get<ExampleClusterCollection>("clusters");
139 if (clusters.isValid()) {
140 auto cluster = clusters[0];
141 for (auto i = cluster.Hits_begin(), end = cluster.Hits_end(); i != end; ++i) {
142 std::cout << " Referenced hit has an energy of " << i->energy() << std::endl;
143 }
144 } else {
145 throw std::runtime_error("Collection 'clusters' should be present");
146 }
147
148 if (fileVersion >= podio::version::Version{0, 13, 2}) {
149 // Read the mcParticleRefs before reading any of the other collections that
150 // are referenced to make sure that all the necessary relations are handled
151 // correctly
152 auto& mcpRefs = store.template get<ExampleMCCollection>("mcParticleRefs");
153 if (!mcpRefs.isValid()) {
154 throw std::runtime_error("Collection 'mcParticleRefs' should be present");
155 }
156
157 // Only doing a very basic check here, that mainly just ensures that the
158 // RelationRange is valid and does not segfault.
159 for (auto ref : mcpRefs) {
160 const auto daughters = ref.daughters();
161 if (!daughters.empty()) {
162 // This will segfault in case things are not working
163 auto d [[maybe_unused]] = daughters[0];
164 }
165
166 const auto parents = ref.parents();
167 if (!parents.empty()) {
168 // This will segfault in case things are not working
169 auto d [[maybe_unused]] = parents[0];
170 }
171 }
172 }
173
174 auto& mcps = store.template get<ExampleMCCollection>("mcparticles");
175 if (!mcps.isValid()) {
176 throw std::runtime_error("Collection 'mcparticles' should be present");
177 }
178
179 // check that we can retrieve the correct parent daughter relation
180 // set in write_test.h :
181 //-------- print relations for debugging:
182 for (auto p : mcps) {
183 std::cout << " particle " << p.getObjectID().index << " has daughters: ";
184 for (auto it = p.daughters_begin(), end = p.daughters_end(); it != end; ++it) {
185 std::cout << " " << it->getObjectID().index;
186 }
187 std::cout << " and parents: ";
188 for (auto it = p.parents_begin(), end = p.parents_end(); it != end; ++it) {
189 std::cout << " " << it->getObjectID().index;
190 }
191 std::cout << std::endl;
192 }
193
194 // particle 0 has particles 2,3,4 and 5 as daughters:
195 auto p = mcps[0];
196
197 auto d0 = p.daughters(0);
198 auto d1 = p.daughters(1);
199 auto d2 = p.daughters(2);
200 auto d3 = p.daughters(3);
201
202 if (!(d0 == mcps[2])) {
203 throw std::runtime_error(" error: 1. daughter of particle 0 is not particle 2 ");
204 }
205 if (!(d1 == mcps[3])) {
206 throw std::runtime_error(" error: 2. daughter of particle 0 is not particle 3 ");
207 }
208 if (!(d2 == mcps[4])) {
209 throw std::runtime_error(" error: 3. daughter of particle 0 is not particle 4 ");
210 }
211 if (!(d3 == mcps[5])) {
212 throw std::runtime_error(" error: 4. daughter of particle 0 is not particle 5 ");
213 }
214
215 // particle 3 has particles 6,7,8 and 9 as daughters:
216 p = mcps[3];
217
218 d0 = p.daughters(0);
219 d1 = p.daughters(1);
220 d2 = p.daughters(2);
221 d3 = p.daughters(3);
222
223 if (!(d0 == mcps[6])) {
224 throw std::runtime_error(" error: 1. daughter of particle 3 is not particle 6 ");
225 }
226 if (!(d1 == mcps[7])) {
227 throw std::runtime_error(" error: 2. daughter of particle 3 is not particle 7 ");
228 }
229 if (!(d2 == mcps[8])) {
230 throw std::runtime_error(" error: 3. daughter of particle 3 is not particle 8 ");
231 }
232 if (!(d3 == mcps[9])) {
233 throw std::runtime_error(" error: 4. daughter of particle 3 is not particle 9 ");
234 }
235
236 // Check the MCParticle subset collection only if it is technically possible
237 // to be in the file
238 if (fileVersion >= podio::version::Version{0, 13, 2}) {
239
240 // Load the subset collection first to ensure that it pulls in objects taht
241 // have not been read yet
242 auto& mcpRefs = store.template get<ExampleMCCollection>("mcParticleRefs");
243 if (!mcpRefs.isValid()) {
244 throw std::runtime_error("Collection 'mcParticleRefs' should be present");
245 }
246
247 for (auto pr : mcpRefs) {
248 if ((unsigned)pr.getObjectID().collectionID == mcpRefs.getID()) {
249 throw std::runtime_error(
250 "objects of a reference collection should have a different collectionID than the reference collection");
251 }
252 }
253
254 auto& moreMCs = store.template get<ExampleMCCollection>("moreMCs");
255
256 // First check that the two mc collections that we store are the same
257 if (mcps.size() != moreMCs.size()) {
258 throw std::runtime_error("'mcparticles' and 'moreMCs' should have the same size");
259 }
260
261 for (size_t index = 0; index < mcps.size(); ++index) {
262 // Not too detailed check here
263 if (mcps[index].energy() != moreMCs[index].energy() ||
264 mcps[index].daughters().size() != moreMCs[index].daughters().size()) {
265 throw std::runtime_error("'mcparticles' and 'moreMCs' do not contain the same elements");
266 }
267 }
268
269 if (mcpRefs.size() != mcps.size()) {
270 throw std::runtime_error("'mcParticleRefs' collection has wrong size");
271 }
272 for (size_t i = 0; i < mcpRefs.size(); ++i) {
273 if (i < 5) { // The first elements point into the mcps collection
274 if (!(mcpRefs[i] == mcps[2 * i + 1])) {
275 throw std::runtime_error("MCParticle reference does not point to the correct MCParticle");
276 }
277 } else { // The second half points into the moreMCs collection
278 const int index = (i - 5) * 2;
279 if (!(mcpRefs[i] == moreMCs[index])) {
280 throw std::runtime_error("MCParticle reference does not point to the correct MCParticle");
281 }
282 }
283 }
284 }
285
286 // std::cout << "Fetching collection 'refs'" << std::endl;
287 auto& refs = store.template get<ExampleReferencingTypeCollection>("refs");
288 if (refs.isValid()) {
289 auto ref = refs[0];
290 for (auto cluster : ref.Clusters()) {
291 for (auto hit [[maybe_unused]] : cluster.Hits()) {
292 // std::cout << " Referenced object has an energy of " << hit.energy() << std::endl;
293 }
294 }
295 } else {
296 throw std::runtime_error("Collection 'refs' should be present");
297 }
298 // std::cout << "Fetching collection 'OneRelation'" << std::endl;
299 auto& rels = store.template get<ExampleWithOneRelationCollection>("OneRelation");
300 if (rels.isValid()) {
301 // std::cout << "Referenced object has an energy of " << (*rels)[0].cluster().energy() << std::endl;
302 } else {
303 throw std::runtime_error("Collection 'OneRelation' should be present");
304 }
305
306 // std::cout << "Fetching collection 'WithVectorMember'" << std::endl;
307 auto& vecs = store.template get<ExampleWithVectorMemberCollection>("WithVectorMember");
308 if (vecs.isValid()) {
309 if (vecs.size() != 2) {
310 throw std::runtime_error("Collection 'WithVectorMember' should have two elements'");
311 }
312
313 for (auto vec : vecs) {
314 if (vec.count().size() != 2) {
315 throw std::runtime_error(
316 "Element of 'WithVectorMember' collection should have two elements in its 'count' vector");
317 }
318 }
319 if (vecs[0].count(0) != eventNum || vecs[0].count(1) != eventNum + 10 || vecs[1].count(0) != eventNum + 1 ||
320 vecs[1].count(1) != eventNum + 11) {
321 throw std::runtime_error("Element values of the 'count' vector in an element of the 'WithVectorMember' "
322 "collection do not have the expected values");
323 }
324
325 for (auto item : vecs) {
326 for (auto c = item.count_begin(), end = item.count_end(); c != end; ++c) {
327 std::cout << " Counter value " << (*c) << std::endl;
328 }
329 }
330 } else {
331 throw std::runtime_error("Collection 'WithVectorMember' should be present");
332 }
333
334 auto& comps = store.template get<ExampleWithComponentCollection>("Component");
335 if (comps.isValid()) {
336 auto comp = comps[0];
337 int a [[maybe_unused]] = comp.component().data.x + comp.component().data.z;
338 }
339
340 auto& arrays = store.template get<ExampleWithArrayCollection>("arrays");
341 if (arrays.isValid() && arrays.size() != 0) {
342 auto array = arrays[0];
343 if (array.myArray(1) != eventNum) {
344 throw std::runtime_error("Array not properly set.");
345 }
346 if (array.arrayStruct().data.p.at(2) != 2 * eventNum) {
347 throw std::runtime_error("Array not properly set.");
348 }
349 if (array.structArray(0).x != eventNum) {
350 throw std::runtime_error("Array of struct not properly set.");
351 }
352 } else {
353 throw std::runtime_error("Collection 'arrays' should be present");
354 }
355
356 auto& nmspaces = store.template get<ex42::ExampleWithARelationCollection>("WithNamespaceRelation");
357 auto& copies = store.template get<ex42::ExampleWithARelationCollection>("WithNamespaceRelationCopy");
358
359 auto cpytest = ex42::ExampleWithARelationCollection{};
360 if (nmspaces.isValid() && copies.isValid()) {
361 for (size_t j = 0; j < nmspaces.size(); j++) {
362 auto nmsp = nmspaces[j];
363 auto cpy = copies[j];
364 cpytest.push_back(nmsp.clone());
365 if (nmsp.ref().isAvailable()) {
366 if (nmsp.ref().component().x != cpy.ref().component().x ||
367 nmsp.ref().component().y != cpy.ref().component().y) {
368 throw std::runtime_error("Copied item has differing component in OneToOne referenced item.");
369 }
370 // check direct accessors of POD sub members
371 if (nmsp.ref().x() != cpy.ref().x()) {
372 throw std::runtime_error("Getting wrong values when using direct accessors for sub members.");
373 }
374 if (nmsp.number() != cpy.number()) {
375 throw std::runtime_error("Copied item has differing member.");
376 }
377 if (!(nmsp.ref().getObjectID() == cpy.ref().getObjectID())) {
378 throw std::runtime_error("Copied item has wrong OneToOne references.");
379 }
380 }
381 auto cpy_it = cpy.refs_begin();
382 for (auto it = nmsp.refs_begin(); it != nmsp.refs_end(); ++it, ++cpy_it) {
383 if (it->component().x != cpy_it->component().x || it->component().y != cpy_it->component().y) {
384 throw std::runtime_error("Copied item has differing component in OneToMany referenced item.");
385 }
386 if (!(it->getObjectID() == cpy_it->getObjectID())) {
387 throw std::runtime_error("Copied item has wrong OneToMany references.");
388 }
389 }
390 }
391 } else {
392 throw std::runtime_error("Collection 'WithNamespaceRelation' and 'WithNamespaceRelationCopy' should be present");
393 }
394
395 if (fileVersion >= podio::version::Version{0, 13, 1}) {
396 const auto& fixedWidthInts = store.template get<ExampleWithFixedWidthIntegersCollection>("fixedWidthInts");
397 if (not fixedWidthInts.isValid() or fixedWidthInts.size() != 3) {
398 throw std::runtime_error("Collection \'fixedWidthInts\' should be present and have 3 elements");
399 }
400
401 auto maxValues = fixedWidthInts[0];
402 const auto& maxComps = maxValues.fixedWidthStruct();
403 check_fixed_width_value(maxValues.fixedI16(), std::numeric_limits<std::int16_t>::max(), "int16");
404 check_fixed_width_value(maxValues.fixedU32(), std::numeric_limits<std::uint32_t>::max(), "uint32");
405 check_fixed_width_value(maxValues.fixedU64(), std::numeric_limits<std::uint64_t>::max(), "uint64");
406 check_fixed_width_value(maxComps.fixedInteger64, std::numeric_limits<std::int64_t>::max(), "int64");
407 check_fixed_width_value(maxComps.fixedInteger32, std::numeric_limits<std::int32_t>::max(), "int32");
408 check_fixed_width_value(maxComps.fixedUnsigned16, std::numeric_limits<std::uint16_t>::max(), "uint16");
409
410 auto minValues = fixedWidthInts[1];
411 const auto& minComps = minValues.fixedWidthStruct();
412 check_fixed_width_value(minValues.fixedI16(), std::numeric_limits<std::int16_t>::min(), "int16");
413 check_fixed_width_value(minValues.fixedU32(), std::numeric_limits<std::uint32_t>::min(), "uint32");
414 check_fixed_width_value(minValues.fixedU64(), std::numeric_limits<std::uint64_t>::min(), "uint64");
415 check_fixed_width_value(minComps.fixedInteger64, std::numeric_limits<std::int64_t>::min(), "int64");
416 check_fixed_width_value(minComps.fixedInteger32, std::numeric_limits<std::int32_t>::min(), "int32");
417 check_fixed_width_value(minComps.fixedUnsigned16, std::numeric_limits<std::uint16_t>::min(), "uint16");
418
419 auto arbValues = fixedWidthInts[2];
420 const auto& arbComps = arbValues.fixedWidthStruct();
421 check_fixed_width_value(arbValues.fixedI16(), std::int16_t{-12345}, "int16");
422 check_fixed_width_value(arbValues.fixedU32(), std::uint32_t{1234567890}, "uint32");
423 check_fixed_width_value(arbValues.fixedU64(), std::uint64_t{1234567890123456789}, "uint64");
424 check_fixed_width_value(arbComps.fixedInteger64, std::int64_t{-1234567890123456789}, "int64");
425 check_fixed_width_value(arbComps.fixedInteger32, std::int32_t{-1234567890}, "int32");
426 check_fixed_width_value(arbComps.fixedUnsigned16, std::uint16_t{12345}, "uint16");
427 }
428
429 if (fileVersion >= podio::version::Version{0, 13, 2}) {
430 auto& usrInts = store.template get<podio::UserDataCollection<uint64_t>>("userInts");
431
432 if (usrInts.size() != (unsigned)eventNum + 1) {
433 throw std::runtime_error("Could not read all userInts properly (expected: " + std::to_string(eventNum + 1) +
434 ", actual: " + std::to_string(usrInts.size()) + ")");
435 }
436
437 auto& uivec = usrInts.vec();
438 int myInt = 0;
439 for (int iu : uivec) {
440 if (iu != myInt++) {
441 throw std::runtime_error("Couldn't read userInts properly");
442 }
443 }
444
445 myInt = 0;
446 for (int iu : usrInts) {
447 if (iu != myInt++) {
448 throw std::runtime_error("Couldn't read userInts properly");
449 }
450 }
451
452 auto& usrDbl = store.template get<podio::UserDataCollection<double>>("userDoubles");
453 if (usrDbl.size() != 100) {
454 throw std::runtime_error(
455 "Could not read all userDoubles properly (expected: 100, actual: " + std::to_string(usrDbl.size()) + ")");
456 }
457
458 for (double d : usrDbl) {
459 if (d != 42.) {
460 throw std::runtime_error("Couldn't read userDoubles properly");
461 }
462 }
463 }
464}
465
467 auto store = podio::EventStore();
468 store.setReader(&reader);
469
470 const auto nEvents = reader.getEntries();
471
472 // Some information in the test files dpends directly on the index. In
473 // read-multiple, the same file is essentially read twice, so that at the file
474 // change the index which is used for testing has to start at 0 again. This
475 // function just wraps that. The magic number of 2000 is the number of events
476 // that are present in each file that is written in write
477 const auto correctIndex = [nEvents](unsigned index) {
478 if (nEvents > 2000) {
479 return index % (nEvents / 2);
480 }
481 return index;
482 };
483
484 for (unsigned i = 0; i < nEvents; ++i) {
485
486 if (i % 1000 == 0) {
487 std::cout << "reading event " << i << std::endl;
488 }
489
490 processEvent(store, correctIndex(i), reader.currentFileVersion());
491 store.clear();
492 reader.endOfEvent();
493 }
494}
495
496// Same as above but only for a specified event
497void run_read_test_event(podio::IReader& reader, unsigned event) {
498 auto store = podio::EventStore();
499 store.setReader(&reader);
500
501 reader.goToEvent(event);
502 processEvent(store, event, reader.currentFileVersion());
503 store.clear();
504 reader.endOfEvent();
505}
506
507#endif // PODIO_TESTS_READ_TEST_H
virtual podio::version::Version currentFileVersion() const =0
Get the podio version with which the current file has been written.
virtual void endOfEvent()=0
Prepare the reader to read the next event.
virtual void goToEvent(unsigned iEvent)=0
virtual unsigned getEntries() const =0
get the number of events available from this reader
bool check_fixed_width_value(FixedWidthT actual, FixedWidthT expected, const std::string &type)
Definition: read_test.h:33
void run_read_test(podio::IReader &reader)
Definition: read_test.h:466
void run_read_test_event(podio::IReader &reader, unsigned event)
Definition: read_test.h:497
void processEvent(StoreT &store, int eventNum, podio::version::Version fileVersion)
Definition: read_test.h:46