Project

General

Profile

Run and SubRun products

Runs and subruns are open-ended entities, from the viewpoint of art--i.e. art allows multiple instances of a Run and a SubRun with the same identification numbers. This can happen whenever a Run or SubRun spans multiple files. Up through art 2.00.02, if a (e.g.) run product had been read for a given Run, and if a subsequent file contained another instance of that same product for the same Run, the second run product would have been ignored. Although this behavior is appropriate for products that are intended to represent a full run, such behavior is incorrect for products that were assembled based on the events that were seen for that Run. For 2.01.00 and newer, the set of events seen in creating a Run and SubRun product will be recorded in each output file. This way, art, and the user, can know to which events a given product corresponds--this set of events (and/or sub-runs) is called a range of validity, which is represented by the art::RangeSet in C++.

Although it will not usually be necessary to interact directly with the art::RangeSet object, the user will be able to access the range of validity via the art::(Valid)Handle:

void beginRun(art::Run const& r) override
{
  auto const& h = r.getValidHandle<MyProduct>(...);
  auto const& rov = h.provenance()->rangeOfValidity();
}

It will, however, be necessary to indicate to art the appropriate range of validity for a product that is 'put' onto a SubRun or Run. This is done by providing a product semantic as an argument to 'put'.

Product semantics and (Sub)Run::put

[ For all examples below, the analogous SubRun behaviors are achieved by replacing "fullRun" and "runFragment" with "fullSubRun" and "subRunFragment", respectively. ]

art::fullRun()

Products that represent a full run -- i.e. they do not represent the result of having processed a given set of events corresponding to that run -- are denoted by specifying art::fullRun() as a function argument to put:

void MyProducer::beginRun(Run& r)
{
  ...
  r.put(std::move(anon), art::fullRun());
  r.put(std::move(named), "instance1", art::fullRun());
}

The product will then be assigned a range-of-validity that corresponds to the entire run.

art::runFragment()

For products that are created as a result of having processed a given set of events or sub-runs, the art::runFragment() semantic is specified as a function argument to put:

void MyProducer::endRun(Run& r)
{
  ...
  r.put(std::move(anon), art::runFragment());
  r.put(std::move(named), "instance2", art::runFragment());
}

This specifies that the range-of-validity assigned to the product is the set of events that were processed between the previous call to endRun and the current call.

N.B. It is a run-time error to specify the art::runFragment() semantic at beginRun.

art::runFragment(RangeSet const&)

In some cases (see here for how to handle such a case), it may be necessary for a user to explicitly specify the range-of-validity. In that case, the art::runFragment function accepts an argument, which is a const reference to an art::RangeSet object.

void MyProducer::beginRun(Run& r)
{
  ...
  auto const& rov = h.provenance()->rangeOfValidity();
  r.put(std::move(anon), art::runFragment(rov));
  r.put(std::move(named), "instance3", art::runFragment(rov));
}

Important: Compile-time check for aggregation behavior

For those who use either of the art::runFragment calls above (or corresponding art::subRunFragment calls), it is required that an aggregation behavior be defined for the C++ type of the product that is being 'put'. For user-defined classes, this means that an aggregate member function must exist. See here for details.

Unspecified semantic

A user who puts a product onto the Run with no specified semantic gives art permission to internally specify the semantic depending on where the call is made.

void MyProducer::beginRun(Run& r) // ===> implies 'art::fullRun()'
{
  ...
  r.put(std::move(anon));
  r.put(std::move(named), "instanceA"); 
}
void MyProducer::endRun(Run& r) // ===> implies 'art::runFragment()'
{
  ...
  r.put(std::move(anon));
  r.put(std::move(named), "instanceB"); 
}

Although an unspecified-semantic interface supports backwards compatibility with earlier versions of art, it also introduces the potential for an exception to be thrown if (a) multiple Run fragments corresponding to the same Run are present in an input file, and (2) no default aggregation behavior is available for one or more of the Run products.

Product aggregation

Because of the (Sub)Run fragmentation that can occur with output-file switching, it is possible that (1) an art/ROOT file may contain multiple fragments of a given Run or SubRun, and (2) that a given Run or SubRun can be split up across multiple files. However, upon reading that file in a subsequent process, only one Run or SubRun will be presented to the user, and any products retrieved for the Run or SubRun will be automatically aggregated. Upon aggregating the products, the ranges-of-validity are also aggregated, thus accurately preserving the set of events that were processed when creating the product.

Product aggregation occurs for fragments in the current input file. Product aggregation does not happen across input files for the current process. However, if the process is writing to one output file, the fragments from the multiple input files will be written to the same output file, and product aggregation will occur whenever that output file is read as input in a subsequent process.

The default aggregation behavior and instructions for customizing product-aggregation for various product types are given here.

Scenarios in which product aggregation occurs

Automatic product aggregation occurs only for Run and SubRun products, and only if the following conditions are satisfied:

  • Multiple product instances corresponding to the same product signature are found in an input file for a given Run or SubRun.
  • The multiple product instances must correspond to disjoint ranges to avoid double counting.

If both conditions are satisfied, then aggregation occurs. Some important points:

  • Product aggregation occurs only for products in the currently-processed input file.
  • Product aggregation occurs only for products that are (perhaps implicitly) specified as corresponding to a fragment.
  • Product aggregation does not occur across (Sub)Runs with different ID numbers.

For example, if run 1 spans two input files, beginRun will be called twice (once for each file open), and any run products presented to the user correspond to the aggregation of products for the currently open input file.