- Table of contents
- Declaring products to consume
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
ProductToken
s orViewToken
s (as returned by the'consumes'
calls) to theget*
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 ofEvent
,SubRun
,Run
, orResults
.tag
is of typeart::InputTag
.- The "consumes" calls that take the
InDataLevel
argument are necessary for products that are retrieved at theSubRun
,Run
, andResults
levels; onlyEvent
-level retrievals do not require a specification ofInEvent
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:
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 anif (condition) { auto const& h = e.getValidHandle(...); }
'if'
-like block) represents an unconditional attempt at product retrieval
This is because theHandle<Prod> h; if (e.getByLabel(..., h)) { // ... }
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
orstdout
(case-insensitive)cerr
orstderr
(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.