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