View Javadoc

1   /*
2    * HelicalTrackCross.java
3    *
4    * Created on May 1, 2008, 11:02 AM
5    *
6    */
7   
8   package org.lcsim.fit.helicaltrack;
9   
10  import hep.physics.matrix.SymmetricMatrix;
11  import hep.physics.vec.BasicHep3Vector;
12  import hep.physics.vec.Hep3Vector;
13  import hep.physics.vec.VecOp;
14  
15  import java.util.ArrayList;
16  import java.util.List;
17  
18  import org.lcsim.event.RawTrackerHit;
19  
20  /**
21   * Encapsulate cross (stereo) hit information needed by HelicalTrackFitter.
22   * The separation between the two sensor planes makes the hit position and
23   * covariance matrix depend on the track direction (track curvature between
24   * the sensor planes is assumed to be negligible).  The nominal hit position
25   * is calculated assuming the track originates from the origin.  A corrected
26   * hit position and covariance matrix, which accounts for the track direction
27   * and uncertainties in the track direction, can be calculated as well.
28   *
29   * Note that the nominal position will have large uncertainties associated
30   * with not knowing the track direction.
31   * @author Richard Partridge
32   * @version 1.0
33   */
34  public class HelicalTrackCross extends HelicalTrackHit {
35      private HelicalTrackStrip _strip1;
36      private HelicalTrackStrip _strip2;
37      private HelicalTrackFit _helix;
38      private static int _type = 3;
39      
40      /**
41       * Creates a new instance of HelicalTrackCross
42       * @param strip1 First of the two strips that form this cross
43       * @param strip2 Second of the two strips that form this cross
44       */
45      public HelicalTrackCross(HelicalTrackStrip strip1, HelicalTrackStrip strip2) {
46          super();
47          init(strip1,strip2);
48  
49      }
50      
51      
52      /**
53       * Creates a new instance of HelicalTrackCross
54       */
55      public HelicalTrackCross() {
56          super();
57      }
58      
59      public void init(HelicalTrackStrip strip1, HelicalTrackStrip strip2) {
60          init(HitUtils.PositionFromOrigin(strip1, strip2), HitUtils.CovarianceFromOrigin(strip1, strip2),
61                  strip1.dEdx()+strip2.dEdx(), 0.5*(strip1.time() + strip2.time()), _type, null,
62                  strip1.detector(), strip1.layer(), strip1.BarrelEndcapFlag());
63          _strip1 = strip1;
64          _strip2 = strip2;
65          _helix = null;
66          init();
67      }
68      
69      
70      private void init() {
71          
72          //  Put the raw hits from the strips into the hit list
73          if (_strip1.rawhits() != null) {
74              for (RawTrackerHit rawhit : (List<RawTrackerHit>) _strip1.rawhits()) {
75                  super.addRawHit(rawhit);
76              }
77          }
78          if (_strip2.rawhits() != null) {
79              for (RawTrackerHit rawhit : (List<RawTrackerHit>) _strip2.rawhits()) {
80                  super.addRawHit(rawhit);
81              }
82          }
83          
84          //  Check if the sensors are parallel to each other
85          if (VecOp.cross(_strip1.w(),_strip2.w()).magnitude() > _epsParallel) {
86              throw new RuntimeException("Trying to construct a stereo hit from non-parallel sensor planes eps=" + Double.toString(_epsParallel) + " value=" + Double.toString(VecOp.cross(_strip1.w(),_strip2.w()).magnitude()));
87          }
88          
89          //  Check that the normals point in the same direction
90          if (VecOp.dot(_strip1.w(),_strip2.w()) < 0.) {
91              throw new RuntimeException("Trying to construct a stereo hit using an in-consistent coordinate system!");
92          }
93          
94          //  Calculate v1hat . u2hat, which is equivalent to sin(alpha) where alpha is the stereo angle
95          double salpha = HitUtils.v1Dotu2(_strip1, _strip2);
96          if (Math.abs(salpha) < _epsStereoAngle) {
97              throw new RuntimeException("Trying to construct a stereo hit using parallel strips!");
98          }
99      }
100     
101     
102     /**
103      * Return a list of HelicalTrackStrips that contains the two strips that
104      * form the cross.
105      * @return list of the two strips that form this cross
106      */
107     public List<HelicalTrackStrip> getStrips() {
108         List<HelicalTrackStrip> striplist = new ArrayList<HelicalTrackStrip>();
109         striplist.add(_strip1);
110         striplist.add(_strip2);
111         return striplist;
112     }
113 
114     public void setTrackDirection(HelicalTrackFit helix) {
115 
116         if (helix != null) {
117             if (helix.equals(_helix)) return;
118             TrackDirection trkdir = HelixUtils.CalculateTrackDirection(helix, helix.PathMap().get(this));
119             setTrackDirection(trkdir, helix.covariance());
120             _helix = helix;
121         } else {
122             resetTrackDirection();
123         }
124     }
125 
126     /**
127      * Set the track direction to be used in calculating the corrected position
128      * and covariance matrix.  Calling this method will cause the corrected
129      * position and covariance matrix to be recalculated and stored and stored
130      * in the parent class.
131      * @param trkdir TrackDirection object containing direction and derivatives
132      * @param hcov covariance matrix for helix parameters
133      */
134     public void setTrackDirection(TrackDirection trkdir, SymmetricMatrix hcov) {
135         //  Get the corrected position and covariance matrix
136         Hep3Vector poscor = HitUtils.PositionOnHelix(trkdir, _strip1, _strip2);
137         SymmetricMatrix covcor = HitUtils.CovarianceOnHelix(trkdir, hcov, _strip1, _strip2);
138         //  Retrieve the nominal position and covariance matrix (i.e., from the origin methods)
139         Hep3Vector pos = new BasicHep3Vector(super.getPosition());
140         SymmetricMatrix cov = new SymmetricMatrix(3, super.getCovMatrix(), true);
141         //  Check to make sure we have sane errors in r-phi, r, and z - problems can occur
142         //  if the track direction is nearly parallel to the sensor plane
143         boolean errok = (drphicalc(poscor, covcor) < drphicalc(pos, cov)   + _eps) &&
144                 (drcalc(poscor, covcor)    < drcalc(pos, cov)      + _eps) &&
145                 (Math.sqrt(covcor.e(2,2))  < Math.sqrt(cov.e(2,2)) + _eps);
146         if (errok) {
147             super.setCorrectedPosition(poscor);
148             super.setCorrectedCovMatrix(covcor);
149             super.setChisq(ChisqPenalty(trkdir, hcov));
150         } else {
151             resetTrackDirection();
152         }
153         return;
154     }
155     
156     /**
157      * Reset the corrected hit position and covariance matrix to their
158      * nominal values (i.e., for a track coming from the origin with
159      * unknown track direction).  This method should be called before
160      * the first attempt to fit a helix to erase the "memory" of the
161      * previous helix fit.  Once there is some knowledge of the track
162      * direction (eg from one or more previous helix fits), invoking
163      * the setTrackDirection method will update the hit position and
164      * covariance matrix and significantly improve the hit position
165      * resolution for cross hits.
166      */
167     public void resetTrackDirection() {
168         super.setCorrectedPosition(HitUtils.PositionFromOrigin(_strip1, _strip2));
169         super.setCorrectedCovMatrix(HitUtils.CovarianceFromOrigin(_strip1, _strip2));
170         super.setChisq(0.);
171         _helix = null;
172     }
173     
174     /**
175      * Calculate a chi^2 penalty if one or both unmeasured coordinates for the hit lie
176      * outside the extant of their respective strips.
177      * @param trkdir track direction
178      * @param hcov helix covariance matrix
179      * @return chi^2 penalty
180      */
181     private double ChisqPenalty(TrackDirection trkdir, SymmetricMatrix hcov) {
182         double chisq = 0.;
183         double v1 = HitUtils.UnmeasuredCoordinate(trkdir, _strip1, _strip2);
184         double v2 = HitUtils.UnmeasuredCoordinate(trkdir, _strip2, _strip1);
185         double dv1 = HitUtils.dv(trkdir, hcov, _strip1, _strip2);
186         double dv2 = HitUtils.dv(trkdir, hcov, _strip2, _strip1);
187         //  Check if strip coordinates are within strip limits, and if so, add a chisq penalty
188         if (v1 < _strip1.vmin()) chisq += Math.pow((v1 - _strip1.vmin()) / dv1, 2);
189         if (v1 > _strip1.vmax()) chisq += Math.pow((v1 - _strip1.vmax()) / dv1, 2);
190         if (v2 < _strip2.vmin()) chisq += Math.pow((v2 - _strip2.vmin()) / dv2, 2);
191         if (v2 > _strip2.vmax()) chisq += Math.pow((v2 - _strip2.vmax()) / dv2, 2);
192         return chisq;
193     }
194 }