ATLAS Offline Software
Loading...
Searching...
No Matches
ColumnarPhysliteTest.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7
8//
9// includes
10//
11
13
14#include <AsgTesting/UnitTest.h>
34
39
40#ifndef XAOD_STANDALONE
42#endif
43
44#include <TFile.h>
45#include <TLeaf.h>
46#include <TTree.h>
47
48#include <boost/core/demangle.hpp>
49
50#include <chrono>
51#include <cstdint>
52#include <format>
53#include <memory>
54#include <vector>
55
56#include <gtest/gtest.h>
57
58//
59// method implementations
60//
61
62namespace columnar
63{
64 // I'm moving code to this namespace but some of the code in this file
65 // is still just in the columnar namespace. As I evolve the code I'll
66 // move more of it to TestUtils.
67 using namespace TestUtils;
68
69 namespace TestUtils
70 {
71 // I never figured out how the keys get calculated, so I looked
72 // at what's in the input file, and hard-coded it here.
73 static const std::unordered_map<std::string,SG::sgkey_t> knownKeys =
74 {
75 {"AnalysisMuons", 0x3a6b126f},
76 {"AnalysisElectrons", 0x3902fec0},
77 {"AnalysisPhotons", 0x35d1472f},
78 {"AnalysisJets", 0x1afd1919},
79 {"egammaClusters", 0x15788d1f},
80 {"GSFConversionVertices", 0x1f3e85c9},
81 {"InDetTrackParticles", 0x1d3890db},
82 {"CombinedMuonTrackParticles", 0x340d9196},
83 {"ExtrapolatedMuonTrackParticles", 0x14e35e9f},
84 {"GSFTrackParticles", 0x2e42db0b},
85 {"InDetForwardTrackParticles", 0x143c6846},
86 {"MuonSpectrometerTrackParticles", 0x3993c8f3},
87 };
88
89 template<typename T>
90 class BranchReader final
91 {
92 std::string m_branchName;
93 TBranch *m_branch = nullptr;
94 bool m_isStatic = std::is_pod_v<T>;
95 T *m_data {new T()};
96
97 public:
98 BranchReader (const std::string& val_branchName)
99 : m_branchName (val_branchName)
100 {
101 if (m_branchName.find ("Aux.") != std::string::npos)
102 m_isStatic = true;
103 }
104
105 ~BranchReader () noexcept
106 {
107 delete m_data;
108 }
109
110 BranchReader (const BranchReader&) = delete;
112
113 void setIsStatic (bool isStatic)
114 {
115 m_isStatic = isStatic;
116 }
117
118 [[nodiscard]] const std::string& branchName () const
119 {
120 return m_branchName;
121 }
122
123 [[nodiscard]] std::string columnName () const
124 {
125 std::string columnName = m_branchName;
126 if (auto index = columnName.find ("AuxDyn."); index != std::string::npos)
127 columnName.replace (index, 6, "");
128 else if (auto index = columnName.find ("Aux."); index != std::string::npos)
129 columnName.replace (index, 3, "");
130 else if (columnName.find (".") != std::string::npos)
131 throw std::runtime_error ("branch name does not contain AuxDyn or Aux: " + m_branchName);
132 return columnName;
133 }
134
135 [[nodiscard]] std::string containerName () const
136 {
137 if (auto index = m_branchName.find ("AuxDyn."); index != std::string::npos)
138 return m_branchName.substr (0, index);
139 else if (auto index = m_branchName.find ("Aux."); index != std::string::npos)
140 return m_branchName.substr (0, index);
141 else if (m_branchName.find (".") == std::string::npos)
142 return m_branchName;
143 else
144 throw std::runtime_error ("branch name does not contain AuxDyn or Aux: " + m_branchName);
145 }
146
147 void connectTree (TTree *tree)
148 {
149 m_branch = tree->GetBranch (m_branchName.c_str());
150 if (!m_branch)
151 throw std::runtime_error ("failed to get branch: " + m_branchName);
152 m_branch->SetMakeClass (1);
153 if (m_isStatic)
154 m_branch->SetAddress (m_data);
155 else
156 m_branch->SetAddress (&m_data);
157 }
158
159 const T& getEntry (Long64_t entry)
160 {
161 if (!m_branch)
162 throw std::runtime_error ("branch not connected: " + m_branchName);
163 if (m_branch->GetEntry (entry) <= 0)
164 throw std::runtime_error ("failed to get entry " + std::to_string (entry) + " for branch: " + m_branchName);
165 if (m_data == nullptr)
166 throw std::runtime_error ("got nullptr reading data for branch: " + m_branchName);
167 return *m_data;
168 }
169
170 const T& getCachedEntry () const
171 {
172 return *m_data;
173 }
174
175 std::optional<float> entrySize () const
176 {
177 if (!m_branch)
178 return std::nullopt;
179 return static_cast<float>(m_branch->GetZipBytes()) / m_branch->GetEntries();
180 }
181
182 std::optional<float> uncompressedSize () const
183 {
184 if (!m_branch)
185 return std::nullopt;
186 return static_cast<float>(m_branch->GetTotBytes()) / m_branch->GetEntries();
187 }
188
189 // technically this is const-correct, but I don't want to convince
190 // the code checker of that
191 std::optional<unsigned> numBaskets ()
192 {
193 if (!m_branch)
194 return std::nullopt;
195 return m_branch->GetListOfBaskets()->GetSize();
196 }
197 };
198
199 template<typename T>
201 {
202 public:
203 std::string m_branchName;
204 TBranch *m_branch = nullptr;
205 std::vector<T> m_dataVec;
206
207 public:
208 BranchReaderArray (const std::string& val_branchName)
209 : m_branchName (val_branchName)
210 {}
211
214
215 [[nodiscard]] std::string columnName () const
216 {
217 std::string columnName = m_branchName;
218 if (auto index = columnName.find ("AuxDyn."); index != std::string::npos)
219 columnName.replace (index, 6, "");
220 else if (auto index = columnName.find ("Aux."); index != std::string::npos)
221 columnName.replace (index, 3, "");
222 else if (columnName.find (".") != std::string::npos)
223 throw std::runtime_error ("branch name does not contain AuxDyn or Aux: " + m_branchName);
224 return columnName;
225 }
226
227 [[nodiscard]] std::string containerName () const
228 {
229 if (auto index = m_branchName.find ("AuxDyn."); index != std::string::npos)
230 return m_branchName.substr (0, index);
231 else if (auto index = m_branchName.find ("Aux."); index != std::string::npos)
232 return m_branchName.substr (0, index);
233 else if (m_branchName.find (".") == std::string::npos)
234 return m_branchName;
235 else
236 throw std::runtime_error ("branch name does not contain AuxDyn or Aux: " + m_branchName);
237 }
238
239 void connectTree (TTree *tree)
240 {
241 m_branch = tree->GetBranch (m_branchName.c_str());
242 if (!m_branch)
243 throw std::runtime_error ("failed to get branch: " + m_branchName);
244 m_branch->SetMakeClass (1);
245 // FIX ME: I have to have some hard-coded size, see explanation
246 // below.
247 m_dataVec.resize (100);
248 if (!m_dataVec.empty())
249 m_branch->SetAddress (m_dataVec.data());
250 }
251
252 std::span<const T> getEntry (Long64_t entry, std::size_t size)
253 {
254 if (!m_branch)
255 throw std::runtime_error ("branch not connected: " + m_branchName);
256 if (m_dataVec.size() < size)
257 {
258 // FIX ME: in one of the latest releases the repointing below
259 // breaks, and causes memory corruption. so I'm now
260 // preallocating and fail rather than reallocate, and the
261 // problem goes away. maybe it should be investigated at some
262 // point, but this is a test and I already spend a fair amount
263 // of time investigating this. the harm is that this test
264 // consumes a few hundreds bytes more in memory and we may have
265 // to occasionally increase the buffer size to cover all test
266 // files and branch lengths.
267 throw std::runtime_error ("requested size exceeds buffer size for branch: " + m_branchName);
268 // m_dataVec.resize (size);
269 // m_branch->SetAddress (m_dataVec.data());
270 }
271 if (size > 0 && m_branch->GetEntry (entry) <= 0)
272 throw std::runtime_error ("failed to get entry " + std::to_string (entry) + " for branch: " + m_branchName);
273 return std::span<const T>(m_dataVec.data(), size);
274 }
275
276 std::optional<float> entrySize () const
277 {
278 if (!m_branch)
279 return std::nullopt;
280 return static_cast<float>(m_branch->GetZipBytes()) / m_branch->GetEntries();
281 }
282
283 std::optional<float> uncompressedSize () const
284 {
285 if (!m_branch)
286 return std::nullopt;
287 return static_cast<float>(m_branch->GetTotBytes()) / m_branch->GetEntries();
288 }
289
290 // technically this is const-correct, but I don't want to convince
291 // the code checker of that
292 std::optional<unsigned> numBaskets ()
293 {
294 if (!m_branch)
295 return std::nullopt;
296 return m_branch->GetListOfBaskets()->GetSize();
297 }
298 };
299
301 {
302 public:
303
305 {
306 std::string name;
307 bool isOffset = false;
308 bool primary = false;
309 bool enabled = false;
310 };
311 std::vector<OutputColumnInfo> outputColumns;
312
313 virtual ~IColumnData () noexcept = default;
314
315 virtual bool connect (TTree *tree, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns) = 0;
316
317 virtual void clearColumns () = 0;
318
319 virtual void getEntry (Long64_t entry) = 0;
320
321 virtual void setData (TestUtils::ToolWrapperData& tool) = 0;
322
323 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) = 0;
324
325 virtual void collectColumnData () = 0;
326 };
327
329 {
330 std::array<ColumnarOffsetType, 2> data = {0, 0};
331
333 {
334 outputColumns.push_back ({.name = numberOfEventsName, .isOffset = true});
335 }
336
337 virtual bool connect (TTree * /*tree*/, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
338 {
339 if (requestedColumns.contains (outputColumns.at(0).name))
340 {
341 requestedColumns.erase (outputColumns.at(0).name);
342 outputColumns.at(0).enabled = true;
343 return true;
344 }
345 return false;
346 }
347
348 virtual void clearColumns () override
349 {
350 data[0] = 0;
351 data[1] = 0;
352 }
353
354 virtual void getEntry (Long64_t /*entry*/) override
355 {
356 data[1] += 1;
357 }
358
359 virtual void setData (TestUtils::ToolWrapperData& tool) override
360 {
361 if (outputColumns.at(0).enabled)
362 tool.setColumn (outputColumns.at(0).name, data.size(), data.data());
363 }
364
365 [[nodiscard]] virtual BranchPerfData getPerfData (float /*emptyTime*/) override
366 {
368 result.name = "EventCount(auto)";
369 return result;
370 }
371
372 virtual void collectColumnData () override
373 {}
374 };
375
376 template<typename T>
378 {
382 std::vector<T> outData;
383 unsigned entries = 0;
384
385 explicit ColumnDataScalar (const std::string& val_branchName)
386 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
387 {
388 outputColumns.push_back ({.name = branchReader.columnName()});
389 }
390
391 virtual bool connect (TTree *tree, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
392 {
393 auto iter = requestedColumns.find (outputColumns.at(0).name);
394 if (iter == requestedColumns.end())
395 return false;
396 outputColumns.at(0).enabled = true;
397 requestedColumns.erase (iter);
398
399 branchReader.connectTree (tree);
400
401 return true;
402 }
403
404 virtual void clearColumns () override
405 {
406 outData.clear ();
407 }
408
409 virtual void getEntry (Long64_t entry) override
410 {
411 benchmark.startTimer ();
412 const auto& branchData = branchReader.getEntry (entry);
413 benchmark.stopTimer ();
414 benchmarkUnpack.startTimer ();
415 outData.push_back (branchData);
416 benchmarkUnpack.stopTimer ();
417 }
418
419 virtual void setData (TestUtils::ToolWrapperData& tool) override
420 {
421 if (outputColumns.at(0).enabled)
422 tool.setColumn (outputColumns.at(0).name, outData.size(), outData.data());
423 }
424
425 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
426 {
428 result.name = branchReader.columnName();
429 result.timeRead = benchmark.getEntryTime(emptyTime);
430 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
431 benchmark.setSilence();
432 benchmarkUnpack.setSilence();
433 result.entrySize = branchReader.entrySize();
434 result.uncompressedSize = branchReader.uncompressedSize();
435 result.numBaskets = branchReader.numBaskets();
436 result.entries = entries;
437 return result;
438 }
439
440 virtual void collectColumnData () override
441 {
442 entries += outData.size();
443 }
444 };
445
446 template<typename T>
448 {
450 const std::vector<ColumnarOffsetType>* offsetColumn = nullptr;
451 std::vector<ColumnarOffsetType> offsets = {0};
452 std::vector<T> outData;
455 unsigned entries = 0;
456
457 explicit ColumnDataVector (const std::string& val_branchName)
458 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
459 {
460 outputColumns.push_back ({.name = branchReader.columnName()});
461 outputColumns.push_back ({.name = branchReader.containerName(), .isOffset = true, .primary = false});
462 }
463
464 virtual bool connect (TTree *tree, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
465 {
466 auto iter = requestedColumns.find (outputColumns.at(0).name);
467 if (iter == requestedColumns.end())
468 return false;
469 outputColumns.at(0).enabled = true;
470
471 branchReader.connectTree (tree);
472
473 if (iter->second.offsetName != outputColumns.at(1).name)
474 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
475
476 requestedColumns.erase (iter);
477
478 if (auto offsetIter = offsetColumns.find (outputColumns.at(1).name); offsetIter != offsetColumns.end())
479 offsetColumn = offsetIter->second;
480 else
481 offsetColumns.emplace (outputColumns.at(1).name, &offsets);
482
483 iter = requestedColumns.find (outputColumns.at(1).name);
484 if (iter != requestedColumns.end())
485 {
486 requestedColumns.erase (iter);
487 outputColumns.at(1).enabled = true;
488 }
489
490 return true;
491 }
492
493 virtual void clearColumns () override
494 {
495 offsets.clear ();
496 offsets.push_back (0);
497 outData.clear ();
498 }
499
500 virtual void getEntry (Long64_t entry) override
501 {
502 benchmark.startTimer ();
503 const auto& branchData = branchReader.getEntry (entry);
504 benchmark.stopTimer ();
505 benchmarkUnpack.startTimer ();
506 outData.insert (outData.end(), branchData.begin(), branchData.end());
507 offsets.push_back (outData.size());
508 benchmarkUnpack.stopTimer ();
509 }
510
511 virtual void setData (TestUtils::ToolWrapperData& tool) override
512 {
513 if (outputColumns.at(0).enabled)
514 tool.setColumn (outputColumns.at(0).name, outData.size(), outData.data());
515 if (outputColumns.at(1).enabled)
516 tool.setColumn (outputColumns.at(1).name, offsets.size(), offsets.data());
517 if (offsetColumn)
518 {
519 if (offsetColumn->size() != offsets.size())
520 throw std::runtime_error ("offset column not filled yet: " + outputColumns.at(1).name);
521 if (offsetColumn->back() != offsets.back())
522 throw std::runtime_error ("offset column does not match: " + outputColumns.at(1).name);
523 }
524 }
525
526 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
527 {
529 result.name = branchReader.columnName();
530 result.timeRead = benchmark.getEntryTime(emptyTime);
531 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
532 benchmark.setSilence();
533 benchmarkUnpack.setSilence();
534 result.entrySize = branchReader.entrySize();
535 result.uncompressedSize = branchReader.uncompressedSize();
536 result.numBaskets = branchReader.numBaskets();
537 result.entries = entries;
538 return result;
539 }
540
541 virtual void collectColumnData () override
542 {
543 entries += outData.size();
544 }
545 };
546
547 template<typename T>
549 {
551 const std::vector<ColumnarOffsetType>* offsetColumn = nullptr;
552 std::vector<T> outData;
553 unsigned entries = 0;
554
555 ColumnDataOutVector (const std::string& val_columnName, const T& val_defaultValue)
556 : defaultValue (val_defaultValue)
557 {
558 outputColumns.push_back ({.name = val_columnName});
559 }
560
561 virtual bool connect (TTree * /*tree*/, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
562 {
563 auto iter = requestedColumns.find (outputColumns.at(0).name);
564 if (iter == requestedColumns.end())
565 return false;
566 outputColumns.at(0).enabled = true;
567
568 // WARNING: absolutely do not switch the next line to a
569 // reference, the pointed to element gets deleted below.
570 const auto offsetName = iter->second.offsetName;
571 if (offsetName.empty())
572 throw std::runtime_error ("missing offset column for: " + outputColumns.at(0).name);
573
574 requestedColumns.erase (iter);
575
576 if (auto offsetIter = offsetColumns.find (offsetName); offsetIter != offsetColumns.end())
577 offsetColumn = offsetIter->second;
578 else
579 throw std::runtime_error ("missing offset column for: " + outputColumns.at(0).name);
580 return true;
581 }
582
583 virtual void clearColumns () override
584 {
585 outData.clear ();
586 }
587
588 virtual void getEntry (Long64_t /*entry*/) override
589 {
590 outData.resize (offsetColumn->back(), defaultValue);
591 }
592
593 virtual void setData (TestUtils::ToolWrapperData& tool) override
594 {
595 if (outputColumns.at(0).enabled)
596 tool.setColumn (outputColumns.at(0).name, outData.size(), outData.data());
597 }
598
599 [[nodiscard]] virtual BranchPerfData getPerfData (float /*emptyTime*/) override
600 {
602 result.name = outputColumns.at(0).name + "(out)";
603 result.entries = entries;
604 return result;
605 }
606
607 virtual void collectColumnData () override
608 {
609 entries += outData.size();
610 }
611 };
612
613 template<typename T>
615 {
617 std::vector<ColumnarOffsetType> offsets = {0};
618 std::vector<T> columnData;
621 unsigned entries = 0;
622
623 explicit ColumnDataVectorVector (const std::string& val_branchName)
624 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
625 {
626 outputColumns.push_back ({.name = branchReader.columnName() + ".data"});
627 outputColumns.push_back ({.name = branchReader.columnName() + ".offset", .isOffset = true});
628 }
629
630 virtual bool connect (TTree *tree, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
631 {
632 auto iter = requestedColumns.find (outputColumns.at(0).name);
633 if (iter == requestedColumns.end())
634 return false;
635 outputColumns.at(0).enabled = true;
636
637 branchReader.connectTree (tree);
638
639 if (iter->second.offsetName != outputColumns.at(1).name)
640 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
641
642 requestedColumns.erase (iter);
643
644 iter = requestedColumns.find (outputColumns.at(1).name);
645 if (iter == requestedColumns.end())
646 return true;
647 requestedColumns.erase (iter);
648 outputColumns.at(1).enabled = true;
649 return true;
650 }
651
652 virtual void clearColumns () override
653 {
654 columnData.clear();
655 offsets.clear();
656 offsets.push_back (0);
657 }
658
659 virtual void getEntry (Long64_t entry) override
660 {
661 benchmark.startTimer ();
662 const auto& branchData = branchReader.getEntry (entry);
663 benchmark.stopTimer ();
664 benchmarkUnpack.startTimer ();
665 for (auto& data : branchData)
666 {
667 columnData.insert (columnData.end(), data.begin(), data.end());
668 offsets.push_back (columnData.size());
669 }
670 benchmarkUnpack.stopTimer ();
671 }
672
673 virtual void setData (TestUtils::ToolWrapperData& tool) override
674 {
675 if (outputColumns.at(0).enabled)
676 tool.setColumn (outputColumns.at(0).name, columnData.size(), columnData.data());
677 if (outputColumns.at(1).enabled)
678 tool.setColumn (outputColumns.at(1).name, offsets.size(), offsets.data());
679 }
680
681 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
682 {
684 result.name = branchReader.columnName();
685 result.timeRead = benchmark.getEntryTime(emptyTime);
686 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
687 benchmark.setSilence();
688 benchmarkUnpack.setSilence();
689 result.entrySize = branchReader.entrySize();
690 result.uncompressedSize = branchReader.uncompressedSize();
691 result.numBaskets = branchReader.numBaskets();
692 result.entries = entries;
693 return result;
694 }
695
696 virtual void collectColumnData () override
697 {
698 entries += columnData.size();
699 }
700 };
701
702 template<typename T>
704 {
707 std::vector<ColumnarOffsetType> offsets = {0};
708 std::vector<typename CM::LinkIndexType> columnData;
709 const std::vector<ColumnarOffsetType>* targetOffsetColumn = nullptr;
714 unsigned entries = 0;
715 unsigned nullEntries = 0;
716
717 explicit ColumnDataVectorVectorLink (const std::string& val_branchName)
718 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
719 {
720 outputColumns.push_back ({.name = branchReader.columnName() + ".data"});
721 outputColumns.push_back ({.name = branchReader.columnName() + ".offset", .isOffset = true});
722 }
723
724 virtual bool connect (TTree *tree, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
725 {
726 auto iter = requestedColumns.find (outputColumns.at(0).name);
727 if (iter == requestedColumns.end())
728 return false;
729 outputColumns.at(0).enabled = true;
730
731 branchReader.connectTree (tree);
732
733 if (iter->second.offsetName != outputColumns.at(1).name)
734 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
735
736 if (iter->second.linkTargetNames.size() != 1)
737 throw std::runtime_error ("expected exactly one link target name for: " + outputColumns.at(0).name);
738 targetContainerName = iter->second.linkTargetNames.at(0);
739 if (auto keyIter = knownKeys.find (targetContainerName); keyIter != knownKeys.end())
740 targetKey = keyIter->second;
741 if (auto offsetIter = offsetColumns.find (iter->second.linkTargetNames.at(0)); offsetIter != offsetColumns.end())
742 targetOffsetColumn = offsetIter->second;
743 else
744 throw std::runtime_error ("missing offset column: " + iter->second.linkTargetNames.at(0));
745
746 requestedColumns.erase (iter);
747
748 iter = requestedColumns.find (outputColumns.at(1).name);
749 if (iter == requestedColumns.end())
750 return true;
751 requestedColumns.erase (iter);
752 outputColumns.at(1).enabled = true;
753 return true;
754 }
755
756 virtual void clearColumns () override
757 {
758 columnData.clear();
759 offsets.clear();
760 offsets.push_back (0);
761 }
762
763 virtual void getEntry (Long64_t entry) override
764 {
765 benchmark.startTimer ();
766 const auto& branchData = branchReader.getEntry (entry);
767 benchmark.stopTimer ();
768 benchmarkUnpack.startTimer ();
769 if (targetOffsetColumn->size() < 2)
770 throw std::runtime_error ("target offset column not yet filled for: " + outputColumns.at(0).name);
771 for (auto& data : branchData)
772 {
773 for (auto& element : data)
774 {
775 if (element.isDefault() || (element.key() == 0 && element.index() == 0))
776 columnData.push_back (invalidObjectIndex);
777 else
778 {
779 columnData.push_back (element.index() + targetOffsetColumn->at (targetOffsetColumn->size()-2));
780 if (element.key() != targetKey)
781 {
782 if (targetKey == 0)
783 {
784 targetKey = element.key();
785 std::cout << "assume target key for " << targetContainerName << " is " << std::hex << targetKey << std::dec << std::endl;
786 } else
787 {
788 throw std::runtime_error(
789 std::format("target key mismatch: {:x} != {:x} for {} with element index {}",
790 element.key(), targetKey, outputColumns.at(0).name, element.index())
791 );
792 }
793 }
794 }
795 }
796 offsets.push_back (columnData.size());
797 }
798 benchmarkUnpack.stopTimer ();
799 }
800
801 virtual void setData (TestUtils::ToolWrapperData& tool) override
802 {
803 if (outputColumns.at(0).enabled)
804 tool.setColumn (outputColumns.at(0).name, columnData.size(), columnData.data());
805 if (outputColumns.at(1).enabled)
806 tool.setColumn (outputColumns.at(1).name, offsets.size(), offsets.data());
807 }
808
809 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
810 {
812 result.name = branchReader.columnName();
813 result.timeRead = benchmark.getEntryTime(emptyTime);
814 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
815 benchmark.setSilence();
816 benchmarkUnpack.setSilence();
817 result.entrySize = branchReader.entrySize();
818 result.uncompressedSize = branchReader.uncompressedSize();
819 result.numBaskets = branchReader.numBaskets();
820 result.entries = entries;
821 result.nullEntries = nullEntries;
822 return result;
823 }
824
825 virtual void collectColumnData () override
826 {
827 entries += columnData.size();
828 for (const auto& index : columnData)
829 {
831 nullEntries += 1;
832 }
833 }
834 };
835
836 template<typename T>
838 {
839 std::string columnName;
841 std::vector<ColumnarOffsetType> outerOffsets = {0};
842 std::vector<ColumnarOffsetType> innerOffsets = {0};
843 std::vector<T> columnData;
846 unsigned entries = 0;
847
848 explicit ColumnDataVectorVectorVector (const std::string& val_branchName)
850 {
851 outputColumns.push_back ({.name = branchReader.columnName() + ".data"});
852 outputColumns.push_back ({.name = branchReader.columnName() + ".innerOffset", .isOffset = true});
853 outputColumns.push_back ({.name = branchReader.columnName() + ".outerOffset", .isOffset = true});
854 }
855
856 virtual bool connect (TTree *tree, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
857 {
858 auto iter = requestedColumns.find (outputColumns.at(0).name);
859 if (iter == requestedColumns.end())
860 return false;
861 outputColumns.at(0).enabled = true;
862
863 branchReader.connectTree (tree);
864
865 if (iter->second.offsetName != outputColumns.at(1).name)
866 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
867
868 requestedColumns.erase (iter);
869
870 iter = requestedColumns.find (outputColumns.at(1).name);
871 if (iter == requestedColumns.end())
872 return true;
873 outputColumns.at(1).enabled = true;
874
875 if (iter->second.offsetName != outputColumns.at(2).name)
876 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(2).name);
877
878 requestedColumns.erase (iter);
879
880 iter = requestedColumns.find (outputColumns.at(2).name);
881 if (iter == requestedColumns.end())
882 return true;
883 outputColumns.at(2).enabled = true;
884 requestedColumns.erase (iter);
885 return true;
886 }
887
888 virtual void clearColumns () override
889 {
890 columnData.clear();
891 innerOffsets.clear();
892 innerOffsets.push_back (0);
893 outerOffsets.clear();
894 outerOffsets.push_back (0);
895 }
896
897 virtual void getEntry (Long64_t entry) override
898 {
899 benchmark.startTimer ();
900 const auto& branchData = branchReader.getEntry (entry);
901 benchmark.stopTimer ();
902 benchmarkUnpack.startTimer ();
903 for (auto& outerData : branchData)
904 {
905 for (auto& innerData : outerData)
906 {
907 columnData.insert (columnData.end(), innerData.begin(), innerData.end());
908 innerOffsets.push_back (columnData.size());
909 }
910 outerOffsets.push_back (innerOffsets.size()-1);
911 }
912 benchmarkUnpack.stopTimer ();
913 }
914
915 virtual void setData (TestUtils::ToolWrapperData& tool) override
916 {
917 if (outputColumns.at(0).enabled)
918 tool.setColumn (outputColumns.at(0).name, columnData.size(), columnData.data());
919 if (outputColumns.at(1).enabled)
920 tool.setColumn (outputColumns.at(1).name, innerOffsets.size(), innerOffsets.data());
921 if (outputColumns.at(2).enabled)
922 tool.setColumn (outputColumns.at(2).name, outerOffsets.size(), outerOffsets.data());
923 }
924
925 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
926 {
928 result.name = branchReader.columnName();
929 result.timeRead = benchmark.getEntryTime(emptyTime);
930 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
931 benchmark.setSilence();
932 benchmarkUnpack.setSilence();
933 result.entrySize = branchReader.entrySize();
934 result.uncompressedSize = branchReader.uncompressedSize();
935 result.numBaskets = branchReader.numBaskets();
936 result.entries = entries;
937 return result;
938 }
939
940 virtual void collectColumnData () override
941 {
942 entries += columnData.size();
943 }
944 };
945
946 template<typename T>
948 {
951 const std::vector<ColumnarOffsetType>* offsetColumn = nullptr;
952 std::vector<ColumnarOffsetType> offsets = {0};
953 std::vector<typename CM::LinkIndexType> columnData;
954 const std::vector<ColumnarOffsetType>* targetOffsetColumn = nullptr;
959 unsigned entries = 0;
960 unsigned nullEntries = 0;
961
962 ColumnDataVectorLink (const std::string& val_branchName)
963 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
964 {
965 outputColumns.push_back ({.name = branchReader.columnName()});
966 outputColumns.push_back ({.name = branchReader.containerName(), .isOffset = true, .primary = false});
967 }
968
969 virtual bool connect (TTree *tree, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
970 {
971 auto iter = requestedColumns.find (outputColumns.at(0).name);
972 if (iter == requestedColumns.end())
973 return false;
974 outputColumns.at(0).enabled = true;
975
976 branchReader.connectTree (tree);
977
978 if (iter->second.offsetName != outputColumns.at(1).name)
979 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
980
981 if (iter->second.linkTargetNames.size() != 1)
982 throw std::runtime_error ("expected exactly one link target name for: " + outputColumns.at(0).name);
983 targetContainerName = iter->second.linkTargetNames.at(0);
984 if (auto keyIter = knownKeys.find (targetContainerName); keyIter != knownKeys.end())
985 targetKey = keyIter->second;
986 if (auto targetOffsetIter = offsetColumns.find (iter->second.linkTargetNames.at(0)); targetOffsetIter != offsetColumns.end())
987 targetOffsetColumn = targetOffsetIter->second;
988 else
989 throw std::runtime_error ("missing offset column(vector-link): " + iter->second.linkTargetNames.at(0));
990
991 requestedColumns.erase (iter);
992
993 if (auto offsetIter = offsetColumns.find (outputColumns.at(1).name); offsetIter != offsetColumns.end())
994 offsetColumn = offsetIter->second;
995 else
996 offsetColumns.emplace (outputColumns.at(1).name, &offsets);
997
998 iter = requestedColumns.find (outputColumns.at(1).name);
999 if (iter != requestedColumns.end())
1000 {
1001 outputColumns.at(1).enabled = true;
1002 requestedColumns.erase (iter);
1003 }
1004
1005 return true;
1006 }
1007
1008 virtual void clearColumns () override
1009 {
1010 columnData.clear();
1011 offsets.clear();
1012 offsets.push_back (0);
1013 }
1014
1015 virtual void getEntry (Long64_t entry) override
1016 {
1017 benchmark.startTimer ();
1018 const auto& branchData = branchReader.getEntry (entry);
1019 benchmark.stopTimer ();
1020 benchmarkUnpack.startTimer ();
1021 if (targetOffsetColumn->size() < 2)
1022 throw std::runtime_error ("target offset column not yet filled for: " + outputColumns.at(0).name);
1023 for (auto& element : branchData)
1024 {
1025 if (element.isDefault() || (element.key() == 0 && element.index() == 0))
1026 columnData.push_back (invalidObjectIndex);
1027 else
1028 {
1029 columnData.push_back (element.index() + targetOffsetColumn->at (targetOffsetColumn->size()-2));
1030 if (element.key() != targetKey)
1031 {
1032 if (targetKey == 0)
1033 {
1034 targetKey = element.key();
1035 std::cout << "assume target key for " << targetContainerName << " is " << std::hex << targetKey << std::dec << std::endl;
1036 } else
1037 {
1038 throw std::runtime_error ("target key mismatch: " + std::to_string (element.key()) + " != " + std::to_string (targetKey) + " for " + outputColumns.at(0).name);
1039 }
1040 }
1041 }
1042 }
1043 offsets.push_back (columnData.size());
1044 if (offsetColumn)
1045 {
1046 if (offsetColumn->size() != offsets.size())
1047 throw std::runtime_error ("offset column not filled yet: " + outputColumns.at(1).name);
1048 if (offsetColumn->back() != offsets.back())
1049 throw std::runtime_error ("offset column does not match: " + outputColumns.at(1).name);
1050 }
1051 benchmarkUnpack.stopTimer ();
1052 }
1053
1054 virtual void setData (TestUtils::ToolWrapperData& tool) override
1055 {
1056 if (outputColumns.at(0).enabled)
1057 tool.setColumn (outputColumns.at(0).name, columnData.size(), columnData.data());
1058 if (outputColumns.at(1).enabled)
1059 tool.setColumn (outputColumns.at(1).name, offsets.size(), offsets.data());
1060 }
1061
1062 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1063 {
1065 result.name = branchReader.columnName();
1066 result.timeRead = benchmark.getEntryTime(emptyTime);
1067 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1068 benchmark.setSilence();
1069 benchmarkUnpack.setSilence();
1070 result.entrySize = branchReader.entrySize();
1071 result.uncompressedSize = branchReader.uncompressedSize();
1072 result.numBaskets = branchReader.numBaskets();
1073 result.entries = entries;
1074 result.nullEntries = nullEntries;
1075 return result;
1076 }
1077
1078 virtual void collectColumnData () override
1079 {
1080 entries += columnData.size();
1081 for (const auto& index : columnData)
1082 {
1084 nullEntries += 1;
1085 }
1086 }
1087 };
1088
1089 template<typename T>
1091 {
1096 const std::vector<ColumnarOffsetType>* offsetColumn = nullptr;
1097 std::vector<ColumnarOffsetType> offsets = {0};
1098 std::vector<typename CM::LinkIndexType> columnData;
1099 std::vector<const std::vector<ColumnarOffsetType>*> targetOffsetColumns;
1100 std::vector<SG::sgkey_t> targetKeys;
1101 std::vector<typename CM::LinkKeyType> keyColumnData;
1104 unsigned entries = 0;
1105 unsigned nullEntries = 0;
1106
1107 ColumnDataVectorSplitLink (const std::string& val_branchName)
1108 : branchReaderSize (val_branchName), branchReaderKey (val_branchName + ".m_persKey"), branchReaderIndex (val_branchName + ".m_persIndex"), benchmarkUnpack (branchReaderSize.columnName()+"(unpack)"), benchmark (branchReaderSize.columnName())
1109 {
1110 outputColumns.push_back ({.name = branchReaderSize.columnName()});
1111 outputColumns.push_back ({.name = branchReaderSize.containerName(), .isOffset = true, .primary = false});
1112 outputColumns.push_back ({.name = branchReaderSize.columnName() + ".keys", .primary = false});
1113 }
1114
1115 virtual bool connect (TTree *tree, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
1116 {
1117 auto iter = requestedColumns.find (outputColumns.at(0).name);
1118 if (iter == requestedColumns.end())
1119 return false;
1120 outputColumns.at(0).enabled = true;
1121
1122 branchReaderSize.connectTree (tree);
1123 branchReaderKey.connectTree (tree);
1124 branchReaderIndex.connectTree (tree);
1125
1126 if (iter->second.offsetName != outputColumns.at(1).name)
1127 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
1128
1129 const auto& linkContainers = iter->second.linkTargetNames;
1130 for (const auto& container : linkContainers)
1131 {
1132 if (auto keyIter = knownKeys.find (container); keyIter != knownKeys.end())
1133 targetKeys.push_back (keyIter->second);
1134 else
1135 throw std::runtime_error ("no key known for link container: " + container);
1136 if (auto targetOffsetIter = offsetColumns.find (container); targetOffsetIter != offsetColumns.end())
1137 targetOffsetColumns.push_back (targetOffsetIter->second);
1138 else
1139 throw std::runtime_error ("missing offset column: " + container);
1140 keyColumnData.push_back (keyColumnData.size());
1141 }
1142 requestedColumns.erase (iter);
1143
1144 if (auto offsetIter = offsetColumns.find (outputColumns.at(1).name); offsetIter != offsetColumns.end())
1145 offsetColumn = offsetIter->second;
1146 else
1147 offsetColumns.emplace (outputColumns.at(1).name, &offsets);
1148
1149 iter = requestedColumns.find (outputColumns.at(1).name);
1150 if (iter != requestedColumns.end())
1151 {
1152 outputColumns.at(1).enabled = true;
1153 requestedColumns.erase (iter);
1154 }
1155
1156 iter = requestedColumns.find (outputColumns.at(2).name);
1157 if (iter != requestedColumns.end())
1158 {
1159 outputColumns.at(2).enabled = true;
1160 requestedColumns.erase (iter);
1161 }
1162
1163 return true;
1164 }
1165
1166 virtual void clearColumns () override
1167 {
1168 columnData.clear();
1169 offsets.clear();
1170 offsets.push_back (0);
1171 }
1172
1173 virtual void getEntry (Long64_t entry) override
1174 {
1175 benchmark.startTimer ();
1176 std::size_t branchDataSize = branchReaderSize.getEntry (entry);
1177 auto branchDataKey = branchReaderKey.getEntry (entry, branchDataSize);
1178 auto branchDataIndex = branchReaderIndex.getEntry (entry, branchDataSize);
1179 benchmark.stopTimer ();
1180 benchmarkUnpack.startTimer ();
1181 for (auto& targetOffsetColumn : targetOffsetColumns)
1182 {
1183 if (targetOffsetColumn->size() <= offsets.size())
1184 throw std::runtime_error ("target offset column not yet filled for: " + outputColumns.at(0).name);
1185 }
1186 for (std::size_t index = 0; index < branchDataSize; ++index)
1187 {
1188 if (branchDataIndex[index] == static_cast<UInt_t>(-1))
1189 columnData.push_back (invalidObjectIndex);
1190 else
1191 {
1193 if (auto keyIter = std::find(targetKeys.begin(), targetKeys.end(), branchDataKey[index]); keyIter != targetKeys.end())
1194 {
1195 keyIndex = std::distance(targetKeys.begin(), keyIter);
1196 } else if (targetKeys.empty())
1197 {
1198 targetKeys.push_back (branchDataKey[index]);
1199 keyIndex = 0;
1200 std::cout << "assume target key for " << outputColumns.at(0).name << " is " << std::hex << branchDataKey[index] << std::dec << std::endl;
1201 } else if (branchDataKey[index] != 0)
1202 {
1203 std::ostringstream error;
1204 error << "target key mismatch: read " << std::hex << branchDataKey[index];
1205 error << ", expected one of";
1206 for (const auto& key : targetKeys)
1207 error << " " << key;
1208 error << " for " << outputColumns.at(0).name;
1209 throw std::runtime_error (std::move (error).str());
1210 }
1211 if (keyIndex == CM::invalidLinkValue)
1212 {
1213 columnData.push_back (CM::invalidLinkValue);
1214 } else
1215 {
1216 auto& targetOffsetColumn = *targetOffsetColumns.at(keyIndex);
1217 auto targetOffset = targetOffsetColumn.at (offsets.size()-1);
1218 CM::LinkIndexType linkIndex = branchDataIndex[index];
1219 linkIndex += targetOffset;
1220 if (linkIndex >= targetOffsetColumn.at(offsets.size()))
1221 throw std::runtime_error (std::format ("index out of range for link: {} >= {} (base index {})", outputColumns.at(0).name, linkIndex, targetOffsetColumn.at(offsets.size()), targetOffset));
1222 columnData.push_back (CM::mergeLinkKeyIndex (keyIndex, branchDataIndex[index] + targetOffset));
1223 }
1224 }
1225 }
1226 offsets.push_back (columnData.size());
1227 if (offsetColumn)
1228 {
1229 if (offsetColumn->size() != offsets.size())
1230 throw std::runtime_error ("offset column not filled yet: " + outputColumns.at(1).name);
1231 if (offsetColumn->back() != offsets.back())
1232 throw std::runtime_error ("offset column does not match: " + outputColumns.at(1).name);
1233 }
1234 benchmarkUnpack.stopTimer ();
1235 }
1236
1237 virtual void setData (TestUtils::ToolWrapperData& tool) override
1238 {
1239 if (outputColumns.at(0).enabled)
1240 tool.setColumn (outputColumns.at(0).name, columnData.size(), columnData.data());
1241 if (outputColumns.at(1).enabled)
1242 tool.setColumn (outputColumns.at(1).name, offsets.size(), offsets.data());
1243 if (outputColumns.at(2).enabled)
1244 tool.setColumn (outputColumns.at(2).name, keyColumnData.size(), keyColumnData.data());
1245 }
1246
1247 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1248 {
1250 result.name = branchReaderSize.columnName();
1251 result.timeRead = benchmark.getEntryTime(emptyTime);
1252 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1253 benchmark.setSilence();
1254 benchmarkUnpack.setSilence();
1255 result.entrySize = branchReaderSize.entrySize().value() + branchReaderKey.entrySize().value() + branchReaderIndex.entrySize().value();
1256 result.uncompressedSize = branchReaderSize.uncompressedSize().value() + branchReaderKey.uncompressedSize().value() + branchReaderIndex.uncompressedSize().value();
1257 result.numBaskets = branchReaderSize.numBaskets().value() + branchReaderKey.numBaskets().value() + branchReaderIndex.numBaskets().value();
1258 result.entries = entries;
1259 result.nullEntries = nullEntries;
1260 return result;
1261 }
1262
1263 virtual void collectColumnData () override
1264 {
1265 entries += columnData.size();
1266 for (const auto& index : columnData)
1267 {
1269 nullEntries += 1;
1270 }
1271 }
1272 };
1273
1274 template<typename T>
1276 {
1279 std::vector<ColumnarOffsetType> offsets = {0};
1280 std::vector<typename CM::LinkIndexType> columnData;
1281 std::vector<typename CM::LinkKeyType> keysColumn;
1282 std::vector<std::string> containers;
1283 std::vector<SG::sgkey_t> containerKeys;
1284 std::vector<const std::vector<ColumnarOffsetType>*> containerOffsets;
1287 unsigned entries = 0;
1288 unsigned nullEntries = 0;
1289
1290 bool checkUnknownKeys = false;
1291 std::unordered_map<SG::sgkey_t,std::unordered_set<std::string>> unknownKeys;
1292
1293 explicit ColumnDataVectorVectorVariantLink (const std::string& val_branchName)
1294 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
1295 {
1296 outputColumns.push_back ({.name = branchReader.columnName() + ".data"});
1297 outputColumns.push_back ({.name = branchReader.columnName() + ".offset", .isOffset = true});
1298 outputColumns.push_back ({.name = branchReader.columnName() + ".keys"});
1299 }
1300
1302 {
1303 // print unknown keys and containers they may be associated
1304 // with, based on whether they were always within the range of
1305 // elements allowed for the container.
1306 for (auto& [key, forbiddenContainer] : unknownKeys)
1307 {
1308 std::cout << "unknown key: " << std::hex << key << std::dec << ", allowed containers:";
1309 for (const auto& container : containers)
1310 {
1311 if (forbiddenContainer.find (container) == forbiddenContainer.end())
1312 std::cout << " " << container;
1313 }
1314 std::cout << std::endl;
1315 }
1316 }
1317
1318 virtual bool connect (TTree *tree, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
1319 {
1320 auto iter = requestedColumns.find (outputColumns.at(0).name);
1321 if (iter == requestedColumns.end())
1322 return false;
1323 outputColumns.at(0).enabled = true;
1324
1325 branchReader.connectTree (tree);
1326
1327 if (iter->second.offsetName != outputColumns.at(1).name)
1328 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
1329 containers = iter->second.linkTargetNames;
1330 if (containers.empty() || iter->second.variantLinkKeyColumn.empty())
1331 throw std::runtime_error ("no variant link containers for: " + outputColumns.at(0).name);
1332 if (iter->second.variantLinkKeyColumn != outputColumns.at(2).name)
1333 throw std::runtime_error ("variant link key column mismatch: " + iter->second.variantLinkKeyColumn + " != " + outputColumns.at(2).name);
1334
1335 for ([[maybe_unused]] auto& container : containers)
1336 {
1337 keysColumn.push_back (keysColumn.size()+1);
1338 if (!offsetColumns.contains (container))
1339 throw std::runtime_error ("missing offset column(variant-link): " + container);
1340 containerOffsets.push_back (offsetColumns.at (container));
1341 if (auto iter = knownKeys.find (container); iter != knownKeys.end())
1342 {
1343 containerKeys.push_back (iter->second);
1344 } else
1345 {
1346 checkUnknownKeys = true;
1347 containerKeys.push_back (0u);
1348 }
1349 }
1350
1351 requestedColumns.erase (iter);
1352
1353 iter = requestedColumns.find (outputColumns.at(1).name);
1354 if (iter != requestedColumns.end())
1355 {
1356 outputColumns.at(1).enabled = true;
1357 requestedColumns.erase (iter);
1358 }
1359
1360 iter = requestedColumns.find (outputColumns.at(2).name);
1361 if (iter != requestedColumns.end())
1362 {
1363 outputColumns.at(2).enabled = true;
1364 requestedColumns.erase (iter);
1365 }
1366 return true;
1367 }
1368
1369 virtual void clearColumns () override
1370 {
1371 columnData.clear();
1372 offsets.clear();
1373 offsets.push_back (0);
1374 }
1375
1376 virtual void getEntry (Long64_t entry) override
1377 {
1378 benchmark.startTimer ();
1379 const auto& branchData = branchReader.getEntry (entry);
1380 benchmark.stopTimer ();
1381 benchmarkUnpack.startTimer ();
1382 for (auto& data : branchData)
1383 {
1384 for (auto& element : data)
1385 {
1386 if (element.isDefault() || (element.key() == 0 && element.index() == 0))
1387 columnData.push_back (invalidObjectIndex);
1388 else
1389 {
1390 typename CM::LinkIndexType key = 0xff;
1391 typename CM::LinkIndexType index = 0;
1392 for (std::size_t i = 0; i < containers.size(); ++i)
1393 {
1394 if (element.key() == containerKeys[i])
1395 {
1396 if (containerOffsets[i]->back() <= element.index())
1397 throw std::runtime_error ("invalid index: " + std::to_string (element.index()) + " in container: " + containers[i] + " with size: " + std::to_string (containerOffsets[i]->back()));
1398 key = keysColumn[i];
1399 if (containerOffsets[i]->size() < 2)
1400 throw std::runtime_error ("container offset not yet filled for: " + containers[i]);
1401 index = containerOffsets[i]->at (containerOffsets[i]->size()-2) + element.index();
1402 break;
1403 }
1404 }
1405 if (key == 0xff && checkUnknownKeys)
1406 {
1407 // this records which containers the unknown key is
1408 // compatible with, so that I may figure out which
1409 // container it is and hard-code it above.
1410 auto& forbiddenContainers = unknownKeys[element.key()];
1411 for (std::size_t i = 0; i < containers.size(); ++i)
1412 {
1413 if (containerOffsets[i]->back() <= containerOffsets[i]->at (containerOffsets[i]->size()-2) + element.index())
1414 forbiddenContainers.insert (containers[i]);
1415 }
1416 }
1417 columnData.push_back (CM::mergeLinkKeyIndex (key, index));
1418 }
1419 }
1420 offsets.push_back (columnData.size());
1421 }
1422 benchmarkUnpack.stopTimer ();
1423 }
1424
1425 virtual void setData (TestUtils::ToolWrapperData& tool) override
1426 {
1427 if (outputColumns.at(0).enabled)
1428 tool.setColumn (outputColumns.at(0).name, columnData.size(), columnData.data());
1429 if (outputColumns.at(1).enabled)
1430 tool.setColumn (outputColumns.at(1).name, offsets.size(), offsets.data());
1431 if (outputColumns.at(2).enabled)
1432 tool.setColumn (outputColumns.at(2).name, keysColumn.size(), keysColumn.data());
1433 }
1434
1435 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1436 {
1438 result.name = branchReader.columnName();
1439 result.timeRead = benchmark.getEntryTime(emptyTime);
1440 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1441 benchmark.setSilence();
1442 benchmarkUnpack.setSilence();
1443 result.entrySize = branchReader.entrySize();
1444 result.uncompressedSize = branchReader.uncompressedSize();
1445 result.numBaskets = branchReader.numBaskets();
1446 result.entries = entries;
1447 result.nullEntries = nullEntries;
1448 return result;
1449 }
1450
1451 virtual void collectColumnData () override
1452 {
1453 entries += columnData.size();
1454 for (const auto& index : columnData)
1455 {
1457 nullEntries += 1;
1458 }
1459 }
1460 };
1461
1463 {
1465 std::vector<ColumnarOffsetType> offsets = {0};
1466 std::vector<char> columnData;
1467 std::vector<std::size_t> columnHashData;
1470
1471 ColumnDataMetNames (const std::string& val_branchName)
1472 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
1473 {
1474 outputColumns.push_back ({.name = branchReader.columnName() + ".data"});
1475 outputColumns.push_back ({.name = branchReader.columnName() + ".offset", .isOffset = true});
1476 outputColumns.push_back ({.name = branchReader.columnName() + "Hash"});
1477 }
1478
1479 virtual bool connect (TTree *tree, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
1480 {
1481 auto iter = requestedColumns.find (outputColumns.at(0).name);
1482 if (iter == requestedColumns.end())
1483 return false;
1484 outputColumns.at(0).enabled = true;
1485
1486 branchReader.connectTree (tree);
1487
1488 if (iter->second.offsetName != outputColumns.at(1).name)
1489 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
1490
1491 requestedColumns.erase (iter);
1492
1493 iter = requestedColumns.find (outputColumns.at(1).name);
1494 if (iter == requestedColumns.end())
1495 {
1496 return true;
1497 }
1498 outputColumns.at(1).enabled = true;
1499 requestedColumns.erase (iter);
1500
1501 iter = requestedColumns.find (outputColumns.at(2).name);
1502 if (iter != requestedColumns.end())
1503 {
1504 outputColumns.at(2).enabled = true;
1505 requestedColumns.erase (iter);
1506 }
1507 return true;
1508 }
1509
1510 virtual void clearColumns () override
1511 {
1512 columnData.clear();
1513 offsets.clear();
1514 offsets.push_back (0);
1515 columnHashData.clear();
1516 }
1517
1518 virtual void getEntry (Long64_t entry) override
1519 {
1520 benchmark.startTimer ();
1521 const auto& branchData = branchReader.getEntry (entry);
1522 benchmark.stopTimer ();
1523 benchmarkUnpack.startTimer ();
1524 for (auto& data : branchData)
1525 {
1526 columnData.insert (columnData.end(), data.begin(), data.end());
1527 offsets.push_back (columnData.size());
1528 columnHashData.push_back (std::hash<std::string> () (data));
1529 }
1530 benchmarkUnpack.stopTimer ();
1531 }
1532
1533 virtual void setData (TestUtils::ToolWrapperData& tool) override
1534 {
1535 if (outputColumns.at(0).enabled)
1536 tool.setColumn (outputColumns.at(0).name, columnData.size(), columnData.data());
1537 if (outputColumns.at(1).enabled)
1538 tool.setColumn (outputColumns.at(1).name, offsets.size(), offsets.data());
1539 if (outputColumns.at(2).enabled)
1540 tool.setColumn (outputColumns.at(2).name, columnHashData.size(), columnHashData.data());
1541 }
1542
1543 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1544 {
1546 result.name = branchReader.columnName();
1547 result.timeRead = benchmark.getEntryTime(emptyTime);
1548 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1549 benchmark.setSilence();
1550 benchmarkUnpack.setSilence();
1551 result.entrySize = branchReader.entrySize();
1552 result.uncompressedSize = branchReader.uncompressedSize();
1553 result.numBaskets = branchReader.numBaskets();
1554 return result;
1555 }
1556
1557 virtual void collectColumnData () override
1558 {}
1559 };
1560
1562 {
1563 std::vector<std::string> termNames;
1564 const std::vector<ColumnarOffsetType>* offsetColumns = nullptr;
1565 std::vector<ColumnarOffsetType> offsets = {0};
1566 std::vector<ColumnarOffsetType> namesOffsets = {0};
1567 std::vector<char> namesData;
1568 std::vector<std::size_t> namesHash;
1569
1570 ColumnDataOutputMet (const std::string& val_columnName, std::vector<std::string> val_termNames)
1571 : termNames (std::move (val_termNames))
1572 {
1573 outputColumns.push_back ({.name = val_columnName, .isOffset = true});
1574 outputColumns.push_back ({.name = val_columnName + ".name.data"});
1575 outputColumns.push_back ({.name = val_columnName + ".name.offset", .isOffset = true});
1576 outputColumns.push_back ({.name = val_columnName + ".nameHash"});
1577 }
1578
1579 virtual bool connect (TTree * /*tree*/, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
1580 {
1581 if (auto iter = requestedColumns.find (outputColumns.at(0).name);
1582 iter != requestedColumns.end())
1583 requestedColumns.erase (iter);
1584 else
1585 return false;
1586 outputColumns.at(0).enabled = true;
1587
1588 if (auto iter = requestedColumns.find (outputColumns.at(1).name);
1589 iter != requestedColumns.end())
1590 {
1591 outputColumns.at(1).enabled = true;
1592 requestedColumns.erase (iter);
1593 }
1594
1595 if (auto iter = requestedColumns.find (outputColumns.at(2).name);
1596 iter != requestedColumns.end())
1597 {
1598 outputColumns.at(2).enabled = true;
1599 requestedColumns.erase (iter);
1600 }
1601
1602 if (auto iter = requestedColumns.find (outputColumns.at(3).name);
1603 iter != requestedColumns.end())
1604 {
1605 outputColumns.at(3).enabled = true;
1606 requestedColumns.erase (iter);
1607 }
1608
1609 if (auto offsetIter = offsetColumns.find (outputColumns.at(0).name); offsetIter != offsetColumns.end())
1610 throw std::runtime_error ("duplicate size column: " + outputColumns.at(0).name);
1611 offsetColumns.emplace (outputColumns.at(0).name, &offsets);
1612
1613 return true;
1614 }
1615
1616 virtual void clearColumns () override
1617 {
1618 offsets.clear ();
1619 offsets.push_back (0);
1620 namesData.clear ();
1621 namesOffsets.clear ();
1622 namesOffsets.push_back (0);
1623 namesHash.clear ();
1624 }
1625
1626 virtual void getEntry (Long64_t /*entry*/) override
1627 {
1628 for (const auto& termName : termNames)
1629 {
1630 namesData.insert (namesData.end(), termName.begin(), termName.end());
1631 namesOffsets.push_back (namesData.size());
1632 namesHash.push_back (std::hash<std::string> () (termName));
1633 }
1634 offsets.push_back (namesHash.size());
1635 }
1636
1637 virtual void setData (TestUtils::ToolWrapperData& tool) override
1638 {
1639 if (outputColumns.at(0).enabled)
1640 tool.setColumn (outputColumns.at(0).name, offsets.size(), offsets.data());
1641 if (outputColumns.at(1).enabled)
1642 tool.setColumn (outputColumns.at(1).name, namesData.size(), namesData.data());
1643 if (outputColumns.at(2).enabled)
1644 tool.setColumn (outputColumns.at(2).name, namesOffsets.size(), namesOffsets.data());
1645 if (outputColumns.at(3).enabled)
1646 tool.setColumn (outputColumns.at(3).name, namesHash.size(), namesHash.data());
1647 }
1648
1649 [[nodiscard]] virtual BranchPerfData getPerfData (float /*emptyTime*/) override
1650 {
1652 result.name = outputColumns.at(0).name + "(met-out)";
1653 return result;
1654 }
1655
1656 virtual void collectColumnData () override
1657 {}
1658 };
1659
1661 {
1663 std::vector<ColumnarOffsetType> offsets = {0};
1664 std::vector<std::uint32_t> columnData;
1667 unsigned entries = 0;
1668
1669 ColumnDataSamplingPattern (const std::string& val_branchName)
1670 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+".samplingPattern(fallback)(unpack)"), benchmark (branchReader.columnName() + ".samplingPattern(fallback)")
1671 {
1672 outputColumns.push_back ({.name = branchReader.columnName() + ".samplingPattern"});
1673 outputColumns.push_back ({.name = branchReader.columnName(), .isOffset = true, .primary = false});
1674 }
1675
1676 virtual bool connect (TTree *tree, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
1677 {
1678 auto iter = requestedColumns.find (outputColumns.at(0).name);
1679 if (iter == requestedColumns.end())
1680 return false;
1681 outputColumns.at(0).enabled = true;
1682
1683 branchReader.connectTree (tree);
1684
1685 if (iter->second.offsetName != outputColumns.at(1).name)
1686 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
1687
1688 requestedColumns.erase (iter);
1689
1690 iter = requestedColumns.find (outputColumns.at(1).name);
1691 if (iter == requestedColumns.end())
1692 {
1693 return true;
1694 }
1695 outputColumns.at(1).enabled = true;
1696 requestedColumns.erase (iter);
1697 return true;
1698 }
1699
1700 virtual void clearColumns () override
1701 {
1702 columnData.clear();
1703 offsets.clear();
1704 offsets.push_back (0);
1705 }
1706
1707 virtual void getEntry (Long64_t entry) override
1708 {
1709 benchmark.startTimer ();
1710 const auto& branchData = branchReader.getEntry (entry);
1711 benchmark.stopTimer ();
1712 benchmarkUnpack.startTimer ();
1713 for (auto data : branchData)
1714 {
1715 columnData.push_back (data->samplingPattern());
1716 }
1717 offsets.push_back (columnData.size());
1718 benchmarkUnpack.stopTimer ();
1719 }
1720
1721 virtual void setData (TestUtils::ToolWrapperData& tool) override
1722 {
1723 if (outputColumns.at(0).enabled)
1724 tool.setColumn (outputColumns.at(0).name, columnData.size(), columnData.data());
1725 if (outputColumns.at(1).enabled)
1726 tool.setColumn (outputColumns.at(1).name, offsets.size(), offsets.data());
1727 }
1728
1729 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1730 {
1732 result.name = branchReader.columnName() + "(fallback)";
1733 result.timeRead = benchmark.getEntryTime(emptyTime);
1734 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1735 benchmark.setSilence();
1736 benchmarkUnpack.setSilence();
1737 result.entrySize = branchReader.entrySize();
1738 result.uncompressedSize = branchReader.uncompressedSize();
1739 result.numBaskets = branchReader.numBaskets();
1740 result.entries = entries;
1741 return result;
1742 }
1743
1744 virtual void collectColumnData () override
1745 {
1746 entries += columnData.size();
1747 }
1748 };
1749 }
1750
1751
1752 ColumnarPhysLiteTest ::
1753 ColumnarPhysLiteTest ()
1754 {
1755 static std::once_flag flag;
1756 std::call_once (flag, [] ()
1757 {
1758#ifdef XAOD_STANDALONE
1759 xAOD::Init().ignore();
1760#else
1761 POOL::Init();
1762#endif
1763 });
1764
1765 auto *fileName = getenv ("ASG_TEST_FILE_LITE_MC");
1766 if (fileName == nullptr)
1767 throw std::runtime_error ("missing ASG_TEST_FILE_LITE_MC");
1768 file.reset (TFile::Open (fileName, "READ"));
1769 if (!file)
1770 throw std::runtime_error ("failed to open file");
1771 tree = dynamic_cast<TTree*> (file->Get ("CollectionTree"));
1772 if (!tree)
1773 throw std::runtime_error ("failed to open tree");
1774 }
1775
1776 ColumnarPhysLiteTest :: ~ColumnarPhysLiteTest () = default;
1777
1778 std::string ColumnarPhysLiteTest :: makeUniqueName ()
1779 {
1780 static std::atomic<unsigned> index = 0;
1781 return "UniquePhysliteTestTool" + std::to_string(++index);
1782 }
1783
1784 bool ColumnarPhysLiteTest ::
1785 checkMode ()
1786 {
1787 return true;
1788 }
1789
1790 void ColumnarPhysLiteTest :: setupKnownColumns (const TestDefinition& testDefinition)
1791 {
1792 using namespace TestUtils;
1793
1794 knownColumns.push_back (std::make_shared<ColumnDataEventCount> ());
1795
1796 tree->SetMakeClass (1);
1797 {
1798 std::unordered_map<std::string,TBranch*> branches;
1799 {
1800 TIter branchIter (tree->GetListOfBranches());
1801 TObject *obj = nullptr;
1802 while ((obj = branchIter()))
1803 {
1804 TBranch *branch = nullptr;
1805 if ((branch = dynamic_cast<TBranch*>(obj)))
1806 {
1807 branches.emplace (branch->GetName(), branch);
1808 TIter subBranchIter (branch->GetListOfBranches());
1809 while ((obj = subBranchIter()))
1810 {
1811 if (auto subBranch = dynamic_cast<TBranch*>(obj))
1812 branches.emplace (subBranch->GetName(), subBranch);
1813 }
1814 }
1815 }
1816 }
1817
1818 for (const auto& [name, branch] : branches)
1819 {
1820 if (name.find ("AuxDyn.") != std::string::npos ||
1821 name.find ("Aux.") != std::string::npos)
1822 {
1823 TClass *branchClass = nullptr;
1824 EDataType branchType {};
1825 branch->GetExpectedType (branchClass, branchType);
1826 if (branchClass == nullptr)
1827 {
1828 switch (branchType)
1829 {
1830 case kInt_t:
1831 knownColumns.push_back (std::make_shared<ColumnDataScalar<std::int32_t>> (branch->GetName()));
1832 break;
1833 case kUInt_t:
1834 knownColumns.push_back (std::make_shared<ColumnDataScalar<std::uint32_t>> (branch->GetName()));
1835 break;
1836 case kULong_t:
1837 knownColumns.push_back (std::make_shared<ColumnDataScalar<std::uint64_t>> (branch->GetName()));
1838 break;
1839 case kULong64_t:
1840 knownColumns.push_back (std::make_shared<ColumnDataScalar<std::uint64_t>> (branch->GetName()));
1841 break;
1842 case kFloat_t:
1843 knownColumns.push_back (std::make_shared<ColumnDataScalar<float>> (branch->GetName()));
1844 break;
1845 default:
1846 // no-op
1847 break;
1848 }
1849 } else
1850 {
1851 if (*branchClass->GetTypeInfo() == typeid(std::vector<float>))
1852 {
1853 knownColumns.push_back (std::make_shared<ColumnDataVector<float>> (branch->GetName()));
1854 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<char>))
1855 {
1856 knownColumns.push_back (std::make_shared<ColumnDataVector<char>> (branch->GetName()));
1857 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::int8_t>))
1858 {
1859 knownColumns.push_back (std::make_shared<ColumnDataVector<std::int8_t>> (branch->GetName()));
1860 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::uint8_t>))
1861 {
1862 knownColumns.push_back (std::make_shared<ColumnDataVector<std::uint8_t>> (branch->GetName()));
1863 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::int16_t>))
1864 {
1865 knownColumns.push_back (std::make_shared<ColumnDataVector<std::int16_t>> (branch->GetName()));
1866 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::uint16_t>))
1867 {
1868 knownColumns.push_back (std::make_shared<ColumnDataVector<std::uint16_t>> (branch->GetName()));
1869 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::int32_t>))
1870 {
1871 knownColumns.push_back (std::make_shared<ColumnDataVector<std::int32_t>> (branch->GetName()));
1872 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::uint32_t>))
1873 {
1874 knownColumns.push_back (std::make_shared<ColumnDataVector<std::uint32_t>> (branch->GetName()));
1875 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::int64_t>))
1876 {
1877 knownColumns.push_back (std::make_shared<ColumnDataVector<std::int64_t>> (branch->GetName()));
1878 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::uint64_t>))
1879 {
1880 knownColumns.push_back (std::make_shared<ColumnDataVector<std::uint64_t>> (branch->GetName()));
1881 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::vector<float>>))
1882 {
1883 knownColumns.push_back (std::make_shared<ColumnDataVectorVector<float>> (branch->GetName()));
1884 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::vector<std::int32_t>>))
1885 {
1886 knownColumns.push_back (std::make_shared<ColumnDataVectorVector<std::int32_t>> (branch->GetName()));
1887 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::vector<std::uint64_t>>))
1888 {
1889 knownColumns.push_back (std::make_shared<ColumnDataVectorVector<std::uint64_t>> (branch->GetName()));
1890 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::vector<std::vector<std::size_t>>>))
1891 {
1892 knownColumns.push_back (std::make_shared<ColumnDataVectorVectorVector<std::size_t>> (branch->GetName()));
1893 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::vector<std::vector<unsigned char>>>))
1894 {
1895 knownColumns.push_back (std::make_shared<ColumnDataVectorVectorVector<unsigned char>> (branch->GetName()));
1896 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::string>))
1897 {
1898 knownColumns.push_back (std::make_shared<ColumnDataMetNames> (branch->GetName()));
1899 }
1900 }
1901 }
1902 }
1903 }
1904
1905 // This is a fallback for the case that we don't have an explicit
1906 // `samplingPattern` branch in our input file (i.e. an older file),
1907 // to allow us to still test tools needing it. This is likely not
1908 // something that actual users can do (they need the new files), but
1909 // for testing it seems like a reasonable workaround.
1910 knownColumns.push_back (std::make_shared<ColumnDataSamplingPattern> ("egammaClusters"));
1911
1912 // For branches that are element links they need to be explicitly
1913 // declared to have the correct xAOD type, correct split setting,
1914 // and correct linked containers.
1915 knownColumns.push_back (std::make_shared<ColumnDataVectorVectorLink<xAOD::CaloClusterContainer>> ("AnalysisElectronsAuxDyn.caloClusterLinks"));
1916 knownColumns.push_back (std::make_shared<ColumnDataVectorVectorLink<xAOD::TrackParticleContainer>> ("AnalysisElectronsAuxDyn.trackParticleLinks"));
1917 knownColumns.push_back (std::make_shared<ColumnDataVectorVectorLink<xAOD::CaloClusterContainer>> ("AnalysisPhotonsAuxDyn.caloClusterLinks"));
1918 knownColumns.push_back (std::make_shared<ColumnDataVectorVectorLink<xAOD::VertexContainer>> ("AnalysisPhotonsAuxDyn.vertexLinks"));
1919 knownColumns.push_back (std::make_shared<ColumnDataVectorSplitLink<xAOD::TrackParticleContainer>> ("AnalysisMuonsAuxDyn.inDetTrackParticleLink"));
1920 knownColumns.push_back (std::make_shared<ColumnDataVectorSplitLink<xAOD::TrackParticleContainer>> ("AnalysisMuonsAuxDyn.combinedTrackParticleLink"));
1921 knownColumns.push_back (std::make_shared<ColumnDataVectorSplitLink<xAOD::TrackParticleContainer>> ("AnalysisMuonsAuxDyn.extrapolatedMuonSpectrometerTrackParticleLink"));
1922 knownColumns.push_back (std::make_shared<ColumnDataVectorVectorLink<xAOD::TrackParticleContainer>> ("GSFConversionVerticesAuxDyn.trackParticleLinks"));
1923 knownColumns.push_back (std::make_shared<ColumnDataVectorSplitLink<xAOD::TrackParticleContainer>> ("GSFTrackParticlesAuxDyn.originalTrackParticle"));
1924 knownColumns.push_back (std::make_shared<ColumnDataVectorVectorVariantLink<xAOD::IParticleContainer>>("AnalysisJetsAuxDyn.GhostTrack"));
1925 knownColumns.push_back (std::make_shared<ColumnDataVectorLink<xAOD::JetContainer>>("METAssoc_AnalysisMETAux.jetLink"));
1926 knownColumns.push_back (std::make_shared<ColumnDataVectorVectorVariantLink<xAOD::IParticleContainer>>("METAssoc_AnalysisMETAux.objectLinks"));
1927
1928 // For METMaker we need to preplace all of the MET terms that we
1929 // expect to be used, that's what this line does.
1930 if (!testDefinition.metTermNames.empty())
1931 knownColumns.push_back (std::make_shared<ColumnDataOutputMet> ("OutputMET", testDefinition.metTermNames));
1932
1933 // For METMaker we need various extra columns to run. This may need
1934 // some work to avoid, but would likey be worth it.
1935 knownColumns.push_back (std::make_shared<ColumnDataOutVector<std::uint16_t>> ("AnalysisMuons.objectType", xAOD::Type::Muon));
1936 knownColumns.push_back (std::make_shared<ColumnDataOutVector<float>> ("AnalysisMuons.m", ParticleConstants::muonMassInMeV));
1937 knownColumns.push_back (std::make_shared<ColumnDataOutVector<std::uint16_t>> ("AnalysisJets.objectType", xAOD::Type::Jet));
1938
1939 // These are columns that represent variables that are normally held
1940 // by METAssociationHelper, or alternatively are decorated on the
1941 // MET terms (even though they are per object).
1942 knownColumns.push_back (std::make_shared<ColumnDataOutVector<float>> ("AnalysisMuons.MetObjectWeight", 0));
1943 knownColumns.push_back (std::make_shared<ColumnDataOutVector<float>> ("AnalysisJets.MetObjectWeight", 0));
1944 knownColumns.push_back (std::make_shared<ColumnDataOutVector<float>> ("AnalysisJets.MetObjectWeightSoft", 0));
1945 knownColumns.push_back (std::make_shared<ColumnDataOutVector<MissingETBase::Types::bitmask_t>> ("METAssoc_AnalysisMET.useObjectFlags", 0));
1946 }
1947
1948 void ColumnarPhysLiteTest :: setupColumns (ToolColumnVectorMap& toolWrapper)
1949 {
1950 using namespace asg::msgUserCode;
1951
1952 std::unordered_map<std::string,ColumnInfo> requestedColumns;
1953 for (auto& column : toolWrapper.getTool().getColumnInfo())
1954 requestedColumns[column.name] = std::move (column);
1955
1956 for (auto& name : toolWrapper.getColumnNames())
1957 std::cout << "requested columns: " << name << std::endl;
1958
1959 for (auto& column : knownColumns)
1960 {
1961 if (column->connect (tree, offsetColumns, requestedColumns))
1962 usedColumns.push_back (column);
1963 }
1964
1965 std::set<std::string> unclaimedColumns;
1966 for (auto& column : requestedColumns)
1967 {
1968 if (!column.second.isOptional)
1969 unclaimedColumns.insert (column.first);
1970 else
1971 std::cout << "optional column not claimed: " << column.first << std::endl;
1972 }
1973 std::erase_if (unclaimedColumns, [&] (auto& columnName)
1974 {
1975 const auto& info = requestedColumns.at (columnName);
1976 if (info.accessMode != ColumnAccessMode::output || !info.fixedDimensions.empty())
1977 return false;
1978 auto offsetIter = std::find_if (usedColumns.begin(), usedColumns.end(), [&] (const std::shared_ptr<TestUtils::IColumnData>& column)
1979 {
1980 for (auto& output : column->outputColumns)
1981 {
1982 if (output.name == info.offsetName)
1983 return true;
1984 }
1985 return false;
1986 });
1987 if (offsetIter == usedColumns.end())
1988 return false;
1989 std::shared_ptr<TestUtils::IColumnData> myColumn;
1990 if (*info.type == typeid(float))
1991 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<float>> (info.name, 0);
1992 else if (*info.type == typeid(char))
1993 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<char>> (info.name, 0);
1994 else if (*info.type == typeid(std::uint16_t))
1995 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<std::uint16_t>> (info.name, 0);
1996 else if (*info.type == typeid(std::uint64_t))
1997 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<std::uint64_t>> (info.name, 0);
1998 else
1999 {
2000 ANA_MSG_WARNING ("unhandled column type: " << info.name << " " << info.type->name());
2001 return false;
2002 }
2003 knownColumns.push_back (myColumn);
2004 if (!myColumn->connect (tree, offsetColumns, requestedColumns))
2005 {
2006 ANA_MSG_WARNING ("failed to connect dynamic output column: " << info.name);
2007 return false;
2008 }
2009 usedColumns.push_back (myColumn);
2010 return true;
2011 });
2012 if (!unclaimedColumns.empty())
2013 {
2014 std::string message = "columns not claimed:";
2015 for (auto& column : unclaimedColumns)
2016 message += " " + column;
2017 throw std::runtime_error (message);
2018 }
2019 }
2020
2021 void ColumnarPhysLiteTest :: doCall (const TestDefinition& testDefinition)
2022 {
2023 using namespace asg::msgUserCode;
2024 auto userConfiguration = TestUtils::UserConfiguration::fromEnvironment();
2025
2026 if (!testDefinition.sysName.empty())
2027 {
2028 auto *sysTool = dynamic_cast<CP::ISystematicsTool*>(testDefinition.tool);
2029 if (!sysTool)
2030 throw std::runtime_error ("tool does not support systematics");
2031 std::cout << "applying systematic variation: " << testDefinition.sysName << std::endl;
2032 if (sysTool->applySystematicVariation (CP::SystematicSet (testDefinition.sysName)).isFailure())
2033 throw std::runtime_error ("failed to apply systematic variation: " + testDefinition.sysName);
2034 }
2035 if constexpr (columnarAccessMode == 2)
2036 {
2037 auto *myTool = dynamic_cast<ColumnarTool<ColumnarModeArray>*>(testDefinition.tool);
2038 if (!testDefinition.containerRenames.empty())
2039 renameContainers (*myTool, testDefinition.containerRenames);
2040 ColumnVectorHeader columnHeader;
2041 ToolColumnVectorMap toolWrapper (columnHeader, *myTool);
2042
2043 setupKnownColumns (testDefinition);
2044 setupColumns (toolWrapper);
2045
2046 Benchmark benchmarkCall (testDefinition.name, userConfiguration.batchSize);
2047 Benchmark benchmarkCall2 (testDefinition.name + "(call2)", userConfiguration.batchSize);
2048 Benchmark benchmarkCheck (testDefinition.name + "(column check)", userConfiguration.batchSize);
2049 Benchmark benchmarkEmpty ("empty");
2050
2051 const auto numberOfEvents = tree->GetEntries();
2052 Long64_t entry = 0;
2053 const auto startTime = std::chrono::high_resolution_clock::now();
2054 bool endLoop = false;
2055 for (; !endLoop; ++entry)
2056 {
2057 // just sample how much overhead there is for starting and
2058 // stopping the timer
2059 benchmarkEmpty.startTimer ();
2060 benchmarkEmpty.stopTimer ();
2061
2062 ColumnVectorData columnData (&columnHeader);
2063 TestUtils::ToolWrapperData toolColumnData (&columnData, &toolWrapper);
2064 for (auto& column : usedColumns)
2065 column->getEntry (entry % numberOfEvents);
2066 if ((entry + 1) % userConfiguration.batchSize == 0)
2067 {
2068 if (entry < numberOfEvents)
2069 {
2070 for (auto& column : usedColumns)
2071 column->collectColumnData ();
2072 }
2073 for (auto& column : usedColumns)
2074 column->setData (toolColumnData);
2075 benchmarkCheck.startTimer ();
2076 columnData.checkData ();
2077 benchmarkCheck.stopTimer ();
2078 benchmarkCall.startTimer ();
2079 columnData.callNoCheck (*myTool);
2080 benchmarkCall.stopTimer ();
2081 if (userConfiguration.runToolTwice)
2082 {
2083 benchmarkCall2.startTimer ();
2084 columnData.callNoCheck (*myTool);
2085 benchmarkCall2.stopTimer ();
2086 }
2087 for (auto& column : usedColumns)
2088 column->clearColumns ();
2089 if ((std::chrono::high_resolution_clock::now() - startTime) > userConfiguration.targetTime)
2090 endLoop = true;
2091 } else if (entry + 1 == numberOfEvents)
2092 {
2093 for (auto& column : usedColumns)
2094 column->collectColumnData ();
2095 }
2096 }
2097 std::cout << "Entries in file: " << numberOfEvents << std::endl;
2098 std::cout << "Total entries read: " << entry << std::endl;
2099 const float emptyTime = benchmarkEmpty.getEntryTime(0).value();
2100 std::cout << "Empty benchmark time: " << emptyTime << "ns" << std::endl;
2101 benchmarkEmpty.setSilence();
2102 {
2103 std::vector<TestUtils::BranchPerfData> branchPerfData;
2105 summary.name = "total";
2106 summary.timeRead = 0;
2107 summary.timeUnpack = 0;
2108 summary.timeShallowCopy = 0;
2109 summary.entries = std::nullopt;
2110 summary.nullEntries = std::nullopt;
2111 for (auto& column : usedColumns)
2112 {
2113 branchPerfData.push_back (column->getPerfData (emptyTime));
2114 summary.timeRead.value() += branchPerfData.back().timeRead.value_or(0);
2115 summary.timeUnpack.value() += branchPerfData.back().timeUnpack.value_or(0);
2116 summary.timeShallowCopy.value() += branchPerfData.back().timeShallowCopy.value_or(0);
2117 }
2118 std::sort (branchPerfData.begin(), branchPerfData.end(), [] (const auto& a, const auto& b) {return a.name < b.name;});
2119 branchPerfData.insert (branchPerfData.end(), summary);
2120 const std::size_t nameWidth = std::max_element (branchPerfData.begin(), branchPerfData.end(), [] (const auto& a, const auto& b) {return a.name.size() < b.name.size();})->name.size();
2121 std::string header = std::format ("{:{}} | read(ns) | unpack(ns) | size(B) | rate(MB/s) | compression | baskets | entries | null", "branch name", nameWidth);
2122 std::cout << "\n" << header << std::endl;
2123 std::cout << std::string (header.size(), '-') << std::endl;
2124 for (auto& data : branchPerfData)
2125 {
2126 if (data.name == "total")
2127 std::cout << std::string (header.size(), '-') << std::endl;
2128 std::cout << std::format ("{:{}} |", data.name, nameWidth);
2129 if (data.timeRead)
2130 std::cout << std::format ("{:>9.0f} |", data.timeRead.value());
2131 else
2132 std::cout << " |";
2133 if (data.timeUnpack)
2134 std::cout << std::format ("{:>11.1f} |", data.timeUnpack.value());
2135 else
2136 std::cout << " |";
2137 if (data.entrySize)
2138 std::cout << std::format ("{:>8.1f} |", data.entrySize.value());
2139 else
2140 std::cout << " |";
2141 if (data.timeRead && data.entrySize)
2142 std::cout << std::format ("{:>11.1f} |", (data.entrySize.value() / (data.timeRead.value() * 1e-3 * 1.024 * 1.024)));
2143 else
2144 std::cout << " |";
2145 if (data.entrySize && data.uncompressedSize)
2146 std::cout << std::format ("{:>12.2f} |", float (data.uncompressedSize.value()) / data.entrySize.value());
2147 else
2148 std::cout << " |";
2149 if (data.numBaskets)
2150 std::cout << std::format ("{:>8} |", data.numBaskets.value());
2151 else
2152 std::cout << " |";
2153 if (data.entries)
2154 std::cout << std::format ("{:>8.2f} |", static_cast<float>(data.entries.value())/numberOfEvents);
2155 else
2156 std::cout << " |";
2157 if (data.nullEntries && data.entries)
2158 std::cout << std::format ("{:>4.0f}%", static_cast<float>(data.nullEntries.value()) / data.entries.value() * 100.0f);
2159 std::cout << std::endl;
2160 }
2161 }
2162 {
2163 std::vector<TestUtils::ToolPerfData> toolPerfData;
2164 toolPerfData.emplace_back ();
2165 toolPerfData.back().name = testDefinition.name;
2166 toolPerfData.back().timeCall = benchmarkCall.getEntryTime(emptyTime);
2167 if (userConfiguration.runToolTwice)
2168 toolPerfData.back().timeCall2 = benchmarkCall2.getEntryTime(emptyTime);
2169 toolPerfData.back().timeCheck = benchmarkCheck.getEntryTime(emptyTime);
2170 benchmarkCall.setSilence();
2171 benchmarkCall2.setSilence();
2172 benchmarkCheck.setSilence();
2173 const std::size_t nameWidth = std::max_element (toolPerfData.begin(), toolPerfData.end(), [] (const auto& a, const auto& b) {return a.name.size() < b.name.size();})->name.size();
2174 std::string header = std::format ("{:{}} | call(ns) | call2(ns) | check(ns)", "tool name", nameWidth);
2175 std::cout << "\n" << header << std::endl;
2176 std::cout << std::string (header.size(), '-') << std::endl;
2177 for (auto& data : toolPerfData)
2178 {
2179 std::cout << std::format ("{:{}} |", data.name, nameWidth);
2180 if (data.timeCall)
2181 std::cout << std::format ("{:>9.0f} |", data.timeCall.value());
2182 else
2183 std::cout << " |";
2184 if (data.timeCall2)
2185 std::cout << std::format ("{:>10.0f} |", data.timeCall2.value());
2186 else
2187 std::cout << " |";
2188 if (data.timeCheck)
2189 std::cout << std::format ("{:>10.1f}", data.timeCheck.value());
2190 std::cout << std::endl;
2191 }
2192 }
2193 } else if constexpr (columnarAccessMode == 0)
2194 {
2195 // this test simply doesn't work in Athena
2196#ifdef XAOD_STANDALONE
2197 xAOD::TEvent event;
2198 xAOD::TStore store;
2199#else
2200 POOL::TEvent event;
2201#endif
2202 ANA_CHECK_THROW (event.readFrom (file.get()));
2203
2204#ifdef XAOD_STANDALONE
2205 Benchmark benchmarkEmptyClear (testDefinition.name + " empty clear");
2206 Benchmark benchmarkCallClear (testDefinition.name + " call clear");
2207 Benchmark benchmarkPrepClear (testDefinition.name + " prep clear");
2208#endif
2209 Benchmark benchmarkRepeatCall (testDefinition.name + " repeat-call");
2210 Benchmark benchmarkCall (testDefinition.name + " call");
2211 Benchmark benchmarkCallCopyRecord (testDefinition.name + " call copy-record");
2212 Benchmark benchmarkCallRetrieve (testDefinition.name + " call retrieve");
2213 Benchmark benchmarkPrep (testDefinition.name + " prep");
2214 Benchmark benchmarkPrepCopyRecord (testDefinition.name + " prep copy-record");
2215 Benchmark benchmarkPrepRetrieve (testDefinition.name + " prep retrieve");
2216 Benchmark benchmarkGetEntry (testDefinition.name + " getEntry");
2217
2218 const auto numberOfEvents = event.getEntries();
2219#ifdef XAOD_STANDALONE
2220 std::cout << "known container keys:" << std::endl;
2221 for (auto& [container, key] : columnar::TestUtils::knownKeys)
2222 {
2223 std::cout << std::format (" {} -> 0x{:x}, 0x{:x} -> {}", container, event.getHash (container), key, event.getName (key)) << std::endl;
2224 }
2225#endif
2226 if (numberOfEvents == 0){
2227 throw std::runtime_error ("ColumnarPhysLiteTest: numberOfEvents == 0");
2228 }
2229 Long64_t entry = 0;
2230
2231 // Instead of running for a fixed number of events, we run for a
2232 // fixed amount of time. That is because individual tools can
2233 // vary wildly in how long they take to run, and we mostly want to
2234 // make sure that we ran the tool enough to get a precise
2235 // performance estimate.
2236 const auto startTime = std::chrono::high_resolution_clock::now();
2237 for (; (std::chrono::high_resolution_clock::now() - startTime) < userConfiguration.targetTime; ++entry)
2238 {
2239 benchmarkGetEntry.startTimer ();
2240 event.getEntry (entry % numberOfEvents);
2241 benchmarkGetEntry.stopTimer ();
2242 benchmarkPrepRetrieve.startTimer ();
2243 ASSERT_SUCCESS (testDefinition.xAODToolCaller->retrieve (*testDefinition.tool->evtStore()));
2244 benchmarkPrepRetrieve.stopTimer ();
2245 benchmarkPrepCopyRecord.startTimer ();
2246 static const std::string prepPostfix = "Prep";
2247 ASSERT_SUCCESS (testDefinition.xAODToolCaller->copyRecord (*testDefinition.tool->evtStore(), prepPostfix));
2248 benchmarkPrepCopyRecord.stopTimer ();
2249 benchmarkPrep.startTimer ();
2250 ASSERT_SUCCESS (testDefinition.xAODToolCaller->call ());
2251 benchmarkPrep.stopTimer ();
2252#ifdef XAOD_STANDALONE
2253 benchmarkPrepClear.startTimer ();
2254 store.clear ();
2255 benchmarkPrepClear.stopTimer ();
2256#endif
2257 benchmarkCallRetrieve.startTimer ();
2258 ASSERT_SUCCESS (testDefinition.xAODToolCaller->retrieve (*testDefinition.tool->evtStore()));
2259 benchmarkCallRetrieve.stopTimer ();
2260 benchmarkCallCopyRecord.startTimer ();
2261 static const std::string callPostfix = "Call";
2262 ASSERT_SUCCESS (testDefinition.xAODToolCaller->copyRecord (*testDefinition.tool->evtStore(), callPostfix));
2263 benchmarkCallCopyRecord.stopTimer ();
2264 benchmarkCall.startTimer ();
2265 ASSERT_SUCCESS (testDefinition.xAODToolCaller->call ());
2266 benchmarkCall.stopTimer ();
2267 if (userConfiguration.runToolTwice)
2268 {
2269 benchmarkRepeatCall.startTimer ();
2270 ASSERT_SUCCESS (testDefinition.xAODToolCaller->call ());
2271 benchmarkRepeatCall.stopTimer ();
2272 }
2273#ifdef XAOD_STANDALONE
2274 benchmarkCallClear.startTimer ();
2275 store.clear ();
2276 benchmarkCallClear.stopTimer ();
2277 benchmarkEmptyClear.startTimer ();
2278 store.clear ();
2279 benchmarkEmptyClear.stopTimer ();
2280#endif
2281 }
2282 std::cout << "Total entries read: " << entry << std::endl;
2283 } else if constexpr (columnarAccessMode == 100)
2284 {
2285 TestUtils::runXaodArrayTest (userConfiguration, testDefinition, file.get());
2286 }
2287 }
2288}
#define ANA_MSG_WARNING(xmsg)
Macro printing warning messages.
#define ANA_CHECK_THROW(EXP)
check whether the given expression was successful, throwing an exception on failure
int numberOfEvents()
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
static Double_t a
A number of constexpr particle constants to avoid hardcoding them directly in various places.
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Interface for all CP tools supporting systematic variations.
Class to wrap a set of SystematicVariations.
a class that holds the columnar data for a single call
void checkData() const
do a basic check of the data vector
void callNoCheck(const IColumnarTool &tool)
call the tool with the assembled data, without performing any checks on the data
the header information for the entire columnar data vector
the base class for all columnar components
virtual std::vector< ColumnInfo > getColumnInfo() const =0
the meta-information for the columns
this is a simple benchmarking helper class wrapping timers from std::chrono
Definition Benchmark.h:51
std::optional< float > getEntryTime(float emptyTime) const
Definition Benchmark.h:74
BranchReaderArray(const std::string &val_branchName)
std::span< const T > getEntry(Long64_t entry, std::size_t size)
BranchReaderArray(const BranchReaderArray &)=delete
std::optional< float > uncompressedSize() const
BranchReaderArray & operator=(const BranchReaderArray &)=delete
const std::string & branchName() const
std::optional< float > entrySize() const
BranchReader(const BranchReader &)=delete
BranchReader(const std::string &val_branchName)
std::optional< unsigned > numBaskets()
BranchReader & operator=(const BranchReader &)=delete
std::optional< float > uncompressedSize() const
virtual void collectColumnData()=0
std::vector< OutputColumnInfo > outputColumns
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns)=0
virtual ~IColumnData() noexcept=default
virtual void getEntry(Long64_t entry)=0
virtual void setData(TestUtils::ToolWrapperData &tool)=0
virtual BranchPerfData getPerfData(float emptyTime)=0
virtual StatusCode call()=0
call the tool for a single event
virtual StatusCode copyRecord(EventStoreType &evtStore, const std::string &postfix)=0
do any copying and recording needed
virtual StatusCode retrieve(EventStoreType &evtStore)=0
retrieve everything we need from the event store
a class that holds a reference to a ToolColumnVectorMap and a ColumnVectorData
Definition ToolWrapper.h:36
a class that interfaces an IColumnarTool to a ColumnVectorHeader
const IColumnarTool & getTool() const
get the wrapped tool
std::vector< std::string > getColumnNames() const
get the list of all defined columns
Tool for accessing xAOD files outside of Athena.
A relatively simple transient store for objects created in analysis.
Definition TStore.h:45
IAppMgrUI * Init(const char *options="POOLRootAccess/basic.opts")
Bootstraps (creates and configures) the Gaudi Application with the provided options file.
constexpr double muonMassInMeV
the mass of the muon (in MeV)
uint32_t sgkey_t
Type used for hashed StoreGate key+CLID pairs.
Definition sgkey_t.h:32
void runXaodArrayTest(const UserConfiguration &userConfiguration, const TestDefinition &testDefinition, TFile *file)
static const std::unordered_map< std::string, SG::sgkey_t > knownKeys
constexpr unsigned columnarAccessMode
Definition ColumnarDef.h:15
const std::string numberOfEventsName
the name used for the column containing the number of events
@ output
an output column
Definition ColumnInfo.h:24
void renameContainers(IColumnarTool &tool, const std::vector< std::pair< std::string, std::string > > &renames)
rename containers in the columnar tool
std::size_t ColumnarOffsetType
the type used for the size and offsets in the columnar data
constexpr ColumnarOffsetType invalidObjectIndex
the value for an invalid element index
Definition index.py:1
STL namespace.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
std::size_t erase_if(T_container &container, T_Func pred)
@ Jet
The object is a jet.
Definition ObjectType.h:40
@ Muon
The object is a muon.
Definition ObjectType.h:48
StatusCode Init(const char *appname)
Function initialising ROOT/PyROOT for using the ATLAS EDM.
Definition Init.cxx:31
a struct that contains meta-information about each column that's needed to interface the column with ...
Definition ColumnInfo.h:35
std::size_t LinkIndexType
the type used for columns that represent element links
Definition ColumnarDef.h:80
static constexpr LinkIndexType invalidLinkValue
the value used for an invalid link (a.k.a. empty/null link)
Definition ColumnarDef.h:83
static LinkIndexType mergeLinkKeyIndex(LinkIndexType key, LinkIndexType index)
merge a key and index value into a link value
std::vector< std::shared_ptr< TestUtils::IColumnData > > knownColumns
std::vector< std::shared_ptr< TestUtils::IColumnData > > usedColumns
void setupColumns(ToolColumnVectorMap &toolWrapper)
std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > offsetColumns
void setupKnownColumns(const TestUtils::TestDefinition &testDefinition)
the performance data for reading a single branch/column
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual bool connect(TTree *, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
std::array< ColumnarOffsetType, 2 > data
virtual BranchPerfData getPerfData(float) override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
std::vector< ColumnarOffsetType > offsets
virtual BranchPerfData getPerfData(float emptyTime) override
virtual void getEntry(Long64_t entry) override
virtual void setData(TestUtils::ToolWrapperData &tool) override
ColumnDataMetNames(const std::string &val_branchName)
BranchReader< std::vector< std::string > > branchReader
ColumnDataOutVector(const std::string &val_columnName, const T &val_defaultValue)
virtual BranchPerfData getPerfData(float) override
virtual void setData(TestUtils::ToolWrapperData &tool) override
const std::vector< ColumnarOffsetType > * offsetColumn
virtual bool connect(TTree *, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
const std::vector< ColumnarOffsetType > * offsetColumns
virtual BranchPerfData getPerfData(float) override
virtual bool connect(TTree *, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
ColumnDataOutputMet(const std::string &val_columnName, std::vector< std::string > val_termNames)
std::vector< ColumnarOffsetType > namesOffsets
std::vector< ColumnarOffsetType > offsets
virtual void setData(TestUtils::ToolWrapperData &tool) override
BranchReader< xAOD::CaloClusterContainer > branchReader
virtual void getEntry(Long64_t entry) override
virtual BranchPerfData getPerfData(float emptyTime) override
ColumnDataSamplingPattern(const std::string &val_branchName)
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual BranchPerfData getPerfData(float emptyTime) override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
ColumnDataScalar(const std::string &val_branchName)
virtual void getEntry(Long64_t entry) override
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual BranchPerfData getPerfData(float emptyTime) override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
BranchReader< std::vector< std::vector< std::vector< T > > > > branchReader
ColumnDataVectorVectorVector(const std::string &val_branchName)
virtual BranchPerfData getPerfData(float emptyTime) override
virtual void setData(TestUtils::ToolWrapperData &tool) override
BranchReader< std::vector< std::vector< T > > > branchReader
ColumnDataVectorVector(const std::string &val_branchName)
virtual void getEntry(Long64_t entry) override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
std::vector< ColumnarOffsetType > offsets
BranchReader< std::vector< T > > branchReader
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
virtual BranchPerfData getPerfData(float emptyTime) override
virtual void getEntry(Long64_t entry) override
ColumnDataVector(const std::string &val_branchName)
const std::vector< ColumnarOffsetType > * offsetColumn
std::vector< std::string > metTermNames
the MET output term names (if empty, MET output columns are omitted)
std::vector< std::pair< std::string, std::string > > containerRenames
the container name remappings to apply
static UserConfiguration fromEnvironment()
create a UserConfiguration, loading from the file pointed to by the COLUMNAR_TEST_CONFIG environment ...
TChain * tree