LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
Principal.cc
Go to the documentation of this file.
2 // vim: set sw=2:
3 
13 #include "cetlib/container_algorithms.h"
14 
15 #include <algorithm>
16 #include <sstream>
17 #include <stdexcept>
18 #include <utility>
19 
20 using namespace cet;
21 using namespace std;
22 using namespace art;
23 
24 namespace {
25 
26  template <typename T>
27  class ReverseIteration;
28 
29  template <typename T>
30  ReverseIteration<T> reverse_iteration(T const&);
31 
32  template <typename T>
33  class ReverseIteration {
34  friend ReverseIteration reverse_iteration<>(T const&);
35  T const& t_;
36  ReverseIteration(T const& t) : t_{t} {};
37 
38  public:
39  auto
40  begin() const
41  {
42  return crbegin(t_);
43  }
44  auto
45  end() const
46  {
47  return crend(t_);
48  }
49  };
50 
51  template <typename T>
52  ReverseIteration<T>
53  reverse_iteration(T const& t)
54  {
55  return ReverseIteration<T>{t};
56  }
57 }
58 
59 Principal::Principal(ProcessConfiguration const& pc,
60  ProcessHistoryID const& hist,
61  cet::exempt_ptr<ProductTable const> presentProducts,
62  std::unique_ptr<BranchMapper>&& mapper,
63  std::unique_ptr<DelayedReader>&& reader)
64  : processConfiguration_{pc}
65  , presentProducts_{presentProducts}
66  , branchMapperPtr_{std::move(mapper)}
67  , store_{std::move(reader)}
68 {
69  if (!hist.isValid()) {
70  return;
71  }
73  ProcessHistory ph;
74  bool const found[[gnu::unused]]{ProcessHistoryRegistry::get(hist, ph)};
75  assert(found);
77 }
78 
79 void
81 {
83  return;
84  }
85  string const& processName = processConfiguration_.processName();
86  for (auto const& val : processHistory_) {
87  if (processName == val.processName()) {
89  << "The process name " << processName
90  << " was previously used on these products.\n"
91  << "Please modify the configuration file to use a "
92  << "distinct process name.\n";
93  }
94  }
95  processHistory_.push_back(processConfiguration_);
96  // OPTIMIZATION NOTE: As of 0_9_0_pre3 For very simple Sources
97  // (e.g. EmptyEvent) this routine takes up nearly 50% of the time
98  // per event, and 96% of the time for this routine is spent in
99  // computing the ProcessHistory id which happens because we are
100  // reconstructing the ProcessHistory for each event. It would
101  // probably be better to move the ProcessHistory construction out to
102  // somewhere which persists for longer than one Event.
103  auto const phid = processHistory_.id();
104  ProcessHistoryRegistry::emplace(phid, processHistory_);
105  setProcessHistoryID(phid);
107 }
108 
111  SelectorBase const& sel) const
112 {
113  auto const& results = findGroupsForProduct(wrapped, sel, true);
114  if (results.empty()) {
115  auto whyFailed =
116  std::make_shared<art::Exception>(art::errors::ProductNotFound);
117  *whyFailed << "getBySelector: Found zero products matching all criteria\n"
118  << "Looking for type: " << wrapped.product_type << "\n";
119  return GroupQueryResult{whyFailed};
120  }
121  if (results.size() > 1) {
123  << "getBySelector: Found " << results.size()
124  << " products rather than one which match all criteria\n"
125  << "Looking for type: " << wrapped.product_type << "\n";
126  }
127  return results[0];
128 }
129 
132 {
133  if (auto const g = getGroupForPtr(pid)) {
134  return GroupQueryResult{g};
135  }
136  auto whyFailed =
137  std::make_shared<art::Exception>(art::errors::ProductNotFound, "InvalidID");
138  *whyFailed << "getGroup: no product with given product id: " << pid << "\n";
139  return GroupQueryResult{whyFailed};
140 }
141 
144  string const& label,
145  string const& productInstanceName,
146  string const& processName) const
147 {
148  Selector const sel{ModuleLabelSelector{label} &&
149  ProductInstanceNameSelector{productInstanceName} &&
150  ProcessNameSelector{processName}};
151  auto const& results = findGroupsForProduct(wrapped, sel, true);
152  if (results.empty()) {
153  auto whyFailed =
154  std::make_shared<art::Exception>(art::errors::ProductNotFound);
155  *whyFailed << "getByLabel: Found zero products matching all criteria\n"
156  << "Looking for type: " << wrapped.product_type << "\n"
157  << "Looking for module label: " << label << "\n"
158  << "Looking for productInstanceName: " << productInstanceName
159  << "\n"
160  << (processName.empty() ? "" : "Looking for process: ")
161  << processName;
162  return GroupQueryResult{whyFailed};
163  }
164  if (results.size() > 1) {
166  << "getByLabel: Found " << results.size()
167  << " products rather than one which match all criteria\n"
168  << "Looking for type: " << wrapped.product_type << "\n"
169  << "Looking for module label: " << label << "\n"
170  << "Looking for productInstanceName: " << productInstanceName << "\n"
171  << (processName.empty() ? "" : "Looking for process: ") << processName
172  << "\n";
173  }
174  return results[0];
175 }
176 
178 Principal::getMany(WrappedTypeID const& wrapped, SelectorBase const& sel) const
179 {
180  return findGroupsForProduct(wrapped, sel, false);
181 }
182 
183 int
185 {
186  int const err = store_->openNextSecondaryFile(nextSecondaryFileIdx_);
187  if (err != -2) {
188  // there are more files to try
190  }
191  return err;
192 }
193 
196 {
197  GroupQueryResultVec results;
198 
199  // Find groups from current process
200  if (producedProducts_) {
201  if (findGroups(producedProducts_->viewLookup, selector, results, true) !=
202  0) {
203  return results;
204  }
205  }
206 
207  // Look through currently opened input files
208  if (results.empty()) {
209  results = matchingSequenceFromInputFile(selector);
210  if (!results.empty()) {
211  return results;
212  }
213 
214  for (auto const& sp : secondaryPrincipals_) {
215  results = sp->matchingSequenceFromInputFile(selector);
216  if (!results.empty()) {
217  return results;
218  }
219  }
220  }
221 
222  // Open more secondary files if necessary
223  if (results.empty()) {
224  while (true) {
225  int const err = tryNextSecondaryFile();
226  if (err == -2) {
227  // No more files.
228  break;
229  }
230  if (err == -1) {
231  // Run, SubRun, or Event not found.
232  continue;
233  }
234  assert(!secondaryPrincipals_.empty());
235  auto& new_sp = secondaryPrincipals_.back();
236  results = new_sp->matchingSequenceFromInputFile(selector);
237  if (!results.empty()) {
238  return results;
239  }
240  }
241  }
242 
243  return results;
244 }
245 
248 {
249  GroupQueryResultVec results;
250  if (!presentProducts_) {
251  return results;
252  }
253 
254  findGroups(presentProducts_->viewLookup, selector, results, true);
255  return results;
256 }
257 
258 void
260 {
261  if (auto g = getGroup(pid)) {
262  g->removeCachedProduct();
263  return;
264  }
265  for (auto const& sp : secondaryPrincipals_) {
266  if (auto g = sp->getGroup(pid)) {
267  g->removeCachedProduct();
268  return;
269  }
270  }
271  throw Exception(errors::ProductNotFound, "removeCachedProduct")
272  << "Attempt to remove unknown product corresponding to ProductID: " << pid
273  << '\n'
274  << "Please contact artists@fnal.gov\n";
275 }
276 
279  SelectorBase const& selector,
280  bool const stopIfProcessHasMatch) const
281 {
282  GroupQueryResultVec results;
283 
284  unsigned ret{};
285  // Find groups from current process
286  if (producedProducts_) {
287  auto const& lookup = producedProducts_->productLookup;
288  auto it = lookup.find(wrapped.product_type.friendlyClassName());
289  if (it != lookup.end()) {
290  ret += findGroups(it->second,
291  selector,
292  results,
293  stopIfProcessHasMatch,
294  wrapped.wrapped_product_type);
295  }
296  }
297 
298  // Look through currently opened input files
299  ret +=
300  findGroupsFromInputFile(wrapped, selector, results, stopIfProcessHasMatch);
301  if (ret) {
302  return results;
303  }
304 
305  for (auto const& sp : secondaryPrincipals_) {
306  if (sp->findGroupsFromInputFile(
307  wrapped, selector, results, stopIfProcessHasMatch)) {
308  return results;
309  }
310  }
311 
312  // Open more secondary files if necessary
313  while (true) {
314  int const err = tryNextSecondaryFile();
315  if (err == -2) {
316  // No more files.
317  break;
318  }
319  if (err == -1) {
320  // Run, SubRun, or Event not found.
321  continue;
322  }
323  assert(!secondaryPrincipals_.empty());
324  auto& new_sp = secondaryPrincipals_.back();
325  if (new_sp->findGroupsFromInputFile(
326  wrapped, selector, results, stopIfProcessHasMatch)) {
327  return results;
328  }
329  }
330  return results;
331 }
332 
333 std::size_t
335  SelectorBase const& selector,
336  GroupQueryResultVec& results,
337  bool const stopIfProcessHasMatch) const
338 {
339  if (!presentProducts_) {
340  return 0;
341  }
342  auto const& lookup = presentProducts_->productLookup;
343  auto it = lookup.find(wrapped.product_type.friendlyClassName());
344  if (it == lookup.end()) {
345  return 0;
346  }
347  return findGroups(it->second,
348  selector,
349  results,
350  stopIfProcessHasMatch,
351  wrapped.wrapped_product_type);
352 }
353 
354 std::size_t
356  SelectorBase const& sel,
357  GroupQueryResultVec& res,
358  bool const stopIfProcessHasMatch,
359  TypeID const wanted_wrapper /*=TypeID()*/) const
360 {
361  // Loop over processes in reverse time order. Sometimes we want to
362  // stop after we find a process with matches so check for that at
363  // each step.
364  std::size_t found{};
365  for (auto const& h : reverse_iteration(processHistory())) {
366  auto it = pl.find(h.processName());
367  if (it != pl.end()) {
368  found += findGroupsForProcess(it->second, sel, res, wanted_wrapper);
369  }
370  if (stopIfProcessHasMatch && !res.empty())
371  break;
372  }
373  return found;
374 }
375 
376 std::size_t
377 Principal::findGroupsForProcess(std::vector<ProductID> const& vpid,
378  SelectorBase const& sel,
379  GroupQueryResultVec& res,
380  TypeID const wanted_wrapper) const
381 {
382  std::size_t found{}; // Horrible hack that should go away
383  for (auto const pid : vpid) {
384  auto group = getGroup(pid);
385  if (!group) {
386  continue;
387  }
388  if (!sel.match(group->productDescription())) {
389  continue;
390  }
391  if (group->productUnavailable()) {
392  continue;
393  }
394  if (wanted_wrapper) {
395  group->resolveProduct(wanted_wrapper);
396  } else {
397  group->resolveProduct(group->producedWrapperType());
398  }
399  // If the product is a dummy filler, group will now be marked unavailable.
400  // Unscheduled execution can fail to produce the EDProduct so check.
401  if (group->productUnavailable()) {
402  continue;
403  }
404  // Found a good match, save it.
405  res.emplace_back(group);
406  ++found;
407  }
408  return found;
409 }
410 
411 EDProductGetter const*
413 {
414  auto it = deferredGetters_.find(pid);
415  if (it != deferredGetters_.end()) {
416  return it->second.get();
417  }
418  deferredGetters_[pid] = std::make_shared<DeferredProductGetter>(
419  cet::exempt_ptr<Principal const>{this}, pid);
420  return deferredGetters_[pid].get();
421 }
422 
424 Principal::getForOutput(ProductID const pid, bool const resolveProd) const
425 {
426  auto const& g = getResolvedGroup(pid, resolveProd);
427  if (g.get() == nullptr) {
428  return OutputHandle::invalid();
429  }
430 
431  if (resolveProd) {
432  // If a request to resolve the product is made, then it should
433  // exist and be marked as present. Return invalid handles if this
434  // is not the case.
435  if (g->anyProduct() == nullptr) {
436  return OutputHandle::invalid();
437  }
438  if (!g->anyProduct()->isPresent()) {
439  return OutputHandle::invalid();
440  }
441  }
442  if (!g->anyProduct() && !g->productProvenancePtr()) {
443  return OutputHandle{g->rangeOfValidity()};
444  }
445  return OutputHandle{g->anyProduct(),
446  &g->productDescription(),
447  g->productProvenancePtr(),
448  g->rangeOfValidity()};
449 }
450 
451 cet::exempt_ptr<Group const>
452 Principal::getResolvedGroup(ProductID const pid, bool const resolveProd) const
453 {
454  // FIXME: This reproduces the behavior of the original getGroup with
455  // resolveProv == false but I am not sure this is correct in the
456  // case of an unavailable product.
457  auto const g = getGroupForPtr(pid);
458  if (!g.get() || !resolveProd) {
459  return g;
460  }
461  bool const gotIt = g->resolveProductIfAvailable(g->producedWrapperType());
462  if (!gotIt) {
463  // Behavior is the same as if the group wasn't there.
464  return nullptr;
465  }
466  return g;
467 }
468 
469 bool
471 {
472  bool present{false};
473  if (presentProducts_) {
474  auto const& lookup = presentProducts_->availableProducts;
475  present = (lookup.find(pid) != lookup.cend());
476  }
477  return present;
478 }
479 
480 cet::exempt_ptr<Group const>
482 {
483  bool produced{false};
484  if (producedProducts_) {
485  auto const& availableProducts = producedProducts_->availableProducts;
486  if (availableProducts.find(pid) != availableProducts.cend()) {
487  produced = true;
488  }
489  }
490 
491  // Look through current process and currently opened primary input file.
492  if (produced || presentFromSource(pid)) {
493  return getGroup(pid);
494  }
495 
496  // Look through secondary files
497  for (auto const& sp : secondaryPrincipals_) {
498  if (sp->presentFromSource(pid)) {
499  return sp->getGroup(pid);
500  }
501  }
502 
503  // Try new secondary files
504  while (true) {
505  int const err = tryNextSecondaryFile();
506  if (err == -2) {
507  // No more files.
508  return nullptr;
509  }
510  if (err == -1) {
511  // Run, SubRun, or Event not found.
512  continue;
513  }
514  assert(!secondaryPrincipals_.empty());
515  auto& new_sp = secondaryPrincipals_.back();
516  if (new_sp->presentFromSource(pid)) {
517  return new_sp->getGroup(pid);
518  }
519  }
520 
521  return nullptr;
522 }
523 
524 cet::exempt_ptr<Group const>
526 {
527  auto it = groups_.find(pid);
528  return it != groups_.cend() ? it->second.get() : nullptr;
529 }
530 
531 EDProductGetter const*
533 {
534  EDProductGetter const* result{getByProductID(pid).result().get()};
535  return result ? result : deferredGetter_(pid);
536 }
cet::exempt_ptr< ProductTable const > presentProducts_
Definition: Principal.h:271
GroupQueryResultVec findGroupsForProduct(WrappedTypeID const &wrapped, SelectorBase const &, bool stopIfProcessHasMatch) const
Definition: Principal.cc:278
std::unique_ptr< BranchMapper > branchMapperPtr_
Definition: Principal.h:284
bool presentFromSource(ProductID) const
Definition: Principal.cc:470
std::map< std::string, std::vector< ProductID >> ProcessLookup
Definition: type_aliases.h:15
size_t findGroupsFromInputFile(WrappedTypeID const &wrapped, SelectorBase const &, GroupQueryResultVec &results, bool stopIfProcessHasMatch) const
Definition: Principal.cc:334
GroupCollection groups_
Definition: Principal.h:280
const std::string label
std::string friendlyClassName() const
Definition: TypeID.cc:33
ProcessHistory processHistory_
Definition: Principal.h:268
void removeCachedProduct(ProductID const pid) const
Definition: Principal.cc:259
STL namespace.
cet::exempt_ptr< Group const > getGroup(ProductID const pid) const
Definition: Principal.cc:525
int tryNextSecondaryFile() const
Definition: Principal.cc:184
cet::exempt_ptr< ProductTable const > producedProducts_
Definition: Principal.h:272
GroupQueryResult getBySelector(WrappedTypeID const &wrapped, SelectorBase const &) const
Definition: Principal.cc:110
std::unique_ptr< DelayedReader > store_
Definition: Principal.h:288
RangeSet const & rangeOfValidity() const
Definition: OutputHandle.h:78
cet::exempt_ptr< Group const > getResolvedGroup(ProductID const pid, bool resolveProd) const
Definition: Principal.cc:452
bool processHistoryModified_
Definition: Principal.h:277
TypeID wrapped_product_type
Definition: WrappedTypeID.h:23
OutputHandle getForOutput(ProductID const, bool resolveProd) const
Definition: Principal.cc:424
static collection_type const & get()
size_t findGroups(ProcessLookup const &, SelectorBase const &, GroupQueryResultVec &results, bool stopIfProcessHasMatch, TypeID wanted_wrapper=TypeID{}) const
Definition: Principal.cc:355
void addToProcessHistory()
Definition: Principal.cc:80
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
GroupQueryResultVec getMatchingSequence(SelectorBase const &) const
Definition: Principal.cc:195
std::map< ProductID, std::shared_ptr< DeferredProductGetter const > > deferredGetters_
Definition: Principal.h:275
std::string const & processName() const
std::vector< GroupQueryResult > GroupQueryResultVec
Definition: Principal.h:54
GroupQueryResultVec getMany(WrappedTypeID const &wrapped, SelectorBase const &) const
Definition: Principal.cc:178
void swap(art::HLTGlobalStatus &lhs, art::HLTGlobalStatus &rhs)
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
EDProductGetter const * productGetter(ProductID const pid) const
Definition: Principal.cc:532
TH2F * hist
Definition: plot.C:136
int nextSecondaryFileIdx_
Definition: Principal.h:297
GroupQueryResultVec matchingSequenceFromInputFile(SelectorBase const &) const
Definition: Principal.cc:247
ProcessConfiguration const & processConfiguration_
Definition: Principal.h:270
cet::exempt_ptr< Group const > result() const
ProcessHistory const & processHistory() const
Definition: Principal.h:132
HLT enums.
static OutputHandle invalid()
Definition: OutputHandle.h:52
bool match(BranchDescription const &p) const
Definition: SelectorBase.h:23
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
size_t findGroupsForProcess(std::vector< ProductID > const &vpid, SelectorBase const &selector, GroupQueryResultVec &results, TypeID wanted_wrapper) const
Definition: Principal.cc:377
EDProductGetter const * deferredGetter_(ProductID const pid) const
Definition: Principal.cc:412
std::vector< std::unique_ptr< Principal > > secondaryPrincipals_
Definition: Principal.h:293
GroupQueryResult getByProductID(ProductID const pid) const
Definition: Principal.cc:131
static auto emplace(value_type const &value)
ProductStatus present()
Definition: ProductStatus.h:16
cet::exempt_ptr< Group const > getGroupForPtr(ProductID const pid) const
Definition: Principal.cc:481
GroupQueryResult getByLabel(WrappedTypeID const &wrapped, std::string const &label, std::string const &productInstanceName, std::string const &processName) const
Definition: Principal.cc:143
virtual void setProcessHistoryID(ProcessHistoryID const &)=0