Converting Data Objects from FMWK

The main difference between FMWK and the CD framework is that the CD framework does not save TObjects so that data objects do not inherit from TObject. Thus, the main difference between the FMWK objects and the CD framework objects is that in the latter framework the definition and implementation files do not have the following:

in a .h file remove

#include "TObject.h" 
: public TObject

in a .cxx file remove


Additional Files Needed

There are two additional files needed in a package that intends to create data objects to be written to the output file. The first defines the types of data products that can be written to the file. The second defines wrappers used by the framework to write the data products.


The best example for this type of file is from the SimulationBase package:

<!--  Include edm::Wrapper lines for objects that we would like to put into the event -->
<!--  Include the non-wrapper lines for all objects on the edm::Wrapper lines and     -->
<!--  for all objects that are data members of those objects.                         -->

explicit type, ie std::set<int> has to be declared -->
 <class name="simb::MCParticle"                                       /> <!-- The classes from the simb namespace all need to be declared -->
 <class name="simb::MCTrajectory"                                     />
 <class name="simb::MCNeutrino"                                       />
 <class name="simb::MCFlux"                                           />
 <class name="simb::MCTruth"                                          />
 <class name="std::pair<TLorentzVector,TLorentzVector>"               /> <!-- std::pair<T> needs to be made explicit for this case -->
 <class name="std::vector< std::pair<TLorentzVector,TLorentzVector> >"/> <!-- a std::vector of std::pairs -->
 <class name="std::vector<simb::MCParticle>"                          /> <!-- declare each kind of vector to be stored too -->
 <class name="std::vector<simb::MCTrajectory>"                        />
 <class name="std::vector<simb::MCNeutrino>"                          />
 <class name="std::vector<simb::MCFlux>"                              />
 <class name="std::vector<simb::MCTruth>"                             />
 <class name="art::Wrapper< std::vector<simb::MCFlux>       >"        /> <!-- wrappers for the objects that get stored -->
 <class name="art::Wrapper< std::vector<simb::MCParticle>   >"        /> 
 <class name="art::Wrapper< std::vector<simb::MCNeutrino>   >"        /> 
 <class name="art::Wrapper< std::vector<simb::MCTrajectory> >"        /> 
 <class name="art::Wrapper< std::vector<simb::MCTruth>      >"        />

Notice that simple data types like int, double, bool, etc are not included. Those are done for you by the framework. The same goes for templated types like std::vector<int>, std::pair<int>, etc. ROOT classes are also handled by the framework. More complicated templated types, like std::pair and std::map do need to be specified.

The art::Wrapper<T> classes are what ultimately get written to the file and are defined in the classes.h file below.

NB objects that inherit from TObject and have pointer data members don't play well with this system. The only place that became an issue is in MCTruth which used to hold objects of type TParticle. To solve the problem a new MCParticle was developed that keeps all aspects of TParticle that were being used in the software.


Again, the example comes from the SimulationBase package:

#include "art/Persistency/Common/Wrapper.h" 

// nutools includes
#include "SimulationBase/simbase.h" 

// Only include objects that we would like to be able to put into the event.
// Do not include the objects they contain internally.

template class std::vector<simb::MCNeutrino>;
template class std::vector<simb::MCTrajectory>;
template class std::vector<simb::MCParticle>;
template class std::vector<simb::MCTruth>;
template class std::vector<simb::MCFlux>;

template class art::Wrapper< std::vector<simb::MCNeutrino> >;
template class art::Wrapper< std::vector<simb::MCTrajectory> >;
template class art::Wrapper< std::vector<simb::MCParticle> >;
template class art::Wrapper< std::vector<simb::MCTruth> >;
template class art::Wrapper< std::vector<simb::MCFlux> >;

NB Notice that you have to include lines both for the std::vectors and the art::Wrappers of those vectors.

To Write Pointers or Not To Write Pointers?

Short answer: not. If you want to have your object contain another object as a data member, then either make it as a non-pointer, a art::Ptr<T> object, or if you need a vector of the objects use an art::PtrVector<T>.

Below are some examples of how to make data products that contain references to other data products:

/// \file  Particle.h
/// \brief Particle class
/// \version $Id: Particle.h,v 1.2 2010/09/28 18:01:37 p-novaart Exp $
/// \author

/// This class describes a particle created in the detector Monte
/// Carlo simulation.


#include "art/Persistency/Common/Ptr.h" 
#include "SimulationBase/MCParticle.h" 

#include <set>
#include <string>
#include <iostream>
#include <functional> // so we can redefine less<> below

namespace simb { class MCTruth; }

namespace sim {

  class Particle : public simb::MCParticle {

    /// An indicator for an uninitialized variable (see Particle.cxx).
    static const int s_uninitialized; //! Don't write this as ROOT output

    /// Standard constructor.  If the mass is not supplied in the
    /// argument, then the PDG mass is used.

    Particle(const int trackId, 
             const int pdg, 
             const edm::Ptr<simb::MCTruth> &primary,
             const std::string process,
             const int mother = -1, 
             const double mass = s_uninitialized,
             const int status = -1);

    // Destructor.

    // Return a reference to the MCTruth object if this is a primary
    // particle.  If it's not, return 0.  Note: If the MCTruth
    // objects were not read in for this event, test the edm::Ptr::isNull()
    const edm::Ptr<simb::MCTruth>& Primary()  const { return m_primary; }


    edm::Ptr<simb::MCTruth> m_primary;       ///< pointer to primary particle definition


} // namespace sim

#endif // SIM_PARTICLE_H

And here is a class that contains an edm::PtrVector<T> to objects

// $Id: Prong.h,v 1.2 2010/09/28 18:01:26 p-novaart Exp $
/// Definition of reco Prong.  A Prong is essentially a list of clusters
/// that may form a track or shower.  Prongs have some basic characteristics
/// such as E_dep and direction.
/// \author $Author: p-novaart $
/// \date   $Date: 2010/09/28 18:01:26 $

#ifndef PRONG_H
#define PRONG_H

#include "art/Persistency/Common/PtrVector.h" 
#include "RecoBase/Cluster.h" 
#include "RecoBase/KalmanState.h" 
#include "Geometry/geo.h" 

#include <vector>

namespace rb {

  class Prong 
      Prong(edm::PtrVector<rb::Cluster>& clvec);

      bool     Add(edm::Ptr<rb::Cluster>& cl);
      int      NCluster()   const {return fCluster.size(); }

      void Clear() { fCluster.clear(); }

      edm::Ptr<rb::Cluster> Cluster(int i) const;

      geo::View_t   View()                         const {return fView; }
      const double* Dir()                          const {return fDir; }
      double        EVis()                         const {return fEVis; }
      double        ZStart()                       const {return fXYZStart[2]; }
      double        ZStop()                        const {return fXYZStop[2]; }
      const double* StartPos()                     const {return fXYZStart; }
      const double* EndPos()                       const {return fXYZStop; }
      void          ViewStartPos(geo::View_t xory,
                                 double *viewpos)  const;
      void          ViewStopPos(geo::View_t xory,
                                double *viewpos)   const;
      int  NKalmanState()     { return fKState.size(); }
      const edm::Ptr<rb::KalmanState> GetKalmanState(unsigned int i)  
        {return fKState[i]; }

      void SetView(geo::View_t v)                    { fView = v; }
      void SetEVis(double e)                         { fEVis = e; }
      void SetStart(const double* xyz);
      void SetStop (const double* xyz);
      void SetDir(const double dir[]);
      void AddKalmanState(const edm::Ptr<rb::KalmanState>& ks) { fKState.push_back(ks);}

      edm::PtrVector<rb::KalmanState> fKState;
      edm::PtrVector<rb::Cluster>  fCluster;

      geo::View_t   fView;
      double fXYZStart[3]; ///< Start location (xyz, cm)
      double fXYZStop[3];  ///< End point (xyz, cm)
      double fEVis;        ///< Total visible energy (units?)
      double fDir[3];      ///< Direction at starting point


#endif // PRONG_H