Writing a new ESProducer

Complete: 3

Overview of ESProducer's purpose

As a reminder, the job of an ESProducer is to add data to one or more EventSetup Records. How this is done is as follows. The constructor of the ESProducer announces what data it is capable of creating via the setWhatProduced method. Then the first time a piece of code asks for the data after the Record has had an IOV change, the appropriate method will be called on the ESProducer (normally the produce method). The EventSetup system will then cache that data into the Record where subsequent data requests during that same IOV will get the cached value rather than calling the ESProducer again.

The simple way

  1. Make the ESProducer skeleton using mkesprod
  2. Edit the produce method
  3. Make sure the data types you are returning have been registered

The manual way

  1. Create your ESProducer class by having it inherit from ESProducer
  2. The constructor must take an const ParameterSet&
  3. In the constructor do setWhatProduced(this) this allows the compiler to deduce what data you are creating and what Record that data must be placed in.
  4. Declare your produce method
    1. The argument must be a const reference to the EventSetup Record into which you wish to place data
    2. The return type must be either
      1. The vast majority of the time the return type of produce should be a std::unique_ptr<T>, where T is the class type of produced data. In most cases, use of other types is discouraged.
      2. A std::shared_ptr can be used if you want to reuse the object over different calls to produce. Usually this occurs when a ReusableObjectHolder is used. There may be other special cases, but special care must be taken to be sure things work properly when running in a mode where multiple IOVs are processed concurrently.
      3. The template parameter of a std::unique_ptr or std::shared_ptr can be declared const, although this is usually not necessary. This is only needed in a few rare cases. One such case, would be where the produce method always returns the same object with the same values. The product is shared by different IOVs, but is always the same (it really is const). Another case would be when some library external to the ESProducer creates the object as const and you need to avoid having a const_cast when constructing the smart pointer. Whether or not it is declared const in the return type of produce, the product will always only be available as const from an ESHandle.
      4. A std::optional. This is only useful in rare cases.
      5. A edm::ESProducts<> (was edm::eventsetup::ESProducts<> in CMSSW_0_1_0) whose template arguments are std::unique_ptr or std::shared_ptr to the objects being created. This is necessary when a single produce function returns multiple products.
    3. Note: std::unique_ptr and std::shared_ptr are supported beginning in CMSSW_8_1_X and CMSSW_8_0_X respectively. For prior releases, use std::auto_ptr or boost::shared_ptr , both of which are no longer supported going forward.
  5. Write your produce method
    1. If you are returning multiple object, do return products(...) with the arguments being the objects you want returned
  6. Make sure the data types you are returning have been registered

Labels

The EventSetup system allows data to be retrieved from a Record using an optional label (when the label is not given, the 'get' method uses the default empty string). This label is intended to allow one to have multiple instances of the same C++ type in one Record (e.g., multiple geometry instances, each for a different sub-detector).

In CMSSW_1_7_0_pre2 the string parameter named appendToDataLabel was added to all ESProducer and ESSource modules. If a value is assigned to appendToDataLabel then that value is appended to any 'get' label which has been assigned in the C++ code. If the 'get' label was never defined (so it was given the default of an empty string) then the value of appendToDataLabel becomes the full label.

Using one label

If you want all the data items created by a 'produce' method to have the same label, just pass the label as the last argument of your 'setWhatProduced' call.
   setWhatProduced(this, "blah");

Using multiple labels

If you wish to return multiple items of the same type from your produce method then the ESProducts type you return must distinguish between these multiple instances. This is handled using the edm::es::L helper class (L stands for Label). The edm::es:L class takes two template arguments: the type of the C++ object to be returned and an integer. The integer is used to distinguish between the different instances of the same C++ type which is being returned by the produce method. The integer is mapped to an actual string label in the call to setWhatProduced.

The recommended method is as follows

  1. Create an 'enum' which contains values corresponding to the labels you want to use
    1. enum { kFi, kFum };
  2. When specifying the template arguments to the ESProducts<> returned by your produce method, use the class edm::es::L< <C++ type>, <enum value> >
    1. typedef ESProducts< edm::es::L<Foo,kFi>, edm::es::L<Foo,kFum> > ReturnType;
  3. In the setWhatProduced method, use the helper function edm::es::label to associate the enum values with their corresponding label string
    1. setWhatProduced(this, edm::es::label("fi",kFi)("fum",kFum));
  4. In the produce method, you have two options to hold the instance of the objects being created
    1. use the edm::es::L as a smart pointer and then pass it directly to edm::es::products
      1. edm::es::L<Foo,kFi> fi = new Foo();
    2. use either a std::shared_ptr<> or std::unique_ptr<> and then in the edm::es::products call use the helper function edm::es::l to associate this object with the proper enum value.
      1. std::unique_ptr<Foo> fum = new Foo();
    3. return edm::es::products( fi, edm::es::l<kFum>(fum));

Advanced

multiple producing methods

The simplest way to write an ESProducer that must create multiple objects is to create a produce method that creates those objects. However, sometimes you may not want to create all those objects at the same time or in the same EventSetup Record. In that case, you can register multiple producing methods in your ESProducer.
  1. Declare your producing methods using what ever name you want, although the arguments and return value must be the same as a regular produce method
    1. std::unique_ptr<Foo> produceFoo(const FooRcd&)
  2. In the ESProducer's constructor, do setWhatProduced(this, &<producer's class name>::<producing method name>) for each producing method you want to use
    1. setWhatProduced(this, &FooProducer::produceFoo)

If you have multiple 'setWhatProduced' calls, they can each have different or the same labels.

   setWhatProduced(this); //used default label
   setWhatProduced(this, &FooProducer::produceFoo); //used default label
   setWhatProduced(this, &FooProducer::produceFloo, "floo");

watching for IOV changes on dependent Records

An ESProducer is allowed to get data from a Record other than the one to which it is placing data, provided that other Record was declared as a dependency. Under such a condition, it is useful to know when the other Record has gone to a new IOV interval and therefore the data in that Record has changed. To handle such a case, one can register a 'callback' to be called just before the produce method for the case where the other Record's IOV has changed since the last time produce was called.

  1. add a member function to your ESProducer to be used as the callback
    1. the argument should be a const reference to the Record you want to watch
    2. the return value should be void
      1. void doWhenChanged(const ParentRcd&)
  2. modify your setWhatProduced call to take an additional argument which should be dependsOn( &<prod class name>::<callback name>).
    1. setWhatProduced(this,dependsOn(&MyProducer::doWhenChanged))

lower level interfaces

The class ESProducer is actually the 'highest level' interface for writing algorithms to plug into the EventSetup. Two other interfaces may also be used: ESProxyFactoryProducer (formerly named eventsetup::ProxyFactoryProducer ) and edm::eventsetup::DataProxyProvider. The latter is the lowest level interface which is used internally by the EventSetup system while the former provides management of the underlying edm::eventsetup::DataProxy objects. These interfaces are primarily used if you need to be able to at run time change what data objects are to be delivered by the Producer. For an algorithmic Producer that would be an extremely rare case. However, an ESSource may very well wish to decide what data objects it should create at run time because the underlying persistency mechanism it is reading from may allow the storage of different objects.

Review Status

Reviewer/Editor and Date (copy from screen) Comments
ChrisDJones - 29 Jul 2005 page author
ChrisDJones - 19 Jan 2007 page content last edited
JennyWilliams - 07 Feb 2007 editing to include in SWGuide
WilliamTanenbaum - 04 Mar 2016 update for std::shared_ptr and std::unique_ptr

Responsible: ChrisDJones
Last reviewed by: Reviewer

Edit | Attach | Watch | Print version | History: r16 < r15 < r14 < r13 < r12 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r16 - 2018-11-09 - DavidDagenhart



 
    • 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