View Javadoc

1   package org.lcsim.detector.tracker.silicon;
2   /*
3    * SiStrips.java
4    *
5    * Created on July 22, 2005, 4:07 PM
6    *
7    * To change this template, choose Tools | Options and locate the template under
8    * the Source Creation and Management node. Right-click the template and choose
9    * Open. You can then make changes to the template in the Source Editor.
10   */
11  
12  //import static org.lcsim.units.clhep.SystemOfUnits.*;
13  import org.lcsim.detector.IDetectorElement;
14  import org.lcsim.detector.ITransform3D;
15  import org.lcsim.detector.Transform3D;
16  import hep.physics.vec.Hep3Vector;
17  import hep.physics.vec.BasicHep3Vector;
18  import hep.physics.vec.VecOp;
19  import java.util.ArrayList;
20  import java.util.SortedMap;
21  import java.util.TreeMap;
22  import java.util.Set;
23  import java.util.HashSet;
24  import java.util.List;
25  import org.lcsim.detector.solids.GeomOp2D;
26  import org.lcsim.detector.solids.GeomOp3D;
27  import org.lcsim.detector.solids.Line3D;
28  import org.lcsim.detector.solids.LineSegment3D;
29  import org.lcsim.detector.solids.Point3D;
30  import org.lcsim.detector.solids.Polygon3D;
31  
32  /**
33   *
34   * @author tknelson
35   */
36  public class SiStrips implements SiSensorElectrodes
37  {
38      
39      // Fields
40      
41      // Object definition
42      private ChargeCarrier _carrier; // charge carrier collected
43      private int _nstrips; // number of strips
44      private double _pitch; // sense pitch
45      private IDetectorElement _detector; // associated detector element
46      private ITransform3D _parent_to_local; // parent to local transform
47      private ITransform3D _local_to_global; // transformation to global coordinates
48      private ITransform3D _global_to_local; // transformation from global coordinates
49      private Polygon3D _geometry; // region in which strips are defined
50      private double _capacitance_intercept = 10.;  // fixed capacitance independent of strip length
51      private double _capacitance_slope = 0.1;  //  capacitance per unit length of strip
52      
53      // Cached for convenience
54      private double _strip_offset;
55  
56       public SiStrips(){
57           
58       };
59      // Constructors
60      //=============
61      public SiStrips(ChargeCarrier carrier, double pitch, IDetectorElement detector, ITransform3D parent_to_local)
62      {
63          
64  //        System.out.println("Plane of polygon in sensor coordinates has... ");
65  //        System.out.println("                        normal: "+((SiSensor)detector).getBiasSurface(carrier).getNormal());
66  //        System.out.println("                        distance: "+((SiSensor)detector).getBiasSurface(carrier).getDistance());
67          
68          setCarrier(carrier);
69          setPitch(pitch);
70          setGeometry(((SiSensor)detector).getBiasSurface(carrier).transformed(parent_to_local));
71          setStripNumbering();
72          setDetectorElement(detector);
73          setParentToLocal(parent_to_local);
74          setGlobalToLocal(Transform3D.multiply(parent_to_local,detector.getGeometry().getGlobalToLocal()));
75          setLocalToGlobal(getGlobalToLocal().inverse());
76      }
77      
78      public SiStrips(ChargeCarrier carrier, double pitch, int nstrips, IDetectorElement detector, ITransform3D parent_to_local)
79      {
80          setCarrier(carrier);
81          setPitch(pitch);
82          setGeometry(((SiSensor)detector).getBiasSurface(carrier).transformed(parent_to_local));
83          setNStrips(nstrips);
84          setDetectorElement(detector);
85          setParentToLocal(parent_to_local);
86          setGlobalToLocal(Transform3D.multiply(parent_to_local,detector.getGeometry().getGlobalToLocal()));
87          setLocalToGlobal(getGlobalToLocal().inverse());
88      }
89      
90       public SiStrips(ChargeCarrier carrier, double pitch, int nstrips, IDetectorElement detector, ITransform3D parent_to_local ,ITransform3D misalignment){
91           
92       }
93       
94         public SiStrips(ChargeCarrier carrier, double pitch,  IDetectorElement detector, ITransform3D parent_to_local ,ITransform3D misalignment){
95           
96       }
97  
98      // SiSensorElectrodes interface
99      //=============================
100     
101     // Mechanical properties
102     public int getNAxes()
103     {
104         return 1;
105     }
106     
107     public IDetectorElement getDetectorElement()
108     {
109         return _detector;
110     }
111     
112     public ITransform3D getParentToLocal()
113     {
114         return _parent_to_local;
115     }
116     
117     public ITransform3D getLocalToGlobal()
118     {
119         return _local_to_global;
120     }
121     
122     public ITransform3D getGlobalToLocal()
123     {
124         return _global_to_local;
125     }
126     
127     public Polygon3D getGeometry()
128     {
129         return _geometry;
130     }
131     
132     public Hep3Vector getMeasuredCoordinate(int axis)
133     {
134         if (axis == 0) return new BasicHep3Vector(1.0,0.0,0.0);
135         else return null;
136     }
137     
138     public Hep3Vector getUnmeasuredCoordinate(int axis)
139     {
140         if (axis == 0) return new BasicHep3Vector(0.0,1.0,0.0);
141         else return null;
142     }
143     
144     public int getNeighborCell(int cell, int ncells_0, int ncells_1)
145     {
146         int neighbor_cell = cell + ncells_0;
147         if (isValidCell(neighbor_cell)) return neighbor_cell;
148         else return -1;
149     }
150     
151     public Set<Integer> getNearestNeighborCells(int cell)
152     {
153         Set<Integer> neighbors = new HashSet<Integer>();
154         for (int ineigh = -1 ; ineigh <= 1; ineigh=ineigh+2)
155         {
156             int neighbor_cell = getNeighborCell(cell,ineigh,0);
157             if (isValidCell(neighbor_cell)) neighbors.add(neighbor_cell);
158         }
159         return neighbors;
160     }
161     
162     public boolean isValidCell(int cell)
163     {
164         return (cell >= 0 && cell < getNCells());
165     }
166     
167     public int getNCells()
168     {
169         return _nstrips;
170     }
171     
172     public int getNCells(int axis)
173     {
174         if (axis == 0)
175         {
176             return _nstrips;
177         }
178         else return 1;
179     }
180     
181     public double getPitch(int axis)
182     {
183         if (axis == 0)
184         {
185             return _pitch;
186         }
187         else return 0;
188     }
189     public int getCellID(Hep3Vector position)
190     {
191         return (int)Math.round((position.x()+_strip_offset)/_pitch);
192     }
193     
194     
195     public int getRowNumber(Hep3Vector position)
196     {
197         return 0;
198     }
199     
200     public int getColumnNumber(Hep3Vector position)
201     {
202         return getCellID(position);
203     }
204     
205     public int getCellID(int row_number, int column_number)
206     {
207         return column_number;
208     }
209     
210     public int getRowNumber(int cell_id)
211     {
212         return 0;
213     }
214     
215     public int getColumnNumber(int cell_id)
216     {
217         return cell_id;
218     }
219     
220     public Hep3Vector getPositionInCell(Hep3Vector position)
221     {
222         return VecOp.sub(position,getCellPosition(getCellID(position)));
223     }
224     
225     public Hep3Vector getCellPosition(int strip_number)
226     {
227         return new BasicHep3Vector(strip_number*_pitch-_strip_offset,0.0,0.0);
228     }
229     
230     // Electrical properties
231     
232     /**
233      * Capacitance intercept parameter.  Units are pF.
234      * 
235      * Capacitance is calculated as:
236      * C = capacitance_intercept + strip_length * capacitance slope
237      * 
238      * @param capacitance_intercept
239      */
240     public void setCapacitanceIntercept(double capacitance_intercept) {
241         _capacitance_intercept = capacitance_intercept;
242     }
243 
244     /**
245      * Capacitance per unit strip length.  Units are pF / mm.
246      *
247      * @param capacitance_slope
248      */
249     public void setCapacitanceSlope(double capacitance_slope) {
250         _capacitance_slope = capacitance_slope;
251     }
252 
253     public ChargeCarrier getChargeCarrier()
254     {
255         return _carrier;
256     }
257 
258     /**
259      * Capacitance for a particular cell.  Units are pF.
260      *
261      * @param cell_id
262      * @return
263      */
264     public double getCapacitance(int cell_id) // capacitance in pF
265     {
266         return _capacitance_intercept + _capacitance_slope*getStripLength(cell_id);
267     }
268     
269     /**
270      * Nominal capacitance used for throwing random noise in the sensor.
271      * Calculated using middle strip.  Units are pF.
272      * 
273      * @return
274      */
275     public double getCapacitance() {
276         return getCapacitance(getNCells(0) / 2);
277     }
278 
279     public SortedMap<Integer,Integer> computeElectrodeData(ChargeDistribution distribution)
280     {
281         SortedMap<Integer,Integer> electrode_data = new TreeMap<Integer,Integer>();
282         
283         int base_strip = getCellID(distribution.getMean());
284         
285         // put charge on strips in window 3-sigma strips on each side of base strip
286         int axis = 0;
287         int window_size = (int)Math.ceil(3.0*distribution.sigma1D(getMeasuredCoordinate(axis))/getPitch(axis));
288         
289         double integral_lower = distribution.getNormalization();
290         double integral_upper = distribution.getNormalization();
291         
292         for (int istrip = base_strip-window_size; istrip <= base_strip+window_size; istrip++)
293         {
294             double cell_edge_upper = getCellPosition(istrip).x() + getPitch(axis)/2.0;
295             
296 //            System.out.println("cell_edge_upper: "+cell_edge_upper);
297             
298             double integration_limit = cell_edge_upper;        //cell_edge_upper-distribution.mean().x();
299             
300 //            System.out.println("integration_limit: "+integration_limit);
301             
302             integral_upper = distribution.upperIntegral1D(getMeasuredCoordinate(axis),integration_limit);
303             
304 //            System.out.println("integral_upper: "+integral_upper);
305             
306             if (integral_lower<integral_upper)
307             {
308                 throw new RuntimeException("Error in integrating Gaussian charge distribution!");
309             }
310             
311             int strip_charge = (int)Math.round(integral_lower-integral_upper);
312             
313 //            System.out.println("strip_charge: "+strip_charge);
314             
315             if (strip_charge != 0)
316             {
317                 electrode_data.put(istrip,strip_charge);
318             }
319             
320             integral_lower = integral_upper;
321         }
322         
323         return electrode_data;
324         
325     }
326     
327     // Strip specific methods
328     
329     // length of strip
330     public double getStripLength(int cell_id)
331     {
332 //        System.out.println("strip_length: "+getStrip(cell_id).getLength());
333         return getStrip(cell_id).getLength();
334     }
335     
336     // center of strip
337     public Hep3Vector getStripCenter(int cell_id)
338     {
339         LineSegment3D strip = getStrip(cell_id);
340         return strip.getEndPoint(strip.getLength()/2);
341     }
342     
343     // line segment for strip
344     public LineSegment3D getStrip(int cell_id)
345     {
346         Line3D strip_line = new Line3D(new Point3D(getCellPosition(cell_id)),getUnmeasuredCoordinate(0));
347         
348 //        System.out.println("Number of strips: "+this._nstrips);
349 //        System.out.println("Strip offset: "+this._strip_offset);
350 //        System.out.println("Pitch: "+this._pitch);
351 //        System.out.println("cell_id: "+cell_id);
352 //        System.out.println("strip_line start point: "+strip_line.getStartPoint());
353 //        System.out.println("strip_line direction: "+strip_line.getDirection());
354         
355         List<Point3D> intersections = new ArrayList<Point3D>();
356         
357         // Get intersections between strip line and edges of electrode polygon
358         for (LineSegment3D edge : _geometry.getEdges())
359         {
360 //            System.out.println("edge start point: "+edge.getStartPoint());
361 //            System.out.println("edge end point: "+edge.getEndPoint());
362             
363             if (GeomOp2D.intersects(strip_line,edge))
364             {
365                 intersections.add(GeomOp3D.lineBetween(strip_line,edge).getStartPoint());
366             }
367         }
368         
369         // Check for rare occurrence of duplicates (can happen at corners of polygon)
370         List<Point3D> strip_ends = new ArrayList<Point3D>(intersections);
371         if (intersections.size() > 2)
372         {
373             for (int ipoint1 = 0; ipoint1 < intersections.size(); ipoint1++)
374             {
375                 Point3D point1 = intersections.get(ipoint1);
376                 for (int ipoint2 = ipoint1+1; ipoint2 < intersections.size(); ipoint2++)
377                 {
378                     Point3D point2 = intersections.get(ipoint2);
379                     if (GeomOp3D.intersects(point1,point2))
380                     {
381                         strip_ends.remove(point2);
382                         if (strip_ends.size() == 2) break;
383                     }
384                 }
385             }
386         }
387         
388         return new LineSegment3D(strip_ends.get(0),strip_ends.get(1));
389     }
390     
391     // Private setters
392     //==================
393     public void setCarrier(ChargeCarrier carrier)
394     {
395         _carrier = carrier;
396     }
397     
398     public void setGeometry(Polygon3D geometry)
399     {
400 //        System.out.println("Plane of polygon has... ");
401 //        System.out.println("                        normal: "+geometry.getNormal());
402 //        System.out.println("                        distance: "+geometry.getDistance());
403 //
404 //        System.out.println("Working plane has... ");
405 //        System.out.println("                        normal: "+GeomOp2D.PLANE.getNormal());
406 //        System.out.println("                        distance: "+GeomOp2D.PLANE.getDistance());
407         
408         if (GeomOp3D.equals(geometry.getPlane(),GeomOp2D.PLANE))
409         {
410             _geometry = geometry;
411         }
412         else
413         {
414             throw new RuntimeException("Electrode geometry must be defined in x-y plane!!");
415         }
416     }
417     
418     private void setStripNumbering()
419     {
420         double xmin = Double.MAX_VALUE;
421         double xmax = Double.MIN_VALUE;
422         for (Point3D vertex : _geometry.getVertices())
423         {
424             xmin = Math.min(xmin,vertex.x());
425             xmax = Math.max(xmax,vertex.x());
426         }
427         
428 //        System.out.println("xmin: " + xmin);
429 //        System.out.println("xmax: " + xmax);
430 //
431 //
432 //        System.out.println("# strips: " +   (int)Math.ceil((xmax-xmin)/getPitch(0)) ) ;
433         
434         setNStrips(  (int)Math.ceil((xmax-xmin)/getPitch(0)) ) ;
435     }
436     
437     private void setNStrips(int nstrips)
438     {
439         _nstrips = nstrips;
440         setStripOffset();
441 //        _strip_offset = (_nstrips-1)*_pitch/2.;
442     }
443     
444     private void setStripOffset()
445     {
446         double xmin = Double.MAX_VALUE;
447         double xmax = Double.MIN_VALUE;
448         for (Point3D vertex : _geometry.getVertices())
449         {
450             xmin = Math.min(xmin,vertex.x());
451             xmax = Math.max(xmax,vertex.x());
452         }
453         
454         double strips_center = (xmin+xmax)/2;
455         
456         _strip_offset = ((_nstrips-1)*_pitch)/2 - strips_center;
457         
458     }
459     
460     private void setPitch(double pitch)
461     {
462         _pitch = pitch;
463     }
464     
465     private void setDetectorElement(IDetectorElement detector)
466     {
467         _detector = detector;
468     }
469     
470     private void setParentToLocal(ITransform3D parent_to_local)
471     {
472         _parent_to_local = parent_to_local;
473     }
474     
475     private void setLocalToGlobal(ITransform3D local_to_global)
476     {
477         _local_to_global = local_to_global;
478     }
479     
480     private void setGlobalToLocal(ITransform3D global_to_local)
481     {
482         _global_to_local = global_to_local;
483     }
484     
485 }
486 
487