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.SiPixels;
30  import org.lcsim.detector.tracker.silicon.SiSensor;
31  import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
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 PixelHitMaker implements Clusterer {
43  
44      private static String _NAME = "PixelClusterer";
45      // Clustering algorithm
46      ClusteringAlgorithm _clustering;
47  
48      // Absolute maximum cluster size
49      int _max_cluster_npixels = 10;
50      // Readout chip needed to decode hit information
51      ReadoutChip _readout_chip;
52      // Sensor simulation needed to correct for Lorentz drift
53      SiSensorSim _simulation;
54      // Identifier helper (reset once per sensor)
55      SiTrackerIdentifierHelper _sid_helper;
56      // Temporary map connecting hits to pixel numbers for sake of speed (reset once per sensor)
57      Map<RawTrackerHit, Integer> _pixel_map = new HashMap<RawTrackerHit, Integer>();
58      double _oneClusterErr = 1 / Math.sqrt(12);
59      double _twoClusterErr = 1 / 5;
60      double _threeClusterErr = 1 / 3;
61      double _fourClusterErr = 1 / 2;
62      double _fiveClusterErr = 1;
63  
64      /**
65       * Create a new instance of PixelHitMaker that uses the default clustering algorithm
66       *
67       * @param simulation charge collection simulation
68       * @param readout_chip readout chip
69       */
70      public PixelHitMaker(SiSensorSim simulation, ReadoutChip readout_chip) {
71          this(simulation, readout_chip, new NearestNeighbor());
72      }
73  
74      /**
75       * Fully qualified constructor for PixelHitMaker
76       * 
77       * @param simulation charge collection simulation
78       * @param readout_chip readout chip
79       * @param clustering clustering algorithm
80       */
81      public PixelHitMaker(SiSensorSim simulation, ReadoutChip readout_chip, ClusteringAlgorithm clustering) {
82          _simulation = simulation;
83          _readout_chip = readout_chip;
84          _clustering = clustering;
85      }
86  
87      public void setClusteringAlgorithm(ClusteringAlgorithm clustering_algorithm) {
88          _clustering = clustering_algorithm;
89      }
90  
91      public void setMaxClusterSize(int max_cluster_npixels) {
92          _max_cluster_npixels = max_cluster_npixels;
93      }
94  
95      public String getName() {
96          return _NAME;
97      }
98  
99      public void SetOneClusterErr(double err) {
100         _oneClusterErr = err;
101     }
102 
103     public void SetTwoClusterErr(double err) {
104         _twoClusterErr = err;
105     }
106 
107     public void SetThreeClusterErr(double err) {
108         _threeClusterErr = err;
109     }
110 
111     public void SetFourClusterErr(double err) {
112         _fourClusterErr = err;
113     }
114 
115     public void SetFiveClusterErr(double err) {
116         _fiveClusterErr = err;
117     }
118 
119     // Make hits for all sensors within a DetectorElement
120     public List<SiTrackerHit> makeHits(IDetectorElement detector) {
121         System.out.println("makeHits(IDetectorElement): " + detector.getName());
122         List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
123         List<SiSensor> sensors = detector.findDescendants(SiSensor.class);
124 
125         // Loop over all sensors
126         for (SiSensor sensor : sensors) {
127             if (sensor.hasPixels()) {
128                 hits.addAll(makeHits(sensor));
129             }
130         }
131 
132         // Return hit list
133         return hits;
134     }
135 
136     // Make hits for a sensor
137     public List<SiTrackerHit> makeHits(SiSensor sensor) {
138 
139         //System.out.println("makeHits: " + sensor.getName());
140 
141         List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
142 
143         // Get SiTrackerIdentifierHelper for this sensor and refresh the pixel map used to increase speed
144         _sid_helper = (SiTrackerIdentifierHelper) sensor.getIdentifierHelper();
145         _pixel_map.clear();
146 
147         // Get hits for this sensor
148         IReadout ro = sensor.getReadout();
149         List<RawTrackerHit> raw_hits = ro.getHits(RawTrackerHit.class);
150 
151         Map<SiSensorElectrodes, List<RawTrackerHit>> electrode_hits = new HashMap<SiSensorElectrodes, List<RawTrackerHit>>();
152 
153         for (RawTrackerHit raw_hit : raw_hits) {
154 
155             // get id and create pixel map, get electrodes.
156             IIdentifier id = raw_hit.getIdentifier();
157             int pixel_number = _sid_helper.getElectrodeValue(id);
158 
159             //  Add this hit to the pixel maps
160             _pixel_map.put(raw_hit, pixel_number);
161 
162             // Get electrodes and check that they are pixels
163             //System.out.println("proc raw hit from: " + DetectorElementStore.getInstance().find(raw_hit.getIdentifier()).get(0).getName());
164             ChargeCarrier carrier = ChargeCarrier.getCarrier(_sid_helper.getSideValue(id));
165             SiSensorElectrodes electrodes = ((SiSensor) raw_hit.getDetectorElement()).getReadoutElectrodes(carrier);
166             if (!(electrodes instanceof SiPixels)) {
167                 continue;
168             }
169 
170             if (electrode_hits.get(electrodes) == null) {
171                 electrode_hits.put(electrodes, new ArrayList<RawTrackerHit>());
172             }
173 
174             electrode_hits.get(electrodes).add(raw_hit);
175         }
176 
177         for (Entry entry : electrode_hits.entrySet()) {
178             hits.addAll(makeHits(sensor, (SiPixels) entry.getKey(), (List<RawTrackerHit>) entry.getValue()));
179         }
180 
181         return hits;
182     }
183 
184     // Private methods
185     //=========================
186     // Make hits for an electrode
187     public List<SiTrackerHit> makeHits(SiSensor sensor, SiSensorElectrodes electrodes, List<RawTrackerHit> raw_hits) {
188 
189         //  Call the clustering algorithm to make clusters
190         List<List<RawTrackerHit>> cluster_list = _clustering.findClusters(electrodes, _readout_chip, raw_hits);
191 
192         //  Create an empty list for the pixel hits to be formed from clusters
193         List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
194 
195         //  Make a pixel hit from this cluster
196         for (List<RawTrackerHit> cluster : cluster_list) {
197 
198             // Make a TrackerHit from the cluster if it meets max cluster size requirement
199             if (cluster.size() <= _max_cluster_npixels) {
200                 SiTrackerHitPixel hit = makeTrackerHit(cluster, electrodes);
201 
202                 // Add to readout and to list of hits
203                 ((SiSensor) electrodes.getDetectorElement()).getReadout().addHit(hit);
204                 hits.add(hit);
205             }
206         }
207 
208         return hits;
209     }
210 
211     //Make the hit
212     private SiTrackerHitPixel makeTrackerHit(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) {
213         Hep3Vector position = getPosition(cluster, electrodes);
214         SymmetricMatrix covariance = getCovariance(cluster, electrodes);
215         double time = getTime(cluster);
216         double energy = getEnergy(cluster);
217         TrackerHitType type = new TrackerHitType(TrackerHitType.CoordinateSystem.GLOBAL, TrackerHitType.MeasurementType.PIXEL);
218 
219         SiTrackerHitPixel hit = new SiTrackerHitPixel(position, covariance, energy, time, cluster, type);
220         return hit;
221     }
222 
223     private List<SimTrackerHit> getSimulatedHits(List<RawTrackerHit> cluster) {
224         Set<SimTrackerHit> simulated_hits = new HashSet<SimTrackerHit>();
225         for (RawTrackerHit hit : cluster) {
226             simulated_hits.addAll(hit.getSimTrackerHits());
227         }
228         return new ArrayList<SimTrackerHit>(simulated_hits);
229     }
230 
231     private Hep3Vector getPosition(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) {
232         List<Double> signals = new ArrayList<Double>();
233         List<Hep3Vector> positions = new ArrayList<Hep3Vector>();
234 
235         for (RawTrackerHit hit : cluster) {
236             signals.add(_readout_chip.decodeCharge(hit));
237             positions.add(electrodes.getCellPosition(_pixel_map.get(hit)));
238         }
239 
240         double total_charge = 0;
241         Hep3Vector position = new BasicHep3Vector(0, 0, 0);
242 
243         for (int ipixel = 0; ipixel < signals.size(); ipixel++) {
244             double signal = signals.get(ipixel);
245 
246             total_charge += signal;
247             position = VecOp.add(position, VecOp.mult(signal, positions.get(ipixel)));
248         }
249         position = VecOp.mult(1 / total_charge, position);
250 
251         // Put position in sensor coordinates
252         electrodes.getParentToLocal().inverse().transform(position);
253 
254 //        System.out.println("Position \n"+position);
255 
256         // Swim position back through lorentz drift direction to midpoint between bias surfaces
257         _simulation.setSensor((SiSensor) electrodes.getDetectorElement());
258         _simulation.lorentzCorrect(position, electrodes.getChargeCarrier());
259 
260 //        System.out.println("Lorentz corrected position \n"+position);
261 
262         // return position in global coordinates
263         return ((SiSensor) electrodes.getDetectorElement()).getGeometry().getLocalToGlobal().transformed(position);
264 //        return electrodes.getLocalToGlobal().transformed(position);
265     }
266 
267     private double getTime(List<RawTrackerHit> cluster) {
268         int time_sum = 0;
269         int signal_sum = 0;
270 
271         for (RawTrackerHit hit : cluster) {
272 
273             int pixel_number = _pixel_map.get(hit);
274             double signal = _readout_chip.decodeCharge(hit);
275             double time = _readout_chip.decodeTime(hit);
276 
277             time_sum += time * signal;
278             signal_sum += signal;
279 
280         }
281         return (double) time_sum / (double) signal_sum;
282     }
283 
284     private SymmetricMatrix getCovariance(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) {
285 
286         SymmetricMatrix covariance = new SymmetricMatrix(3);
287         covariance.setElement(0, 0, Math.pow(getXResolution(cluster, electrodes), 2));
288         covariance.setElement(1, 1, Math.pow(getYResolution(cluster, electrodes), 2));
289         covariance.setElement(2, 2, 0.0);
290 
291         SymmetricMatrix covariance_global = electrodes.getLocalToGlobal().transformed(covariance);
292 
293 //        System.out.println("Global covariance matrix: \n"+covariance_global);
294 
295         return covariance_global;
296 
297     }
298 
299     private double getXResolution(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) {
300 
301         double measured_resolution;
302 
303         Set<Integer> rows = new HashSet<Integer>();
304         for (RawTrackerHit hit : cluster) {
305             rows.add(electrodes.getRowNumber(_pixel_map.get(hit)));
306         }
307 
308         int cluster_width = rows.size();
309         double sense_pitch = ((SiSensor) electrodes.getDetectorElement()).getSenseElectrodes(electrodes.getChargeCarrier()).getPitch(0);
310 
311         if (cluster_width == 1) {
312             measured_resolution = sense_pitch * _oneClusterErr;
313         } else if (cluster_width == 2) {
314             measured_resolution = sense_pitch * _twoClusterErr;
315         } else if (cluster_width == 3) {
316             measured_resolution = sense_pitch * _threeClusterErr;
317         } else if (cluster_width == 4) {
318             measured_resolution = sense_pitch * _fourClusterErr;
319         } else {
320             measured_resolution = sense_pitch * _fiveClusterErr;
321         }
322 
323         return measured_resolution;
324 
325     }
326 
327     private double getYResolution(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes) {
328 
329         double measured_resolution;
330 
331         Set<Integer> columns = new HashSet<Integer>();
332         for (RawTrackerHit hit : cluster) {
333             columns.add(electrodes.getColumnNumber(_pixel_map.get(hit)));
334         }
335 
336         int cluster_width = columns.size();
337         double sense_pitch = ((SiSensor) electrodes.getDetectorElement()).getSenseElectrodes(electrodes.getChargeCarrier()).getPitch(1);
338 
339         if (cluster_width == 1) {
340             measured_resolution = sense_pitch * _oneClusterErr;
341         } else if (cluster_width == 2) {
342             measured_resolution = sense_pitch * _twoClusterErr;
343         } else if (cluster_width == 3) {
344             measured_resolution = sense_pitch * _threeClusterErr;
345         } else if (cluster_width == 4) {
346             measured_resolution = sense_pitch * _fourClusterErr;
347         } else {
348             measured_resolution = sense_pitch * _fiveClusterErr;
349         }
350 
351         return measured_resolution;
352 
353     }
354 
355     private double getEnergy(List<RawTrackerHit> cluster) {
356         double total_charge = 0.0;
357         for (RawTrackerHit hit : cluster) {
358 
359             int pixel_number = _pixel_map.get(hit);
360             double signal = _readout_chip.decodeCharge(hit);
361 
362             total_charge += signal;
363         }
364         return total_charge * DopedSilicon.ENERGY_EHPAIR;
365     }
366 }