The primary goal of the HelixIntersection facility is to calculate the intersection points of a KTHelix with a given list of surfaces, while performing user-specified operations on the KTHelix at each surface encountered. Because these operations are, in general, non-abelian, HelixIntersection needs to perform ray tracing to determine not only which surfaces are intersected, but also the order in which they are intersected. This problem is trivial to solve for concentric cylinders (as in the DR), but for partially overlapping surfaces (as in the SVD), the procedure is more involved.

Originally, HelixIntersection was designed to provide an interface between the track fitters, which implement a Kalman filter technique, and the geometry and material description of the CLEO detector (encapsulated in the DetectorGeometry package). However, the design of HelixIntersection has been generalized to support other applications, such as segment finding in the silicon detector.



Any track fitting algorithm needs the derivatives of the distance of closest approach (DCA) of a track to a given hit with respect to the five (or more) track parameters. It is possible to implement these derivative calculations approximately uniformly for all types of surfaces, but in general, these derivatives depend on the geometry of the sense surface where the hit occurs.

Also, the Kalman filter modifies the error matrix of a track based on the expected energy loss and multiple scattering at each measurement point along the trajectory. Therefore it is necessary for the track propagator to accumulate a description of the material traversed.

A final requirement is to decouple the intersection surfaces from the detector's geometry description. In the CLEO II implementation of the Kalman filter, it was found that proper behavior could not be achieved unless stops were taken within a single silicon wafer. Otherwise, the multiple scattering induced by an entire wafer would lie outside the Gaussian regime. Therefore, it should be possible to create intersection surfaces that lie between real physical boundaries of the detector elements.



The HelixIntersection package consists of two main components:

The intersection surfaces are generated by the user by parsing the DetectorGeometry. These surfaces can take any arbitrary shape, but will most commonly be planes or cylinders. The use of planes and cylinders provides easy interaction with KTHelix, which contains member functions moveToPlane(...) and moveToCylinder(...). The surface is a boundary between two physical volumes, and, therefore, it has access to the material properties of both these volumes. Each surface also contains member functions for calculating the DCA and its derivatives, given a KTHelix.

In determining whether a helix intersects a given surface, one may want to enforce additional conditions. For instance, one basic condition is that the track's position should lie within the physical z-boundaries of the detector element. These conditions are given by the user and are encapsulated in a separate object, to which the surfaces holds a pointer.

Once an intersection has been established and the helix has been propagated to that point, the user may wish to modify the helix. In the case of the Kalman filter, the energy of the track needs to be updated to reflect its passage through material and the width of the Gaussian multiple scattering needs to be calculated. The specific operation to be performed may vary with the type of surface. Therefore, as with the conditions described above, each surface also contains a pointer to an object that encapsulates these operations.

Both the condition classes and the operation classes are implemented as Composites. In other words, objects that contain a single condition (or operation) have the same interface as objects that contain multiple conditions (or operations) because both inherit from the same base class. However, instead of implementing a specific condition, the composite condition contains a list of other concrete conditions, each of which is executed in turn. Thus, whether the object is a single condition or a container of other conditions is transparent to the user.

The helix intersector encapsulates the interactions between the KTHelix and the intersection surfaces. To find the surfaces intersected by the helix, the intersector performs ray-tracing operations and then checks whether the condition associated with each surface is met. Then, the intersector propagates the helix appropriately. At each surface encountered, the intersector performs the associated helix operation.

Just as with the intersection surfaces, the helix intersector also contains pointers to a condition object and an operation object. However, this condition is applied globally, after each intersection has been found. Before performing the operation associated with the surface intersected, the helix intersector tests this global condition. If satisfied, it overrides the surface's operation with the global operation. Otherwise, the surface's operation is executed. A typical use of the global condition and operation might be to check the number of radiation lengths to the next intersection. If it exceeds some nominal value, then the global operation would propagate the helix to some intermediate distance instead of performing the surface's operation.



The class diagrams below show only the most salient features of each class, omitting trivial constructors, accessors, and member data.

To use the HelixIntersector package, the user first creates an STL vector of HIIntersectionSurface objects, which also entails creating the HICondition and HIOperation objects associated with each HIIntersectionSurface. Then, the HIHelixIntersector is initialized with the vector of HIIntersectionSurfaces and the KTHelix under consideration. The user also calls the member functions of the HIHelixIntersector to propagate the KTHelix from surface to surface. A brief description of each class is given below.

This is the object which provides the interface between helices and user-defined material surfaces. It is initialized with a vector<HIIntersectionSurface*> and perhaps a KTHelix, as well as pointers to HICondition and HIHelixOperation objects. A resetHelix() member function allows the user to reuse the same set of surfaces with a different KTHelix.

The propagation member functions take as argument a direction (defined in an enum, corresponding to swimming along or against the track's momentum vector), analogous to the member functions of KTHelix. At each step in the propagation, HIHelixIntersector first checks whether the condition associated with the current surface is satisfied. If so, then the HIHelixIntersector tests its global condition, which if satisfied, triggers the execution of the global operation instead of the surface's operation. If the global condition is not satisfied, then the surface modifies the KTHelix by performing its own operation.

The member function swimToNextIntersection(...) transports the helix surface by surface, while swimToSurface(...) transports the helix to a given surface in a single function call (but applying the conditions and helix operations at each intermediate surface). The swimWhile(...) member function propagates the helix as long as the condition given as an argument is satisfied. The HICondition object used here is of the same type as those used with HIIntersectionSurfaces (described below). This condition does not override those associated with the HIIntersectionSurfaces but is an additional condition to determine whether the HIHelixIntersector should attempt helix transport to the next HIIntersectionSurface.
This abstract base class defines a surface with which a KTHelix intersects. The pure virtual member functions are those for calculating the DCA and its derivatives as well as the vector normal to the surface at a given point. These functions are implemented in the concrete subclasses. Operations performed on the KTHelix and conditions for establishing an intersection are managed by HIIntersectionSurface. The information passed to the HICondition and HIHelixOperation objects are the KTHelix, the point of intersection, the arc length traveled by the helix since the "previous" surface, and the surface itself. Most conditions and operations will not need so much information, but certain ones, like calculating energy loss, will. So, to avoid painful future modifications of the interface, more information is given to these objects than may be necessary.
HIIntersectionPlane and HIIntersectionCylinder
These concrete subclasses are initialized with a description of the surface's geometry as well as with pointers to the HICondition and HIOperation to be associated with each surface.
In addition to the features of HIIntersectionCylinder, HIIntersectionWireLayer also contains a pointer to a CalibratedHit, which is needed to calculate the DCA. There are additional subclasses inheriting from HIIntersectionWireLayer for axial and stereo DR layers.


HICondition and HIHelixOperation
These two families of classes have parallel structures. Each contains one member function (HICondition::satisfied(...) and HIHelixOperation::perform(...)) which is called by the HIIntersectionSurface object that owns it. The arguments to these member functions are listed above (in the description of HIIntersectionSurface). The base classes implement a sensible default behavior.
HICompositeCondition and HICompositeOperation
These two composite objects contain a list of concrete objects of the same base class type. Since both the single and the composite objects inherit from the same base class, it is possible to create composites of composites, thus encouraging code reuse. The composite objects contain additional member functions for manipulating the list of concrete objects, such as adding or removing items from the list and retrieving a specific entry in the list.