Project

General

Profile

Declaring products to consume

As mentioned here, products are retrieved (or consumed) by calling any of the get* interface provided by the Event, SubRun, Run, or Results data-containment objects. As of art 2.08.00, it is possible and encouraged to declare through "consumes" expressions which products will be retrieved by a given module. Doing so is beneficial for several reasons:

  • It unambiguously tells any reader of the module source code which products will be consumed by that module
  • Providing ProductTokens or ViewTokens (as returned by the 'consumes' calls) to the get* interface can allow for more expedient data-product retrieval
  • It can allow art to detect data-dependency errors introduced by mis-constructed paths in a user's configuration
  • It can allow art to schedule modules in a way that increases parallelism in executing user-provided module overrides

When and how do I call consumes?

A "consumes" function should be called for all products with a few exceptions. The following table shows what consumes call should be made depending on how the product is retrieved. In what follows:

  • DataLevel is a placeholder for any of Event, SubRun, Run, or Results.
  • tag is of type art::InputTag.
  • The "consumes" calls that take the InDataLevel argument are necessary for products that are retrieved at the SubRun, Run, and Results levels; only Event-level retrievals do not require a specification of InEvent when calling a "consumes" function.
  • Unconditional retrieval means that an attempt to retrieve the product is made each time the framework calls the module override.
  • Conditional means that an attempt to retrieve the product is not always made each time the framework calls the module override. One of the ways this can happen is if a user places the product-retrieval call inside of an 'if' block--for example:
    if (condition) { 
      auto const& h = e.getValidHandle(...); 
    }
    
    There are other ways, however, in which product retrieval can be conditional. It is up to the module author to know in which circumstances unconditional vs. conditional consumes calls should be made. Note that the following code block (assuming it does not lie within an 'if'-like block) represents an unconditional attempt at product retrieval
    Handle<Prod> h;
    if (e.getByLabel(..., h)) { 
      // ... 
    }
    
    This is because the e.getByLabel(...) call is not made inside of an 'if' block, but it is made to determine whether or not the 'if' block should be entered.
Data-retrieval call Consumes expressions Consumes call
return type
Unconditional retrieval Conditional retrieval
DataLevel::getByLabel consumes<Prod>(tag)
consumes<Prod, InDataLevel>(tag)
mayConsume<Prod>(tag)
mayConsume<Prod, InDataLevel>(tag)
ProductToken<Prod>
DataLevel::getByToken
DataLevel::getPointerByLabel
DataLevel::getValidHandle
DataLevel::getMany consumesMany<Prod>()
consumesMany<Prod, InDataLevel>()
mayConsumeMany<Prod>()
mayConsumeMany<Prod, InDataLevel()
void
DataLevel::getManyByType
DataLevel::getView consumesView<Elem>(tag)
consumesView<Elem, InDataLevel>(tag)
mayConsumeView<Elem>(tag)
mayConsumeView<Elem, InDataLevel>(tag)
ViewToken<Elem>
DataLevel::get No "consumes" call available.

Product tokens

Product tokens are opaque objects1 that are returned when calling (some of) the "consumes" functions. They are objects of type ProductToken<Prod> for normal product lookup, or of type ViewToken<Elem> when the retrieved product is represented as an art::View<Elem> or an std::vector<Elem const*>. The tokens can be provided to data-level objects for looking up products.

1 Besides their copy and move constructors, product tokens and view tokens can be constructed only by the framework.

Consider the following class definition:

class POTSummaryInspector : public art::EDAnalyzer {
public: 

  // Allowed configuration
  struct Config {
    fhicl::Atom<string> label { fhicl::Name{"label"} };
  };
  using Parameters = Table<Config>;

  explicit POTSummaryInspector(Parameters const& p);

private:

  void endSubRun(art::SubRun const&) override;

  art::InputTag const tag_;
  art::ProductToken<POTSummary> const summaryToken_;
};

The private data members have been marked const to illustrate that once they have been initialized for a given module of type POTSummaryInspector, they will not change for the lifetime of that module.

The constructor of this class, with its "consumes" call, looks like:

POTSummaryInspector::POTSummaryInspector(Parameters const& p) : 
  tag_{p().label()},
  summaryToken_{consumes<POTSummary, art::InSubRun>(tag_)}
{}

Now that the product token has been initialized, it can be provided to the SubRun object for product lookup:

void POTSummaryInspector::endSubRun(art::SubRun const& sr)
{
  // Require handle to be valid  
  auto const& potH1 = sr.getValidHandle(summaryToken_);
  // ...

  // Product allowed to not be present
  art::Handle<POTSummary> potH2;
  if (sr.getByToken(summaryToken_, potH2)) {
    // ...
  }
}

The same pattern is used for unconditional and conditional retrievals of products and views.

Command-line diagnostics for consumes

 --mt-diagnostics, -M <destination>

To assist users in determining which consumes calls should be made, the --mt-diagnostics (or -M) option should be used, where the argument is a supplied messagefacility-destination specification. For example:

art -c ... -M stdout

will output consumes-related information to standard output. The allowed values for the destination are:

  • cout or stdout (case-insensitive)
  • cerr or stderr (case-insensitive)
  • Anything else is interpreted to be a file name (/dev/null falls in this category)

For each module that retrieves products without providing a consumes statement, an output similar to the following will be provided at the end of the job:

============================================================
The following consumes (or mayConsume) statements are missing from
module label: 'o2#rpr2' of class type 'RPTestReader'
------------------------------------------------------------
  consumes<arttest::IntProduct, art::InResults>("o2#rpw");
============================================================

Note that art cannot know, in general, if consumes or mayConsume is the appropriate call to make. It is the responsibility of the user to provide the appropriate call2.

2 Instead of providing the literal value of the InputTag (i.e. "o2#rp2"), the user presumably provides a variable inputTag_ that is configurable at run-time.
 

 --errorOnMissingConsumes

At some point, it will become mandatory for consumes information to be provided by user modules. A failure to specify the appropriate consumes statement will trigger a run-time exception that, if thrown, will gracefully shutdown the program. One can require the presence of consumes information by specifying the --errorOnMissingConsumes program-option on the command line. On the first attempt to retrieve a product that is missing a consumes statement, an exception will be thrown, leading to a graceful shutdown of the process. This behavior is not the default behavior, but it will eventually become so.