View Javadoc

1   /*
2    * StripHitMaker.java
3    *
4    * Created on September 26, 2007, 1:57 PM
5    *
6    * To change this template, choose Tools | Template Manager
7    * and open the template in the editor.
8    */
9   package org.lcsim.recon.tracking.digitization.sisim;
10  
11  import hep.physics.matrix.SymmetricMatrix;
12  import hep.physics.vec.BasicHep3Vector;
13  import hep.physics.vec.Hep3Vector;
14  import hep.physics.vec.VecOp;
15  
16  import java.util.ArrayList;
17  import java.util.HashMap;
18  import java.util.HashSet;
19  import java.util.List;
20  import java.util.Map;
21  import java.util.Set;
22  import java.util.Map.Entry;
23  
24  import org.lcsim.detector.IDetectorElement;
25  import org.lcsim.detector.IReadout;
26  import org.lcsim.detector.identifier.IIdentifier;
27  import org.lcsim.detector.tracker.silicon.ChargeCarrier;
28  import org.lcsim.detector.tracker.silicon.DopedSilicon;
29  import org.lcsim.detector.tracker.silicon.SiSensor;
30  import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
31  import org.lcsim.detector.tracker.silicon.SiStrips;
32  import org.lcsim.detector.tracker.silicon.SiTrackerIdentifierHelper;
33  import org.lcsim.event.RawTrackerHit;
34  import org.lcsim.event.SimTrackerHit;
35  
36  /**
37   *
38   * @author tknelson
39   * 
40   *  @version $Id:
41   */
42  public class StripHitMaker implements Clusterer {
43  
44      private static String _NAME = "StripClusterer";
45  
46      // Clustering algorithm
47      ClusteringAlgorithm _clustering;
48      // Number of strips beyond which charge is averaged on center strips
49      int _max_noaverage_nstrips = 4;
50      // Absolute maximum cluster size
51      int _max_cluster_nstrips = 10;
52      // Readout chip needed to decode hit information
53      ReadoutChip _readout_chip;
54      // Sensor simulation needed to correct for Lorentz drift
55      SiSensorSim _simulation;
56      // Identifier helper (reset once per sensor)
57      SiTrackerIdentifierHelper _sid_helper;
58      // Temporary map connecting hits to strip numbers for sake of speed (reset once per sensor)
59      Map<RawTrackerHit, Integer> _strip_map = new HashMap<RawTrackerHit, Integer>();
60      double _oneClusterErr = 1 / Math.sqrt(12);
61      double _twoClusterErr = 1 / 5;
62      double _threeClusterErr = 1 / 3;
63      double _fourClusterErr = 1 / 2;
64      double _fiveClusterErr = 1;
65  
66      /**
67       * Create a new instance of StripHitMaker that uses the default clustering algorithm
68       *
69       * @param simulation charge collection simulation
70       * @param readout_chip readout chip
71       */
72      public StripHitMaker(SiSensorSim simulation, ReadoutChip readout_chip) {
73          this(simulation, readout_chip, new NearestNeighbor());
74      }
75  
76      /**
77       * Fully qualified constructor for StripHitMaker
78       *
79       * @param simulation charge collection simulation
80       * @param readout_chip readout chip
81       * @param clustering clustering algorithm
82       */
83      public StripHitMaker(SiSensorSim simulation, ReadoutChip readout_chip, ClusteringAlgorithm clustering) {
84          _simulation = simulation;
85          _readout_chip = readout_chip;
86          _clustering = clustering;
87      }
88  
89      public void setClusteringAlgorithm(ClusteringAlgorithm clustering_algorithm) {
90          _clustering = clustering_algorithm;
91      }
92  
93      public void setCentralStripAveragingThreshold(int max_noaverage_nstrips) {
94          _max_noaverage_nstrips = max_noaverage_nstrips;
95      }
96  
97      public void setMaxClusterSize(int max_cluster_nstrips) {
98          _max_cluster_nstrips = max_cluster_nstrips;
99      }
100 
101     public String getName() {
102         return _NAME;
103     }
104 
105     // Make hits for all sensors within a DetectorElement
106     public List<SiTrackerHit> makeHits(IDetectorElement detector) {
107         System.out.println("makeHits(IDetectorElement): " + detector.getName());
108         List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
109         List<SiSensor> sensors = detector.findDescendants(SiSensor.class);
110 
111         // Loop over all sensors
112         for (SiSensor sensor : sensors) {
113             if (sensor.hasStrips()) {
114                 hits.addAll(makeHits(sensor));
115             }
116         }
117 
118         // Return hit list
119         return hits;
120     }
121 
122     // Make hits for a sensor
123     public List<SiTrackerHit> makeHits(SiSensor sensor) {
124 
125         //System.out.println("makeHits: " + sensor.getName());
126 
127         List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
128 
129         // Get SiTrackerIdentifierHelper for this sensor and refresh the strip map used to increase speed
130         _sid_helper = (SiTrackerIdentifierHelper) sensor.getIdentifierHelper();
131         _strip_map.clear();
132 
133         // Get hits for this sensor
134         IReadout ro = sensor.getReadout();
135         List<RawTrackerHit> raw_hits = ro.getHits(RawTrackerHit.class);
136 
137         Map<SiSensorElectrodes, List<RawTrackerHit>> electrode_hits = new HashMap<SiSensorElectrodes, List<RawTrackerHit>>();
138 
139         for (RawTrackerHit raw_hit : raw_hits) {
140 
141             // get id and create strip map, get electrodes.
142             IIdentifier id = raw_hit.getIdentifier();
143             _strip_map.put(raw_hit, _sid_helper.getElectrodeValue(id));
144 
145             // Get electrodes and check that they are strips
146             //System.out.println("proc raw hit from: " + DetectorElementStore.getInstance().find(raw_hit.getIdentifier()).get(0).getName());
147             ChargeCarrier carrier = ChargeCarrier.getCarrier(_sid_helper.getSideValue(id));
148             SiSensorElectrodes electrodes = ((SiSensor) raw_hit.getDetectorElement()).getReadoutElectrodes(carrier);
149             if (!(electrodes instanceof SiStrips)) {
150                 continue;
151             }
152 
153             if (electrode_hits.get(electrodes) == null) {
154                 electrode_hits.put(electrodes, new ArrayList<RawTrackerHit>());
155             }
156 
157             electrode_hits.get(electrodes).add(raw_hit);
158         }
159 
160         for (Entry entry : electrode_hits.entrySet()) {
161             hits.addAll(makeHits(sensor, (SiStrips) entry.getKey(), (List<RawTrackerHit>) entry.getValue()));
162         }
163 
164         return hits;
165     }
166 
167     public void SetOneClusterErr(double err) {
168         _oneClusterErr = err;
169     }
170 
171     public void SetTwoClusterErr(double err) {
172         _twoClusterErr = err;
173     }
174 
175     public void SetThreeClusterErr(double err) {
176         _threeClusterErr = err;
177     }
178 
179     public void SetFourClusterErr(double err) {
180         _fourClusterErr = err;
181     }
182 
183     public void SetFiveClusterErr(double err) {
184         _fiveClusterErr = err;
185     }
186     // Private methods
187     //=========================
188 
189     // Make hits for an electrode
190     public List<SiTrackerHit> makeHits(SiSensor sensor, SiSensorElectrodes electrodes, List<RawTrackerHit> raw_hits) {
191 
192         //  Call the clustering algorithm to make clusters
193         List<List<RawTrackerHit>> cluster_list = _clustering.findClusters(electrodes, _readout_chip, raw_hits);
194 
195         //  Create an empty list for the pixel hits to be formed from clusters
196         List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
197 
198         //  Make a pixel hit from this cluster
199         for (List<RawTrackerHit> cluster : cluster_list) {
200 
201             // Make a TrackerHit from the cluster if it meets max cluster size requirement
202             if (cluster.size() <= _max_cluster_nstrips) {
203                 SiTrackerHitStrip1D hit = makeTrackerHit(cluster, electrodes);
204 
205                 // Add to readout and to list of hits
206                 ((SiSensor) electrodes.getDetectorElement()).getReadout().addHit(hit);
207                 hits.add(hit);
208             }
209         }
210 
211         return hits;
212     }
213 
214     //Make the hit
215     private SiTrackerHitStrip1D makeTrackerHit(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) {
216         Hep3Vector position = getPosition(cluster, electrodes);
217         SymmetricMatrix covariance = getCovariance(cluster, electrodes);
218         double time = getTime(cluster);
219         double energy = getEnergy(cluster);
220         TrackerHitType type = new TrackerHitType(TrackerHitType.CoordinateSystem.GLOBAL, TrackerHitType.MeasurementType.STRIP_1D);
221 
222         SiTrackerHitStrip1D hit = new SiTrackerHitStrip1D(position, covariance, energy, time, cluster, type);
223         return hit;
224     }
225 
226     private List<SimTrackerHit> getSimulatedHits(List<RawTrackerHit> cluster) {
227         Set<SimTrackerHit> simulated_hits = new HashSet<SimTrackerHit>();
228         for (RawTrackerHit hit : cluster) {
229             simulated_hits.addAll(hit.getSimTrackerHits());
230         }
231         return new ArrayList<SimTrackerHit>(simulated_hits);
232     }
233 
234     private Hep3Vector getPosition(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) {
235         List<Double> signals = new ArrayList<Double>();
236         List<Hep3Vector> positions = new ArrayList<Hep3Vector>();
237 
238         for (RawTrackerHit hit : cluster) {
239             signals.add(_readout_chip.decodeCharge(hit));
240             positions.add(((SiStrips) electrodes).getStripCenter(_strip_map.get(hit)));
241         }
242 
243         // Average charge on central strips of longer clusters
244         if (signals.size() > _max_noaverage_nstrips) {
245             int nstrips_center = signals.size() - 2;
246 
247             // collect sum of charges on center strips
248             double center_charge_sum = 0.0;
249             for (int istrip = 1; istrip < signals.size() - 1; istrip++) {
250                 center_charge_sum += signals.get(istrip);
251             }
252 
253             // distribute evenly on center strips
254             double center_charge_strip = center_charge_sum / nstrips_center;
255             for (int istrip = 1; istrip < signals.size() - 1; istrip++) {
256                 signals.set(istrip, center_charge_strip);
257             }
258         }
259 
260         double total_charge = 0;
261         Hep3Vector position = new BasicHep3Vector(0, 0, 0);
262 
263         for (int istrip = 0; istrip < signals.size(); istrip++) {
264             double signal = signals.get(istrip);
265 
266             total_charge += signal;
267             position = VecOp.add(position, VecOp.mult(signal, positions.get(istrip)));
268         }
269         position = VecOp.mult(1 / total_charge, position);
270 
271 //        double total_charge = 0;
272 //        Hep3Vector position = new BasicHep3Vector(0,0,0);
273 //        
274 //        for (RawTrackerHit hit : cluster)
275 //        {
276 //            int strip_number = _strip_map.get(hit);
277 //            double signal = _readout_chip.decodeCharge(hit);
278 //            
279 //            total_charge += signal;
280 //            position = VecOp.add(position,VecOp.mult(signal,((SiStrips)electrodes).getStripCenter(strip_number)));
281 //        }
282 //        position = VecOp.mult(1/total_charge,position);
283 
284         // Put position in sensor coordinates
285         electrodes.getParentToLocal().inverse().transform(position);
286 
287 //        System.out.println("Position \n"+position);
288 
289         // Swim position back through lorentz drift direction to midpoint between bias surfaces
290         _simulation.setSensor((SiSensor) electrodes.getDetectorElement());
291         _simulation.lorentzCorrect(position, electrodes.getChargeCarrier());
292 
293 //        System.out.println("Lorentz corrected position \n"+position);
294 
295         // return position in global coordinates
296         return ((SiSensor) electrodes.getDetectorElement()).getGeometry().getLocalToGlobal().transformed(position);
297 //        return electrodes.getLocalToGlobal().transformed(position);
298     }
299 
300     private double getTime(List<RawTrackerHit> cluster) {
301         int time_sum = 0;
302         int signal_sum = 0;
303 
304         for (RawTrackerHit hit : cluster) {
305 
306             int strip_number = _strip_map.get(hit);
307             double signal = _readout_chip.decodeCharge(hit);
308             double time = _readout_chip.decodeTime(hit);
309 
310             time_sum += time * signal;
311             signal_sum += signal;
312 
313         }
314         return (double) time_sum / (double) signal_sum;
315     }
316 
317     private SymmetricMatrix getCovariance(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) {
318         SymmetricMatrix covariance = new SymmetricMatrix(3);
319         covariance.setElement(0, 0, Math.pow(getMeasuredResolution(cluster, electrodes), 2));
320         covariance.setElement(1, 1, Math.pow(getUnmeasuredResolution(cluster, electrodes), 2));
321         covariance.setElement(2, 2, 0.0);
322 
323         SymmetricMatrix covariance_global = electrodes.getLocalToGlobal().transformed(covariance);
324 
325 //        System.out.println("Global covariance matrix: \n"+covariance_global);
326 
327         return covariance_global;
328 
329 //        BasicHep3Matrix rotation_matrix = (BasicHep3Matrix)electrodes.getLocalToGlobal().getRotation().getRotationMatrix();
330 //        BasicHep3Matrix rotation_matrix_transposed = new BasicHep3Matrix(rotation_matrix);
331 //        rotation_matrix_transposed.transpose();
332 //
333 ////        System.out.println("Rotation matrix: \n"+rotation_matrix);
334 ////        System.out.println("Rotation matrix transposed: \n"+rotation_matrix_transposed);
335 ////        System.out.println("Local covariance matrix: \n"+covariance);
336 //
337 //        BasicHep3Matrix covariance_global = (BasicHep3Matrix)VecOp.mult(rotation_matrix,VecOp.mult(covariance,rotation_matrix_transposed));
338 //
339 ////        System.out.println("Global covariance matrix: \n"+covariance_global);
340 //
341 //        return new SymmetricMatrix((Matrix)covariance_global);
342     }
343 
344     private double getMeasuredResolution(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) // should replace this by a ResolutionModel class that gives expected resolution.  This could be a big job.
345     {
346         double measured_resolution;
347 
348         double sense_pitch = ((SiSensor) electrodes.getDetectorElement()).getSenseElectrodes(electrodes.getChargeCarrier()).getPitch(0);
349 
350 //        double readout_pitch = electrodes.getPitch(0);
351 //        double noise = _readout_chip.getChannel(strip_number).computeNoise(electrodes.getCapacitance(strip_number));
352 //        double signal_expected = (0.000280/DopedSilicon.ENERGY_EHPAIR) *
353 //                ((SiSensor)electrodes.getDetectorElement()).getThickness(); // ~280 KeV/mm for thick Si sensors
354 
355         if (cluster.size() == 1) {
356             measured_resolution = sense_pitch *_oneClusterErr;
357         } else if (cluster.size() == 2) {
358             measured_resolution = sense_pitch *_twoClusterErr;
359         } else if (cluster.size() == 3) {
360             measured_resolution = sense_pitch *_threeClusterErr;
361         } else if (cluster.size() == 4) {
362             measured_resolution = sense_pitch *_fourClusterErr;
363         } else {
364             measured_resolution = sense_pitch*_fiveClusterErr;
365         }
366 
367         return measured_resolution;
368     }
369 
370     private double getUnmeasuredResolution(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) {
371         // Get length of longest strip in hit
372         double hit_length = 0;
373         for (RawTrackerHit hit : cluster) {
374             hit_length = Math.max(hit_length, ((SiStrips) electrodes).getStripLength(_strip_map.get(hit)));
375         }
376         return hit_length / Math.sqrt(12);
377     }
378 
379     private double getEnergy(List<RawTrackerHit> cluster) {
380         double total_charge = 0.0;
381         for (RawTrackerHit hit : cluster) {
382 
383             int strip_number = _strip_map.get(hit);
384             double signal = _readout_chip.decodeCharge(hit);
385 
386             total_charge += signal;
387         }
388         return total_charge * DopedSilicon.ENERGY_EHPAIR;
389     }
390 }