Project

General

Profile

Using the Framework » History » Version 56

Version 55 (Brian Rebel, 08/08/2012 02:42 PM) → Version 56/70 (Brian Rebel, 08/21/2012 01:36 PM)

{{toc}}

h1. Using the Framework

The ART framework uses a fairly basic structure for interacting with data - all the algorithms are stored in modules, the event information is accessed using objects living in the art namespace, etc. While the I/O uses ROOT, it is not based on TObjects in the ART framework. The objects that are stored in a file do not derive from TObject and it is likely that TObject derived objects will also not play nicely with the I/O. The reason for this is ROOT's way of handling pointer data members - ROOT does not store the fields for the data members of pointers, which means on readback those data members may or may not contain sensible information.

h2. Basic Concepts

The art namespace contains the handles to information stored in an event. Objects that are stored in an event are collectively known as data products. They can either be added to an event using an art::EDProducer derived module or they can be retrieved and operated on using an art::EDAnalyzer module. Once an object has been stored in the event, its data cannot be altered.

Other namespaces to be aware of are

* fhicl - the namespace corresponding to the ParameterSet information described below
* cet - the namespace where the exceptions and some other utilities live.
* mf - the namespace of the message logger facility

There is a link to interface for each concept in the heading for that concept.

h3. "art::EDProducer":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/entry/art/Framework/Core/EDProducer.h

This is a type of module that makes data products and stores them in the art::Event. The module takes a fhicl::ParameterSet in the constructor and uses that to configure that module.

The module can also implement a reconfigure method to allow for run time reconfiguration, for example while running the event display. Reconfiguration during a batch job would not make sense.

The user must supply the implementation for the art::EDProducer::produce() method to create and store data products and the art::EDProducer::reconfigure() method to allow for reconfiguration from the event display.

h3. "art::EDAnalyzer":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/entry/art/Framework/Core/EDAnalyzer.h

This is a type of module that analyzes data products but cannot write them in an art::Event. The module takes a fhicl::ParameterSet in the constructor and uses that to configure that module.

The module can also implement a reconfigure method to allow for run time reconfiguration, for example while running the event display. Reconfiguration during a batch job would not make sense.

The user must supply the implementation for the art::EDAnalyzer::analyze() method to analyze data products and the art::EDProducer::reconfigure() method to allow for reconfiguration from the event display.

h3. art::EDProducer(Analyzer)::beginJob, endJob, etc

These are methods that do tasks that are needed only once a job starts, ends, or a run starts or ends, etc. For example, a beginJob method would likely contain definitions of histograms that might need to be filled during the operation of the module.

h3. "art::Event.h":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/entry/art/Framework/Principal/Event.h

The art::Event is the primary way to access products made by EDProducer type modules.

It also provide the user with information about an event such as the run, event number, etc through methods like

<pre><code class="c">

// assume we have an art::Event &evt

// get the run number RunNumber_t is a typedef to unsigned int
art::RunNumber_t run = evt.run();

// get the subrun number SubRunNumber_t is a typedef to unsigned int
art::SubRunNumber_t subRun = evt.subRun();

// get the time stamp. art::Timestamp::value() returns a TimeValue_t which is a typedef to unsigned long long.
// The conventional use is for the upper 32 bits to have the seconds since 1970 epoch and the lower 32 bits to be
// the number of nanoseconds with the current second.
art::Timestamp ts = evt.time();

// make it into a TTimeStamp
uint32_t tslow = ts.timeLow();
uint32_t tshigh = ts.timeHigh();

TTimeStamp tts(tshigh, tslo);

// get the event number - this calls a reference to art::EventID(). EventNumber_t is a typedef to unsigned int
art::EventNumber_t event = evt.id().event();
</code></pre>

The header files for the classes mentioned above are at

"art::EventID.h":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/entry/art/Persistency/Provenance/EventID.h
"art::Timestamp.h":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/entry/art/Persistency/Provenance/Timestamp.h

The art::Event can also be used to access products by asking it to return an art::Handle.

h3. "art::Handle":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/entry/art/Framework/Principal/Handle.h

An art::Handle is what is returned to a Module when a data product is requested. The request can either be from a art::EDProducer that is attempting to get objects stored in a previous reconstruction or analysis step, or it can be from a art::EDAnalyzer that is attempting to do some analysis task using the information in the object. For example, to get the data product mp::MyProd from the event, one should do

<pre><code class="c">
art::Handle< std::vector<mp::MyProd> > mplistHandle;
evt.getByLabel("moduleprocesslabel",mplistHandle);
</code></pre>

where evt is an object of type art::Event discussed below. The art::Event::getByLabel method takes two arguments, the first is the name of the process associated with the module that produced the list of mp::MyProd objects, and the second is the art::Handle that is to be associated to the list.

You can also get all objects of a given type out of the event using the art::Event::getByType method:

<pre><code class="c">
art::Handle< std::vector<mp::MyProd> > mplistHandle;
evt.getByType(mplistHandle);
</code></pre>

Notice that no module label is used because we are getting all objects of the specified type out of the event.

art::Handles look like a pointer in the code in that the data members of the object being handled are accessed using the "->". For example, to get the size of the list one can do

<pre><code class="c">
mplistHandle->size();
</code></pre>

To use the objects in the handle collection, you can

* Use the art::Handle directly,
<pre><code class="c">
// in the code below, ev is an art::Event...
art::Handle<std::vector<mp::MyProd> > hnd;
ev.getByLabel("...", hnd); // use the appropriate label, not "..."

for(size_t i = 0; i < hnd->size(); ++i){
const mp::MyProd& mp = hnd->at(i);
}
</code></pre>

* Get the collection from the art::Handle,
<pre><code class="c">
// in the code below, ev is an art::Event...
art::Handle<std::vector<mp::MyProd> > hnd;
ev.getByLabel("...", hnd); // use the appropriate label, not "..."

std::vector<mp::MyProd>& mpvec(*hnd);
}
</code></pre>

* Make a std::list of art::Ptr<mp::MyProd>,
<pre><code class="c">
// in the code below, ev is an art::Event...
art::Handle<std::vector<mp::MyProd> > hnd;
ev.getByLabel("...", hnd); // use the appropriate label, not "..."

std::list<Ptr<mp::MyProd> > ptrs;
art::fill_ptr_list(ptrs, hnd);
// now ptrs contains Ptr<mp::MyProd> instances, each pointing
// to one of the rb::Tracks in the collection to which hnd
// refers.
</code></pre>

* Make a std::vector of art::Ptr<mp::MyProd>,
<pre><code class="c">
// in the code below, ev is an art::Event...
art::Handle<std::vector<mp::MyProd> > hnd;
ev.getByLabel("...", hnd); // use the appropriate label, not "..."

std::vector<Ptr<mp::MyProd> > ptrs;
art::fill_ptr_vector(ptrs, hnd);
// now ptrs contains Ptr<mp::MyProd> instances, each pointing
// to one of the rb::Tracks in the collection to which hnd
// refers.
</code></pre>

Use the const std::vector<mp::MyProd>, std::list< art::Ptr<mp::MyProd> >, or std::vector< art::Ptr<mp::MyProd> > if you want to be able to modify the collection of objects.

* Make a art::PtrVector (discussed below).
<pre><code class="c">
// make an art::PtrVector of the objects
art::PtrVector<mp::MyProd> prodvec;
for(unsigned int i = 0; i < mplistHandle->size(); ++i){
art::Ptr<mp::MyProd> prod(mplistHandle, i);
prodvec.push_back(prod);
}
</code></pre>

The reason for using std::list or std::vector rather than art::PtrVector<T> for this use case is that we expected people to want to modify the collection, e.g. to re-order it, or to remove elements. This is more efficient if done with the list or vector rather than the art::PtrVector.

Most code in the modules should probably use the std::list to establish the final set of art::Ptrs to mp::MyProd data objects stored in the event. The final set of art::Ptrs can then be saved in a new data product as an art::PtrVector if that is needed.

*NB* Only art::PtrVectors correctly save the references to objects made in other modules, so if you want to save the collection, it must be done as an art::PtrVector.

h3. Upcast on read

The upcast on read functionality can be used to read back objects written into a file that follow a simple inheritance scheme, ie reading in objects of a derived type using the base class type. For instance, rb::Tracks which inherit from rb::Prongs. The objects are retrieved from the art::Event by passing a std::vector<const myprod::MyObject*> to the art::Event::getView() method. An example of using this functionality is

<pre><code class="c">
// declare the std::vector
std::vector<const rb::Prong*> prongs;

// Read in the list of rb::Tracks we made in fTrackModuleLabel as rb::Prongs.
evt.getView(fTrackModuleLabel,prongs);

</code></pre>

Notice that the vector is of const pointers of the requested type. You shouldn't save these vectors anywhere (ie as collections in other data objects). Instead they are should only be used for information, ie in the event display.

h3. "cet::search_path":https://cdcvs.fnal.gov/redmine/projects/cetlib/repository/revisions/master/entry/cetlib/search_path.h

This is a utility that will search a list of predefined directories for a relative location of a file. For instance, if you want to use the geometry definition for the near detector, neardet.gdml, as the input for the Geometry service, you would pass the geometry service the value "Geometry/gdml/neardet.gdml" as an std::string. The cet::search_path object then searches through the previously defined @$FW_SEARCH_PATH@ variable to see if it can locate the specified file. It will then allow access to information about the file, including its full path. This is helpful when writing code that should search for a given file in several locations such as private and public contexts in the SRT build system. The necessary variables are set when a user sets up the environment. If a user wants the search path to include a test release, the the user should do

@$srt_setup -a@

from within that test release.

An example of using cet::search_path is

<pre><code class="c">

// constructor decides if initialized value is a path or an environment variable
// FW_SEARCH_PATH is set to be a cascade with SRT_PRIVATE_CONTEXT, SRT_PUBLIC_CONTEXT and
// directory where perhaps auxiliary root files are stored
cet::search_path sp("FW_SEARCH_PATH");

// taking a parameter from the parameter set passed into the geometry as the first argument,
// the second argument is the local variable storing the full path - both are std::string objects
sp.find_file(pset.get< std::string >("GDML"), fGDMLFile); //fGDMLFile is the relative path to a file

// Open the GDML file and test if it is there
struct stat sb;
if (fGDMLFile.empty() || stat(fGDMLFile.c_str(), &sb)!=0)
// failed to resolve the file name
throw cet::exception("NoGDMLGeometry")
<< "geometry gdml file " << fGDMLFile << " not found!";

</code></pre>

h3. "fhicl::ParameterSet":https://cdcvs.fnal.gov/redmine/projects/fhicl-cpp/repository/revisions/master/entry/fhiclcpp/ParameterSet.h

This object keeps track of which parameters are to be set by the user at run time for a module or art::Service. It can interpret several data types, including those listed below. An example for how to read the parameter types from the module constructor is listed for each type. See [[Running Jobs]] for examples of the job configuration file syntax for each type.

* bool: fMyBool (pset.get< bool >("MyBool"))
* int: fMyInt (pset.get< int >("MyInt"))
* unsigned int: fMyUInt (pset.get< unsigned int >("MyUInt"))
* std::vector<int>: fMyVInt (pset.get< std::vector<int> >("MyVInt"))
* std::vector<unsigned int>: fMyVUInt (pset.get< std::vector<unsigned int> >("MyVUInt"))
* std::string: fMyString (pset.get< std::string >("MyString"))
* std::vector<std::string>: fMyVString (pset.get< std::vector<std::string> >("MyVString"))
* double: fMyDouble (pset.get< double >("MyDouble"))
* std::vector<double>: fMyVDouble (pset.get< std::vector<double> >("MyDouble"))

Other types are available, but the above list should serve almost all a user's needs.

h3. "art::ServiceHandle":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/changes/art/Framework/Services/Registry/Service.h

The art::ServiceHandle is a templated object that behaves like a singleton, except that it is owned and managed by the framework. A service can be used within any module. Services can be configured using the job configuration file. A typical example of the use of a service is the detector Geometry. The Geometry is needed in just about every module, but you don't want to keep making instances of the Geometry. Additionally, the different detectors may have to set different parameter values that should be handled in the job configuration.

h3. "art::TFileService":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/entry/art/Framework/Services/Optional/TFileService.h

This is a specialized service that connects up to the file where histograms made by modules are to be stored. It provides a mechanism for making TObjects to be stored in that file and managing the memory for those objects. For example

<pre><code class="c">
// get the geometry to figure out something for the histogram
art::ServiceHandle<geo::Geometry> geo;

// get access to the TFile service
art::ServiceHandle<art::TFileService> tfs;

// make the histogram - fHist is assumed to have been declared in the .h file
fHist = tfs->make<TH1D>("channels", ";channel;# PE", geo->Nchannels(), 0, geo->Nchannels());

// note that for some reason ROOT does not automatically connect TGraphs to the output directory when created
// like it does for histograms. So we have to do that ourselves using the ROOT global directory variable gDirectory
fGraph = tfs->make<TGraph>(); //default constructor, set number of points and values later
gDirectory->Append(fGraph);

</code></pre>

h3. "MessageLogger":https://cdcvs.fnal.gov/redmine/projects/messagefacility/repository/revisions/master/entry/messagefacility/MessageLogger/MessageLogger.h

The MessageLogger provides several levels of messages that can be used to print information to an output log. The levels most likely to be useful are LogDebug, mf::LogInfo, mf::LogWarning and mf::LogError. Note there is no mf:: in front of LogDebug because it is a macro that will include the file and line numbers of the code producing the output. These are listed in order of severity. The MessageLogger can be configured to set the number of messages printed and to send each class of message to a different output stream.

In order to issue messages, the module must include the MessageLogger header:

<pre><code class="c">
#include "messagefacility/MessageLogger/MessageLogger.h"
</code></pre>

In addition, it is strongly recommended (for consistency with the way all services are used ) that the .fcl file contain at least the line

<pre>
message: { }
</pre>

In the services block.

The braces can enclose specifications of parameters to adjust the MessageLogger behavior (see MessageLogger Parameters ); if no parameters are supplied, a sensible default behavior is provided.

If the .fcl file does not specify the MessageLogger service, or if a message is issued in code executed before any services are initiated, then the response to issuing a message will be that the content will be sent to cerr. Having included the necessary MessageLogger header, when code wishes to issue a message, one of these functions can be used:

<pre><code class="c">
mf::LogError ("category") << a << b << ... << z;
mf::LogWarning ("category") << a << b << ... << z;
mf::LogInfo ("category") << a << b << ... << z;
mf::LogVerbatim ("category") << a << b << ... << z;
</code></pre>

When issuing messages:

* LogInfo, LogWarning, and LogError represent three levels of "severity" of the message. It is possible (see MessageLogger Parameters ) to configure the job to ignore all LogInfo messages, or all messages of severity less than LogError.
* LogVerbatim is identical in all ways to LogInfo, except that absolutely no message formatting is performed, and no context, module, or other information is appended to the message. This is appropriate, for example, if the program has prepared a nicely-formatted table for output.
* The category should specify what this message is about. The category will generally appear as the first part of the message, but it also plays two other roles:
1. It is possible to set limits on how many times some specific type of message will be sent to the outputs of the logger. By "type" we mean any messages with some specific category. See MessageLogger Parameters for details.
2. When message statistics are provided, the counts of how many times messages of a given type were issued are keyed to category, module label, and (if provided) subroutine.
Normally a category name should be up to 20 characters long, without special characters other than underscore.
* It is unnecessary to explicitly specify the module label or the run/event number; these are automatically provided by the logger.
* An arbitrary number of additional objects << a << b << ... << z can be appended to the message. These can be strings, ints, doubles, or any object that has an operator<< to an ostream. (Or the message can be issued with no additional objects at all.)
* There is no need to add spaces at the beginning or end of text items sent to the message, or to add text separators between numerical items. This spacing is taken care of by the logger. However, if any item appended to a message ends in a space, then it is assumed that the user is handling spacing explicitly, and no further automatic spaces are inserted for that message.
* There is no need to affix any sort of endl; when the statement ends the message will be dispatched.
* Newline characters can be included in the objects appended to the message. These will be used in formatting the message. But they are generally not necessary: Line breaks are automatically inserted if the next appended object would cause the line to exceed 80 characters.

There is an additional form for issuing a message:

LOG_DEBUG("category") << a << b << ... << z;

This is identical to the others, except:

* LOG_DEBUG affixes the __FILE__ and __LINE__ number to the message.
* LOG_DEBUG messages are considered to be lower in severity than mf::LogInfo messages.
* By default, LOG_DEBUG messages will be rapidly discarded with a minimum of overhead. The user must specify in the .fcl file LOG_DEBUG messages from various modules are to be enabled; see Controlling LogDebug Behavior: Enabling LogDebug Messages for how that is done.
* Because it must get __FILE__ and __LINE__ from the spot issuing the message, LogDebug is implemented as a macro rather than a free function.
* Because LOG_DEBUG is a macro, it is not prepended with the art:: namespace designation.

An alternative function for issuing a debug message is:

LOG_TRACE("category") << a << b << ... << z;

LOG_TRACE is identical in every way to LOG_DEBUG, except that absolutely no formatting or in formation appending will be done. This is appropriate, for example, for trace output coming from a package which assumes it has full control of formatting.

All configuration of what is done when LOG_TRACE messages are issued is taken from the control issued for LOG_DEBUG. Similarly, the configuration of what is done when mf::LogVerbatim messages are issued is taken from the control issued for mf::LogInfo.

Details on how to set message levels and verbosity, etc, can be found "here":http://www.uscms.org/LPC/lpc_offl/MessageLogger/MessageLogger.html

h3. art::RandomNumberGenerator Service

A nice description of how to use this service can be found "here":http://mu2e.fnal.gov/public/hep/computing/Random.shtml. Note that this write up is for the older fw implementation of art, but there are only minor differences.

To store the "state":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/entry/art/Persistency/Common/RNGsnapshot.h of the random number engines for each event one must add the RandomNumberSaver module to the list of physics producers to be run by the job. The necessary line to add to the fcl file is

<pre><code class="C">
physics{
producers{
...
rns: { module_type: "RandomNumberSaver" }
}

...
}
</code></pre>

h3. "cet::exception":https://cdcvs.fnal.gov/redmine/projects/cetlib/repository/revisions/master/entry/cetlib/exception.h

The cet::exception can be used to cause the framework to end a job gracefully if some predetermined bad thing happens. The use of the art::exception can be configured to skip a module, or skip to the next event, run, etc. Different exception classes can be set to do different things.

art::exception can be used as follows:

<pre><code class="c">
if(x > 2) throw cet::exception("SomeUsefulDescription") << "x = " << x << " is too big";
</code></pre>

Detailed instructions for using exceptions under the former incarnation of ART are attached to this page, attachment:CMS_SWGuideEdmExceptionUse.pdf. These instructions may no longer be accurate.

In short however, the default behavior of the framework upon catching an exception is to rethrow (except for some system exceptions, which skip the event). However, one can specify the behavior for exceptions with the following configuration fragment:

<pre>
services.scheduler.XXXX: [ "SomeUsefulDescription", "SomeOtherUsefulDescription", ... ]
</pre>

where @XXX@ can be:
* @Rethrow@;
* @IgnoreCompletely@;
* @SkipEevent@;
* @FailModule@ (behave as if the module returned a failure value for this event);
* @FailPath@ (behave as if the path rejected this event).

Note that the @FailModule@ setting does not imply a path rejection if the module throwing the exception so configured is a filter set to "VETO" or "IGNORE."

h3. "art::Ptr<T>":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/entry/art/Persistency/Common/Ptr.h and "art::PtrVector<T>":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/entry/art/Persistency/Common/PtrVector.h

The art::Ptr<T> is a template class that acts like a ROOT TRef. It provides a linkage between objects written into different areas of the event (and output file). For example, the rb::Cluster object holds an art::PtrVector<rb::CellHit> pointing to the hits contained in the rb::Cluster. The art::Ptr<T> behaves like a pointer (ie you access the methods of the T using the "->"). It also has functionality to return the actual pointer to the object in question using art::Ptr<T>::get() or to check if the art::Ptr<T> is pointing to a legitimate object using edm::Ptr<T>::isNull().

An art::Ptr<T> can only be made from an object that has been stored in the event record and is being fetched from the event record. Put another way, you can only make an art::Ptr<T> if you have an art::Handle to a collection of objects of type T. art::Ptr<T> cannot be instantiated like an object of type T,

<pre><code class="c">
// The following line will NOT work
art::Ptr<T> myt = new T();
</code></pre>

or similar will not work because the object you are interested in for that code has not been first stored in the event record.

An art::PtrVector<T> is a vector of art::Ptr<T> objects. It provides the basic functionality you would expect from a std::vector, including iterators, size(), begin() and end() methods. It is useful when storing the connections of many objects of the same type in an object, for example rb::CellHits in a rb::Cluster. It can also be sorted,

<pre><code class="c">
art::PtrVector< mp::MyProd > mpcol;
mpcol.sort();
</code></pre>

This example makes use of the predefined "<" operator of the mp::MyProd. If you want to sort using a function, first define a predicate in the namespace of your module

<pre><code class="c">
namespace mymodule {

struct SortByTime {
bool operator()(mp::MyProd const& a, mp::MyProd const& b) const { return a.Time() < b.Time(); }
};

//////--------- intervening code calling constructors, destructors, etc, now we are in the produce method ---/////////


art::PtrVector< mp::MyProd > mpcol;
// fill the PtrVector as in the examples in the art::Handle section above

mpcol.sort(mymodule::SortByTime());

</code></pre>

h3. "art::Filter":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/entry/art/Framework/Core/EDFilter.h

The object allows one to filter spills based on information obtained about the event.

h3. "art::Assns":https://cdcvs.fnal.gov/redmine/projects/art/repository/revisions/master/changes/art/Persistency/Common/Assns.h

art::Assns are a way to associate (Assns is a contraction for associations) objects of one type with another. For example, you may want to associate a recob::Cluster with the rb::Hit objects comprising the rb::Cluster. The art:Assns object allows you to navigate these associations bidirectionally, that is you can ask a recob::Cluster which rb::Hits it contains, as well as as a rb::Hit to which rb::Cluster it belongs. The art::Assns also allow us to avoid storing these connections in the higher level object that is being associated. Instead the associations are stored in the event record.

A set of utility functions to perform the necessary steps to associate objects for storage in the art::Event are found in
source:Utilities/AssociationUtil.h There are also methods to retrieve a collection of objects of one type that are not associated with objects of another type. Those methods allow one to retrieve, for example, all rb::Hits from an event that are not associated with rb::Tracks. The comments in that file describe how to use the functions.

To make use of the associations and retrieve objects from the file, one would do

<pre><code class="C">

// below trackListHandle is of type art::Handle< std::vector<rb::Track> >,
// evt is an art::Event, and assnCreatorModule is an std::string holding the
// label of the module making the associations of hits to tracks...and possibly the same that made the tracks
art::FindMany<rb::Hit> fmh(trackListHandle, evt, assnCreatorModule);

// loop over all tracks in the handle and get their hits
for(size_t t = 0; t < trackListHandle->size(); ++t){
std::vector<const rb::Hit*> hits = fmh.at(t);
}

// can also get a collection of art::Ptrs instead of const pointers
art::FindManyP<rb::Hit> fmh(trackListHandle, evt, assnCreatorModule);

// loop over all tracks in the handle and get their hits
for(size_t t = 0; t < trackListHandle->size(); ++t){
std::vector<art::Ptr<rb::Hit> > hits = fmh.at(t);
}

</pre>

One can also use the art::FindOne and art::FindOneP, see the detailed description on how to use art::Assns is "here.":https://cdcvs.fnal.gov/redmine/projects/art/wiki/Inter-Product_References The art::FindOne returns a cet::maybe_ref, whose interface is defined "here.":http://cdcvs.fnal.gov/lxr/cetlib/source/cetlib/maybe_ref.h#044 The cet::maybe_ref can be tested for validity, allowing a user to be sure a valid association was created.

*NB* The art::FindMany(P) and art::FindOne(P) are smart query objects and should only be instantiated once for a given collection. If they are instantiated once for each item in a art::Handle, art::PtrVector, art::View or std::vector< art::Ptr<T> > then a heavy performance price will be paid as a lookup table is made multiple times.

h2. Making Objects to Store in the Output

Making objects to store in the art::Event is a straightforward operation. The first step is to declare a container for the objects,

<pre><code class="c">
std::auto_ptr<std::vector<mp::MyProd> > mpCollection(new std::vector<mp::MyProd>);
</code></pre>

Here we used the std::auto_ptr because it handles the cleanup of the memory for the collection for us.

The mpCollection now behaves just like a std::vector, except one accesses the std::vector methods using a "->". Once the collection has been filled (and it can be a collection of just one object), it is written to the event by doing

<pre><code class="c">
event.put(mpCollection);
</code></pre>

Now the ownership of the collection belongs to the event and the user cannot modify the collection or the objects in the collection any more.

h2. Schema Evolution for Data Products

Data products may change over time and we will want to do everything we can to ensure backwards compatibility between old and new versions. Please see "this page":https://cdcvs.fnal.gov/redmine/projects/art/wiki/Facilitating_Schema_Evolution_for_Data_Products on the ART wiki for information on how to evolve a data product while still maintaining backwards compatibility.

h2. Making a Module

The framework provides a command called 'artmod' to generate the boilerplate code required for adding a module to ART. See [[Using_artmod]] for more details.
Below are examples of how to make both an EDProducer module and an EDAnalyzer module. The examples show basic .h and .cxx files for each. One other file needs to be made for the module to be recognized by the framework at run time and that is called the _module.cc file. An example of the module file is also included.

To recap, you need three files to make a module and they should be named as follows:

*MyModule.h - the file defining the interface
*MyModule.cxx - the implementation file
*MyModule_module.cc - the file defining the connection to the framework.

*Important* Module names may not contain underscores. Underscores are special characters used by the ART system for storing data products in an event to label the products according to what module, instance and process created them. Using underscores in module names will result in your job not running.

*NB* *NB Objects are stored in the art::Event as collections of references, not pointers. You need to get them out of the event as collections of references, not pointers.

Additionally, if you are getting an object out of an art::Event, you must declare the local variable in your code to be an art::Ptr<T>, not a standard C pointer. See the examples below for details*

h3. EDProducer

<pre><code class="c">
#ifndef MYPRODUCER_H
#define MYPRODUCER_H

#include "art/Framework/EDProducer.h"

class TH1D;

///My Module
namespace mm {

///class to produce a data product
class MyProducer : public art::EDProducer {

public:

explicit MyProducer(fhicl::ParameterSet const& pset); // the explicit tag tells the compiler that MyProducer is different from fhicl::ParameterSet
virtual ~MyProducer();
void produce(art::Event& evt); // makes the objects I want made
void beginJob(); // does things like make histograms at the beginning of the job, also beginRun and beginSpill methods available.

private:

double fDouble; ///< some data member
std::string fPrevModuleLabel; ///< label of the module making objects that i need for this step
TH1D* fHist; ///< a histogram data member

}; // class MyProducer
}

#endif // MYPRODUCER_H
</code></pre>

The implementation file is then (Note: Where "Core" shows up may need to be "Principal" for your code to actually work)

<pre><code class="c">

#include <iostream>

// Framework includes
#include "art/Framework/Core/Event.h"
#include "fhiclcpp/ParameterSet.h"
#include "art/Persistency/Common/Handle.h"
#include "art/Persistency/Common/OrphanHandle.h"
#include "art/Persistency/Common/Ptr.h"
#include "art/Persistency/Common/PtrVector.h"
#include "art/Framework/Services/Registry/Service.h"
#include "art/Framework/Services/Optional/TFileService.h"
#include "art/Framework/Core/TFileDirectory.h"
#include "messagefacility/MessageLogger/MessageLogger.h"

#include "MyModule/MyProducer.h"
#include "Geometry/geo.h"
#include "MyProducts/MyProduct.h"
#include "MyProducts/MyOtherProduct.h"

#include "TH1.h"

namespace mm{

//-----------------------------------------------------
MyProducer::MyProducer(fhicl::ParameterSet const& pset) :
fDouble (pset.get< double > ("TheDouble")),
fPrevModuleLabel (pset.get< std::string >("PreviousModuleLabel"))
{
produces< std::vector<mp::MyOtherProduct> >(); // this line tells the module what it is going to make, you must have one line
// for each type of collection to be made

}

//-----------------------------------------------------
MyProducer::~MyProducer()
{
}

//-----------------------------------------------------
void MyProducer::beginJob()
{
// get access to the TFile service
art::ServiceHandle<art::TFileService> tfs;

// get the geometry to figure out something for the histogram
art::ServiceHandle<geo::Geometry> geo;

fHist = tfs->make<TH1D>("channels", ";channels;", geo->NPlanes()*geo->Plane(0)->Ncells(), 0, geo->NPlanes()*geo->Plane(0)->Ncells());

return;
}

//-----------------------------------------------------
void MyProducer::produce(art::Event& evt)
{

//get a collection of electrons
std::auto_ptr<std::vector<mp::MyOtherProduct> > mopcol(new std::vector<mp::MyOtherProduct>);

// maybe I will need the geometry service here too
art::ServiceHandle<geo::Geometry> geom;

double xyz[3] = {0.};
double xyz1[3] = {0.};
int planes = geom->NPlanes();

///plane 0 is the first induction plane, every plane has a wire 0
geom->Plane(0)->GetCenter(xyz);

// grab the mp::MyProducts made in the last module
art::Handle< std::vector<mp::MyProduct> > mplistHandle;
evt.getByLabel(fPrevModuleLabel,mplistHandle);

// loop over the list of MyProducts
for(unsigned int i = 0; i < mplistHandle->size(); ++i){

//get a edm::Ptr to the MyProducts
art::Ptr<mp::MyProduct> mpMyProd(mplistHandle, i);

// do something to turn out MyOtherProducts - not shown here

// add the new MyOtherProduct to the collection
mopcol->push_back(myOtherProd)
}

evt.put(mopcol);

// mopcol is no longer a valid pointer - don't use it any more!
// if for some reason you still want access to the products in mopcol, then use
// this syntax where the return value is a "read only pointer" to the data product
// art::OrphanHandle< std::vector<mp::MyOtherProd> > q = event.put(mopcol);
// mf::LogInfo("NumMyProds") << "Number of products: " << q->size();

return;

}

}
</code></pre>

And now the _module.cc file. The need for separate files for the implementation and this file was not obvious to me to begin with. Having separate files allows you to produce .so libraries for both the plugin and the rest of the objects in the package. SRT also likes to have .cxx targets to build, so that is another reason to have separate .cxx and _module.cc files.

For this example, the plugin file is named MyProducer_plugin.cc.

<pre><code class="c">
// Framework includes
#include "art/Framework/Core/ModuleMacros.h"

// NOvASoft includes
#include "MyModule/MyProducer.h"

namespace mm {

// A macro required for a JobControl module.
DEFINE_ART_MODULE(MyProducer);

} // namespace mm
</code></pre>

h3. EDAnalyzer

<pre><code class="c">
#ifndef MYANALYZERER_H
#define MYANALYZER_H

#include "art/Framework/Core/EDAnalyzer.h"

class TH1D;


// My Module
namespace mm {

// class to produce a data product
class MyAnalyzer : public art::EDAnalyzer {

public:

explicit MyAnalyzer(fhicl::ParameterSet const& pset); // the explicit tag tells the compiler that MyProducer is different from fhicl::ParameterSet
virtual ~MyAnalyzer();
void analyze(const art::Event& evt); // makes the objects I want made
void beginJob(); // does things like make histograms at the beginning of the job, also beginRun and beginSpill methods available.

private:

double fDouble; ///< some data member
std::string fPrevModuleLabel; ///< label of the module making objects that i now want to look at
TH1D* fHist; ///< a histogram data member

}; // class MyProducer
}

#endif // MYPRODUCER_H
</code></pre>

The implementation file is then

<pre><code class="c">
#include <iostream>

// Framework includes
#include "art/Framework/Principal/Event.h"
#include "fhiclcpp/ParameterSet.h"
#include "art/Persistency/Common/Handle.h"
#include "art/Framework/Services/Registry/ServiceHandle.h"
#include "art/Framework/Services/Optional/TFileService.h"
#include "art/Framework/Core/TFileDirectory.h"
#include "messagefacility/MessageLogger/MessageLogger.h"

#include "MyModule/MyAnalyzer.h"
#include "Geometry/geo.h"
#include "MyProducts/MyProduct.h"
#include "MyProducts/MyOtherProduct.h"

#include "TH1.h"

namespace mm{

//-----------------------------------------------------
MyAnalyzer::MyAnalyzer(fhicl::ParameterSet const& pset) :
fDouble (pset.get< double > ("TheDouble")),
fPrevModuleLabel(pset.get< std::string >("PreviousModuleLabel"))
{
}

//-----------------------------------------------------
MyAnalyzer::~MyAnalyzer()
{
}

//-----------------------------------------------------
void MyAnalyzer::beginJob()
{
// get access to the TFile service
art::ServiceHandle<art::TFileService> tfs;

// get the geometry to figure out something for the histogram
art::ServiceHandle<geo::Geometry> geo;

fHist = tfs->make<TH1D>("channels", ";channels;", geo->NPlanes()*geo->Plane(0)->Ncells(), 0, geo->NPlanes()*geo->Plane(0)->Ncells());

return;
}

//-----------------------------------------------------
void MyAnalyzer::analyze(const art::Event& evt)
{

// maybe I will need the geometry service here too
art::ServiceHandle<geo::Geometry> geom;

double xyz[3] = {0.};
double xyz1[3] = {0.};
int planes = geom->NPlanes();

///plane 0 is the first induction plane, every plane has a wire 0
geom->Plane(0)->GetCenter(xyz);

// grab the mp::MyProducts made in a previous module
art::Handle< std::vector<mp::MyProduct> > mplistHandle;
evt.getByLabel(fPrevModuleLabel,mplistHandle);

// loop over the list of MyProducts
for(unsigned int i = 0; i < mplistHandle->size(); ++i){

//get a edm::Ptr to the MyProducts
art::Ptr<mp::MyProduct> mpMyProd(mplistHandle, i);

// do something to analyze them

}

return;

}

}
</code></pre>

And now the _module.cc file. The need for separate files for the implementation and the module was not obvious to me to begin with. Having separate files allows you to produce .so libraries for both the plugin and the rest of the objects in the package. SRT also likes to have .cxx targets to build, so that is another reason to have separate .cxx and _module.cc files.

For this example, the plugin file is named MyAnalyzer_module.cc.

<pre><code class="c">
// Framework includes
#include "art/Framework/Core/ModuleMacros.h"

// NOvASoft includes
#include "MyModule/MyAnalyzer.h"

namespace mm {

// A macro required for a JobControl module.
DEFINE_ART_MODULE(MyAnalyzer);

} // namespace mm
</code></pre>

h3. EDFilter

A simple example of filtering on even or odd event numbers is below.

First the header file:
<pre><code class="c">
// Framework includes
#include "art/Framework/Core/EDFilter.h"

namespace filt{

class SelectEvents : public art::EDFilter {
public:
explicit SelectEvents(fhicl::ParameterSet const& pset);
virtual ~SelectEvents() { }
virtual bool filter(art::Event& e);

private:

// Control parameter: 1 to select odd numbered events;
// else select even numbered event.
int _keepOddOrEven;

};

</code></pre>

Now the implementation:

<pre><code class="c">
#include "SelectEvents.h"

namespace filt{

SelectEvents::SelectEvents(fhicl::ParameterSet const& pset):
_keepOddOrEven(pset.get<int>("keepOddOrEven",1))
{
}

bool SelectEvents::filter(art::Event& e)
{

// EventSetup is a cms leftover that we do not use.

// Get event number from the event.
int event = e.id().event();

// Always keep event 3.
if ( event == 3 ) return true;

// Always discard event 4.
if ( event == 4 ) return false;

// Is this an odd numbered event?
bool isOdd = ((event % 2) != 0);

// Keep only events with odd or even event numbers, as
// controled by the parameter from the ParameterSet.
if ( _keepOddOrEven == 1){
return isOdd;
} else{
return !isOdd;
}

}
}//end namespace
</code></pre>

And now the _module.cc:

<pre><code class="c">
// Framework includes
#include "art/Framework/Core/ModuleMacros.h"

// NOvASoft includes
#include "SelectEvents.h"

namespace filt {

// A macro required for a JobControl module.
DEFINE_ART_MODULE(SelectEvents);

} // namespace filt
</code></pre>

h2. Configuring a Job

See the [[Running Jobs]] page.