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