ATLAS Offline Software
Loading...
Searching...
No Matches
ColumnarPhysliteTest.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7//
8// includes
9//
10
12
13#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 "ROOT/RNTuple.hxx"
49#include "ROOT/RNTupleInspector.hxx"
50#include "ROOT/RNTupleReader.hxx"
51#include <ROOT/RNTupleView.hxx>
52
53#include <algorithm>
54#include <chrono>
55#include <cstdint>
56#include <format>
57#include <memory>
58#include <span>
59#include <vector>
60
61#include <gtest/gtest.h>
62
63//
64// method implementations
65//
66
67namespace columnar
68{
69 // I'm moving code to this namespace but some of the code in this file
70 // is still just in the columnar namespace. As I evolve the code I'll
71 // move more of it to TestUtils.
72 using namespace TestUtils;
73
74 namespace TestUtils
75 {
76
78 ROOT::RNTupleReader* reader = nullptr;
79 ROOT::Experimental::RNTupleInspector* inspector = nullptr;
80 };
81
82 using Backend = std::variant<TTree*, RNTupleBackend*>;
83 template <typename T>
84 class BranchReader final
85 {
86 std::string m_branchName;
87 TBranch* m_branch = nullptr;
88 bool m_isStatic = std::is_pod_v<T>;
89 T* m_data{new T()};
90
91 public:
92 BranchReader(const std::string& val_branchName)
93 : m_branchName(val_branchName)
94 {
95 if (m_branchName.find("Aux.") != std::string::npos)
96 m_isStatic = true;
97 }
98
99 ~BranchReader() noexcept
100 {
101 delete m_data;
102 }
103
104 BranchReader(const BranchReader&) = delete;
106
107 void setIsStatic(bool isStatic)
108 {
109 m_isStatic = isStatic;
110 }
111
112 [[nodiscard]] const std::string& branchName() const
113 {
114 return m_branchName;
115 }
116
117 [[nodiscard]] std::string columnName() const
118 {
119 std::string columnName = m_branchName;
120 if (auto index = columnName.find("AuxDyn."); index != std::string::npos)
121 columnName.replace(index, 6, "");
122 else if (auto index = columnName.find("Aux."); index != std::string::npos)
123 columnName.replace(index, 3, "");
124 else if (columnName.find(".") != std::string::npos)
125 throw std::runtime_error("branch name does not contain AuxDyn or Aux: " +m_branchName);
126 return columnName;
127 }
128
129 [[nodiscard]] std::string containerName() const
130 {
131 if (auto index = m_branchName.find("AuxDyn."); index != std::string::npos)
132 return m_branchName.substr(0, index);
133 else if (auto index = m_branchName.find("Aux."); index != std::string::npos)
134 return m_branchName.substr(0, index);
135 else if (m_branchName.find(".") == std::string::npos)
136 return m_branchName;
137 else
138 throw std::runtime_error("branch name does not contain AuxDyn or Aux: " +m_branchName);
139 }
140
141 void connectTree(TTree* tree)
142 {
143 m_branch = tree->GetBranch(m_branchName.c_str());
144 if (!m_branch)
145 throw std::runtime_error("failed to get branch: " + m_branchName);
146 m_branch->SetMakeClass(1);
147 if (m_isStatic)
148 m_branch->SetAddress(m_data);
149 else
150 m_branch->SetAddress(&m_data);
151 }
152
153 void connectTree(const Backend& b)
154 {
155 auto* tree = std::get<TTree*>(b); // throws if wrong backend
157 }
158
159 const T& getEntry(Long64_t entry)
160 {
161 if (!m_branch)
162 throw std::runtime_error("branch not connected: " + m_branchName);
163 if (m_branch->GetEntry(entry) <= 0)
164 throw std::runtime_error("failed to get entry " + std::to_string(entry) + " for branch: " + m_branchName);
165 if (m_data == nullptr)
166 throw std::runtime_error("got nullptr reading data for branch: " + m_branchName);
167 return *m_data;
168 }
169
170 const T& getCachedEntry() const
171 {
172 return *m_data;
173 }
174
175 std::optional<float> entrySize() const
176 {
177 if (!m_branch)
178 return std::nullopt;
179 return static_cast<float>(m_branch->GetZipBytes()) / m_branch->GetEntries();
180 }
181
182 std::optional<float> uncompressedSize() const
183 {
184 if (!m_branch)
185 return std::nullopt;
186 return static_cast<float>(m_branch->GetTotBytes()) / m_branch->GetEntries();
187 }
188
189 // technically this is const-correct, but I don't want to convince
190 // the code checker of that
191 std::optional<unsigned> numBaskets()
192 {
193 if (!m_branch)
194 return std::nullopt;
195 return m_branch->GetListOfBaskets()->GetSize();
196 }
197 };
198
199 template <typename T>
200 class BranchReaderArray final
201 {
202 public:
203 std::string m_branchName;
204 TBranch* m_branch = nullptr;
205 std::vector<T> m_dataVec;
206
207 public:
208 BranchReaderArray(const std::string& val_branchName)
209 : m_branchName(val_branchName)
210 {}
211
214
215 [[nodiscard]] std::string columnName() const
216 {
217 std::string columnName = m_branchName;
218 if (auto index = columnName.find("AuxDyn."); index != std::string::npos)
219 columnName.replace(index, 6, "");
220 else if (auto index = columnName.find("Aux."); index != std::string::npos)
221 columnName.replace(index, 3, "");
222 else if (columnName.find(".") != std::string::npos)
223 throw std::runtime_error("branch name does not contain AuxDyn or Aux: " + m_branchName);
224 return columnName;
225 }
226
227 [[nodiscard]] std::string containerName() const
228 {
229 if (auto index = m_branchName.find("AuxDyn."); index != std::string::npos)
230 return m_branchName.substr(0, index);
231 else if (auto index = m_branchName.find("Aux."); index != std::string::npos)
232 return m_branchName.substr(0, index);
233 else if (m_branchName.find(".") == std::string::npos)
234 return m_branchName;
235 else
236 throw std::runtime_error("branch name does not contain AuxDyn or Aux: " + m_branchName);
237 }
238 void connectTree (TTree *tree)
239 {
240 m_branch = tree->GetBranch (m_branchName.c_str());
241 if (!m_branch)
242 throw std::runtime_error ("failed to get branch: " + m_branchName);
243 m_branch->SetMakeClass (1);
244 // FIX ME: I have to have some hard-coded size, see explanation
245 // below.
246 m_dataVec.resize (100);
247 if (!m_dataVec.empty())
248 m_branch->SetAddress (m_dataVec.data());
249 }
250
251 std::span<const T> getEntry (Long64_t entry, std::size_t size)
252 {
253 if (!m_branch)
254 throw std::runtime_error ("branch not connected: " + m_branchName);
255 if (m_dataVec.size() < size)
256 {
257 // FIX ME: in one of the latest releases the repointing below
258 // breaks, and causes memory corruption. so I'm now
259 // preallocating and fail rather than reallocate, and the
260 // problem goes away. maybe it should be investigated at some
261 // point, but this is a test and I already spend a fair amount
262 // of time investigating this. the harm is that this test
263 // consumes a few hundreds bytes more in memory and we may have
264 // to occasionally increase the buffer size to cover all test
265 // files and branch lengths.
266 throw std::runtime_error ("requested size exceeds buffer size for branch: " + m_branchName);
267 // m_dataVec.resize (size);
268 // m_branch->SetAddress (m_dataVec.data());
269 }
270 if (size > 0 && m_branch->GetEntry (entry) <= 0)
271 throw std::runtime_error ("failed to get entry " + std::to_string (entry) + " for branch: " + m_branchName);
272 return std::span<const T>(m_dataVec.data(), size);
273 }
274
275 std::optional<float> entrySize () const
276 {
277 if (!m_branch)
278 return std::nullopt;
279 return static_cast<float>(m_branch->GetZipBytes()) / m_branch->GetEntries();
280 }
281
282 std::optional<float> uncompressedSize () const
283 {
284 if (!m_branch)
285 return std::nullopt;
286 return static_cast<float>(m_branch->GetTotBytes()) / m_branch->GetEntries();
287 }
288
289 // technically this is const-correct, but I don't want to convince
290 // the code checker of that
291 std::optional<unsigned> numBaskets ()
292 {
293 if (!m_branch)
294 return std::nullopt;
295 return m_branch->GetListOfBaskets()->GetSize();
296 }
297 };
298
300 {
303 public:
304
306
308 {
309 if (!m_unknownKeysAllowedTargets.empty())
310 {
311 std::cout << "found unknown keys for " << m_columnName << ":";
312 for (auto& [key, allowedSet] : m_unknownKeysAllowedTargets)
313 {
314 std::cout << " " << std::hex << key << std::dec << " (allowed targets:";
315 for (auto index : allowedSet)
316 std::cout << " " << m_targetNames.at(index);
317 std::cout << ")";
318 }
319 }
320 }
321
322 [[nodiscard]] std::vector<std::string> connect (const ColumnInfo& columnInfo, const std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& offsetColumns, const std::unordered_map<std::string,ColumnInfo>& requestedColumns)
323 {
324 m_columnName = columnInfo.name;
325 std::vector<std::string> keyColumnNames;
326 if (!columnInfo.soleLinkTargetName.empty())
327 {
328 addTarget (columnInfo.soleLinkTargetName, offsetColumns, columnInfo.soleLinkTargetClid);
329 } else
330 {
331 for (auto& [requestedName, requestedInfo] : requestedColumns)
332 {
333 if (requestedInfo.keyColumnForVariantLink == m_columnName)
334 {
335 keyColumnNames.push_back (requestedName);
336 m_keysColumns.emplace_back();
337 for (const auto& targetName : requestedInfo.variantLinkTargetNames)
338 addTarget (targetName, offsetColumns);
339 }
340 }
341 if (m_keysColumns.empty())
342 throw std::runtime_error ("no key column found for variant link: " + m_columnName);
343 }
344 return keyColumnNames;
345 }
346
347 void clear ()
348 {
349 m_columnData.clear();
350 }
351
352 void checkOffsets (unsigned eventIndex)
353 {
354 for (std::size_t i = 0; i < m_targetNames.size(); ++ i)
355 {
356 auto& targetOffsetColumn = *m_targetOffsetColumns.at(i);
357 if (eventIndex + 1 >= targetOffsetColumn.size())
358 throw std::runtime_error ("target offset column not yet filled for: " + m_targetNames.at(i) + " when checking link column " + m_columnName);
359 }
360 }
361
362 template<typename T>
363 void addLink (const ElementLink<T>& element, unsigned eventIndex)
364 {
365 if (element.isDefault())
366 {
367 addEmptyLink();
368 return;
369 }
370
371 addSplitLink (element.index(), element.key(), eventIndex);
372 }
373
375 {
377 }
378
379 void addSplitLink (std::size_t linkIndex, SG::sgkey_t linkKey, unsigned eventIndex)
380 {
381 if (linkIndex == 0 && linkKey == 0)
382 {
383 addEmptyLink();
384 return;
385 }
386
387 unsigned targetIndex = 0u;
388 while (targetIndex < m_targetKeys.size() && m_targetKeys.at(targetIndex) != linkKey)
389 ++ targetIndex;
390
391 // We didn't find the key, so we try to figure out which of the
392 // targets it could be. The idea is that you wouldn't rely on
393 // this for real tests, but that you then go and fill in those
394 // keys in the central lookup table. It will always record and
395 // report, that means if there is a variant link with extra
396 // targets you didn't declare you will get a diagnostic. This
397 // may be overly cautious, but it gives an extra diagnostic if
398 // maybe you missed a target.
399 if (targetIndex == m_targetKeys.size())
400 {
401 if (!m_unknownKeysAllowedTargets.contains (linkKey))
402 {
403 auto& allowedSet = m_unknownKeysAllowedTargets[linkKey];
404 for (std::size_t i = 0; i < m_targetKeys.size(); ++ i)
405 {
406 if (m_targetKeys.at(i) == 0)
407 allowedSet.insert(i);
408 }
409 }
410 auto& allowedSet = m_unknownKeysAllowedTargets[linkKey];
411 for (auto iter = allowedSet.begin(); iter != allowedSet.end();)
412 {
413 auto index = *iter;
414 auto& targetOffsetColumn = *m_targetOffsetColumns.at(index);
415 if (eventIndex + 1 >= targetOffsetColumn.size())
416 throw std::runtime_error ("target offset column not yet filled for: " + m_targetNames.at(index));
417 if (targetOffsetColumn.at(eventIndex) + linkIndex >= targetOffsetColumn.at(eventIndex + 1))
418 iter = allowedSet.erase(iter);
419 else
420 ++ iter;
421 }
422 // Not quite sure whether it is safer to use or not use one of
423 // the targets from the allowed set in this case. In general
424 // tools are expected to handle invalid links gracefully,
425 // worst case they throw an exception when trying to access
426 // it. So what I came up with is that for variant links we
427 // assume it invalid, but for non-variant links the tool
428 // expects exactly one target and we either found it or throw
429 // an exception.
430 if (m_keysColumns.empty())
431 {
432 if (allowedSet.size() == 1 && m_targetKeys.at(*allowedSet.begin()) == 0 && m_unknownKeysAllowedTargets.size() == 1)
433 targetIndex = *allowedSet.begin();
434 else
435 {
436 std::ostringstream error;
437 error << "target key mismatch: read sgkey " << std::hex << linkKey << std::dec;
438 error << " for column " << m_columnName << " with element index " << linkIndex << " targeting " << m_targetNames.at(0);
439 if (m_targetKeys.at(0) != 0u)
440 {
441 error << ", expected sgkey " << std::hex << m_targetKeys.at(0) << std::dec;
442 } else if (m_unknownKeysAllowedTargets.size() > 1)
443 {
444 error << ", alternate key found for non-variant link:";
445 for (auto& [key, allowedSet] : m_unknownKeysAllowedTargets)
446 {
447 if (key != linkKey)
448 error << " " << std::hex << key << std::dec;
449 }
450 } else
451 {
452 error << ", no expected sgkey configured but the maximum allowed index for the target is " << m_targetOffsetColumns.at(0)->at(eventIndex + 1) - m_targetOffsetColumns.at(0)->at(eventIndex) - 1;
453 }
454 throw std::runtime_error (std::move (error).str());
455 }
456 }
457 }
458
459 if (targetIndex == m_targetKeys.size())
460 {
461 // this creates a link with an unknown key, which the user
462 // will ignore
463 m_columnData.push_back (CM::mergeLinkKeyIndex (0xff, linkIndex));
464 return;
465 }
466
467 auto& targetOffsetColumn = *m_targetOffsetColumns.at(targetIndex);
468 if (eventIndex + 1 >= targetOffsetColumn.size())
469 throw std::runtime_error ("target offset column not yet filled for: " + m_targetNames.at(targetIndex));
470 auto myLinkIndex = linkIndex + targetOffsetColumn.at(eventIndex);
471 if (myLinkIndex >= targetOffsetColumn.at(eventIndex + 1))
472 throw std::runtime_error ("index out of range for link: " + m_columnName + " with element index " + std::to_string(linkIndex) + " targeting " + m_targetNames.at(targetIndex) + " with offset " + std::to_string(targetOffsetColumn.at(eventIndex)) + " and next offset " + std::to_string(targetOffsetColumn.at(eventIndex + 1)));
473
474 m_columnData.push_back (CM::mergeLinkKeyIndex (targetIndex, myLinkIndex));
475 }
476
477 [[nodiscard]] std::size_t size () const noexcept
478 {
479 return m_columnData.size();
480 }
481
482 [[nodiscard]] const typename CM::LinkIndexType* data () const noexcept
483 {
484 return m_columnData.data();
485 }
486
487 [[nodiscard]] auto begin () const noexcept { return m_columnData.begin(); }
488 [[nodiscard]] auto end () const noexcept { return m_columnData.end(); }
489
490 [[nodiscard]] const std::vector<typename CM::LinkKeyType>& keysColumn (std::size_t index) const
491 {
492 return m_keysColumns.at(index);
493 }
494
495
496
499 private:
500
501 std::vector<typename CM::LinkIndexType> m_columnData;
502
503 std::string m_columnName;
504
505 std::vector<std::string> m_targetNames;
506 std::vector<SG::sgkey_t> m_targetKeys;
507 std::vector<const std::vector<ColumnarOffsetType>*> m_targetOffsetColumns;
508
509 // there can be multiple keys-columns, hence this is a vector of
510 // vectors. if this is empty, then it is a single-target link
511 std::vector<std::vector<typename CM::LinkKeyType>> m_keysColumns;
512
513 std::unordered_map<SG::sgkey_t,std::unordered_set<std::size_t>> m_unknownKeysAllowedTargets;
514
515
516
517 void addTarget (const std::string& name, const std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& offsetColumns, std::uint32_t clid = 0)
518 {
519 unsigned targetIndex = 0;
520 while (targetIndex < m_targetNames.size() && m_targetNames.at(targetIndex) != name)
521 ++ targetIndex;
522 if (targetIndex == m_targetNames.size())
523 {
524 m_targetNames.push_back(name);
525 if (auto offsetIter = offsetColumns.find (name); offsetIter != offsetColumns.end())
526 m_targetOffsetColumns.push_back (offsetIter->second);
527 else
528 throw std::runtime_error ("missing offset column: " + name);
529 if (clid != 0)
530 m_targetKeys.push_back (computeSgKey (name, clid));
531 else if (auto keyIter = knownSgKeys.find (name); keyIter != knownSgKeys.end())
532 m_targetKeys.push_back (keyIter->second);
533 else
534 m_targetKeys.push_back (0);
535 }
536 if (!m_keysColumns.empty())
537 m_keysColumns.back().push_back (targetIndex);
538 }
539 };
540
541 template <typename T>
542 class RNTFieldReader final
543 {
544 std::string m_FieldName;
545 std::unique_ptr<ROOT::RNTupleView<T>> m_view;
546 ROOT::Experimental::RNTupleInspector* m_inspector = nullptr;
547 ROOT::RNTupleReader* m_reader = nullptr;
548 const T* m_data = nullptr;
549
550 public:
551 RNTFieldReader(const std::string& val_fieldName)
552 : m_FieldName(val_fieldName)
553 {}
554
555 ~RNTFieldReader() noexcept {}
558
559 [[nodiscard]] const std::string& fieldName() const
560 {
561 return m_FieldName;
562 }
563
564 [[nodiscard]] std::string columnName() const
565 {
566 std::string columnName = m_FieldName;
567 if (auto index = columnName.find("AuxDyn:"); index != std::string::npos)
568 columnName.replace(index, 6, "");
569 else if (auto index = columnName.find("Aux:."); index != std::string::npos)
570 columnName.replace(index, 4, "");
571 else if (auto index = columnName.find("Aux:"); index != std::string::npos)
572 columnName.replace(index, 3, "");
573 else if (columnName.find(":") != std::string::npos)
574 throw std::runtime_error("field name does not contain AuxDyn or Aux: " + m_FieldName);
575 std::replace(columnName.begin(), columnName.end(), ':', '.');
576
577 return columnName;
578 }
579
580 [[nodiscard]] std::string containerName() const
581 {
582 if (auto index = m_FieldName.find("AuxDyn:"); index != std::string::npos)
583 return m_FieldName.substr(0, index);
584 else if (auto index = m_FieldName.find("Aux:"); index != std::string::npos)
585 return m_FieldName.substr(0, index);
586 else if (m_FieldName.find(":") == std::string::npos)
587 return m_FieldName;
588 else
589 throw std::runtime_error("field name does not contain AuxDyn or Aux: " + m_FieldName);
590 }
591
592 void connectRNTuple(ROOT::RNTupleReader* reader,
593 ROOT::Experimental::RNTupleInspector* inspector)
594 {
595 m_inspector = inspector;
596 m_reader = reader;
597 m_view = std::make_unique<ROOT::RNTupleView<T>>(reader->GetView<T>(m_FieldName));
598
599 if (!m_view)
600 throw std::runtime_error("failed to get field: " + m_FieldName);
601 }
602
603 void connectTree(const Backend& b)
604 {
605 auto* rntbackend = std::get<RNTupleBackend*>(b); // throws if wrong backend
606
607 if (!rntbackend->reader || !rntbackend->inspector)
608 throw std::runtime_error("RNTuple backend not properly initialized");
609 connectRNTuple(rntbackend->reader, rntbackend->inspector);
610 }
611
612
613 const T& getEntry(Long64_t entry)
614 {
615 if (!m_view)
616 throw std::runtime_error("field not connected: " + m_FieldName);
617
618 m_data = &((*m_view)(static_cast<ROOT::NTupleSize_t>(entry)));
619
620 if (m_data == nullptr)
621 throw std::runtime_error("got nullptr reading data for field: " + m_FieldName);
622 return *m_data;
623 }
624
625 const T& getCachedEntry() const
626 {
627 return *m_data;
628 }
629
630 std::optional<float> entrySize() const
631 {
632
633 const ROOT::Experimental::RNTupleInspector::RFieldTreeInspector& fieldTreeInspector = m_inspector->GetFieldTreeInspector(m_FieldName);
634 return static_cast<float>(fieldTreeInspector.GetCompressedSize()) /
635 m_inspector->GetDescriptor().GetNEntries();
636 }
637
638 std::optional<float> uncompressedSize() const
639 {
640
641 const ROOT::Experimental::RNTupleInspector::RFieldTreeInspector& fieldTreeInspector = m_inspector->GetFieldTreeInspector(m_FieldName);
642
643 return static_cast<float>(fieldTreeInspector.GetUncompressedSize()) /
644 m_inspector->GetDescriptor().GetNEntries();
645 }
646
647 std::optional<unsigned> numBaskets()
648 {
649 // placeholder
650 return std::nullopt;
651 }
652 };
653
655 {
656 public:
657
659 {
660 std::string name;
661 bool isOffset = false;
662 bool primary = false;
663 bool enabled = false;
665 };
666 std::vector<OutputColumnInfo> outputColumns;
667
668 virtual ~IColumnData () noexcept = default;
669
670 virtual bool connect(Backend source, std::unordered_map<std::string, const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string, ColumnInfo>& requestedColumns) = 0;
671
674 {
675 for (auto& col : outputColumns)
676 {
677 if (col.enabled)
678 col.columnIndex = header.getColumnIndex (col.name);
679 }
680 }
681
682 virtual void clearColumns () = 0;
683
684 virtual void getEntry (Long64_t entry) = 0;
685
686 virtual void setData (ColumnVectorData& columnData) = 0;
687
688 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) = 0;
689
690 virtual void collectColumnData () = 0;
691 };
692
694 {
695 std::array<ColumnarOffsetType, 2> data = {0, 0};
696
698 {
699 outputColumns.push_back ({.name = eventRangeColumnName, .isOffset = true});
700 }
701
702 virtual bool connect(Backend /*source*/, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/,std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
703 {
704 if (requestedColumns.contains(outputColumns.at(0).name))
705 {
706 requestedColumns.erase(outputColumns.at(0).name);
707 outputColumns.at(0).enabled = true;
708 return true;
709 }
710 return false;
711 }
712 virtual void clearColumns () override
713 {
714 data[0] = 0;
715 data[1] = 0;
716 }
717
718 virtual void getEntry (Long64_t /*entry*/) override
719 {
720 data[1] += 1;
721 }
722
723 virtual void setData (ColumnVectorData& columnData) override
724 {
725 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
726 columnData.setColumn (outputColumns.at(0).columnIndex, data.size(), data.data());
727 }
728
729 [[nodiscard]] virtual BranchPerfData getPerfData (float /*emptyTime*/) override
730 {
731 BranchPerfData result;
732 result.name = "EventCount(auto)";
733 return result;
734 }
735
736 virtual void collectColumnData () override
737 {}
738 };
739
740
741 template <typename T, template <typename> class Reader>
743 {
744 Reader<T> branchReader;
747 std::vector<T> outData;
748 unsigned entries = 0;
749
750 explicit ColumnDataScalar (const std::string& val_branchName)
751 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
752 {
753 outputColumns.push_back ({.name = branchReader.columnName()});
754 }
755
756 virtual bool connect( Backend source, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/,std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
757 {
758 auto iter = requestedColumns.find (outputColumns.at(0).name);
759 if (iter == requestedColumns.end())
760 return false;
761 outputColumns.at(0).enabled = true;
762 requestedColumns.erase (iter);
763
764 branchReader.connectTree (source);
765
766 return true;
767 }
768 virtual void clearColumns () override
769 {
770 outData.clear ();
771 }
772
773 virtual void getEntry (Long64_t entry) override
774 {
775 benchmark.startTimer ();
776 const auto& branchData = branchReader.getEntry (entry);
777 benchmark.stopTimer ();
778 benchmarkUnpack.startTimer ();
779 outData.push_back (branchData);
780 benchmarkUnpack.stopTimer ();
781 }
782
783 virtual void setData (ColumnVectorData& columnData) override
784 {
785 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
786 columnData.setColumn (outputColumns.at(0).columnIndex, outData.size(), outData.data());
787 }
788
789 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
790 {
791 BranchPerfData result;
792 result.name = branchReader.columnName();
793 result.timeRead = benchmark.getEntryTime(emptyTime);
794 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
795 benchmark.setSilence();
796 benchmarkUnpack.setSilence();
797 result.entrySize = branchReader.entrySize();
798 result.uncompressedSize = branchReader.uncompressedSize();
799 result.numBaskets = branchReader.numBaskets();
800 result.entries = entries;
801 return result;
802 }
803
804 virtual void collectColumnData () override
805 {
806 entries += outData.size();
807 }
808 };
809
810 template <typename T, template <typename> class Reader>
812 {
813 Reader<std::vector<T>> branchReader;
814 const std::vector<ColumnarOffsetType>* offsetColumn = nullptr;
815 std::vector<ColumnarOffsetType> offsets = {0};
816 std::vector<T> outData;
819 unsigned entries = 0;
820
821 explicit ColumnDataVector (const std::string& val_branchName)
822 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
823 {
824 outputColumns.push_back ({.name = branchReader.columnName()});
825 outputColumns.push_back ({.name = branchReader.containerName(), .isOffset = true, .primary = false});
826 }
827
828 virtual bool connect(Backend source, std::unordered_map<std::string, const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
829 {
830 auto iter = requestedColumns.find (outputColumns.at(0).name);
831 if (iter == requestedColumns.end())
832 return false;
833 outputColumns.at(0).enabled = true;
834
835 branchReader.connectTree(source);
836
837 if (iter->second.offsetName != outputColumns.at(1).name)
838 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
839
840 requestedColumns.erase (iter);
841
842 if (auto offsetIter = offsetColumns.find (outputColumns.at(1).name); offsetIter != offsetColumns.end())
843 offsetColumn = offsetIter->second;
844 else
845 offsetColumns.emplace (outputColumns.at(1).name, &offsets);
846
847 iter = requestedColumns.find (outputColumns.at(1).name);
848 if (iter != requestedColumns.end())
849 {
850 requestedColumns.erase (iter);
851 outputColumns.at(1).enabled = true;
852 }
853
854 return true;
855 }
856
857 virtual void clearColumns () override
858 {
859 offsets.clear ();
860 offsets.push_back (0);
861 outData.clear ();
862 }
863
864 virtual void getEntry (Long64_t entry) override
865 {
866 benchmark.startTimer ();
867 const auto& branchData = branchReader.getEntry (entry);
868 benchmark.stopTimer ();
869 benchmarkUnpack.startTimer ();
870 outData.insert (outData.end(), branchData.begin(), branchData.end());
871 offsets.push_back (outData.size());
872 benchmarkUnpack.stopTimer ();
873 }
874
875 virtual void setData (ColumnVectorData& columnData) override
876 {
877 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
878 columnData.setColumn (outputColumns.at(0).columnIndex, outData.size(), outData.data());
879 if (outputColumns.at(1).columnIndex != ColumnVectorHeader::nullIndex)
880 columnData.setColumn (outputColumns.at(1).columnIndex, offsets.size(), offsets.data());
881 if (offsetColumn)
882 {
883 if (offsetColumn->size() != offsets.size())
884 throw std::runtime_error ("offset column not filled yet: " + outputColumns.at(1).name);
885 if (offsetColumn->back() != offsets.back())
886 throw std::runtime_error ("offset column does not match: " + outputColumns.at(1).name);
887 }
888 }
889
890 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
891 {
892 BranchPerfData result;
893 result.name = branchReader.columnName();
894 result.timeRead = benchmark.getEntryTime(emptyTime);
895 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
896 benchmark.setSilence();
897 benchmarkUnpack.setSilence();
898 result.entrySize = branchReader.entrySize();
899 result.uncompressedSize = branchReader.uncompressedSize();
900 result.numBaskets = branchReader.numBaskets();
901 result.entries = entries;
902 return result;
903 }
904
905 virtual void collectColumnData () override
906 {
907 entries += outData.size();
908 }
909 };
910
911 template <typename T, template <typename> class Reader>
913 {
915 const std::vector<ColumnarOffsetType>* offsetColumn = nullptr;
916 std::vector<T> outData;
917 unsigned entries = 0;
918
919 ColumnDataOutVector (const std::string& val_columnName, const T& val_defaultValue)
920 : defaultValue (val_defaultValue)
921 {
922 outputColumns.push_back ({.name = val_columnName});
923 }
924
925 virtual bool connect([[maybe_unused]]Backend source, std::unordered_map<std::string, const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
926 {
927 auto iter = requestedColumns.find (outputColumns.at(0).name);
928 if (iter == requestedColumns.end())
929 return false;
930 outputColumns.at(0).enabled = true;
931
932 const auto & offsetName = iter->second.offsetName;
933 if (offsetName.empty())
934 throw std::runtime_error ("missing offset column for: " + outputColumns.at(0).name);
935
936 if (auto offsetIter = offsetColumns.find (offsetName); offsetIter != offsetColumns.end())
937 offsetColumn = offsetIter->second;
938 else
939 throw std::runtime_error ("missing offset column for: " + outputColumns.at(0).name + " (offset column: " + offsetName + ")");
940
941 // IMPORTANT: This has to be erased at the end of the function,
942 // since erasing it earlier would invalidate the offsetName
943 // reference.
944 requestedColumns.erase (iter);
945 return true;
946 }
947
948 virtual void clearColumns () override
949 {
950 outData.clear ();
951 }
952
953 virtual void getEntry (Long64_t /*entry*/) override
954 {
955 outData.resize (offsetColumn->back(), defaultValue);
956 }
957
958 virtual void setData (ColumnVectorData& columnData) override
959 {
960 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
961 columnData.setColumn (outputColumns.at(0).columnIndex, outData.size(), outData.data());
962 }
963
964 [[nodiscard]] virtual BranchPerfData getPerfData (float /*emptyTime*/) override
965 {
966 BranchPerfData result;
967 result.name = outputColumns.at(0).name + "(out)";
968 result.entries = entries;
969 return result;
970 }
971
972 virtual void collectColumnData () override
973 {
974 entries += outData.size();
975 }
976 };
977
978 template <typename T, template <typename> class Reader>
980 {
981 Reader<std::vector<std::vector<T>>> branchReader;
982 std::vector<ColumnarOffsetType> offsets = {0};
983 std::vector<T> columnData;
986 unsigned entries = 0;
987
988 explicit ColumnDataVectorVector (const std::string& val_branchName)
989 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
990 {
991 outputColumns.push_back ({.name = branchReader.columnName() + ".data"});
992 outputColumns.push_back ({.name = branchReader.columnName() + ".offset", .isOffset = true});
993 }
994
995 virtual bool connect(Backend source, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/, std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
996 {
997 auto iter = requestedColumns.find (outputColumns.at(0).name);
998 if (iter == requestedColumns.end())
999 return false;
1000 outputColumns.at(0).enabled = true;
1001
1002 branchReader.connectTree(source);
1003
1004 if (iter->second.offsetName != outputColumns.at(1).name)
1005 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
1006
1007 requestedColumns.erase (iter);
1008
1009 iter = requestedColumns.find (outputColumns.at(1).name);
1010 if (iter == requestedColumns.end())
1011 return true;
1012 requestedColumns.erase (iter);
1013 outputColumns.at(1).enabled = true;
1014 return true;
1015 }
1016
1017 virtual void clearColumns () override
1018 {
1019 columnData.clear();
1020 offsets.clear();
1021 offsets.push_back (0);
1022 }
1023
1024 virtual void getEntry (Long64_t entry) override
1025 {
1026 benchmark.startTimer ();
1027 const auto& branchData = branchReader.getEntry (entry);
1028 benchmark.stopTimer ();
1029 benchmarkUnpack.startTimer ();
1030 for (auto& data : branchData)
1031 {
1032 columnData.insert (columnData.end(), data.begin(), data.end());
1033 offsets.push_back (columnData.size());
1034 }
1035 benchmarkUnpack.stopTimer ();
1036 }
1037
1038 virtual void setData (ColumnVectorData& colData) override
1039 {
1040 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
1041 colData.setColumn (outputColumns.at(0).columnIndex, columnData.size(), columnData.data());
1042 if (outputColumns.at(1).columnIndex != ColumnVectorHeader::nullIndex)
1043 colData.setColumn (outputColumns.at(1).columnIndex, offsets.size(), offsets.data());
1044 }
1045
1046 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1047 {
1048 BranchPerfData result;
1049 result.name = branchReader.columnName();
1050 result.timeRead = benchmark.getEntryTime(emptyTime);
1051 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1052 benchmark.setSilence();
1053 benchmarkUnpack.setSilence();
1054 result.entrySize = branchReader.entrySize();
1055 result.uncompressedSize = branchReader.uncompressedSize();
1056 result.numBaskets = branchReader.numBaskets();
1057 result.entries = entries;
1058 return result;
1059 }
1060
1061 virtual void collectColumnData () override
1062 {
1063 entries += columnData.size();
1064 }
1065 };
1066
1067 template <typename T, template <typename> class Reader>
1069 {
1071 Reader<std::vector<std::vector<ElementLink<T>>>> branchReader;
1072 std::vector<ColumnarOffsetType> offsets = {0};
1073 std::vector<ColumnarOffsetType> eventOffsets = {0};
1077 unsigned entries = 0;
1078 unsigned nullEntries = 0;
1079
1080 explicit ColumnDataVectorVectorLink (const std::string& val_branchName)
1081 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
1082 {
1083 outputColumns.push_back ({.name = branchReader.columnName() + ".data"});
1084 outputColumns.push_back ({.name = branchReader.columnName() + ".offset", .isOffset = true});
1085 }
1086
1087 virtual bool connect(Backend source, std::unordered_map<std::string, const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
1088 {
1089 auto iter = requestedColumns.find (outputColumns.at(0).name);
1090 if (iter == requestedColumns.end())
1091 return false;
1092 outputColumns.at(0).enabled = true;
1093
1094 branchReader.connectTree(source);
1095
1096 if (iter->second.offsetName != outputColumns.at(1).name)
1097 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
1098 for (const auto & keyColumn : columnData.connect (iter->second, offsetColumns, requestedColumns))
1099 {
1100 outputColumns.push_back ({.name = keyColumn, .primary = false, .enabled = true});
1101 requestedColumns.erase (keyColumn);
1102 }
1103
1104 requestedColumns.erase (iter);
1105
1106 iter = requestedColumns.find (outputColumns.at(1).name);
1107 if (iter == requestedColumns.end())
1108 return true;
1109 requestedColumns.erase (iter);
1110 outputColumns.at(1).enabled = true;
1111 return true;
1112 }
1113
1114 virtual void clearColumns () override
1115 {
1116 columnData.clear();
1117 offsets.clear();
1118 offsets.push_back (0);
1119 eventOffsets.clear();
1120 eventOffsets.push_back (0);
1121 }
1122
1123 virtual void getEntry (Long64_t entry) override
1124 {
1125 benchmark.startTimer ();
1126 const auto& branchData = branchReader.getEntry (entry);
1127 benchmark.stopTimer ();
1128 benchmarkUnpack.startTimer ();
1129 columnData.checkOffsets (eventOffsets.size() - 1);
1130 for (auto& data : branchData)
1131 {
1132 for (auto& element : data)
1133 {
1134 columnData.addLink (element, eventOffsets.size()-1);
1135 }
1136 offsets.push_back (columnData.size());
1137 }
1138 eventOffsets.push_back (offsets.size());
1139 benchmarkUnpack.stopTimer ();
1140 }
1141
1142 virtual void setData (ColumnVectorData& colData) override
1143 {
1144 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
1145 colData.setColumn (outputColumns.at(0).columnIndex, columnData.size(), columnData.data());
1146 if (outputColumns.at(1).columnIndex != ColumnVectorHeader::nullIndex)
1147 colData.setColumn (outputColumns.at(1).columnIndex, offsets.size(), offsets.data());
1148 for (std::size_t i = 2; i < outputColumns.size(); ++ i)
1149 {
1150 if (outputColumns.at(i).columnIndex != ColumnVectorHeader::nullIndex)
1151 colData.setColumn (outputColumns.at(i).columnIndex, columnData.keysColumn(i-2).size(), columnData.keysColumn(i-2).data());
1152 }
1153 }
1154
1155 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1156 {
1157 BranchPerfData result;
1158 result.name = branchReader.columnName();
1159 result.timeRead = benchmark.getEntryTime(emptyTime);
1160 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1161 benchmark.setSilence();
1162 benchmarkUnpack.setSilence();
1163 result.entrySize = branchReader.entrySize();
1164 result.uncompressedSize = branchReader.uncompressedSize();
1165 result.numBaskets = branchReader.numBaskets();
1166 result.entries = entries;
1167 result.nullEntries = nullEntries;
1168 return result;
1169 }
1170
1171 virtual void collectColumnData () override
1172 {
1173 entries += columnData.size();
1174 for (const auto& index : columnData)
1175 {
1177 nullEntries += 1;
1178 }
1179 }
1180 };
1181
1182 template <typename T, template <typename> class Reader>
1184 {
1185 std::string columnName;
1186 Reader<std::vector<std::vector<std::vector<T>>>> branchReader;
1187 std::vector<ColumnarOffsetType> outerOffsets = {0};
1188 std::vector<ColumnarOffsetType> innerOffsets = {0};
1189 std::vector<T> columnData;
1192 unsigned entries = 0;
1193
1194 explicit ColumnDataVectorVectorVector (const std::string& val_branchName)
1196 {
1197 outputColumns.push_back ({.name = branchReader.columnName() + ".data"});
1198 outputColumns.push_back ({.name = branchReader.columnName() + ".innerOffset", .isOffset = true});
1199 outputColumns.push_back ({.name = branchReader.columnName() + ".outerOffset", .isOffset = true});
1200 }
1201
1202 virtual bool connect(Backend source, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/, std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
1203 {
1204 auto iter = requestedColumns.find (outputColumns.at(0).name);
1205 if (iter == requestedColumns.end())
1206 return false;
1207 outputColumns.at(0).enabled = true;
1208
1209 branchReader.connectTree(source);
1210
1211 if (iter->second.offsetName != outputColumns.at(1).name)
1212 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
1213
1214 requestedColumns.erase (iter);
1215
1216 iter = requestedColumns.find (outputColumns.at(1).name);
1217 if (iter == requestedColumns.end())
1218 return true;
1219 outputColumns.at(1).enabled = true;
1220
1221 if (iter->second.offsetName != outputColumns.at(2).name)
1222 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(2).name);
1223
1224 requestedColumns.erase (iter);
1225
1226 iter = requestedColumns.find (outputColumns.at(2).name);
1227 if (iter == requestedColumns.end())
1228 return true;
1229 outputColumns.at(2).enabled = true;
1230 requestedColumns.erase (iter);
1231 return true;
1232 }
1233
1234 virtual void clearColumns () override
1235 {
1236 columnData.clear();
1237 innerOffsets.clear();
1238 innerOffsets.push_back (0);
1239 outerOffsets.clear();
1240 outerOffsets.push_back (0);
1241 }
1242
1243 virtual void getEntry (Long64_t entry) override
1244 {
1245 benchmark.startTimer ();
1246 const auto& branchData = branchReader.getEntry (entry);
1247 benchmark.stopTimer ();
1248 benchmarkUnpack.startTimer ();
1249 for (auto& outerData : branchData)
1250 {
1251 for (auto& innerData : outerData)
1252 {
1253 columnData.insert (columnData.end(), innerData.begin(), innerData.end());
1254 innerOffsets.push_back (columnData.size());
1255 }
1256 outerOffsets.push_back (innerOffsets.size()-1);
1257 }
1258 benchmarkUnpack.stopTimer ();
1259 }
1260
1261 virtual void setData (ColumnVectorData& colData) override
1262 {
1263 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
1264 colData.setColumn (outputColumns.at(0).columnIndex, columnData.size(), columnData.data());
1265 if (outputColumns.at(1).columnIndex != ColumnVectorHeader::nullIndex)
1266 colData.setColumn (outputColumns.at(1).columnIndex, innerOffsets.size(), innerOffsets.data());
1267 if (outputColumns.at(2).columnIndex != ColumnVectorHeader::nullIndex)
1268 colData.setColumn (outputColumns.at(2).columnIndex, outerOffsets.size(), outerOffsets.data());
1269 }
1270
1271 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1272 {
1273 BranchPerfData result;
1274 result.name = branchReader.columnName();
1275 result.timeRead = benchmark.getEntryTime(emptyTime);
1276 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1277 benchmark.setSilence();
1278 benchmarkUnpack.setSilence();
1279 result.entrySize = branchReader.entrySize();
1280 result.uncompressedSize = branchReader.uncompressedSize();
1281 result.numBaskets = branchReader.numBaskets();
1282 result.entries = entries;
1283 return result;
1284 }
1285
1286 virtual void collectColumnData () override
1287 {
1288 entries += columnData.size();
1289 }
1290 };
1291
1292 template <typename T, template <typename> class Reader>
1294 {
1296 Reader<std::vector<ElementLink<T>>> branchReader;
1297 const std::vector<ColumnarOffsetType>* offsetColumn = nullptr;
1298 std::vector<ColumnarOffsetType> offsets = {0};
1302 unsigned entries = 0;
1303 unsigned nullEntries = 0;
1304
1305 ColumnDataVectorLink (const std::string& val_branchName)
1306 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
1307 {
1308 outputColumns.push_back ({.name = branchReader.columnName()});
1309 outputColumns.push_back ({.name = branchReader.containerName(), .isOffset = true, .primary = false});
1310 }
1311
1312
1313 virtual bool connect(Backend source, 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(source);
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 for (const auto & keyColumn : columnData.connect (iter->second, offsetColumns, requestedColumns))
1325 {
1326 outputColumns.push_back ({.name = keyColumn, .primary = false, .enabled = true});
1327 requestedColumns.erase (keyColumn);
1328 }
1329
1330 requestedColumns.erase (iter);
1331
1332 if (auto offsetIter = offsetColumns.find (outputColumns.at(1).name); offsetIter != offsetColumns.end())
1333 offsetColumn = offsetIter->second;
1334 else
1335 offsetColumns.emplace (outputColumns.at(1).name, &offsets);
1336
1337 iter = requestedColumns.find (outputColumns.at(1).name);
1338 if (iter != requestedColumns.end())
1339 {
1340 outputColumns.at(1).enabled = true;
1341 requestedColumns.erase (iter);
1342 }
1343
1344 return true;
1345 }
1346
1347 virtual void clearColumns () override
1348 {
1349 columnData.clear();
1350 offsets.clear();
1351 offsets.push_back (0);
1352 }
1353
1354 virtual void getEntry (Long64_t entry) override
1355 {
1356 benchmark.startTimer ();
1357 const auto& branchData = branchReader.getEntry (entry);
1358 benchmark.stopTimer ();
1359 benchmarkUnpack.startTimer ();
1360 columnData.checkOffsets (offsets.size() - 1);
1361 for (auto& element : branchData)
1362 columnData.addLink (element, offsets.size()-1);
1363 offsets.push_back (columnData.size());
1364 if (offsetColumn)
1365 {
1366 if (offsetColumn->size() != offsets.size())
1367 throw std::runtime_error ("offset column not filled yet: " + outputColumns.at(1).name);
1368 if (offsetColumn->back() != offsets.back())
1369 throw std::runtime_error ("offset column does not match: " + outputColumns.at(1).name);
1370 }
1371 benchmarkUnpack.stopTimer ();
1372 }
1373
1374 virtual void setData (ColumnVectorData& colData) override
1375 {
1376 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
1377 colData.setColumn (outputColumns.at(0).columnIndex, columnData.size(), columnData.data());
1378 if (outputColumns.at(1).columnIndex != ColumnVectorHeader::nullIndex)
1379 colData.setColumn (outputColumns.at(1).columnIndex, offsets.size(), offsets.data());
1380 for (std::size_t i = 2; i < outputColumns.size(); ++ i)
1381 {
1382 if (outputColumns.at(i).columnIndex != ColumnVectorHeader::nullIndex)
1383 colData.setColumn (outputColumns.at(i).columnIndex, columnData.keysColumn(i-2).size(), columnData.keysColumn(i-2).data());
1384 }
1385 }
1386
1387 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1388 {
1389 BranchPerfData result;
1390 result.name = branchReader.columnName();
1391 result.timeRead = benchmark.getEntryTime(emptyTime);
1392 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1393 benchmark.setSilence();
1394 benchmarkUnpack.setSilence();
1395 result.entrySize = branchReader.entrySize();
1396 result.uncompressedSize = branchReader.uncompressedSize();
1397 result.numBaskets = branchReader.numBaskets();
1398 result.entries = entries;
1399 result.nullEntries = nullEntries;
1400 return result;
1401 }
1402
1403 virtual void collectColumnData () override
1404 {
1405 entries += columnData.size();
1406 for (const auto& index : columnData)
1407 {
1409 nullEntries += 1;
1410 }
1411 }
1412 };
1413
1414 template <typename T, template <typename> class Reader>
1416 {
1418 Reader<std::vector<ElementLink<T>>> branchReader;
1419 const std::vector<ColumnarOffsetType>* offsetColumn = nullptr;
1420 std::vector<ColumnarOffsetType> offsets = {0};
1424 unsigned entries = 0;
1425 unsigned nullEntries = 0;
1426
1427 ColumnDataVectorRLink(const std::string& val_branchName)
1428 : branchReader(val_branchName), benchmarkUnpack(branchReader.columnName() + "(unpack)"), benchmark(branchReader.columnName())
1429 {
1430 outputColumns.push_back({.name = branchReader.columnName()});
1431 outputColumns.push_back({.name = branchReader.containerName(), .isOffset = true, .primary = false});
1432 }
1433
1434 virtual bool connect(Backend source, std::unordered_map<std::string, const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
1435 {
1436 auto iter = requestedColumns.find(outputColumns.at(0).name);
1437 if (iter == requestedColumns.end())
1438 return false;
1439 outputColumns.at(0).enabled = true;
1440
1441 branchReader.connectTree(source);
1442 if (iter->second.offsetName != outputColumns.at(1).name)
1443 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
1444
1445 for (const auto & keyColumn : columnData.connect (iter->second, offsetColumns, requestedColumns))
1446 {
1447 outputColumns.push_back ({.name = keyColumn, .primary = false, .enabled = true});
1448 requestedColumns.erase (keyColumn);
1449 }
1450 requestedColumns.erase (iter);
1451
1452 if (auto offsetIter = offsetColumns.find (outputColumns.at(1).name); offsetIter != offsetColumns.end())
1453 offsetColumn = offsetIter->second;
1454 else
1455 offsetColumns.emplace (outputColumns.at(1).name, &offsets);
1456
1457 iter = requestedColumns.find (outputColumns.at(1).name);
1458 if (iter != requestedColumns.end())
1459 {
1460 outputColumns.at(1).enabled = true;
1461 requestedColumns.erase (iter);
1462 }
1463
1464 return true;
1465 }
1466
1467 virtual void clearColumns() override
1468 {
1469 columnData.clear();
1470 offsets.clear();
1471 offsets.push_back(0);
1472 }
1473
1474 virtual void getEntry(Long64_t entry) override
1475 {
1476 benchmark.startTimer();
1477 const auto& branchData = branchReader.getEntry(entry);
1478 benchmark.stopTimer();
1479 benchmarkUnpack.startTimer();
1480
1481 columnData.checkOffsets (offsets.size() - 1);
1482 for (const auto& element : branchData)
1483 {
1484 if (element.isDefault() || element.index() == static_cast<unsigned int>(-1))
1485 columnData.addEmptyLink ();
1486 else
1487 columnData.addSplitLink (element.index(), element.key(), offsets.size()-1);
1488 }
1489
1490
1491 offsets.push_back(columnData.size());
1492
1493 if (offsetColumn) {
1494 if (offsetColumn->size() != offsets.size())
1495 {
1496 throw std::runtime_error("offset column not filled yet: " + outputColumns.at(1).name);
1497 }
1498 if (offsetColumn->back() != offsets.back())
1499 {
1500 throw std::runtime_error("offset column does not match: " + outputColumns.at(1).name);
1501 }
1502 }
1503
1504 benchmarkUnpack.stopTimer();
1505 }
1506
1507 virtual void setData(ColumnVectorData& colData) override
1508 {
1509 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
1510 colData.setColumn(outputColumns.at(0).columnIndex, columnData.size(), columnData.data());
1511 if (outputColumns.at(1).columnIndex != ColumnVectorHeader::nullIndex)
1512 colData.setColumn(outputColumns.at(1).columnIndex, offsets.size(), offsets.data());
1513 for (std::size_t i = 2; i < outputColumns.size(); ++ i)
1514 {
1515 if (outputColumns.at(i).columnIndex != ColumnVectorHeader::nullIndex)
1516 colData.setColumn (outputColumns.at(i).columnIndex, columnData.keysColumn(i-2).size(), columnData.keysColumn(i-2).data());
1517 }
1518 }
1519
1520 [[nodiscard]] virtual BranchPerfData getPerfData(float emptyTime) override
1521 {
1522 BranchPerfData result;
1523 result.name = branchReader.columnName();
1524 result.timeRead = benchmark.getEntryTime(emptyTime);
1525 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1526 benchmark.setSilence();
1527 benchmarkUnpack.setSilence();
1528 result.entrySize = branchReader.entrySize();
1529 result.uncompressedSize = branchReader.uncompressedSize();
1530 result.numBaskets = branchReader.numBaskets();
1531 result.entries = entries;
1532 result.nullEntries = nullEntries;
1533 return result;
1534 }
1535
1536 virtual void collectColumnData() override
1537 {
1538 entries += columnData.size();
1539 for (const auto& index : columnData)
1540 {
1542 nullEntries += 1;
1543 }
1544 }
1545 };
1546
1547
1548 template<typename T>
1550 {
1555 const std::vector<ColumnarOffsetType>* offsetColumn = nullptr;
1556 std::vector<ColumnarOffsetType> offsets = {0};
1560 unsigned entries = 0;
1561 unsigned nullEntries = 0;
1562
1563 ColumnDataVectorSplitLink (const std::string& val_branchName)
1564 : branchReaderSize (val_branchName), branchReaderKey (val_branchName + ".m_persKey"), branchReaderIndex (val_branchName + ".m_persIndex"), benchmarkUnpack (branchReaderSize.columnName()+"(unpack)"), benchmark (branchReaderSize.columnName())
1565 {
1566 outputColumns.push_back ({.name = branchReaderSize.columnName()});
1567 outputColumns.push_back ({.name = branchReaderSize.containerName(), .isOffset = true, .primary = false});
1568 }
1569
1570 virtual bool connect (Backend source, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns) override
1571 {
1572 auto iter = requestedColumns.find (outputColumns.at(0).name);
1573 if (iter == requestedColumns.end())
1574 return false;
1575 outputColumns.at(0).enabled = true;
1576 auto* tree = std::get<TTree*>(source);
1577 branchReaderSize.connectTree (tree);
1578 branchReaderKey.connectTree (tree);
1579 branchReaderIndex.connectTree (tree);
1580
1581 if (iter->second.offsetName != outputColumns.at(1).name)
1582 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
1583
1584 for (const auto & keyColumn : columnData.connect (iter->second, offsetColumns, requestedColumns))
1585 {
1586 outputColumns.push_back ({.name = keyColumn, .primary = false, .enabled = true});
1587 requestedColumns.erase (keyColumn);
1588 }
1589 requestedColumns.erase (iter);
1590
1591 if (auto offsetIter = offsetColumns.find (outputColumns.at(1).name); offsetIter != offsetColumns.end())
1592 offsetColumn = offsetIter->second;
1593 else
1594 offsetColumns.emplace (outputColumns.at(1).name, &offsets);
1595
1596 iter = requestedColumns.find (outputColumns.at(1).name);
1597 if (iter != requestedColumns.end())
1598 {
1599 outputColumns.at(1).enabled = true;
1600 requestedColumns.erase (iter);
1601 }
1602
1603 return true;
1604 }
1605
1606 virtual void clearColumns () override
1607 {
1608 columnData.clear();
1609 offsets.clear();
1610 offsets.push_back (0);
1611 }
1612
1613 virtual void getEntry (Long64_t entry) override
1614 {
1615 benchmark.startTimer ();
1616 std::size_t branchDataSize = branchReaderSize.getEntry (entry);
1617 auto branchDataKey = branchReaderKey.getEntry (entry, branchDataSize);
1618 auto branchDataIndex = branchReaderIndex.getEntry (entry, branchDataSize);
1619 benchmark.stopTimer ();
1620 benchmarkUnpack.startTimer ();
1621 columnData.checkOffsets (offsets.size() - 1);
1622 for (std::size_t index = 0; index < branchDataSize; ++index)
1623 {
1624 if (branchDataIndex[index] == static_cast<UInt_t>(-1))
1625 columnData.addEmptyLink ();
1626 else
1627 columnData.addSplitLink (branchDataIndex[index], branchDataKey[index], offsets.size()-1);
1628 }
1629 offsets.push_back (columnData.size());
1630 if (offsetColumn)
1631 {
1632 if (offsetColumn->size() != offsets.size())
1633 throw std::runtime_error ("offset column not filled yet: " + outputColumns.at(1).name);
1634 if (offsetColumn->back() != offsets.back())
1635 throw std::runtime_error ("offset column does not match: " + outputColumns.at(1).name);
1636 }
1637 benchmarkUnpack.stopTimer ();
1638 }
1639
1640 virtual void setData (ColumnVectorData& colData) override
1641 {
1642 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
1643 colData.setColumn (outputColumns.at(0).columnIndex, columnData.size(), columnData.data());
1644 if (outputColumns.at(1).columnIndex != ColumnVectorHeader::nullIndex)
1645 colData.setColumn (outputColumns.at(1).columnIndex, offsets.size(), offsets.data());
1646 for (std::size_t i = 2; i < outputColumns.size(); ++ i)
1647 {
1648 if (outputColumns.at(i).columnIndex != ColumnVectorHeader::nullIndex)
1649 colData.setColumn (outputColumns.at(i).columnIndex, columnData.keysColumn(i-2).size(), columnData.keysColumn(i-2).data());
1650 }
1651 }
1652
1653 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1654 {
1655 BranchPerfData result;
1656 result.name = branchReaderSize.columnName();
1657 result.timeRead = benchmark.getEntryTime(emptyTime);
1658 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1659 benchmark.setSilence();
1660 benchmarkUnpack.setSilence();
1661 result.entrySize = branchReaderSize.entrySize().value() + branchReaderKey.entrySize().value() + branchReaderIndex.entrySize().value();
1662 result.uncompressedSize = branchReaderSize.uncompressedSize().value() + branchReaderKey.uncompressedSize().value() + branchReaderIndex.uncompressedSize().value();
1663 result.numBaskets = branchReaderSize.numBaskets().value() + branchReaderKey.numBaskets().value() + branchReaderIndex.numBaskets().value();
1664 result.entries = entries;
1665 result.nullEntries = nullEntries;
1666 return result;
1667 }
1668
1669 virtual void collectColumnData () override
1670 {
1671 entries += columnData.size();
1672 for (const auto& index : columnData)
1673 {
1675 nullEntries += 1;
1676 }
1677 }
1678 };
1679
1680 template <typename T, template <typename> class Reader>
1682 {
1684 Reader<std::vector<std::vector<ElementLink<T>>>> branchReader;
1685 std::vector<ColumnarOffsetType> offsets = {0};
1686 std::vector<ColumnarOffsetType> eventOffsets = {0};
1690 unsigned entries = 0;
1691 unsigned nullEntries = 0;
1692
1693 explicit ColumnDataVectorVectorVariantLink (const std::string& val_branchName)
1694 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
1695 {
1696 outputColumns.push_back ({.name = branchReader.columnName() + ".data"});
1697 outputColumns.push_back ({.name = branchReader.columnName() + ".offset", .isOffset = true});
1698 }
1699
1700 virtual bool connect(Backend source, std::unordered_map<std::string, const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
1701 {
1702 auto iter = requestedColumns.find (outputColumns.at(0).name);
1703 if (iter == requestedColumns.end())
1704 return false;
1705 outputColumns.at(0).enabled = true;
1706
1707 branchReader.connectTree(source);
1708
1709 if (iter->second.offsetName != outputColumns.at(1).name)
1710 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
1711
1712 for (const auto & keyColumn : columnData.connect (iter->second, offsetColumns, requestedColumns))
1713 {
1714 outputColumns.push_back ({.name = keyColumn, .primary = false, .enabled = true});
1715 requestedColumns.erase (keyColumn);
1716 }
1717
1718 requestedColumns.erase (iter);
1719
1720 iter = requestedColumns.find (outputColumns.at(1).name);
1721 if (iter != requestedColumns.end())
1722 {
1723 outputColumns.at(1).enabled = true;
1724 requestedColumns.erase (iter);
1725 }
1726
1727 iter = requestedColumns.find (outputColumns.at(2).name);
1728 if (iter != requestedColumns.end())
1729 {
1730 outputColumns.at(2).enabled = true;
1731 requestedColumns.erase (iter);
1732 }
1733 return true;
1734 }
1735
1736 virtual void clearColumns () override
1737 {
1738 columnData.clear();
1739 offsets.clear();
1740 offsets.push_back (0);
1741 eventOffsets.clear();
1742 eventOffsets.push_back (0);
1743 }
1744
1745 virtual void getEntry (Long64_t entry) override
1746 {
1747 benchmark.startTimer ();
1748 const auto& branchData = branchReader.getEntry (entry);
1749 benchmark.stopTimer ();
1750 benchmarkUnpack.startTimer ();
1751 columnData.checkOffsets (eventOffsets.size() - 1);
1752 for (auto& data : branchData)
1753 {
1754 for (auto& element : data)
1755 {
1756 columnData.addLink (element, eventOffsets.size()-1);
1757 }
1758 offsets.push_back (columnData.size());
1759 }
1760 eventOffsets.push_back (offsets.size());
1761 benchmarkUnpack.stopTimer ();
1762 }
1763
1764 virtual void setData (ColumnVectorData& colData) override
1765 {
1766 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
1767 colData.setColumn (outputColumns.at(0).columnIndex, columnData.size(), columnData.data());
1768 if (outputColumns.at(1).columnIndex != ColumnVectorHeader::nullIndex)
1769 colData.setColumn (outputColumns.at(1).columnIndex, offsets.size(), offsets.data());
1770 for (std::size_t i = 2; i < outputColumns.size(); ++ i)
1771 {
1772 if (outputColumns.at(i).columnIndex != ColumnVectorHeader::nullIndex)
1773 colData.setColumn (outputColumns.at(i).columnIndex, columnData.keysColumn(i-2).size(), columnData.keysColumn(i-2).data());
1774 }
1775 }
1776
1777 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1778 {
1779 BranchPerfData result;
1780 result.name = branchReader.columnName();
1781 result.timeRead = benchmark.getEntryTime(emptyTime);
1782 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1783 benchmark.setSilence();
1784 benchmarkUnpack.setSilence();
1785 result.entrySize = branchReader.entrySize();
1786 result.uncompressedSize = branchReader.uncompressedSize();
1787 result.numBaskets = branchReader.numBaskets();
1788 result.entries = entries;
1789 result.nullEntries = nullEntries;
1790 return result;
1791 }
1792
1793 virtual void collectColumnData () override
1794 {
1795 entries += columnData.size();
1796 for (const auto& index : columnData)
1797 {
1799 nullEntries += 1;
1800 }
1801 }
1802 };
1803
1804 template <template <typename> class Reader>
1806 {
1807 Reader<std::vector<std::string>> branchReader;
1808 std::vector<ColumnarOffsetType> offsets = {0};
1809 std::vector<char> columnData;
1810 std::vector<std::size_t> columnHashData;
1813
1814 ColumnDataMetNames (const std::string& val_branchName)
1815 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+"(unpack)"), benchmark (branchReader.columnName())
1816 {
1817 outputColumns.push_back ({.name = branchReader.columnName() + ".data"});
1818 outputColumns.push_back ({.name = branchReader.columnName() + ".offset", .isOffset = true});
1819 outputColumns.push_back ({.name = branchReader.columnName() + "Hash"});
1820 }
1821
1822 virtual bool connect(Backend source, std::unordered_map<std::string, const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/, std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
1823 {
1824 auto iter = requestedColumns.find (outputColumns.at(0).name);
1825 if (iter == requestedColumns.end())
1826 return false;
1827 outputColumns.at(0).enabled = true;
1828
1829 branchReader.connectTree(source);
1830
1831 if (iter->second.offsetName != outputColumns.at(1).name)
1832 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
1833
1834 requestedColumns.erase (iter);
1835
1836 iter = requestedColumns.find (outputColumns.at(1).name);
1837 if (iter == requestedColumns.end())
1838 {
1839 return true;
1840 }
1841 outputColumns.at(1).enabled = true;
1842 requestedColumns.erase (iter);
1843
1844 iter = requestedColumns.find (outputColumns.at(2).name);
1845 if (iter != requestedColumns.end())
1846 {
1847 outputColumns.at(2).enabled = true;
1848 requestedColumns.erase (iter);
1849 }
1850 return true;
1851 }
1852
1853 virtual void clearColumns () override
1854 {
1855 columnData.clear();
1856 offsets.clear();
1857 offsets.push_back (0);
1858 columnHashData.clear();
1859 }
1860
1861 virtual void getEntry (Long64_t entry) override
1862 {
1863 benchmark.startTimer ();
1864 const auto& branchData = branchReader.getEntry (entry);
1865 benchmark.stopTimer ();
1866 benchmarkUnpack.startTimer ();
1867 for (auto& data : branchData)
1868 {
1869 columnData.insert (columnData.end(), data.begin(), data.end());
1870 offsets.push_back (columnData.size());
1871 columnHashData.push_back (std::hash<std::string> () (data));
1872 }
1873 benchmarkUnpack.stopTimer ();
1874 }
1875
1876 virtual void setData (ColumnVectorData& colData) override
1877 {
1878 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
1879 colData.setColumn (outputColumns.at(0).columnIndex, columnData.size(), columnData.data());
1880 if (outputColumns.at(1).columnIndex != ColumnVectorHeader::nullIndex)
1881 colData.setColumn (outputColumns.at(1).columnIndex, offsets.size(), offsets.data());
1882 if (outputColumns.at(2).columnIndex != ColumnVectorHeader::nullIndex)
1883 colData.setColumn (outputColumns.at(2).columnIndex, columnHashData.size(), columnHashData.data());
1884 }
1885
1886 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
1887 {
1888 BranchPerfData result;
1889 result.name = branchReader.columnName();
1890 result.timeRead = benchmark.getEntryTime(emptyTime);
1891 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
1892 benchmark.setSilence();
1893 benchmarkUnpack.setSilence();
1894 result.entrySize = branchReader.entrySize();
1895 result.uncompressedSize = branchReader.uncompressedSize();
1896 result.numBaskets = branchReader.numBaskets();
1897 return result;
1898 }
1899
1900 virtual void collectColumnData () override
1901 {}
1902 };
1903
1904 template <template <typename> class Reader>
1906 {
1907 std::vector<std::string> termNames;
1908 const std::vector<ColumnarOffsetType>* offsetColumns = nullptr;
1909 std::vector<ColumnarOffsetType> offsets = {0};
1910 std::vector<ColumnarOffsetType> namesOffsets = {0};
1911 std::vector<char> namesData;
1912 std::vector<std::size_t> namesHash;
1913
1914 ColumnDataOutputMet (const std::string& val_columnName, std::vector<std::string> val_termNames)
1915 : termNames (std::move (val_termNames))
1916 {
1917 outputColumns.push_back ({.name = val_columnName, .isOffset = true});
1918 outputColumns.push_back ({.name = val_columnName + ".name.data"});
1919 outputColumns.push_back ({.name = val_columnName + ".name.offset", .isOffset = true});
1920 outputColumns.push_back ({.name = val_columnName + ".nameHash"});
1921 }
1922
1923 virtual bool connect([[maybe_unused]]Backend source, std::unordered_map<std::string, const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
1924 {
1925 if (auto iter = requestedColumns.find (outputColumns.at(0).name);
1926 iter != requestedColumns.end())
1927 requestedColumns.erase (iter);
1928 else
1929 return false;
1930 outputColumns.at(0).enabled = true;
1931
1932 if (auto iter = requestedColumns.find (outputColumns.at(1).name);
1933 iter != requestedColumns.end())
1934 {
1935 outputColumns.at(1).enabled = true;
1936 requestedColumns.erase (iter);
1937 }
1938
1939 if (auto iter = requestedColumns.find (outputColumns.at(2).name);
1940 iter != requestedColumns.end())
1941 {
1942 outputColumns.at(2).enabled = true;
1943 requestedColumns.erase (iter);
1944 }
1945
1946 if (auto iter = requestedColumns.find (outputColumns.at(3).name);
1947 iter != requestedColumns.end())
1948 {
1949 outputColumns.at(3).enabled = true;
1950 requestedColumns.erase (iter);
1951 }
1952
1953 // For multi-tool support, skip if offset column already registered
1954 if (auto offsetIter = offsetColumns.find (outputColumns.at(0).name); offsetIter == offsetColumns.end())
1955 offsetColumns.emplace (outputColumns.at(0).name, &offsets);
1956
1957 return true;
1958 }
1959
1960 virtual void clearColumns () override
1961 {
1962 offsets.clear ();
1963 offsets.push_back (0);
1964 namesData.clear ();
1965 namesOffsets.clear ();
1966 namesOffsets.push_back (0);
1967 namesHash.clear ();
1968 }
1969
1970 virtual void getEntry (Long64_t /*entry*/) override
1971 {
1972 for (const auto& termName : termNames)
1973 {
1974 namesData.insert (namesData.end(), termName.begin(), termName.end());
1975 namesOffsets.push_back (namesData.size());
1976 namesHash.push_back (std::hash<std::string> () (termName));
1977 }
1978 offsets.push_back (namesHash.size());
1979 }
1980
1981 virtual void setData (ColumnVectorData& colData) override
1982 {
1983 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
1984 colData.setColumn (outputColumns.at(0).columnIndex, offsets.size(), offsets.data());
1985 if (outputColumns.at(1).columnIndex != ColumnVectorHeader::nullIndex)
1986 colData.setColumn (outputColumns.at(1).columnIndex, namesData.size(), namesData.data());
1987 if (outputColumns.at(2).columnIndex != ColumnVectorHeader::nullIndex)
1988 colData.setColumn (outputColumns.at(2).columnIndex, namesOffsets.size(), namesOffsets.data());
1989 if (outputColumns.at(3).columnIndex != ColumnVectorHeader::nullIndex)
1990 colData.setColumn (outputColumns.at(3).columnIndex, namesHash.size(), namesHash.data());
1991 }
1992
1993 [[nodiscard]] virtual BranchPerfData getPerfData (float /*emptyTime*/) override
1994 {
1995 BranchPerfData result;
1996 result.name = outputColumns.at(0).name + "(met-out)";
1997 return result;
1998 }
1999
2000 virtual void collectColumnData () override
2001 {}
2002 };
2003
2004 template <template <typename> class Reader>
2006 {
2007 Reader<xAOD::CaloClusterContainer> branchReader;
2008 std::vector<ColumnarOffsetType> offsets = {0};
2009 std::vector<std::uint32_t> columnData;
2012 unsigned entries = 0;
2013
2014 ColumnDataSamplingPattern (const std::string& val_branchName)
2015 : branchReader (val_branchName), benchmarkUnpack (branchReader.columnName()+".samplingPattern(fallback)(unpack)"), benchmark (branchReader.columnName() + ".samplingPattern(fallback)")
2016 {
2017 outputColumns.push_back ({.name = branchReader.columnName() + ".samplingPattern"});
2018 outputColumns.push_back ({.name = branchReader.columnName(), .isOffset = true, .primary = false});
2019 }
2020
2021 virtual bool connect(Backend source, std::unordered_map<std::string,const std::vector<ColumnarOffsetType>*>& /*offsetColumns*/, std::unordered_map<std::string, ColumnInfo>& requestedColumns) override
2022 {
2023 auto iter = requestedColumns.find (outputColumns.at(0).name);
2024 if (iter == requestedColumns.end())
2025 return false;
2026 outputColumns.at(0).enabled = true;
2027
2028 branchReader.connectTree(source);
2029 if (iter->second.offsetName != outputColumns.at(1).name)
2030 throw std::runtime_error ("offset name mismatch: " + iter->second.offsetName + " != " + outputColumns.at(1).name);
2031
2032 requestedColumns.erase (iter);
2033
2034 iter = requestedColumns.find (outputColumns.at(1).name);
2035 if (iter == requestedColumns.end())
2036 {
2037 return true;
2038 }
2039 outputColumns.at(1).enabled = true;
2040 requestedColumns.erase (iter);
2041 return true;
2042 }
2043
2044 virtual void clearColumns () override
2045 {
2046 columnData.clear();
2047 offsets.clear();
2048 offsets.push_back (0);
2049 }
2050
2051 virtual void getEntry (Long64_t entry) override
2052 {
2053 benchmark.startTimer ();
2054 const auto& branchData = branchReader.getEntry (entry);
2055 benchmark.stopTimer ();
2056 benchmarkUnpack.startTimer ();
2057 for (auto data : branchData)
2058 {
2059 columnData.push_back (data->samplingPattern());
2060 }
2061 offsets.push_back (columnData.size());
2062 benchmarkUnpack.stopTimer ();
2063 }
2064
2065 virtual void setData (ColumnVectorData& colData) override
2066 {
2067 if (outputColumns.at(0).columnIndex != ColumnVectorHeader::nullIndex)
2068 colData.setColumn (outputColumns.at(0).columnIndex, columnData.size(), columnData.data());
2069 if (outputColumns.at(1).columnIndex != ColumnVectorHeader::nullIndex)
2070 colData.setColumn (outputColumns.at(1).columnIndex, offsets.size(), offsets.data());
2071 }
2072
2073 [[nodiscard]] virtual BranchPerfData getPerfData (float emptyTime) override
2074 {
2075 BranchPerfData result;
2076 result.name = branchReader.columnName() + "(fallback)";
2077 result.timeRead = benchmark.getEntryTime(emptyTime);
2078 result.timeUnpack = benchmarkUnpack.getEntryTime(emptyTime);
2079 benchmark.setSilence();
2080 benchmarkUnpack.setSilence();
2081 result.entrySize = branchReader.entrySize();
2082 result.uncompressedSize = branchReader.uncompressedSize();
2083 result.numBaskets = branchReader.numBaskets();
2084 result.entries = entries;
2085 return result;
2086 }
2087
2088 virtual void collectColumnData () override
2089 {
2090 entries += columnData.size();
2091 }
2092 };
2093
2094 namespace
2095 {
2097 struct ToolData
2098 {
2099 std::string name;
2100 ColumnarTool<ColumnarModeArray>* tool = nullptr;
2101 std::unique_ptr<ToolColumnVectorMap> toolWrapper;
2102 bool noRepeatCall = false;
2103 bool runToolTwice = false;
2104
2105 Benchmark benchmarkCall;
2106 Benchmark benchmarkCall2;
2107
2108 ToolData (const UserConfiguration& config, const TestDefinition& td,
2109 ColumnVectorHeader& columnHeader)
2110 : name (td.name)
2111 , noRepeatCall (td.noRepeatCall)
2112 , runToolTwice (config.runToolTwice)
2113 , benchmarkCall ("", config.batchSize)
2114 , benchmarkCall2 ("", config.batchSize)
2115 {
2116 tool = dynamic_cast<ColumnarTool<ColumnarModeArray>*>(td.tool);
2117 if (!tool)
2118 throw std::runtime_error ("tool is not a ColumnarTool<ColumnarModeArray>: " + td.name);
2119 if (!td.containerRenames.empty())
2121 toolWrapper = std::make_unique<ToolColumnVectorMap> (columnHeader, *tool);
2122 }
2123
2125 void call (ColumnVectorData& columnData)
2126 {
2127 benchmarkCall.startTimer ();
2128 columnData.callNoCheck (*tool);
2129 benchmarkCall.stopTimer ();
2130 if (runToolTwice && !noRepeatCall)
2131 {
2132 benchmarkCall2.startTimer ();
2133 columnData.callNoCheck (*tool);
2134 benchmarkCall2.stopTimer ();
2135 }
2136 }
2137 };
2138 }
2139 }
2140
2141
2142
2143
2144 ColumnarPhysLiteTest ::
2145 ColumnarPhysLiteTest ()
2146 {
2147 static std::once_flag flag;
2148 std::call_once (flag, [] ()
2149 {
2150#ifdef XAOD_STANDALONE
2151 xAOD::Init().ignore();
2152#else
2153 POOL::Init();
2154#endif
2155 });
2156
2157 auto userConfiguration = TestUtils::UserConfiguration::fromEnvironment();
2158 if (userConfiguration.isrntuple)
2159 {
2160 auto* fileName = getenv("ASG_TEST_FILE_RNTUPLE_LITE_MC");
2161 if (fileName == nullptr)
2162 throw std::runtime_error("missing ASG_TEST_FILE_RNTUPLE_LITE_MC");
2163 rntreader = ROOT::RNTupleReader::Open("EventData", fileName);
2164 inspector = ROOT::Experimental::RNTupleInspector::Create("EventData", fileName);
2166 if (!rntreader or !inspector)
2167 throw std::runtime_error("failed to open rntuple");
2168 } else
2169 {
2170 auto* fileName = getenv("ASG_TEST_FILE_LITE_MC");
2171 if (fileName == nullptr)
2172 throw std::runtime_error("missing ASG_TEST_FILE_LITE_MC");
2173 file.reset(TFile::Open(fileName, "READ"));
2174 if (!file)
2175 throw std::runtime_error("failed to open file");
2176 tree = dynamic_cast<TTree*>(file->Get("CollectionTree"));
2177 if (!tree)
2178 throw std::runtime_error("failed to open rntuple");
2179 }
2180 }
2181
2182 ColumnarPhysLiteTest ::~ColumnarPhysLiteTest()
2183 {
2184 if (rntbackend)
2185 delete rntbackend;
2186 }
2187
2188 std::string ColumnarPhysLiteTest :: makeUniqueName ()
2189 {
2190 static std::atomic<unsigned> index = 0;
2191 return "UniquePhysliteTestTool" + std::to_string(++index);
2192 }
2193
2194 bool ColumnarPhysLiteTest ::
2195 checkMode ()
2196 {
2197 return true;
2198 }
2199
2200 void ColumnarPhysLiteTest :: setupKnownColumns (std::span<const TestDefinition> testDefinitions)
2201 {
2202 using namespace TestUtils;
2203
2204 knownColumns.push_back (std::make_shared<ColumnDataEventCount> ());
2205
2206 if (tree)
2207 {
2208 tree->SetMakeClass(1);
2209 {
2210 std::unordered_map<std::string, TBranch*> branches;
2211 {
2212 TIter branchIter(tree->GetListOfBranches());
2213 TObject* obj = nullptr;
2214 while ((obj = branchIter()))
2215 {
2216 TBranch* branch = nullptr;
2217 if ((branch = dynamic_cast<TBranch*>(obj)))
2218 {
2219 branches.emplace(branch->GetName(), branch);
2220 TIter subBranchIter(branch->GetListOfBranches());
2221 while ((obj = subBranchIter()))
2222 {
2223 if (auto subBranch = dynamic_cast<TBranch*>(obj))
2224 branches.emplace(subBranch->GetName(), subBranch);
2225 }
2226 }
2227 }
2228 }
2229
2230 for (const auto& [name, branch] : branches)
2231 {
2232 if (name.find("AuxDyn.") != std::string::npos ||
2233 name.find("Aux.") != std::string::npos)
2234 {
2235 TClass* branchClass = nullptr;
2236 EDataType branchType{};
2237 branch->GetExpectedType(branchClass, branchType);
2238 if (branchClass == nullptr)
2239 {
2240 switch (branchType)
2241 {
2242 case kInt_t:
2243 knownColumns.push_back(std::make_shared<ColumnDataScalar<std::int32_t, BranchReader>>(branch->GetName()));
2244 break;
2245 case kUInt_t:
2246 knownColumns.push_back(std::make_shared<ColumnDataScalar<std::uint32_t, BranchReader>>(branch->GetName()));
2247 break;
2248 case kULong_t:
2249 knownColumns.push_back(std::make_shared<ColumnDataScalar<std::uint64_t, BranchReader>>(branch->GetName()));
2250 break;
2251 case kULong64_t:
2252 knownColumns.push_back(std::make_shared<ColumnDataScalar<std::uint64_t, BranchReader>>(branch->GetName()));
2253 break;
2254 case kFloat_t:
2255 knownColumns.push_back(std::make_shared<ColumnDataScalar<float, BranchReader>>(branch->GetName()));
2256 break;
2257 default:
2258 // no-op
2259 break;
2260 }
2261 } else
2262 {
2263 if (*branchClass->GetTypeInfo() == typeid(std::vector<float>))
2264 {
2265 knownColumns.push_back (std::make_shared<ColumnDataVector<float,BranchReader>> (branch->GetName()));
2266 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<char>))
2267 {
2268 knownColumns.push_back (std::make_shared<ColumnDataVector<char,BranchReader>> (branch->GetName()));
2269 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::int8_t>))
2270 {
2271 knownColumns.push_back (std::make_shared<ColumnDataVector<std::int8_t,BranchReader>> (branch->GetName()));
2272 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::uint8_t>))
2273 {
2274 knownColumns.push_back (std::make_shared<ColumnDataVector<std::uint8_t,BranchReader>> (branch->GetName()));
2275 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::int16_t>))
2276 {
2277 knownColumns.push_back (std::make_shared<ColumnDataVector<std::int16_t,BranchReader>> (branch->GetName()));
2278 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::uint16_t>))
2279 {
2280 knownColumns.push_back (std::make_shared<ColumnDataVector<std::uint16_t,BranchReader>> (branch->GetName()));
2281 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::int32_t>))
2282 {
2283 knownColumns.push_back (std::make_shared<ColumnDataVector<std::int32_t,BranchReader>> (branch->GetName()));
2284 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::uint32_t>))
2285 {
2286 knownColumns.push_back (std::make_shared<ColumnDataVector<std::uint32_t,BranchReader>> (branch->GetName()));
2287 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::int64_t>))
2288 {
2289 knownColumns.push_back (std::make_shared<ColumnDataVector<std::int64_t,BranchReader>> (branch->GetName()));
2290 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::uint64_t>))
2291 {
2292 knownColumns.push_back (std::make_shared<ColumnDataVector<std::uint64_t,BranchReader>> (branch->GetName()));
2293 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::vector<float>>))
2294 {
2295 knownColumns.push_back (std::make_shared<ColumnDataVectorVector<float,BranchReader>> (branch->GetName()));
2296 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::vector<std::int32_t>>))
2297 {
2298 knownColumns.push_back (std::make_shared<ColumnDataVectorVector<std::int32_t,BranchReader>> (branch->GetName()));
2299 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::vector<std::uint64_t>>))
2300 {
2301 knownColumns.push_back (std::make_shared<ColumnDataVectorVector<std::uint64_t,BranchReader>> (branch->GetName()));
2302 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::vector<std::vector<std::size_t>>>))
2303 {
2304 knownColumns.push_back (std::make_shared<ColumnDataVectorVectorVector<std::size_t,BranchReader>> (branch->GetName()));
2305 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::vector<std::vector<unsigned char>>>))
2306 {
2307 knownColumns.push_back (std::make_shared<ColumnDataVectorVectorVector<unsigned char,BranchReader>> (branch->GetName()));
2308 } else if (*branchClass->GetTypeInfo() == typeid(std::vector<std::string>))
2309 {
2310 knownColumns.push_back (std::make_shared<ColumnDataMetNames<BranchReader>> (branch->GetName()));
2311 }
2312 }
2313 }
2314 }
2315 }
2316 // This is a fallback for the case that we don't have an explicit
2317 // `samplingPattern` branch in our input file (i.e. an older file),
2318 // to allow us to still test tools needing it. This is likely not
2319 // something that actual users can do (they need the new files), but
2320 // for testing it seems like a reasonable workaround.
2321 knownColumns.push_back(std::make_shared<ColumnDataSamplingPattern<BranchReader>>("egammaClusters"));
2322
2323 // For branches that are element links they need to be explicitly
2324 // declared to have the correct xAOD type, correct split setting,
2325 // and correct linked containers.
2326
2327 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorLink<xAOD::CaloClusterContainer,BranchReader>>("AnalysisElectronsAuxDyn.caloClusterLinks"));
2328 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorLink<xAOD::TrackParticleContainer, BranchReader>>("AnalysisElectronsAuxDyn.trackParticleLinks"));
2329 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorLink<xAOD::CaloClusterContainer,BranchReader>>("AnalysisPhotonsAuxDyn.caloClusterLinks"));
2330 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorLink<xAOD::VertexContainer, BranchReader>>("AnalysisPhotonsAuxDyn.vertexLinks"));
2331 knownColumns.push_back(std::make_shared<ColumnDataVectorSplitLink<xAOD::TrackParticleContainer>>("AnalysisMuonsAuxDyn.inDetTrackParticleLink"));
2332 knownColumns.push_back(std::make_shared<ColumnDataVectorSplitLink<xAOD::TrackParticleContainer>>("AnalysisMuonsAuxDyn.combinedTrackParticleLink"));
2333 knownColumns.push_back(std::make_shared<ColumnDataVectorSplitLink<xAOD::TrackParticleContainer>>("AnalysisMuonsAuxDyn.extrapolatedMuonSpectrometerTrackParticleLink"));
2334 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorLink<xAOD::TrackParticleContainer, BranchReader>>("GSFConversionVerticesAuxDyn.trackParticleLinks"));
2335 knownColumns.push_back(std::make_shared<ColumnDataVectorSplitLink<xAOD::TrackParticleContainer>>("GSFTrackParticlesAuxDyn.originalTrackParticle"));
2336 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorVariantLink<xAOD::IParticleContainer, BranchReader>>("AnalysisJetsAuxDyn.GhostTrack"));
2337 knownColumns.push_back(std::make_shared<ColumnDataVectorLink<xAOD::JetContainer, BranchReader>>("METAssoc_AnalysisMETAux.jetLink"));
2338 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorVariantLink<xAOD::IParticleContainer, BranchReader>>("METAssoc_AnalysisMETAux.objectLinks"));
2339
2340 }else if (rntbackend)
2341 {
2342 std::unordered_map<std::string, ROOT::DescriptorId_t> fields;
2343 {
2344 const auto& desc = rntreader->GetDescriptor();
2345
2346 for (const auto& field : desc.GetTopLevelFields())
2347 {
2348 fields.emplace(desc.GetQualifiedFieldName(field.GetId()), field.GetId());
2349
2350 std::vector<ROOT::DescriptorId_t> subFieldIds{field.GetId()};
2351 while (!subFieldIds.empty())
2352 {
2353 const auto parentId = subFieldIds.back();
2354 auto parentname=desc.GetQualifiedFieldName(parentId);
2355 subFieldIds.pop_back();
2356
2357 for (const auto& subField : desc.GetFieldIterable(parentId))
2358 {
2359 auto subFieldName = desc.GetQualifiedFieldName(subField.GetId());
2360
2361 fields.emplace(desc.GetQualifiedFieldName(subField.GetId()), subField.GetId());
2362
2363 subFieldIds.push_back(subField.GetId());
2364 }
2365 }
2366 }
2367 }
2368
2369 const auto& desc = rntreader->GetDescriptor();
2370 for (const auto& [name, fieldId] : fields)
2371 {
2372 auto fieldName = desc.GetQualifiedFieldName(fieldId);
2373
2374 if (name.find("AuxDyn:") != std::string::npos ||
2375 name.find("Aux:") != std::string::npos)
2376 {
2377
2378 const auto& fieldDesc = desc.GetFieldDescriptor(fieldId);
2379 const std::string typeName = desc.GetTypeNameForComparison(fieldDesc);
2380 if (typeName == "std::int32_t" || typeName == "int")
2381 {
2382 knownColumns.push_back(std::make_shared<ColumnDataScalar<std::int32_t, RNTFieldReader>>(name));
2383 } else if (typeName == "std::uint32_t" || typeName == "unsigned int")
2384 {
2385 knownColumns.push_back(std::make_shared<ColumnDataScalar<std::uint32_t, RNTFieldReader>>(name));
2386 } else if (typeName == "std::uint64_t" || typeName == "unsigned long" || typeName == "unsigned long long")
2387 {
2388 knownColumns.push_back(std::make_shared<ColumnDataScalar<std::uint64_t, RNTFieldReader>>(name));
2389 } else if (typeName == "float")
2390 {
2391 knownColumns.push_back(std::make_shared<ColumnDataScalar<float, RNTFieldReader>>(name));
2392 } else if (typeName == "std::vector<float>")
2393 {
2394 knownColumns.push_back(std::make_shared<ColumnDataVector<float, RNTFieldReader>>(name));
2395 } else if (typeName == "std::vector<char>")
2396 {
2397 knownColumns.push_back(std::make_shared<ColumnDataVector<char, RNTFieldReader>>(name));
2398 } else if (typeName == "std::vector<std::int8_t>")
2399 {
2400 knownColumns.push_back(std::make_shared<ColumnDataVector<std::int8_t, RNTFieldReader>>(name));
2401 } else if (typeName == "std::vector<std::uint8_t>")
2402 {
2403 knownColumns.push_back(std::make_shared<ColumnDataVector<std::uint8_t, RNTFieldReader>>(name));
2404 } else if (typeName == "std::vector<std::int16_t>")
2405 {
2406 knownColumns.push_back(std::make_shared<ColumnDataVector<std::int16_t, RNTFieldReader>>(name));
2407 } else if (typeName == "std::vector<std::uint16_t>")
2408 {
2409 knownColumns.push_back(std::make_shared<ColumnDataVector<std::uint16_t, RNTFieldReader>>(name));
2410 } else if (typeName == "std::vector<std::int32_t>")
2411 {
2412 knownColumns.push_back(std::make_shared<ColumnDataVector<std::int32_t, RNTFieldReader>>(name));
2413 } else if (typeName == "std::vector<std::uint32_t>")
2414 {
2415 knownColumns.push_back(std::make_shared<ColumnDataVector<std::uint32_t, RNTFieldReader>>(name));
2416 } else if (typeName == "std::vector<std::int64_t>")
2417 {
2418 knownColumns.push_back(std::make_shared<ColumnDataVector<std::int64_t, RNTFieldReader>>(name));
2419 } else if (typeName == "std::vector<std::uint64_t>")
2420 {
2421 knownColumns.push_back(std::make_shared<ColumnDataVector<std::uint64_t, RNTFieldReader>>(name));
2422 } else if (typeName == "std::vector<std::vector<float>>")
2423 {
2424 knownColumns.push_back(std::make_shared<ColumnDataVectorVector<float, RNTFieldReader>>(name));
2425 } else if (typeName == "std::vector<std::vector<std::int32_t>>")
2426 {
2427 knownColumns.push_back(std::make_shared<ColumnDataVectorVector<std::int32_t, RNTFieldReader>>(name));
2428 } else if (typeName == "std::vector<std::vector<std::uint64_t>>")
2429 {
2431 } else if (typeName =="std::vector<std::vector<std::vector<std::size_t>>>")
2432 {
2434 }else if (typeName =="std::vector<std::vector<std::vector<std::uint64_t>>>")
2435 {
2437 }else if (typeName =="std::vector<std::vector<std::vector<std::uint8_t>>>")
2438 {
2440 } else if (typeName =="std::vector<std::vector<std::vector<unsigned char>>>")
2441 {
2443 } else if (typeName == "std::vector<std::string>")
2444 {
2445 knownColumns.push_back(std::make_shared<ColumnDataMetNames<RNTFieldReader>>(name));
2446 }
2447 }
2448 }
2449 knownColumns.push_back(std::make_shared<ColumnDataSamplingPattern<RNTFieldReader>>("egammaClusters"));
2450
2451 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorLink<xAOD::CaloClusterContainer,RNTFieldReader>>("AnalysisElectronsAuxDyn:caloClusterLinks"));
2452 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorLink<xAOD::TrackParticleContainer, RNTFieldReader>>("AnalysisElectronsAuxDyn:trackParticleLinks"));
2453 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorLink<xAOD::CaloClusterContainer,RNTFieldReader>>("AnalysisPhotonsAuxDyn:caloClusterLinks"));
2454 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorLink<xAOD::VertexContainer, RNTFieldReader>>("AnalysisPhotonsAuxDyn:vertexLinks"));
2455 knownColumns.push_back(std::make_shared<ColumnDataVectorRLink<xAOD::TrackParticleContainer,RNTFieldReader>>("AnalysisMuonsAuxDyn:inDetTrackParticleLink"));
2456 knownColumns.push_back(std::make_shared<ColumnDataVectorRLink<xAOD::TrackParticleContainer,RNTFieldReader>>("AnalysisMuonsAuxDyn:combinedTrackParticleLink"));
2457 knownColumns.push_back(std::make_shared<ColumnDataVectorRLink< xAOD::TrackParticleContainer, RNTFieldReader>>("AnalysisMuonsAuxDyn:extrapolatedMuonSpectrometerTrackParticleLink"));
2458 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorLink<xAOD::TrackParticleContainer, RNTFieldReader>>("GSFConversionVerticesAuxDyn:trackParticleLinks"));
2459 knownColumns.push_back(std::make_shared<ColumnDataVectorRLink<xAOD::TrackParticleContainer,RNTFieldReader>>("GSFTrackParticlesAuxDyn:originalTrackParticle"));
2460 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorVariantLink<xAOD::IParticleContainer, RNTFieldReader>>("AnalysisJetsAuxDyn:GhostTrack"));
2461 knownColumns.push_back(std::make_shared<ColumnDataVectorLink<xAOD::JetContainer, RNTFieldReader>>("METAssoc_AnalysisMETAux:.jetLink"));
2462 knownColumns.push_back(std::make_shared<ColumnDataVectorVectorVariantLink<xAOD::IParticleContainer, RNTFieldReader>>("METAssoc_AnalysisMETAux:.objectLinks"));
2463
2464 }
2465
2466
2467 // For METMaker we need to preplace all of the MET terms that we
2468 // expect to be used, that's what this line does.
2469 std::vector<std::string> allMetTermNames;
2470 for (const auto& td : testDefinitions)
2471 {
2472 for (const auto& name : td.metTermNames)
2473 {
2474 if (std::find (allMetTermNames.begin(), allMetTermNames.end(), name) == allMetTermNames.end())
2475 allMetTermNames.push_back (name);
2476 }
2477 }
2478
2479
2480 if (tree)
2481 {
2482 if (!allMetTermNames.empty())
2483 knownColumns.push_back(std::make_shared<ColumnDataOutputMet<BranchReader>>("OutputMET",allMetTermNames));
2484
2485 // For METMaker we need various extra columns to run. This may need
2486 // some work to avoid, but would likey be worth it.
2487 knownColumns.push_back(std::make_shared<ColumnDataOutVector<std::uint16_t, BranchReader>>("AnalysisMuons.objectType", xAOD::Type::Muon));
2488 knownColumns.push_back(std::make_shared<ColumnDataOutVector<float, BranchReader>>("AnalysisMuons.m", ParticleConstants::muonMassInMeV));
2489 knownColumns.push_back(std::make_shared<ColumnDataOutVector<std::uint16_t, BranchReader>>("AnalysisJets.objectType", xAOD::Type::Jet));
2490
2491 // These are columns that represent variables that are normally held
2492 // by METAssociationHelper, or alternatively are decorated on the
2493 // MET terms (even though they are per object).
2494 knownColumns.push_back(std::make_shared<ColumnDataOutVector<float, BranchReader>>("AnalysisMuons.MetObjectWeight", 0));
2495 knownColumns.push_back(std::make_shared<ColumnDataOutVector<float, BranchReader>>("AnalysisJets.MetObjectWeight", 0));
2496 knownColumns.push_back(std::make_shared<ColumnDataOutVector<float, BranchReader>>("AnalysisJets.MetObjectWeightSoft", 0));
2497 knownColumns.push_back(std::make_shared<ColumnDataOutVector<MissingETBase::Types::bitmask_t,BranchReader>>("METAssoc_AnalysisMET.useObjectFlags", 0));
2498 } else if (rntbackend)
2499 {
2500 if (!allMetTermNames.empty())
2501 knownColumns.push_back(std::make_shared<ColumnDataOutputMet<BranchReader>>("OutputMET",allMetTermNames));
2502
2503 // For METMaker we need various extra columns to run. This may need
2504 // some work to avoid, but would likey be worth it.
2505 knownColumns.push_back(std::make_shared<ColumnDataOutVector<std::uint16_t, RNTFieldReader>>("AnalysisMuons.objectType", xAOD::Type::Muon));
2506 knownColumns.push_back(std::make_shared<ColumnDataOutVector<float, RNTFieldReader>>("AnalysisMuons.m", ParticleConstants::muonMassInMeV));
2507 knownColumns.push_back(std::make_shared<ColumnDataOutVector<std::uint16_t, RNTFieldReader>>("AnalysisJets.objectType", xAOD::Type::Jet));
2508
2509 // These are columns that represent variables that are normally held
2510 // by METAssociationHelper, or alternatively are decorated on the
2511 // MET terms (even though they are per object).
2512 knownColumns.push_back(std::make_shared<ColumnDataOutVector<float, RNTFieldReader>>("AnalysisMuons.MetObjectWeight", 0));
2513 knownColumns.push_back(std::make_shared<ColumnDataOutVector<float, RNTFieldReader>>("AnalysisJets.MetObjectWeight", 0));
2514 knownColumns.push_back(std::make_shared<ColumnDataOutVector<float, RNTFieldReader>>("AnalysisJets.MetObjectWeightSoft", 0));
2515 knownColumns.push_back(std::make_shared<ColumnDataOutVector<MissingETBase::Types::bitmask_t,RNTFieldReader>>("METAssoc_AnalysisMET.useObjectFlags", 0));
2516 }
2517 } // namespace columnar
2518
2519 void ColumnarPhysLiteTest :: setupColumns (const ColumnVectorHeader& columnHeader)
2520 {
2521 using namespace asg::msgUserCode;
2522
2523 // Get all column info directly from the header (all tools have already
2524 // registered their columns via ToolColumnVectorMap)
2525 auto requestedColumns = columnHeader.getAllColumnInfo();
2526
2527 // Print requested columns
2528 for (auto& [name, info] : requestedColumns)
2529 std::cout << "requested columns: " << name << std::endl;
2530
2531 for (auto& column : knownColumns)
2532 {
2533 if (tree)
2534 {
2535 if (column->connect (tree, offsetColumns, requestedColumns))
2536 usedColumns.push_back (column);
2537 } else if (rntbackend)
2538 {
2539 if (column->connect(rntbackend, offsetColumns, requestedColumns))
2540 usedColumns.push_back(column);
2541 }
2542 }
2543
2544 std::set<std::string> unclaimedColumns;
2545 for (auto& column : requestedColumns)
2546 {
2547 if (!column.second.isOptional)
2548 unclaimedColumns.insert (column.first);
2549 else
2550 std::cout << "optional column not claimed: " << column.first << std::endl;
2551 }
2552 std::erase_if (unclaimedColumns, [&] (auto& columnName)
2553 {
2554 const auto& info = requestedColumns.at (columnName);
2555 if (info.accessMode != ColumnAccessMode::output || !info.fixedDimensions.empty())
2556 return false;
2557 auto offsetIter = std::find_if (usedColumns.begin(), usedColumns.end(), [&] (const std::shared_ptr<TestUtils::IColumnData>& column)
2558 {
2559 for (auto& output : column->outputColumns)
2560 {
2561 if (output.name == info.offsetName)
2562 return true;
2563 }
2564 return false;
2565 });
2566 if (offsetIter == usedColumns.end())
2567 return false;
2568 std::shared_ptr<TestUtils::IColumnData> myColumn;
2569 if (tree)
2570 {
2571 if (*info.type == typeid(float))
2572 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<float, BranchReader>>(info.name, 0);
2573 else if (*info.type == typeid(char))
2574 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<char, BranchReader>>(info.name, 0);
2575 else if (*info.type == typeid(std::uint16_t))
2576 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<std::uint16_t, BranchReader>>(info.name, 0);
2577 else if (*info.type == typeid(std::uint64_t))
2578 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<std::uint64_t, BranchReader>>(info.name, 0);
2579 else
2580 {
2581 ANA_MSG_WARNING("unhandled column type: " << info.name << " "<< info.type->name());
2582 return false;
2583 }
2584 } else if (rntbackend)
2585 {
2586 if (*info.type == typeid(float))
2587 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<float, RNTFieldReader>>(info.name,0);
2588 else if (*info.type == typeid(char))
2589 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<char, RNTFieldReader>>(info.name, 0);
2590 else if (*info.type == typeid(std::uint16_t))
2591 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<std::uint16_t, RNTFieldReader>>(info.name, 0);
2592 else if (*info.type == typeid(std::uint64_t))
2593 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<std::uint64_t, RNTFieldReader>>(info.name, 0);
2594 else
2595 {
2596 ANA_MSG_WARNING("unhandled column type: " << info.name << " " << info.type->name());
2597 return false;
2598 }
2599 }
2600 knownColumns.push_back(myColumn);
2601 if (tree) {
2602 if (!myColumn->connect(tree, offsetColumns, requestedColumns))
2603 {
2604 ANA_MSG_WARNING("failed to connect dynamic output column: " << info.name);
2605 return false;
2606 }
2607 } else if (rntbackend)
2608 {
2609 if (!myColumn->connect(rntbackend, offsetColumns, requestedColumns))
2610 {
2611 ANA_MSG_WARNING("failed to connect dynamic output column: " << info.name);
2612 return false;
2613 }
2614 }
2615 usedColumns.push_back(std::move(myColumn));
2616 return true;
2617 });
2618 if (!unclaimedColumns.empty())
2619 {
2620 std::string message = "columns not claimed:";
2621 for (auto& column : unclaimedColumns)
2622 message += " " + column;
2623 throw std::runtime_error(message);
2624 }
2625 }
2626
2627 void ColumnarPhysLiteTest :: doCall (const TestDefinition& testDefinition)
2628 {
2629 doCallMulti ({testDefinition});
2630 }
2631
2632
2633void ColumnarPhysLiteTest ::doCallMulti(
2634 const std::vector<TestDefinition>& testDefinitions) {
2635 using namespace asg::msgUserCode;
2636 auto userConfiguration = TestUtils::UserConfiguration::fromEnvironment();
2637
2638 // apply systematics for all test definitions
2639 for (const auto& td : testDefinitions) {
2640 if (!td.sysName.empty()) {
2641 auto* sysTool = dynamic_cast<CP::ISystematicsTool*>(td.tool);
2642 if (!sysTool)
2643 throw std::runtime_error("tool does not support systematics");
2644 std::cout << "applying systematic variation: " << td.sysName << std::endl;
2645 if (sysTool->applySystematicVariation(CP::SystematicSet(td.sysName))
2646 .isFailure())
2647 throw std::runtime_error("failed to apply systematic variation: " +
2648 td.sysName);
2649 }
2650 }
2651
2652 if constexpr (std::is_same_v<columnar::ColumnarMode,columnar::ColumnarModeArray>) {
2653 // Create shared column header for all tools
2654 ColumnVectorHeader columnHeader;
2655
2656 // Build vector of ToolData from all testDefinitions
2657 std::vector<TestUtils::ToolData> toolDataVec;
2658 for (const auto& td : testDefinitions)
2659 toolDataVec.emplace_back(userConfiguration, td, columnHeader);
2660
2661 setupKnownColumns(testDefinitions);
2662 // Set up columns using the shared header (all tools have already
2663 // registered their columns via ToolColumnVectorMap, so we get all columns
2664 // from the header)
2665 setupColumns(columnHeader);
2666
2667 // connect column indices from header to each column for direct setting
2668 for (auto& column : usedColumns)
2669 column->connectColumnIndices(columnHeader);
2670
2671 Benchmark benchmarkEmpty("empty");
2672 Benchmark benchmarkCheck("", userConfiguration.batchSize);
2673 auto numberOfEvents = 0;
2674 if (tree) {
2675 numberOfEvents = tree->GetEntries();
2676 } else if (rntbackend) {
2677 numberOfEvents = rntreader->GetNEntries();
2678 }
2679 Long64_t entry = 0;
2680 const auto startTime = std::chrono::high_resolution_clock::now();
2681 bool endLoop = false;
2682 for (; !endLoop; ++entry) {
2683 // just sample how much overhead there is for starting and
2684 // stopping the timer
2685 benchmarkEmpty.startTimer();
2686 benchmarkEmpty.stopTimer();
2687 ColumnVectorData columnData(&columnHeader);
2688 for (auto& column : usedColumns)
2689 column->getEntry(entry % numberOfEvents);
2690 if ((entry + 1) % userConfiguration.batchSize == 0) {
2691 if (entry < numberOfEvents) {
2692 for (auto& column : usedColumns)
2693 column->collectColumnData();
2694 }
2695 for (auto& column : usedColumns)
2696 column->setData(columnData);
2697
2698 // Check data once (shared column data)
2699 benchmarkCheck.startTimer();
2700 columnData.checkData();
2701 benchmarkCheck.stopTimer();
2702 // Call each tool
2703 for (auto& toolData : toolDataVec) {
2704 toolData.call(columnData);
2705 }
2706 for (auto& column : usedColumns)
2707 column->clearColumns();
2708 if ((std::chrono::high_resolution_clock::now() - startTime) >
2709 userConfiguration.targetTime)
2710 endLoop = true;
2711 } else if (entry + 1 == numberOfEvents) {
2712 for (auto& column : usedColumns)
2713 column->collectColumnData();
2714 }
2715 }
2716 std::cout << "Entries in file: " << numberOfEvents << std::endl;
2717 std::cout << "Total entries read: " << entry << std::endl;
2718 const float emptyTime = benchmarkEmpty.getEntryTime(0).value();
2719 std::cout << "Empty benchmark time: " << emptyTime << "ns (tick=" << Benchmark::getTickDuration() << "ns)" << std::endl;
2720 benchmarkEmpty.setSilence();
2721 const auto checkTime = benchmarkCheck.getEntryTime(emptyTime);
2722 if (checkTime)
2723 std::cout << "Check data time: " << checkTime.value() << "ns" << std::endl;
2724 benchmarkCheck.setSilence();
2725 {
2726 std::vector<TestUtils::BranchPerfData> branchPerfData;
2728 summary.name = "total";
2729 summary.timeRead = 0;
2730 summary.timeUnpack = 0;
2731 summary.timeShallowCopy = 0;
2732 summary.entrySize = 0;
2733 summary.uncompressedSize = 0;
2734 summary.numBaskets = 0;
2735 summary.entries = std::nullopt;
2736 summary.nullEntries = std::nullopt;
2737 for (auto& column : usedColumns)
2738 {
2739 branchPerfData.push_back (column->getPerfData (emptyTime));
2740 summary.timeRead.value() += branchPerfData.back().timeRead.value_or(0);
2741 summary.timeUnpack.value() += branchPerfData.back().timeUnpack.value_or(0);
2742 summary.entrySize.value() += branchPerfData.back().entrySize.value_or(0);
2743 summary.uncompressedSize.value() += branchPerfData.back().uncompressedSize.value_or(0);
2744 summary.numBaskets.value() += branchPerfData.back().numBaskets.value_or(0);
2745 summary.timeShallowCopy.value() += branchPerfData.back().timeShallowCopy.value_or(0);
2746 }
2747 std::sort (branchPerfData.begin(), branchPerfData.end(), [] (const auto& a, const auto& b) {return a.name < b.name;});
2748 branchPerfData.insert (branchPerfData.end(), summary);
2749 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();
2750 std::string label = userConfiguration.isrntuple ? "field name" : "branch name";
2751 std::string header = std::format ("{:{}} | read(ns) | unpack(ns) | size(B) | rate(MB/s) | compression | baskets | entries | null", label, nameWidth);
2752 std::cout << "\n" << header << std::endl;
2753 std::cout << std::string (header.size(), '-') << std::endl;
2754 for (auto& data : branchPerfData)
2755 {
2756 if (data.name == "total")
2757 std::cout << std::string (header.size(), '-') << std::endl;
2758 std::cout << std::format ("{:{}} |", data.name, nameWidth);
2759 if (data.timeRead)
2760 std::cout << std::format ("{:>9.0f} |", data.timeRead.value());
2761 else
2762 std::cout << " |";
2763 if (data.timeUnpack)
2764 std::cout << std::format ("{:>11.1f} |", data.timeUnpack.value());
2765 else
2766 std::cout << " |";
2767 if (data.entrySize)
2768 std::cout << std::format ("{:>8.1f} |", data.entrySize.value());
2769 else
2770 std::cout << " |";
2771 if (data.timeRead && data.entrySize)
2772 std::cout << std::format ("{:>11.1f} |", (data.entrySize.value() / (data.timeRead.value() * 1e-3 * 1.024 * 1.024)));
2773 else
2774 std::cout << " |";
2775 if (data.entrySize && data.uncompressedSize)
2776 std::cout << std::format ("{:>12.2f} |", float (data.uncompressedSize.value()) / data.entrySize.value());
2777 else
2778 std::cout << " |";
2779 if (data.numBaskets)
2780 std::cout << std::format ("{:>8} |", data.numBaskets.value());
2781 else
2782 std::cout << " |";
2783 if (data.entries)
2784 std::cout << std::format ("{:>8.2f} |", static_cast<float>(data.entries.value())/numberOfEvents);
2785 else
2786 std::cout << " |";
2787 if (data.nullEntries && data.entries)
2788 std::cout << std::format ("{:>4.0f}%", static_cast<float>(data.nullEntries.value()) / data.entries.value() * 100.0f);
2789 std::cout << std::endl;
2790 }
2791 }
2792 {
2793 std::vector<TestUtils::ToolPerfData> toolPerfData;
2794 for (auto& toolData : toolDataVec)
2795 {
2796 toolPerfData.emplace_back ();
2797 toolPerfData.back().name = toolData.name;
2798 toolPerfData.back().timeCall = toolData.benchmarkCall.getEntryTime (emptyTime);
2799 if (userConfiguration.runToolTwice)
2800 toolPerfData.back().timeCall2 = toolData.benchmarkCall2.getEntryTime (emptyTime);
2801 }
2802 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();
2803 std::string header = std::format ("{:{}} | call(ns) | call2(ns)", "tool name", nameWidth);
2804 std::cout << "\n" << header << std::endl;
2805 std::cout << std::string (header.size(), '-') << std::endl;
2806 for (auto& data : toolPerfData)
2807 {
2808 std::cout << std::format ("{:{}} |", data.name, nameWidth);
2809 if (data.timeCall)
2810 std::cout << std::format ("{:>9.0f} |", data.timeCall.value());
2811 else
2812 std::cout << " |";
2813 if (data.timeCall2)
2814 std::cout << std::format ("{:>10.0f}", data.timeCall2.value());
2815 else
2816 std::cout << " ";
2817 std::cout << std::endl;
2818 }
2819 // Add totals line for multiple tools
2820 if (toolPerfData.size() > 1)
2821 {
2822 std::optional<float> totalCall, totalCall2;
2823 for (const auto& data : toolPerfData)
2824 {
2825 if (data.timeCall)
2826 totalCall = totalCall.value_or (0) + data.timeCall.value();
2827 if (data.timeCall2)
2828 totalCall2 = totalCall2.value_or (0) + data.timeCall2.value();
2829 }
2830 std::cout << std::string (header.size(), '-') << std::endl;
2831 std::cout << std::format ("{:{}} |", "total", nameWidth);
2832 if (totalCall)
2833 std::cout << std::format ("{:>9.0f} |", totalCall.value());
2834 else
2835 std::cout << " |";
2836 if (totalCall2)
2837 std::cout << std::format ("{:>10.0f}", totalCall2.value());
2838 else
2839 std::cout << " ";
2840 std::cout << std::endl;
2841 }
2842 }
2843 } else if constexpr (std::is_same_v<columnar::ColumnarMode,columnar::ColumnarModeXAOD>)
2844 {
2845 TestUtils::runXaodTest (userConfiguration, testDefinitions, file.get());
2846 } else if constexpr (std::is_same_v<columnar::ColumnarMode,columnar::ColumnarModeXAODArray>)
2847 {
2848 const auto& testDefinition = testDefinitions[0];
2849 TestUtils::runXaodArrayTest (userConfiguration, testDefinition, file.get());
2850 }
2851 }
2852}
#define ANA_MSG_WARNING(xmsg,...)
Macro printing warning messages.
void checkTime()
int numberOfEvents()
static Double_t a
A number of constexpr particle constants to avoid hardcoding them directly in various places.
if(pathvar)
size_t size() const
Number of registered mappings.
Interface for all CP tools supporting systematic variations.
Class to wrap a set of SystematicVariations.
bool isDefault() const
Test to see if this link is in the default state.
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 bool connect(Backend source, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns)=0
virtual void collectColumnData()=0
std::vector< OutputColumnInfo > outputColumns
virtual void setData(ColumnVectorData &columnData)=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
std::vector< typename CM::LinkIndexType > m_columnData
const CM::LinkIndexType * data() const noexcept
void addLink(const ElementLink< T > &element, unsigned eventIndex)
std::vector< const std::vector< ColumnarOffsetType > * > m_targetOffsetColumns
void addTarget(const std::string &name, const std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::uint32_t clid=0)
std::vector< std::vector< typename CM::LinkKeyType > > m_keysColumns
void addSplitLink(std::size_t linkIndex, SG::sgkey_t linkKey, unsigned eventIndex)
std::unordered_map< SG::sgkey_t, std::unordered_set< std::size_t > > m_unknownKeysAllowedTargets
const std::vector< typename CM::LinkKeyType > & keysColumn(std::size_t index) const
std::vector< std::string > connect(const ColumnInfo &columnInfo, const std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, const std::unordered_map< std::string, ColumnInfo > &requestedColumns)
RNTFieldReader(const RNTFieldReader &)=delete
ROOT::Experimental::RNTupleInspector * m_inspector
void connectRNTuple(ROOT::RNTupleReader *reader, ROOT::Experimental::RNTupleInspector *inspector)
std::optional< float > entrySize() const
std::optional< float > uncompressedSize() const
RNTFieldReader & operator=(const RNTFieldReader &)=delete
std::unique_ptr< ROOT::RNTupleView< T > > m_view
RNTFieldReader(const std::string &val_fieldName)
std::string label(const std::string &format, int i)
Definition label.h:19
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
std::variant< TTree *, RNTupleBackend * > Backend
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 > knownSgKeys
lookup table from container name to its sgkey hash
Definition KnownSgKeys.h:32
@ output
an output column
Definition ColumnInfo.h:25
void renameContainers(IColumnarTool &tool, const std::vector< std::pair< std::string, std::string > > &renames)
rename containers in the columnar tool
const std::string eventRangeColumnName
the default name for the column containing the event range
std::size_t ColumnarOffsetType
the type used for the size and offsets in the columnar data
SG::sgkey_t computeSgKey(const std::string &name, std::uint32_t clid)
compute the StoreGate hashed key for a container
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.
@ 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:36
std::string soleLinkTargetName
for simple link columns: the name of the target container
Definition ColumnInfo.h:132
std::uint32_t soleLinkTargetClid
for simple link columns: the CLID of the target container
Definition ColumnInfo.h:146
std::string name
the name of the column
Definition ColumnInfo.h:43
std::size_t LinkIndexType
the type used for columns that represent element links
static LinkIndexType mergeLinkKeyIndex(LinkIndexType key, LinkIndexType index)
merge a key and index value into a link value
columnar::TestUtils::RNTupleBackend * rntbackend
std::vector< std::shared_ptr< TestUtils::IColumnData > > knownColumns
std::vector< std::shared_ptr< TestUtils::IColumnData > > usedColumns
std::unique_ptr< ROOT::Experimental::RNTupleInspector > inspector
std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > offsetColumns
void setupKnownColumns(std::span< const TestUtils::TestDefinition > testDefinitions)
void setupColumns(const ColumnVectorHeader &columnHeader)
std::unique_ptr< ROOT::RNTupleReader > rntreader
void doCallMulti(const std::vector< TestUtils::TestDefinition > &testDefinitions)
the performance data for reading a single branch/column
virtual void setData(ColumnVectorData &columnData) override
std::array< ColumnarOffsetType, 2 > data
virtual BranchPerfData getPerfData(float) override
virtual bool connect(Backend, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
std::vector< ColumnarOffsetType > offsets
Reader< std::vector< std::string > > branchReader
ColumnDataMetNames(const std::string &val_branchName)
virtual BranchPerfData getPerfData(float emptyTime) override
virtual void getEntry(Long64_t entry) override
virtual void setData(ColumnVectorData &colData) override
virtual bool connect(Backend source, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
virtual bool connect(Backend source, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
const std::vector< ColumnarOffsetType > * offsetColumn
virtual void setData(ColumnVectorData &columnData) override
ColumnDataOutVector(const std::string &val_columnName, const T &val_defaultValue)
virtual BranchPerfData getPerfData(float) override
std::vector< ColumnarOffsetType > namesOffsets
const std::vector< ColumnarOffsetType > * offsetColumns
virtual BranchPerfData getPerfData(float) override
std::vector< ColumnarOffsetType > offsets
virtual void setData(ColumnVectorData &colData) override
virtual bool connect(Backend source, 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)
virtual void setData(ColumnVectorData &colData) override
virtual bool connect(Backend source, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
virtual BranchPerfData getPerfData(float emptyTime) override
ColumnDataSamplingPattern(const std::string &val_branchName)
Reader< xAOD::CaloClusterContainer > branchReader
virtual void getEntry(Long64_t entry) override
virtual void setData(ColumnVectorData &columnData) override
ColumnDataScalar(const std::string &val_branchName)
virtual bool connect(Backend source, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
virtual void getEntry(Long64_t entry) override
virtual BranchPerfData getPerfData(float emptyTime) override
ColumnDataVectorVectorVector(const std::string &val_branchName)
virtual bool connect(Backend source, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
virtual BranchPerfData getPerfData(float emptyTime) override
Reader< std::vector< std::vector< std::vector< T > > > > branchReader
virtual void setData(ColumnVectorData &colData) override
virtual BranchPerfData getPerfData(float emptyTime) override
Reader< std::vector< std::vector< T > > > branchReader
virtual void setData(ColumnVectorData &colData) override
virtual void getEntry(Long64_t entry) override
virtual bool connect(Backend source, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
ColumnDataVectorVector(const std::string &val_branchName)
virtual void getEntry(Long64_t entry) override
virtual bool connect(Backend source, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
const std::vector< ColumnarOffsetType > * offsetColumn
std::vector< ColumnarOffsetType > offsets
ColumnDataVector(const std::string &val_branchName)
virtual void setData(ColumnVectorData &columnData) override
virtual BranchPerfData getPerfData(float emptyTime) override
ROOT::Experimental::RNTupleInspector * inspector
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