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