Detector Description Tutorial

This page is intended to summarize the practical steps needed to provide specific sub-detector description parameters to physics algorithms. Please refer to the Detector Description  chapter in the Gaudi User Guide for an overview of the Detector Description framework.

  1. Defining the sub-detector element classes
  2. Defining the XML sub-detector specific DTD
  3. Writing the XML sub-detector files
  4. Building the sub-detector XML converters
  5. Modifying Algorithms to access to detector information (not yet written)
  6. CMT requirement files and JobOptions files (not yet written)

Defining the sub-detector element classes

Define your sub-detector specific detector element class (transient). You must inherit your class from DetectorElement from where you will get the generic functionality and add your data members (your parameters) and specific methods. The following example is extracted from the VeloDetector class

#ifndef VELODETECTORELEMENT_H
#define VELODETECTORELEMENT_H 1
// Include files
#include "DetDesc/DetectorElement.h"
#include "DetDesc/IGeometryInfo.h"
// CLHEP files
#include "CLHEP/Geometry/Transform3D.h"
#include "CLHEP/Units/SystemOfUnits.h"
#include "CLHEP/Units/PhysicalConstants.h"
// CLID needs to be allocated
static const CLID CLID_VeloDetectorElement = 4021;
/** @class VeloDetectorElement 
 *  Velo detector element.
 *  This class specialises the DetectorElement class to contain
 *  information which may be common to \f$R\f$ and \f$\phi\f$
 *  silicon detectors.
 */
class VeloDetectorElement : public DetectorElement {
  public:
  /// Detector types
  enum Type {R, Phi};
  /// Detector orientation
  enum Orientation {Upstream, Downstream, Unknown};
  /// Constructors
  VeloDetectorElement() : 
    m_orientation(Unknown) { }
  VeloDetectorElement(Type type) :
    m_type(type),
    m_orientation(Unknown) { }
  /// Destructor
  virtual ~VeloDetectorElement() { }
  /// Return detector type (\f$R\f$ or \f$\phi\f$)
  virtual Type type() const { return m_type; }
  /// Set detector type
  virtual void setType(Type type) { m_type = type; }
  /// Query detector type: is it an \f$R\f$ detector?
  virtual bool isR() const { return m_type==R; }
  /// Query detector type: is it a \f$\phi\f$ detector?
  virtual bool isPhi() const {return m_type==Phi; }
  /// Return detector orientation (upstream or downstream)
  virtual Orientation orientation() const {
    if (m_orientation == Unknown) {
      HepRotation rot = this->geometry()->matrixInv().getRotation();
      Hep3Vector axis;
      HepDouble angle;
      rot.getAngleAxis(angle, axis);
      if (axis.theta()<halfpi) {
	m_orientation = Upstream;
      } else {
	m_orientation = Downstream;
      }
    }
    return m_orientation;
  }
  /// Set detector orientation
  virtual void setOrientation(Orientation orientation) { m_orientation = orientation;}
private:
  Type                       m_type;       ///< Detector type (\f$R\f$ or \f$\phi\f$)
  mutable Orientation        m_orientation;///< Detector orientation (upstream or downstream)
};
#endif // VELODETECTORELEMENT_H

The CLID number needs to be allocated for your class. This number is used to match the transient class to the XML representation (you will need to use this number in the XML file). Implement your sub-detector specific methods in the .cpp file. The implementation of these classes should not include any XML stuff. 

The sub-detector element specific classes should be put in a sub-detector package under the Det hat. The name of the package should contain the sub-detector name. For example the Det/VeloDet .

Defining the XML sub-detector specific DTD

The element <detelem/> is used to define a detector element and it allows to include a <specific/> section in where the sub-detector specific information will be placed. The specification of <specific/> is done with a DTD fragment in the header of the file as is shown in this example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE DDDB SYSTEM "../../DTD/structure.dtd" [
  <!-- Velo specific entities -->  
  <!ENTITY VeloDetID "4021">
  <!-- Velo specific tags -->
  <!ELEMENT Detector EMPTY>
  <!ATTLIST Detector type ( R | Phi ) #REQUIRED>
]>

Writing the XML sub-detector files

The XML for a instance of a sub-detector element uses the <specific/> to pass specific parameters. In the following example this is  the type of Velo detector (r or phi). In addition, to the specific paramters, the end-use has to define a number of parameters which apply to all detector elements, in particular the geometry information. All the XML files for all sub-detectors of LHCb are stored in the CVS repository in the Det/XmlDDDB package.

<detelem classID="&VeloDetID;" name="Detector00">
  <author>Bruce Hay</author>
  <version>0.1</version>
  <geometryinfo lvname ="/dd/Geometry/Velo/lvVeloDetector"
                support="/dd/Structure/LHCb/Velo"
                rpath  ="0/0"/>
  <specific>
    <Detector type="Phi"/>
  </specific>
</detelem>

Building the sub-detector XML converters

For each type of specific detector element we need to provide a specific XML converter (the usual pattern within the Gaudi framework). This user specific converter needs to be capable of creating a new instances of the specific detector elements and initialize them with the information stored in the XML files. The end-user accessing the detector information do not need bother about the XML converters. Only the sub-detector specialists need to provide them.

We use the DOM interface of the XML parser to access the information in the XML file starting from version v8 of Gaudi. The user converter needs to inherit of templated class XmlUserDetElemCnv.

// Include files
#include "DetDesc/XmlUserDetElemCnv.h"
#include "DeMuonStation.h"

/** @class XmlMuonStationCnv
*
* XML converter for VeloDetector
*
* @author Sebastien Ponce
*/

class XmlVeloDetectorCnv : public XmlUserDetElemCnv<VeloDetectorElement> {
public:
/// Constructor for this converter
XmlVeloDetectorCnv (ISvcLocator* svc);

/// Default destructor
~XmlVeloDetectorCnv() {}

protected:

/** This fills the current object for specific child.
* Overrides the default implementation in XmlUserDetElemCnv.
* @param childElement the specific child processed here
* @param refpObject the object to be filled
* @return status depending on the completion of the call
*/

virtual StatusCode i_fillSpecificObj (DOM_Element childElement,
                                      DeMuonStation* dataObj);
};

/// Instantiation of a static factory used by clients to create instances
static CnvFactory<XmlVeloDetectorCnv> st_factory;
const ICnvFactory& XmlVeloDetectorFactory = st_factory;

/// Constructor
XmlVeloDetectorCnv::XmlVeloDetectorCnv(ISvcLocator* svc) :
  XmlUserDetElemCnv<VeloDetectorElement> (svc) { }

  /// Fill an object with a new specific child element
  StatusCode XmlMuonStationCnv::i_fillSpecificObj (DOM_Element childElement,
                                                 DeMuonStation* dataObj) {
  MsgStream log (msgSvc(), "XmlVeloDetectorCnv");

  // gets the element's name
  std::string tagName = dom2Std (childElement.getNodeName());
  if( "Detector" == tagName ) {
    // get a value of the 'type' attribute
    const std::string value = dom2Std (childElement.getAttribute ("type"));  

    std::string type = attributes.getValue("type");
    if (!type.empty()) {
           log << MSG::DEBUG << "type has value : " << value << endreq;
     
if      (type == "R")   dataObj->setType(VeloDetectorElement::R);
           else if (type == "Phi") dataObj->setType(VeloDetectorElement::Phi);
    }
 
} else {
    // Unknown tag, a warning message could be issued here
    }
  return StatusCode::SUCCESS;
}