Getting Data from the EventSetup

Complete: 3

Data Model

An EventSetup object holds Records and Records in turn hold data. The data is uniquely identified by
  • C++ type of the data
  • a string label (which defaults to the empty string)

ESInputTag

NOTE: ESInputTag was added in CMSSW_3_1_0

The string label is recommended to be expressed as ESInputTag (similar to InputTag for Event products). The ESInputTag has two compoments

  • module label: the label of the ESProducer. It is not used for the data product lookup, but it is used as a cross-check after the product has been found. Empty value corresponds to a wild card matching to any module.
  • product label: the label of the product (string passed to setWhatProduced() call in ESProducer). Can be empty.

Example of constructing ESInputTag in python configuration

cms.ESInputTag("moduleLabel", "productLabel")

and in C++ code

edm::ESInputTag("moduleLabel", "productLabel");

ESGetToken

NOTE: ESGetToken was added in CMSSW_10_4_0

When registering what data is to be requested, see consumes below, the registration function returns or sets a edm::ESGetToken<PROD, REC> which must be used to get the specific data.

Registering for data access

In ESProducer

The setWhatProduced() call returns an edm::ESConsumesCollector (the type REC is the Record type that the producing function given to setWhatProduced() takes as an argument). The collector is then used to register all the data products that may be accessed by the producing function. If the ESProducer registers multiple producing functions, the data access needs to be registered separately for each of them.

Some examples

class Producer: public edm::ESProducer {
  ...
  std::unique_ptr<AnyProduct> produce(SomeRecord const& iRecord);
  ...
  edm::ESGetToken<SomeProduct, SomeRecord> token1_;
  edm::ESGetToken<AnotherProduct, DependentRecord> token2_;
  edm::ESGetToken<ThirdProduct, AnyRecord> token3_;
};

...

Producer::Producer(edm::ParameterSet const& iConfig) {
  auto cc = setWhatProduced(this);

  // Register data access from the same record as the produce() argument
  token1_ = cc.consumes<SomeProduct>();

  // Register data access from a dependent record of the produce() argument
  token2_ = cc.consumesFrom<SomeProduct, DependentRecord>();

  // Use type deduction to register data access from the same or the dependent record
  // Returns edm::ESConsumesCollector, so setConsumes() calls can be chained
  cc.setConsumes(token3_);
}

All of the functions above (consumes(), consumesFrom(), setConsumes()) take also an edm::ESInputTag as an optional argument.

NOTE: the proper way to migrate from iRecord.get(handle, label) is edm::ESInputTag{"", label}.

In ED module

NOTE: at the moment the consumption of EventSetup products does not have to be registered in ED modules

In an ED module the EventSetup data access registration follows the Event data access registration. The function to be called is esConsumes<PROD, REC>(edm::ESInputTag), which returns edm::ESGetToken<PROD, REC>. The edm::ConsumesCollector also has this function.

Accessing Data

Getting data from EventSetup (with token)

If the caller always needs the product, the product object can be asked for directly as in below. If the product (or record) is missing, an exception is thrown.

auto const& data = iEventSetup.getData(token_);
If the caller want's to check whether the data product exists, it can ask for the handle (edm::ESHandle). Note that in case the Record of the data product is missing, an exception is thrown.
if(auto handle = iEventSetup.getHandle(token_)) {
    auto const& data = *handle;
  }
  else {
    // handle missing product
  }
If the caller wants to optimize the memory usage, the edm::ESTransientHandle must be asked for (for both cases of always accessing the product, or handling for the missing product)
auto transientHandle = iEventSetup.getTransientHandle(token_));

Getting a Record from the EventSetup (without token)

A Record can be returned from the EventSetup by calling the get<> templated method

const FooRecord& fooRecord = iEventSetup.get<FooRecord>();
If the Record is not available, an exception will be thrown.

Getting data from a Record

With token

Getting data product from a Record with edm:ESGetToken<PROD, RECO> is similar to getting the product from EventSetup (only difference being replacing getData() with get())

If the caller always needs the product, the product object can be asked for directly as in below. If the product (or record) is missing, an exception is thrown.

auto const& data = iRecord.get(token_);
If the caller want's to check whether the data product exists, it can ask for the handle (edm::ESHandle). Note that in case the Record of the data product is missing, an exception is thrown.
if(auto handle = iRecord.getHandle(token_)) {
    auto const& data = *handle;
  }
  else {
    // handle missing product
  }
If the caller wants to optimize the memory usage, the edm::ESTransientHandle must be asked for (for both cases of always accessing the product, or handling for the missing product)
auto transientHandle = iRecord.getTransientHandle(token_));

Without token

A data item can be retrieved from an EventSetup Record by passing an ESHandle<> to the Record's get method
edm::ESHandle<Foo> fooH;
  fooRecord.get(fooH);
If a label other then the default empty label is assigned to the data, you must pass that label as the first argument to get
edm::ESHandle<Foo> fooH;
  fooRecord.get("bar", fooH);
If the data item request can not be found, an exception will be thrown.

Behind the scenes, the EventSetup system only runs the algorithm used to create the data in a Record the first time that data is requested after a Record has changed its IOV. All subsequent requests will get the cached value.

Optimizing memory usage

If the data item will not be held (e.g. via a pointer) by the module for use later and only needs to be accessed once per IOV (say because the data item is read and then a new data structure is created from that data) then you should use an ESTransientHandle<> instead of an ESHandle<>. If all modules which access this data item use an ESTransientHandle<> then the data item will be deleted after the framework has finished processing of the event during which the data item was obtained. This allows the framework to reclaim memory which will no longer be needed. If at least one module still access the data item via an ESHandle<> then the data item will not be deleted and will remain in memory for the full IOV. If you need to access the data item for each event then you should still use an ESHandle<> in order to avoid having the data item created and deleted each event.

If you have any doubt as to whether you should use an ESHandle<> or an ESTransientHandle<> you should pick the ESHandle<>.

Getting data each time a Record changes

Accessing data from the EventSetup system is very efficient, so it is normally fine to access the data again for each new Event. However, there are times when you want to do a complex calculation only when the data in a Record has changed and then cache the results of the calculation. The edm::ESWatcher<> class is available to make it easier to watch for Record changes.

Seeing that a Record has changed

The simplest use of a edm::ESWatcher<> is to use it to return a true everytime a Record has changed since the last time the edm::ESWatcher<> was called. To do this
  1. Add an edm::ESWatcher<> with the template argument being the Record you want to watch as a member data to the class which wants to know when a Record changes [E.g. as a member data of an EDProducer ]
  2. Call the check(const edm::EventSetup&) method of the edm::ESWatcher<> to see if the Record has changed since the last call.

class FooWatcher : edm::EDAnalyzer {
  ...
  edm::ESWatcher<FooRecord> fooWatcher_;
};

void FooWatcher::analyze(const edm::Event&, const edm::EventSetup& iSetup ) {
   if ( fooWatcher_.check(iSetup) ) {
     std::cout <<"a new FooRecord is available"<<std::endl;
     ...

Calling a function when a Record changes

It is also possible to register a function to be called whenever a Record changes. To make use of this facility you
  1. Add an edm::ESWatcher<> with the template argument being the Record you want to watch as a member data to the class which wants to know when a Record changes [E.g. as a member data of an EDProducer ]
  2. Pass the function to be called as an argument to the edm::ESWatcher<> 's constructor.
  3. Call the check(const edm::EventSetup&) method of the edm::ESWatcher<> to see if the Record has changed since the last call.

class FooWatcher : edm::EDAnalyzer {
  ...
  //will be called each time FooRecord changes
  void newFoo(const FooRecord&);

  edm::ESWatcher<FooRecord> fooWatcher_;
};

void FooWatcher::FooWatcher(...) :
  ...
  fooWatcher_(this, &FooWatcher::newFoo) { ... }

void FooWatcher::analyze(const edm::Event&, const edm::EventSetup& iSetup ) {
   //automatically calls 'newFoo()' each time FooRecord changes
   fooWatcher_.check(iSetup);
     ...
} 

void FooWatcher::newFoo(const FooRecord& iRcd)
{ ... }

Review Status

Main.chrjones - 17 Sep 2007 - Page Author


Responsible: Main.chrjones
Edit | Attach | Watch | Print version | History: r9 < r8 < r7 < r6 < r5 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r9 - 2019-05-24 - ChrisDJones



 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    CMSPublic All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright & 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback