View Javadoc

1   /*
2    * MultipleScattering.java
3    *
4    * Created on January 23, 2008, 2:53 PM
5    *
6    */
7   
8   package org.lcsim.recon.tracking.seedtracker;
9   
10  import hep.physics.vec.BasicHep3Vector;
11  import hep.physics.vec.Hep3Vector;
12  import hep.physics.vec.VecOp;
13  
14  import java.util.ArrayList;
15  import java.util.Collections;
16  import java.util.List;
17  import java.util.Map;
18  
19  import org.lcsim.fit.helicaltrack.HelicalTrackFit;
20  import org.lcsim.fit.helicaltrack.HelicalTrackHit;
21  import org.lcsim.fit.helicaltrack.HelixUtils;
22  import org.lcsim.fit.helicaltrack.MultipleScatter;
23  
24  /**
25   * Calculate the multiple scattering contribution to the hit position
26   * error.
27   * @author Richard Partridge
28   * @version 1.0
29   */
30  public class MultipleScattering {
31      protected MaterialManager _materialmanager;
32      protected double _bfield = 0.;
33      private int _mxint = 10;
34      protected boolean _debug = false;
35  
36      /**
37       * Creates a new instance of MultipleScattering
38       * @param materialmanager MaterialManager provides access to the scattering material
39       */
40      public MultipleScattering(MaterialManager materialmanager) {
41          _materialmanager = materialmanager;
42      }
43  
44      /**
45       * Find the path lengths and multiple scattering angles for each
46       * intersection of the helix with tracker material
47       * @param helix HelicalTrackFit for this helix
48       * @return List of path lengths and scattering angles
49       */
50      public List<ScatterAngle> FindScatters(HelicalTrackFit helix) {
51          
52          //  Check that B Field is set
53          if (_bfield == 0.) throw new RuntimeException("B Field must be set before calling FindScatters method");
54  
55          //  Create a new list to contain the mutliple scatters
56          List<ScatterAngle> scatters = new ArrayList<ScatterAngle>();
57  
58          //  Retrieve the cylinder and disk material models from the material manager
59          List<MaterialCylinder> matcyl = _materialmanager.getMaterialCylinders();
60          List<MaterialDisk> matdsk = _materialmanager.getMaterialDisks();
61          List<MaterialXPlane> matxpl = _materialmanager.getMaterialXPlanes();
62  
63          //  Find the largest path length to a hit
64          double smax = 9999.;
65  
66          //  We can't go further than the ECal, however
67          double rmax = _materialmanager.getRMax();
68          List<Double> slist = HelixUtils.PathToCylinder(helix, rmax, smax, 1);
69          if (slist.size() > 0) smax = Math.min(smax, slist.get(0));
70          double zmax = _materialmanager.getZMax();
71          if (helix.slope() < 0.) zmax = -zmax;
72          smax = Math.min(smax, HelixUtils.PathToZPlane(helix, zmax));
73  
74          for (MaterialDisk disk : matdsk) {
75              double s = HelixUtils.PathToZPlane(helix, disk.z());
76              if (s > 0. && s < smax) {
77                  Hep3Vector pos = HelixUtils.PointOnHelix(helix, s);
78                  double r = Math.sqrt(Math.pow(pos.x(), 2) + Math.pow(pos.y(),2));
79                  if (r >= disk.rmin() && r <= disk.rmax()) {
80                      double cth = Math.abs(helix.cth());
81                      double radlen = disk.ThicknessInRL() / Math.max(cth, .001);
82                      double angle = msangle(helix.p(_bfield), radlen);
83                      scatters.add(new ScatterAngle(s, angle));
84                  }
85              }
86          }
87  
88          for (MaterialCylinder cyl : matcyl) {
89              double r = cyl.radius();
90              double scmin = HelixUtils.PathToZPlane(helix, cyl.zmin());
91              double scmax = HelixUtils.PathToZPlane(helix, cyl.zmax());
92              if (scmin > scmax) {
93                  double temp = scmin;
94                  scmin = scmax;
95                  scmax = temp;
96              }
97              List<Double> pathlist = HelixUtils.PathToCylinder(helix, r, smax, _mxint);
98              for (Double s : pathlist) {
99                  if (s > scmin && s < scmax) {
100                     Hep3Vector dir = HelixUtils.Direction(helix, s);
101                     Hep3Vector pos = HelixUtils.PointOnHelix(helix, s);
102                     Hep3Vector rhat = VecOp.unit(new BasicHep3Vector(pos.x(), pos.y(), 0.));
103                     double cth = Math.abs(VecOp.dot(dir, rhat));
104                     double radlen = cyl.ThicknessInRL() / Math.max(cth, 0.001);
105                     double angle = msangle(helix.p(_bfield), radlen);
106                     scatters.add(new ScatterAngle(s, angle));
107                 }
108         }
109         }
110         //mg 3/14/11  add in XPlanes
111         for (MaterialXPlane xpl : matxpl) {          
112             List<Double> pathlist = HelixUtils.PathToXPlane(helix, xpl.x(), smax, _mxint);
113             for (Double s : pathlist) {
114                 Hep3Vector dir = HelixUtils.Direction(helix, s);
115                 Hep3Vector pos = HelixUtils.PointOnHelix(helix, s);
116                 double y=pos.y();
117                 double z=pos.z();
118                 if (y >= xpl.ymin() && y <= xpl.ymax()&&z >= xpl.zmin() && z <= xpl.zmax()) {
119                     Hep3Vector xhat = VecOp.unit(new BasicHep3Vector(pos.x(),0. , 0.));
120                     double cth = Math.abs(VecOp.dot(dir, xhat));
121                     double radlen = xpl.ThicknessInRL() / Math.max(cth, .001);
122                     double angle = msangle(helix.p(_bfield), radlen);
123                     scatters.add(new ScatterAngle(s, angle));
124                 }
125             }
126         }
127         //  Sort the multiple scatters by their path length
128         Collections.sort(scatters);
129         return scatters;
130     }
131 
132     public static MultipleScatter CalculateScatter(HelicalTrackHit hit, HelicalTrackFit helix, List<ScatterAngle> scatters) {
133 
134         //  Retreive the x-y path length and calculate sin^2(theta) for this helix
135         double sth2 = Math.pow(helix.sth(), 2);
136         
137         //  Make sure the hit has an x-y path lengths.  Hits added since the last fit
138         //  won't have path lengths, so estimate the path length measured from the DCA
139         Map<HelicalTrackHit, Double> pathmap = helix.PathMap();
140         if (!pathmap.containsKey(hit)) {
141             pathmap.put(hit, (Double) HelixUtils.PathLength(helix, hit));
142         }
143 
144         double hitpath = pathmap.get(hit);
145 
146         //  Loop over scattering points and sum in quadrature ms errors for this hit.
147         //  It is assumed that we can ignore ms correlations during the track-finding stage.
148         double rphi_ms2 = 0.;
149         double z_ms2 = 0.;
150         for (ScatterAngle scat : scatters) {
151 
152             //  Find the x-y path length to this scatter
153             double scatpath = scat.PathLen();
154             
155             //  If the scatter is before the hit, calculate the ms errors for this scatter
156             if (scatpath > hitpath) break;
157 
158             //  Get the multiple scattering plane angle for this scatter
159             double angle = scat.Angle();
160 
161             //  Sum in quadrature the r-phi ms errors.  It is assumed that we
162             //  can ignore track curvature in calculating these errors during
163             //  the track-finding stage.
164             rphi_ms2 += Math.pow((hitpath - scatpath) * angle, 2);
165 
166             //  Sum in quadrature the z ms errors assuming a barrel geometry where
167             //  the path length is fixed.  While z is fixed for disk detectors, we
168             //  still do a z vs s fit by assuming the track direction is reasonably
169             //  well known and converting the radial measurement error into an effective
170             //  z coordinate error.
171             z_ms2 += Math.pow((hitpath - scatpath) * angle, 2)/sth2;
172         }
173         
174         //  Return the requested MultipleScatter
175         return new MultipleScatter(Math.sqrt(rphi_ms2), Math.sqrt(z_ms2));
176     }
177 
178     public void setBField(double bfield) {
179         _bfield = bfield;
180     }
181 
182 //  Calculate the multiple scattering angle for a given momentum and thickness
183     public double msangle(double p, double radlength) {
184         double angle = (0.0136 / p) * Math.sqrt(radlength) * (1.0 + 0.038 * Math.log(radlength));
185         return angle;
186     }
187 
188     public void setDebug(boolean debug) {
189         _debug = debug;
190     }
191     }