Writing Calibrations from TDS to ROOT

Background

It doesn't make sense to do the write automatically through the usual conversion service mechanism since it doesn't need to get written every event. On the contrary, it should get done only at the explicit request of user code. (Also, to read in a calibration actually involves a two-step conversion which can't readily be reversed for write. I'm just trying to reverse the 2nd part.)

Keep in mind that these files are much simpler than event data files. They will only consist of one large object, corresponding to a leaf in the TDS. That is, information is not indexed by event and there is no hierarchy of converters to correspond to hierarchical data in the TDS.

A typical calibration in the TDS, say calorimeter gains, is represented by a class with the following inheritance:

 CalCalibGain >>  CalCalibBase >> CalibBase >> DataObject 

where >> means is derived from.

An analogous hierarchy of ROOT classes exists (in namespace calibRootData in the to-be-released package of the same name)

 CalGainCol >> CalBase >> Base >> TObject

So, rephrased, the task is, upon user request, to take a CalCalibGain (or other calibration) object, create a CalGainCol (or other) ROOT object containing the same information, and write it to a physical ROOT file.

A plan

As is true for XML conversion, there will be a class hierarchy of converters mirroring that for TDS class. For our example suppose it's

 RootCalGainCnv >> RootCalBaseCnv >> RootBaseCnv 

The new CalibRootCnvSvc will satisfy an abstract interface including methods

  StatusCode writeToRoot(std::string outputFile, std::string tdsPath);
  StatusCode writeToRoot(std::string outputFile, CalibData::CalibBase *calib);

I'm not yet sure how much of the standard conversion machinery I'll want to (and be able to) bypass. For now, assume there is some way for CalibRootCnvSvc to look up the right converter for the specified TDS object, instantiate it and call its methods.

RootBaseCnv will have protected methods for standard sequences of ROOT operations needed by all converters, or they might be part of the abstract interface satisfied by CalibRootCnvSvc.

When one of the writeToRoot methods is called, sequence of events is something like the following:

  1. Find correct converter type; instantiate.
  2. Call a method of the converter, something like
    createRoot(std::string fname, CalibData::CalibBase *pTDSObj)
  3. createRoot will invoke the standard ROOT helper methods to
  4. createRoot instantiates a new calibRootData::CalGainCol object. Should I use it to make a branch at this point?
  5. createRoot calls its own fillRoot method
    fillRoot(CalibData::CalibBase* pTDSObj, calibRootData::Base* pRootObj)
  6. fillRoot is implemented for RootCalBaseCnv and RootBaseCnv as well as for "leaf" converters. Each implementation first calls its base class version, if any, then fills in the parts of the ROOT object which are its responsibility.
  7. Finish up with the rest of the standard ROOT stuff:

Two-step conversion The opaque address associated with a node in the calibration TDS has information needed to find an appropriate entry, if any, in the (MySQL) calibration metadata database. Storage type is MySQL and the associated conversion service is CalibMySQLCnvSvc. Step 1 is for the service to fetch information from the row in the MySQL database, including a value for the format of the data, such as XML or ROOT. Based on this value, CalibMySQLCnvSvc will go through the rigamarole necessary to (step 2) get the proper conversion service, such as CalibXmlCnvSvc, invoked to read the file and store in the TDS.

Look up converter Apparently a conversion service can look up the converter, if it has one, for a particular object via ConversionSvc::converter(const CLID& clid).