Feature #18979

Retrieve art::InputTag by art::ProductID

Added by Gianluca Petrillo about 3 years ago. Updated almost 3 years ago.

Target version:
Start date:
Due date:
% Done:


Estimated time:
2.00 h
Spent time:
SSI Package:


I find that getting a data product by product ID fails unless the product has already been read.
This is the result of my attempt to solve a LArSoft issue reported via e-mail by David Caratelli.

Less-than-minimal example

The attached example is comprised of a module source code, its CMakeLists.txt (untested in that form, sorry) and a job configuration.
The attached module reads the association, then reads the first cluster pointer (but not the cluster itself!), and tries to get the product with the ID from that art pointer. If it fails (and oh it verily does), it throws an exception.
A line commented out reads and discards a handle to a cluster collection I know beforehand the associated clusters belong to. When that line is put back in, the get() call succeeds.

Run outcome

To run it form woof:

lar -c davidtest.fcl -s /home/petrillo/LArSoft/software/build/develop/debug/input/test_v06_26_01_08_bnbon.root

The output I get ends with:
%MSG-s ArtException:  PostEndJob 12-Feb-2018 19:02:58 CST ModuleEndJob
cet::exception caught in art
---- OtherArt BEGIN
  ---- EventProcessorFailure BEGIN
    EventProcessor: an exception occurred during current event processing
    ---- EventProcessorFailure BEGIN
      EndPathExecutor: an exception occurred during current event processing
      ---- ScheduleExecutionFailure BEGIN
        Path: ProcessingStopped.
        ---- ProductNotFound BEGIN
          Clusters with ID=3022751813 not found.
          cet::exception going through module DavidTest/davidtest run: 5412 subRun: 36 event: 1806
        ---- ProductNotFound END
        Exception going through path end_path
      ---- ScheduleExecutionFailure END
    ---- EventProcessorFailure END
  ---- EventProcessorFailure END
---- OtherArt END

(note that the exception is thrown by user code checking whether the read was successful, not by art).

Compilation of the example

The input I have been given can be found at: It contains, among other things, a collection of recob::Cluster and associations of those to some recob::PFParticle.

For compilation, a MicroBooNE setup is required (source /cvmfs/ followed by a regular MRB setup with LArSoft/uboonecode v06_67_01.

CMakeLists.txt (149 Bytes) CMakeLists.txt cmake build directives (cetbuildtools) Gianluca Petrillo, 02/12/2018 07:12 PM
davidtest.fcl (209 Bytes) davidtest.fcl test job configuration Gianluca Petrillo, 02/12/2018 07:12 PM (2.21 KB) test module source code Gianluca Petrillo, 02/12/2018 07:12 PM

Related issues

Related to art - Support #19143: event.get method acting unexpectedlyClosed02/26/2018

Blocks LArSoft - Feature #18980: Failure of FindManyInChainP when the associated products haven't been read yetAccepted02/12/2018


#1 Updated by Gianluca Petrillo about 3 years ago

  • Blocks Feature #18980: Failure of FindManyInChainP when the associated products haven't been read yet added

#2 Updated by Kyle Knoepfel about 3 years ago

  • Status changed from New to Feedback

Yes, the behavior is implemented exactly as you describe. What is the use case for needing to resolve a product explicitly (via e.get(id, handle)) instead of allowing the automatic product resolution to happen whenever an art::Ptr is resolved?

#3 Updated by Gianluca Petrillo about 3 years ago

The actual use case is to get the metadata, and in particular the input tag, from an art pointer.
The pattern I implemented is art::Ptr --(1)--> art::ProductId --(2)--> art::Handle --(3)--> metadata.
The step (2) is where the failure happens.

#4 Updated by Kyle Knoepfel about 3 years ago

That is a heavy-handed approach to getting the art::InputTag. You can get the input tag without reading a product. For your case, I suggest doing the following for art 2.09.06 (this will be quite a bit easier to do in art 3.00.00):

#include "art/Persistency/Provenance/ProductMetaData.h" 

art::InputTag get_input_tag(art::ProductID const pid)
  auto const& products = art::ProductMetaData::instance().productList();
  for (auto const& pr : products) {
    auto const& bd = pr.second;
    if (bd.productID() == pid) {
      return art::InputTag{bd.moduleLabel(), bd.productInstanceName(), bd.processName()};
  return art::InputTag{};

Note that this function can be called (in principle) in the constructor of the module, instead of needing to find the art::InputTag anew for every event.

It would not be unreasonable to request that art provide this facility.

Does this meet your needs?

#5 Updated by Gianluca Petrillo about 3 years ago

It does. It also slaps multithreading in its face with both hands at once, but I can live with that as long as it will produce a clear failure when multithreading is introduced (i.e. as long it's not my face).
That is guaranteed by the disappearance of product list with art 3. If you opt for removing it earlier than that, then my request would be for the use case I report here to be supported in some other way.

About requesting this as a feature: I would love that, or anything like template <typename Event> art::InputTag get_input_tag(Event const& event, art::ProductID const& id).
But if the implementation is as shown, it should be well documented that using it in a loop is not efficient.

Last thing: if art::Event::get() behaves now as it is expected to do, that behaviour should be documented. My opinion is that as it works now, that method is harmful in the public interface, but you may differ.

#6 Updated by Kyle Knoepfel almost 3 years ago

  • Related to Support #19143: event.get method acting unexpectedly added

#7 Updated by Kyle Knoepfel almost 3 years ago

  • Tracker changed from Bug to Feature
  • Subject changed from Can't get data product by ID to Retrieve art::InputTag by art::ProductID
  • Status changed from Feedback to Assigned
  • Assignee set to Kyle Knoepfel
  • Target version set to 2.11.00
  • Estimated time set to 2.00 h
  • Occurs In deleted (2.09.06)

#8 Updated by Kyle Knoepfel almost 3 years ago

  • Category set to Metadata
  • Status changed from Assigned to Resolved
  • % Done changed from 0 to 100

This feature has been implemented by providing a member function of art::ProductMetaData:

#include "art/Persistency/Provenance/ProductMetaData.h" 

void f()
  using namespace art;
  ProductID const pid{...};
  InputTag const tag = ProductMetaData::instance().inputTag(pid);

  // art::InputTag::empty() added for art 2.11
  if (tag.empty()) { 
    // Bad ProductID

If the provided ProductID corresponds to a product that is known to art, the corresponding InputTag will be returned. Otherwise, tag will be empty.

For a multi-threaded art (3.00.00), this will be done is through the (e.g.) art::Event:

void MyAnalyzer::analyze(art::Event const& e) override
  ProductID const pid{...};
  auto pd = e.getProductDescription(pid);

  if (pd != nullptr) {
    auto const tag = pd->inputTag();
    assert(!tag.empty()); // Will be guaranteed to be non-empty in this case

Note that the BranchDescription class has also gained the accessor inputTag() as of art 2.11.00.

Implemented with commits:

#9 Updated by Kyle Knoepfel almost 3 years ago

  • Status changed from Resolved to Closed

Also available in: Atom PDF