5 The Local Alignment Interface

DDAlign implements a machinery to apply and access the alignment parameters describing the difference between an ideal detector given by an ideal geometry and the geometry of the actually built assembly in real life. To ease its usage for the clients and to shield clients from the internals when actually dealing with realigned geometries, a set of helper classes was designed. The access to the alignment parameters in read-only mode was separated from the import or export thereof.

As a basic concept within DD4hep any sizable detector component can be realigned. Sizable as a rule of thumb is anything, which is manufactured as an individual piece and which you may ”hold in your hands”. Such objects are also described by a detector element of type DetElement. An example is e.g. a single silicon wafer of a tracking device or the entire tracking detector itself. The access to the alignment parameters is possible from each DetElement instance as described in Section 5.1. The interface assumes ”planar” alignment parameters i.e. the shape of a given volume does not change 3 .

As mentioned earlier, in the local alignment DDAlign allowed to retrieve time dependent alignment parameters and transformations. This time dependency was relatively easy achieved by re-using the conditions mechanism from DDCond . In this spirit Alignment transformations are practically no different from conditions like temperatures, pressures etc. To access the alignment conditions clearly not only some identifier must be provided, but also a interval of validity, which defines from which point in the past to which point in the future the required alignment constants may be applied.

Please be aware that the extensive use of misalignments is highly memory consuming.

5.1 Access to Alignment Parameters from the Detector Element

The DetAlign class as shown in Figure 1 gives the user access to the alignment structure of type Alignment as illustrated in the following example:

    ConditionsSlice slice = ...  // Prepared slice containing all condiitons  
    DetElement wafer_det  = ...  // Valid handle to a detector element  
    DetAlign   wafer = wafer_det;  
    Alignment  wafer_alignment = wafer.get();  
    if ( wafer_alignment.isValid() )  {  
        // This wafer’s placement differs from the ideal geometry when  
        // alignment parameters are present.  
 
        // Access the misalignment transformation with respect to the parent volume:  
        Transform3D tr = wafer_alignment.toMotherDelta();  
    }

The access to details of an invalid alignment object results in a runtime exception. The following calls allow clients to access alignment information from the DetElement structure:

      /// Access to the actual alignment information  
      Alignment alignment() const;  
 
      /// Access to the survey alignment information  
      Alignment surveyAlignment() const;

The call to alignment() return the parameters applied to the the existing ideal geometry. The call surveyAlignment() returns optional constants used to perform numerical calculations as described in section 2.3.

All functionality of the DetElement, which depends on applied alignment parameters are automatically updated in the event of changes. These are typically the geometry transformations with respect to the mother- and the world volume:

      /// Create cached matrix to transform to world coordinates  
      const TGeoHMatrix& worldTransformation() const;  
 
      /// Create cached matrix to transform to parent coordinates  
      const TGeoHMatrix& parentTransformation() const;  
 
      /// Transformation from local coordinates of the placed volume to the world system  
      bool localToWorld(const Position& local, Position& global) const;  
 
      /// Transformation from local coordinates of the placed volume to the parent system  
      bool localToParent(const Position& local, Position& parent) const;  
 
      /// Transformation from world coordinates of the local placed volume coordinates  
      bool worldToLocal(const Position& global, Position& local) const;  
 
      /// Transformation from world coordinates of the local placed volume coordinates  
      bool parentToLocal(const Position& parent, Position& local) const;

it is worth noting that the update of cached information is performed by the DetElement objects, other user defined cached information is not updated. To update user caches it is mandatory to provide a user defined update callback to the DetElement:

    template <typename Q, typename T>  
    void callAtUpdate(unsigned int type, Q* pointer,  
                      void (T::*pmf)(unsigned long typ, DetElement& det, void* opt_par)) const;

The interface of the Alignment structure to access detector alignment parameters is as follows (see also the corresponding header file DD4hep/Alignment.h):

      /// Number of nodes in this branch (=depth of the placement hierarchy from the top level volume)  
      int numNodes() const;  
 
      /// Access the placement of this node  
      PlacedVolume placement()   const;  
 
      /// Access the placement of the mother of this node  
      PlacedVolume motherPlacement(int level_up = 1)   const;  
 
      /// Access the placement of a node in the chain of placements for this branch  
      PlacedVolume nodePlacement(int level=-1)   const;  
 
      /// Access the currently applied alignment/placement matrix with respect to the world  
      Transform3D toGlobal(int level=-1) const;  
 
      /// Transform a point from local coordinates of a given level to global coordinates  
      Position toGlobal(const Position& localPoint, int level=-1) const;  
 
      /// Transform a point from global coordinates to local coordinates of a given level  
      Position globalToLocal(const Position& globalPoint, int level=-1) const;  
 
      /// Access the currently applied alignment/placement matrix with respect to mother volume  
      Transform3D toMother(int level=-1) const;  
 
      /// Access the currently applied alignment/placement matrix (mother to daughter)  
      Transform3D nominal() const;  
 
      /// Access the currently applied correction matrix (delta) (mother to daughter)  
      Transform3D delta() const;  
 
      /// Access the inverse of the currently applied correction matrix (delta) (mother to daughter)  
      Transform3D invDelta() const;

  • The calls in line 3-8 allow access to the relative position of the nth. element in the alignment stack with respect to its next level parent. Element numNodes() 1 denotes the lowest level and element 0 is the world volume. The default argument (1) addresses the lowest placement in the hierarchy.
  • Calls in line 9-12 allow to access/execute transformations from a given level in the placement hierarchy to coordinates in the top level volume (world).
  • The call in line 14 allows to transform a global coordinate to the local coordinate system in a given level of the hierarchy.
  • The call toMother in line 16 returns the local transformation of the node at a given level to the mother’s coordinate system.
  • The calls in line 17-20 give access to the nominal placement matrix of the realigned node with respect to the parent volume and the changes thereof.

Besides these convenience calls the full interface to the class TGeoPhysicalNode, which implements in the ROOT geometry package alignment changes, is accessible from the Alignment handle using the overloaded operator > (). Further documentation is available directly from the ROOT site .

5.2 Manipulation of Alignment Parameters

There are multiple possibilities to apply alignment parameters:

  • The pedestrian way ”by hand” using C++ as described in Subsection 5.2.1
  • Loading a whole set of misalignment constants from XML, the ”poor man’s” database. This mechanism is described in Subsection ??
  • Loading a whole set of misalignment constants from a database. This possibility depends heavily on the database and its schema used. A typical use case is to load misalignment constants depending on the experiment conditions at the time the event data were collected. DDAlign does not provide an implementation. This possibility here is only mentioned for completeness and will be subject to further developments to support conditions in DD4hep .

5.2.1 Manipulation of Alignment Parameters for Pedestrians using C++

In this section we describe how to apply geometry imperfections to an existing detector geometry in memory using C++. To apply misalignment to an existing geometry two classes are collaborating, the AlignmentCache attached to the geometry container Detector and a temporary structure the AlignmentStack. The AlignmentCache allows to access all existing alignment entries based on their subdetector. The AlignmentStack may exist in exactly one instance and is used to insert a consistent set of alignment entries. Consistency is important because changes may occur at any hierarchical level and internal transformation caches of the ROOT geometry package must be revalidated for all branches containing a higher level node. For this reason it is highly advisable to apply realignment constants for a complete subdetector. Note that this restriction is not imposed, in principle a consistent set of misalignments may be applied at any level of the geometry hierarchy.

Though the application of alignment is much simpler using XML files, the following description should give an insight on the mechanisms used behind the scene and to understand the concept.

Any manipulations are transaction based must be embraced by the following two calls opening and closing a transaction:

// Required include file(s)  
#include "DDAlign/AlignmentCache.h"  
 
    Detector& detector = ....;  
    AlignmentCache* cache = detector.extension<Geometry::AlignmentCache>();  
 
    // First things first: open the transaction.  
    cache->openTransaction();  
 
    // Prepare the entry containing the alignment data  
    AlignmentStack::StackEntry* entry =  .....;  
    //.... and add the element to the AlignmentStack .....  
    AlignmentStack::insert(entry);  
 
    // Finally close the transaction. At this moment the changes are applied.  
    cache->closeTransaction();

In the following we describe the mechanism to create and prepare the StackEntry instances of the above code snippet. The calls to open and close the alignment transaction do not have to be in the same code fragment where also the alignment entries are prepared. However, all changes are only applied when the transaction is closed. The alignment entries do not necessarily have to be prepared in the sequence of the hierarchy they should be applied, internally the entries are re-ordered and follow the geometry hierarchy top to bottom i.e. mother volumes are always re-aligned before the daughters are re-aligned.

The StackEntry instances carry all information to apply the re-alignment of a given volume. This information contains:

  • The transformation matrix describing the positional change of the volume with respect to its mother volume.
  • The placement path of the volume to be realigned.
  • A flag to reset the volume to its ideal position before the change is applied.
  • A flag to also reset all daughter volumes to their ideal position before the change is applied.
  • A flag to check for overlaps after the application of the change and
  • the actual precision used to perform this check.

The ROOT::Math library provides several ways to construct the required 3D transformation as described in Section 2.1:

// Required include file(s)  
#include "DD4hep/Objects.h"  
 
    Position      trans(x_translation, y_translation, z_translation);  
    RotationZYX   rot  (z_angle, y_angle, x_angle);  
    Translation3D pivot(x_pivot, y_pivot, z_pivot);  
 
    Transform3D trafo;  
    /// Construct a 3D transformation for a translation and a rotation around a pivot point:  
    trafo = Transform3D(Translation3D(trans)*pivot*rot*(pivot.Inverse()));  
 
    /// Construct a 3D transformation for a translation and a rotation around the origin  
    trafo = Transform3D(rot,pos);  
 
    /// Construct a 3D transformation for a rotation around a pivot point  
    trafo = Transform3D(piv*rot*(piv.Inverse()));  
 
    /// Construct a 3D transformation for a rotation around the origin  
    trafo = Transform3D(rot);  
 
    /// Construct a 3D transformation for simple translation  
    trafo = Transform3D(pos);  

The following code snippet shows how to extract this information from the DetElement and prepare such a StackEntry instance:

// Required include file(s)  
#include "DDAlign/AlignmentStack.h"  
 
    // Prepare the entry containing the alignment data  
    typedef AlignmentStack::StackEntry Entry;  
    /// Detector element to be realigned  
    DetElement element = ...;  
    /// The transformation describing the relative change with respect to the mother volume  
    Transform3D trafo = ...;  
    /// Instantiate a new alignment entry  
    Entry* entry = new Entry(element);  
    entry->setTransformation(trafo)                         // Apply the transformation matrix  
        .applyReset(/* argument default: true */)           // Set the reset flag  
        .applyResetChildren(/* argument default: true */)   // Set the daughter reset flag  
        .checkOverlaps(/* argument default: true */)        // Set flag to check overlaps  
        .overlapPrecision(0.001/mm);                        // With this precision in mm  
 
    /// Now add the entry to the alignment stack:  
    AlignmentStack::insert(entry);

The constructor will automatically determine the volumes placement path from the DetElement. Then the transformation is applied and the flags to reset the volume, its children and to trigger the overlap checks with the given precision.

When passing the entry to the AlignmentStack the AlignmentStack takes ownership and subsequently the entry is deleted after being applied to the geometry. For further shortcuts in the calling sequence please consult the AlignmentStack header file.