DataGetterHelper.cc
Go to the documentation of this file.
2 // vim: set sw=2 expandtab :
3 
9 
14 #include "gallery/EventNavigator.h"
15 
16 #include "canvas_root_io/Streamers/AssnsStreamer.h"
17 #include "canvas_root_io/Streamers/BranchDescriptionStreamer.h"
18 #include "canvas_root_io/Streamers/CacheStreamers.h"
19 #include "canvas_root_io/Streamers/ProductIDStreamer.h"
20 #include "canvas_root_io/Streamers/RefCoreStreamer.h"
21 #include "canvas_root_io/Streamers/TransientStreamer.h"
22 #include "canvas_root_io/Streamers/setPtrVectorBaseStreamer.h"
23 
24 #include "TClass.h"
25 #include "TTree.h"
26 
27 #include <algorithm>
28 #include <cassert>
29 
30 namespace {
31 
32  constexpr char underscore{'_'};
33  constexpr char period{'.'};
34 
35  void
36  initializeStreamers()
37  {
38  art::setCacheStreamers();
39  art::setProvenanceTransientStreamers();
40  art::detail::setBranchDescriptionStreamer();
41  art::detail::setPtrVectorBaseStreamer();
42  art::configureProductIDStreamer();
43  art::configureRefCoreStreamer();
44  }
45 
47  buildBranchName(gallery::InfoForTypeLabelInstance const& info,
48  std::string const& processName)
49  {
50  std::string branchName{info.type().friendlyClassName()};
51  unsigned int const branchNameSize =
52  branchName.size() + info.label().size() + info.instance().size() +
53  processName.size() + 4;
54  branchName.reserve(branchNameSize);
55  branchName += underscore;
56  branchName += info.label();
57  branchName += underscore;
58  branchName += info.instance();
59  branchName += underscore;
60  branchName += processName;
61  branchName += period;
62  return branchName;
63  }
64 
65 } // unnamed namespace
66 
67 namespace gallery {
68 
70  EventNavigator const* eventNavigator,
71  std::shared_ptr<EventHistoryGetter> historyGetter)
72  : eventNavigator_{eventNavigator}, historyGetter_{historyGetter}
73  {
74  initializeStreamers();
75  }
76 
78  DataGetterHelper::getByLabel(std::type_info const& typeInfoOfWrapper,
79  art::InputTag const& inputTag) const
80  {
83  }
84  art::TypeID const type{typeInfoOfWrapper};
85  auto const& info =
86  getInfoForTypeLabelInstance(type, inputTag.label(), inputTag.instance());
87 
88  if (inputTag.process().empty()) {
89  // search in reverse order of the ProcessHistory
90  for (auto reverseIter = crbegin(info.productIDsOrderedByHistory()),
91  iEnd = crend(info.productIDsOrderedByHistory());
92  reverseIter != iEnd;
93  ++reverseIter) {
94  if (auto edProduct = readProduct(*reverseIter, type)) {
95  // If the product was present in the input file and we
96  // successfully read it then we are done
97  return std::make_pair(edProduct, *reverseIter);
98  }
99  }
100  } else { // process is not empty
101  auto itProcess = processNameToProcessIndex_.find(inputTag.process());
102  if (itProcess != cend(processNameToProcessIndex_)) {
103  unsigned int const processIndex = itProcess->second;
104  auto branchData = getBranchData(info, processIndex);
105  if (branchData) {
106  auto pd = branchMapReader_.productDescription(info, itProcess->first);
107  assert(pd);
108  auto product = branchData->uniqueProduct_(type);
109  return std::make_pair(product, pd->productID());
110  }
111  }
112  }
113  return std::make_pair(nullptr, art::ProductID::invalid());
114  }
115 
116  std::vector<art::BranchDescription const*>
118  art::TypeID const& typeIDOfWrapper) const
119  {
120  std::vector<art::BranchDescription const*> result;
123  }
124  auto const fcn = typeIDOfWrapper.friendlyClassName();
125  for (auto const& pr : branchMapReader_.productDescriptions()) {
126  auto const& pd = pr.second;
127  if (pd.friendlyClassName() != fcn) {
128  continue;
129  }
130 
131  result.push_back(&pd);
132  }
133  return result;
134  }
135 
136  std::vector<art::InputTag>
137  DataGetterHelper::getInputTags(std::type_info const& typeInfoOfWrapper) const
138  {
139  std::vector<art::InputTag> result;
140  art::TypeID const type{typeInfoOfWrapper};
141  for (auto const* pd : getProductDescriptions(type)) {
142  result.push_back(pd->inputTag());
143  }
144  return result;
145  }
146 
147  std::vector<ProductWithID>
148  DataGetterHelper::getManyByType(std::type_info const& typeInfoOfWrapper) const
149  {
150  std::vector<ProductWithID> result;
151  art::TypeID const type{typeInfoOfWrapper};
152  for (auto const* pd : getProductDescriptions(type)) {
153  auto itProcess = processNameToProcessIndex_.find(pd->processName());
154  if (itProcess == cend(processNameToProcessIndex_)) {
155  continue;
156  }
157 
158  auto const& info = getInfoForTypeLabelInstance(
159  type, pd->moduleLabel(), pd->productInstanceName());
160 
161  unsigned int const processIndex = itProcess->second;
162  auto branchData = getBranchData(info, processIndex);
163  if (!branchData) {
164  continue;
165  }
166 
167  if (auto product = branchData->uniqueProduct_(type)) {
168  result.emplace_back(product, pd->productID());
169  }
170  }
171  return result;
172  }
173 
174  void
176  TTree* iTree,
177  bool const initializeTheCache)
178  {
179  tree_ = iTree;
180  art::configureProductIDStreamer(); // Null out the ProductID streamer
182  art::configureProductIDStreamer(branchMapReader_.branchIDLists());
183  if (initializeTheCache) {
184  tree_->SetCacheSize();
185  tree_->AddBranchToCache(eventNavigator_->eventAuxiliaryBranch(), kTRUE);
186  }
187  for (auto& info : infoVector_) {
188  std::vector<IndexProductIDPair> old;
189  old.swap(info.processIndexToProductID());
190  info.processIndexToProductID().reserve(processNames_.size());
191  for (unsigned int processIndex{}; processIndex < processNames_.size();
192  ++processIndex) {
193  auto const& processName = processNames_[processIndex];
194  auto bd = branchMapReader_.productDescription(info, processName);
195  if (bd == nullptr) {
196  // Product not available.
197  continue;
198  }
199 
200  auto const productID = getMaybeValidProductID(old, processIndex);
201  if (productID.isValid()) {
202  auto& branchData = *branchDataMap_.at(productID);
203  auto branch = tree_->GetBranch(branchData.branchName().c_str());
204  // This will update the pointer to the TBranch in
205  // BranchData. This loop is sufficient to update all
206  // BranchData objects in the vector.
207  branchData.updateFile(branch);
208 
209  // A little paranoia here. What if in one input file
210  // Assns<A,B,C> is written into the file and Assns<B,A,C> is
211  // written into another? The following deals properly with
212  // that case by constructing a new AssnsBranchData object,
213  // although I imagine it might never happen in practice.
214  if (info.isAssns() && branch != nullptr) {
215  TClass* tClass = getTClass(info, processName);
216 
217  art::TypeID const typeIDInDescription{tClass->GetTypeInfo()};
218  art::TypeID const typeIDInBranchData{
219  branchData.tClass()->GetTypeInfo()};
220  if (typeIDInDescription != typeIDInBranchData) {
221  std::string branchName = branchData.branchName();
222  branchDataMap_[productID] =
223  std::make_unique<AssnsBranchData>(typeIDInDescription,
224  tClass,
225  branch,
227  this,
228  move(branchName),
229  info.type(),
230  info.partnerType());
231  }
232  }
233  info.processIndexToProductID().emplace_back(processIndex,
234  bd->productID());
235  if (initializeTheCache && branch) {
236  tree_->AddBranchToCache(branch, kTRUE);
237  }
239  productID)) {
241  bd->branchName(), processIndex, info, initializeTheCache);
242  }
243  }
245  }
246  if (initializeTheCache) {
247  tree_->StopCacheLearningPhase();
248  }
249  // This must be cleared because the BranchIDLists may be different
250  // in different input files.
251  branchDataMissingSet_.clear();
252  updateEvent();
253  }
254 
255  void
257  {
258  tree_->SetCacheSize();
259  tree_->AddBranchToCache(eventNavigator_->eventAuxiliaryBranch(), kTRUE);
260  for (auto const& info : infoVector_) {
261  for (auto const& i : info.processIndexToProductID()) {
262  auto const productID = i.second;
263  auto& branchData = *branchDataMap_.at(productID);
264  if (auto branch = branchData.branch()) {
265  tree_->AddBranchToCache(branch, kTRUE);
266  }
267  }
268  }
269  tree_->StopCacheLearningPhase();
270  }
271 
272  void
274  {
276  }
277 
278  void
280  {
282  // Do nothing if the process names in the process history are the same
283  auto const processHistoryID = historyGetter_->processHistoryID();
284  if (processHistoryID == previousProcessHistoryID_) {
285  return;
286  }
287  previousProcessHistoryID_ = processHistoryID;
288  art::ProcessHistory const& processHistory =
289  historyGetter_->processHistory();
290  if (previousProcessHistoryNames_.size() == processHistory.size()) {
291  bool same = true;
292  auto iPrevious = previousProcessHistoryNames_.begin();
293  for (auto i = processHistory.begin(), iEnd = processHistory.end();
294  i != iEnd;
295  ++i, ++iPrevious) {
296  if (i->processName() != *iPrevious) {
297  same = false;
298  break;
299  }
300  }
301  if (same) {
302  return;
303  }
304  }
306  // update for the new process history
307  orderedProcessIndexes_.clear();
308  for (auto const& processConfig : processHistory) {
309  std::string const& processName = processConfig.processName();
310  previousProcessHistoryNames_.push_back(processName);
311  auto itFind = processNameToProcessIndex_.find(processName);
312  if (itFind == processNameToProcessIndex_.end()) {
313  addProcess(processName);
314  itFind = processNameToProcessIndex_.find(processName);
315  }
316  orderedProcessIndexes_.push_back(itFind->second);
317  }
318  for (auto const& info : infoVector_) {
320  }
321  }
322 
323  void
324  DataGetterHelper::addProcess(std::string const& processName) const
325  {
326  unsigned int const processIndex = processNames_.size();
327  processNames_.push_back(processName);
328  processNameToProcessIndex_[processName] = processIndex;
329  for (auto& info : infoVector_) {
330  auto pd = branchMapReader_.productDescription(info, processName);
331  if (pd == nullptr) {
332  continue;
333  }
334  assert(branchMapReader_.branchInRegistryOfAnyOpenedFile(pd->productID()));
335  addBranchData(pd->branchName(), processIndex, info);
336  }
337  }
338 
339  void
341  unsigned int const processIndex,
342  InfoForTypeLabelInstance const& info,
343  bool const initializeTheCache) const
344  {
345  auto branch = tree_->GetBranch(branchName.c_str());
346  if (branch == nullptr) {
347  return;
348  }
349  auto pd =
351  assert(pd);
352  auto const productID = pd->productID();
353  if (info.isAssns()) {
354  auto const& processName = processNames_[processIndex];
355  auto tClass = getTClass(info, processName);
356 
357  art::TypeID const typeIDInDescription{tClass->GetTypeInfo()};
358  branchDataMap_[productID] =
359  std::make_unique<AssnsBranchData>(typeIDInDescription,
360  tClass,
361  branch,
363  this,
364  move(branchName),
365  info.type(),
366  info.partnerType());
367  } else {
368  branchDataMap_[productID] =
369  std::make_unique<BranchData>(info.type(),
370  info.tClass(),
371  branch,
373  this,
374  move(branchName));
375  }
376  info.processIndexToProductID().emplace_back(processIndex, productID);
377  if (initializeTheCache && branch) {
378  tree_->AddBranchToCache(branch, kTRUE);
379  }
380  }
381 
382  TClass*
384  std::string const& processName) const
385  {
386  auto bd = branchMapReader_.productDescription(info, processName);
387  if (bd == nullptr) {
389  "DataGetterHelper::getTClass: "}
390  << "TBranch exists but no BranchDescription in ProductRegistry.\n"
391  << "This shouldn't be possible. For type " << info.type().className()
392  << "\n";
393  }
394 
395  art::detail::AssnsStreamer::init_streamer(bd->producedClassName());
396  auto tClass = TClass::GetClass(bd->wrappedName().c_str());
397  if (tClass == nullptr) {
399  "DataGetterHelper::getTClass: "}
400  << "Missing dictionary for wrapped Assns class.\n"
401  << bd->wrappedName() << "\n";
402  }
403  return tClass;
404  }
405 
408  art::TypeID const& type,
409  std::string const& label,
410  std::string const& instance) const
411  {
412  if (label.empty()) {
414  << "getValidHandle was passed an empty module label. Not allowed.\n";
415  }
416  TypeLabelInstanceKey const key{type, label, instance};
417  auto itFind = infoMap_.find(key);
418  if (itFind == cend(infoMap_)) {
419  addTypeLabelInstance(type, label, instance);
420  itFind = infoMap_.find(key);
421  }
422  return infoVector_[itFind->second];
423  }
424 
425  void
427  std::string const& label,
428  std::string const& instance) const
429  {
430  dictChecker_.checkDictionaries(art::uniform_type_name(type.typeInfo()),
431  true);
432  dictChecker_.reportMissingDictionaries();
433  unsigned int infoIndex = infoVector_.size();
434  infoVector_.emplace_back(type, label, instance);
435  insertIntoInfoMap(type, label, instance, infoIndex);
436  InfoForTypeLabelInstance const& info = infoVector_[infoIndex];
437  if (info.isAssns()) {
438  insertIntoInfoMap(info.partnerType(), label, instance, infoIndex);
439  }
440  unsigned int processIndex{};
441  for (auto const& processName : processNames_) {
442  std::string branchName{buildBranchName(info, processName)};
443  art::ProductID const productID{branchName};
445  addBranchData(move(branchName), processIndex, info);
446  }
447  ++processIndex;
448  }
450  }
451 
452  void
454  std::string const& label,
455  std::string const& instance,
456  unsigned int const infoIndex) const
457  {
458  TypeLabelInstanceKey const newKey{type, label, instance};
459  infoMap_[newKey] = infoIndex;
460  }
461 
462  art::EDProduct const*
464  art::TypeID const& type) const
465  {
466  auto const& branchData = branchDataMap_.at(productID);
467  return branchData->uniqueProduct_(type);
468  }
469 
472  std::vector<IndexProductIDPair> const& processIndexToProductID,
473  unsigned int const processIndex) const
474  {
475  auto itBranchDataIndex = lower_bound(
476  processIndexToProductID.cbegin(),
477  processIndexToProductID.cend(),
478  std::make_pair(processIndex, art::ProductID::invalid()),
479  [](auto const& l, auto const& r) { return l.first < r.first; });
480  if (itBranchDataIndex != processIndexToProductID.cend() &&
481  itBranchDataIndex->first == processIndex) {
482  return itBranchDataIndex->second;
483  }
484  return art::ProductID::invalid();
485  }
486 
487  BranchData const*
489  unsigned int const processIndex) const
490  {
491  auto const pid =
492  getMaybeValidProductID(info.processIndexToProductID(), processIndex);
493  return pid.isValid() ? branchDataMap_.at(pid).get() : nullptr;
494  }
495 
496  void
498  InfoForTypeLabelInstance const& info) const
499  {
500  info.productIDsOrderedByHistory().clear();
501  if (info.productIDsOrderedByHistory().capacity() <
502  orderedProcessIndexes_.size()) {
503  info.productIDsOrderedByHistory().reserve(orderedProcessIndexes_.size());
504  }
505  for (auto processIndex : orderedProcessIndexes_) {
506  auto const& orderedProcessName = processNames_[processIndex];
507  auto pd = branchMapReader_.productDescription(info, orderedProcessName);
508  if (pd == nullptr) {
509  continue;
510  }
511  auto branchData = getBranchData(info, processIndex);
512  if (branchData && branchData->branch() != nullptr) {
513  info.productIDsOrderedByHistory().emplace_back(pd->productID());
514  }
515  }
516  }
517 
518  BranchData const*
520  {
523  }
524  TClass* tClass = TClass::GetClass(desc.wrappedName().c_str());
525  if (tClass == nullptr) {
527  "DataGetterHelper::getBranchData: ")
528  << "Missing dictionary for wrapped class.\n"
529  << desc.wrappedName() << "\n";
530  }
531 
532  auto const& typeInfoOfWrapper = *tClass->GetTypeInfo();
533  art::TypeID const type{typeInfoOfWrapper};
534  auto const& info = getInfoForTypeLabelInstance(
535  type, desc.moduleLabel(), desc.productInstanceName());
536  auto itProcess = processNameToProcessIndex_.find(desc.processName());
537  if (itProcess != cend(processNameToProcessIndex_)) {
538  unsigned int const processIndex = itProcess->second;
539  auto branchData = getBranchData(info, processIndex);
540  if (branchData && branchData->branch() != nullptr) {
541  return branchData;
542  }
543  }
544  return nullptr;
545  }
546 
549  {
550  auto pd = branchMapReader_.productDescription(productID);
551  if (pd == nullptr) {
553  "DataGetterHelper::getProductDescription: "}
554  << "No product description could be found for ProductID " << productID
555  << ".\n";
556  }
557  return *pd;
558  }
559 
560  art::EDProductGetter const*
562  {
563  auto itFind = branchDataMap_.find(productID);
564  if (itFind != cend(branchDataMap_)) {
565  return itFind->second.get();
566  }
567 
568  if (branchDataMissingSet_.find(productID) != cend(branchDataMissingSet_)) {
569  return &invalidBranchData_;
570  }
571 
572  auto const pd = branchMapReader_.productDescription(productID);
573  if (pd == nullptr) {
574  return &invalidBranchData_;
575  }
576 
577  auto branchData = getBranchData(*pd);
578  if (branchData == nullptr) {
579  branchDataMissingSet_.insert(productID);
580  return &invalidBranchData_;
581  }
582  return branchData;
583  }
584 
585 } // namespace gallery
art::EDProductGetter const * getEDProductGetter_(art::ProductID const &) const override
std::map< art::ProductID, std::unique_ptr< BranchData > > branchDataMap_
const_iterator end() const
std::set< art::ProductID > branchDataMissingSet_
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Definition: StdUtils.h:87
static QCString result
art::BranchDescription const * productDescription(InfoForTypeLabelInstance const &info, std::string const &process) const
std::vector< art::BranchDescription const * > getProductDescriptions(art::TypeID const &typeIDOfWrapper) const
void updateFile(TFile *iFile, TTree *iTree, bool initializeTheCache)
std::string friendlyClassName() const
Definition: TypeID.cc:61
std::string const & wrappedName() const noexcept
void addTypeLabelInstance(art::TypeID const &type, std::string const &label, std::string const &instance) const
std::string string
Definition: nybbler.cc:12
type * first()
Definition: qinternallist.h:87
void addBranchData(std::string branchName, unsigned int processIndex, InfoForTypeLabelInstance const &info, bool initializeTheCache=false) const
const_iterator begin() const
const std::string instance
std::string const & instance() const noexcept
Definition: InputTag.cc:85
void initializeForProcessHistory() const
void insertIntoInfoMap(art::TypeID const &type, std::string const &label, std::string const &instance, unsigned int infoIndex) const
ProductWithID getByLabel(std::type_info const &typeInfoOfWrapper, art::InputTag const &inputTag) const
InfoForTypeLabelInstance & getInfoForTypeLabelInstance(art::TypeID const &type, std::string const &label, std::string const &instance) const
static QStrList * l
Definition: config.cpp:1044
std::string const & process() const noexcept
Definition: InputTag.cc:91
void addProcess(std::string const &processName) const
art::ProductID getMaybeValidProductID(std::vector< IndexProductIDPair > const &processIndexToProductID, unsigned int processIndex) const
std::string const & processName() const noexcept
TBranch * eventAuxiliaryBranch() const
std::vector< std::string > previousProcessHistoryNames_
std::string const & label() const noexcept
Definition: InputTag.cc:79
std::string uniform_type_name(std::type_info const &tid)
std::map< art::ProductID, art::BranchDescription > const & productDescriptions() const
void updateFile(TFile *tFile)
def key(type, name=None)
Definition: graph.py:13
art::ProcessHistoryID previousProcessHistoryID_
std::string const & instance() const noexcept
def move(depos, offset)
Definition: depos.py:107
void updateBranchDataIndexOrderedByHistory(InfoForTypeLabelInstance const &info) const
std::vector< art::ProductID > & productIDsOrderedByHistory() const noexcept
std::vector< art::InputTag > getInputTags(std::type_info const &typeInfoOfWrapper) const
BranchData const * getBranchData(InfoForTypeLabelInstance const &info, unsigned int processIndex) const
art::BranchDescription const & getProductDescription(art::ProductID) const
std::vector< IndexProductIDPair > & processIndexToProductID() const noexcept
art::TypeID const & partnerType() const noexcept
std::string className() const
Definition: TypeID.cc:48
std::map< std::string, unsigned int > processNameToProcessIndex_
bool branchInRegistryOfAnyOpenedFile(art::ProductID const &) const
EventNavigator const * eventNavigator_
std::map< TypeLabelInstanceKey, unsigned int > infoMap_
std::string const & moduleLabel() const noexcept
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
BranchMapReader branchMapReader_
std::string const & label() const noexcept
std::vector< ProductWithID > getManyByType(std::type_info const &typeInfoOfWrapper) const
art::TypeID const & type() const noexcept
std::pair< art::EDProduct const *, art::ProductID > ProductWithID
size_type size() const
std::string const & productInstanceName() const noexcept
std::shared_ptr< EventHistoryGetter > historyGetter_
std::vector< InfoForTypeLabelInstance > infoVector_
static QCString type
Definition: declinfo.cpp:672
static constexpr ProductID invalid() noexcept
Definition: ProductID.h:26
std::vector< unsigned int > orderedProcessIndexes_
art::EDProduct const * readProduct(art::ProductID const productID, art::TypeID const &type) const
TClass * getTClass(InfoForTypeLabelInstance const &info, std::string const &processName) const
cet::exempt_ptr< art::BranchIDLists const > branchIDLists() const
std::vector< std::string > processNames_
std::type_info const & typeInfo() const
Definition: TypeID.cc:36
DataGetterHelper(EventNavigator const *eventNavigator, std::shared_ptr< EventHistoryGetter > historyGetter)
art::root::DictionaryChecker dictChecker_