View Javadoc

1   package org.lcsim.recon.cat;
2   
3   import java.util.*;
4   
5   import org.lcsim.event.*;
6   import org.lcsim.util.Driver;
7   import org.lcsim.geometry.Subdetector;
8   
9   import org.lcsim.recon.cat.util.Const;
10  import org.lcsim.recon.cat.util.NoSuchParameterException;
11  
12  /**
13   * This processor converts tracker hits into GarfieldHit objects.
14   * It lets the user to specify collections to be included, or ignore the hits
15   * picked up by previously run tracking algorithms.  It also gets rid of
16   * multiple adjacent hits due to delta electrons.
17   * <p>
18   * Most of this machinery will become unnecessary once proper digitization
19   * packages are available, and standard two-dimensional tracker hit interface is
20   * specified.
21   *
22   * @author  E. von Toerne
23   * @author D. Onoprienko
24   * @version $Id: GarfieldHitConverter.java,v 1.1 2007/04/06 21:48:14 onoprien Exp $
25   */
26  final public class GarfieldHitConverter extends Driver {
27    
28  // --  Constructors :  ---------------------------------------------------------
29    
30    public GarfieldHitConverter() {}
31    
32  // -- Setters :  ---------------------------------------------------------------
33  
34    /** 
35     * Set any <tt>String</tt> parameter. 
36     * The following parameters can be set with this method:<br>
37     * <tt>"OUTPUT_COLLECTION_NAME"</tt> - name of output <tt>TrackerHit</tt> collection. Default: "GarfieldHits"<br>
38     * <tt>"INCLIDE_HIT_COLLECTION"</tt> - name of input <tt>SimTrackerHit</tt> collection to be included in processing.<br>
39     * @param name   Name of parameter to be set. Case is ignored.
40     * @param value  Value to be assigned to the parameter.
41     * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
42     *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
43     *         and set their own parameters.
44     */
45    public void set(String name, String value) {
46      if (name.equalsIgnoreCase("OUTPUT_COLLECTION_NAME")) {
47        outputCollectionName = value;
48      } else if (name.equalsIgnoreCase("INCLIDE_HIT_COLLECTION")) {
49        inputCollectionNames.add(value);
50      } else {
51        throw new NoSuchParameterException(name, this.getClass());
52      }
53    }
54    
55    /** 
56     * Set any <tt>boolean</tt> parameter. 
57     * The following parameters can be set with this method:<br>
58     * <tt>"INCLUDE_VXD"</tt> - Process <tt>SimTrackerHit</tt>s from VXD. Default: <tt>true</tt><br>
59     * <tt>"OUTSIDE_IN"</tt> - sort hits for outside-in processing. Default: <tt>true</tt><br>
60     * @param name   Name of parameter to be set. Case is ignored.
61     * @param value  Value to be assigned to the parameter.
62     * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
63     *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
64     *         and set their own parameters.
65     */
66    public void set(String name, boolean value) {
67      if (name.equalsIgnoreCase("INCLUDE_VXD")) {
68        modeUseVXD = value;
69      } else if (name.equalsIgnoreCase("OUTSIDE_IN")) {
70        modeFromOutsideIn = value;
71      } else {
72        throw new NoSuchParameterException(name, this.getClass());
73      }
74    }
75    
76    /** 
77     * Set any <tt>boolean</tt> parameter to <tt>true</tt>.
78     * See {@link #set(String, boolean)} for a list of parameters that can be set with this method.
79     * @param name   Name of parameter to be set
80     * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
81     *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
82     *         and set their own parameters.
83     */
84    public void set(String name) {set(name, true);}
85    
86    /** 
87     * Set any <tt>double</tt> parameter. 
88     * The following parameters can be set with this method:<br>
89     * <tt>"DISTANCE_CUT"</tt> - Combine <tt>SimTrackerHit</tt>s that are less than this distance apart. Default: 200 mkm.<br>
90     * <tt>"BARREL_TILING"</tt> - Default: 10 cm.<br>
91     * <tt>"ENDCAP_TILING"</tt> - Default: 10 cm.<br>
92     * <tt>"SIMPLE_ERROR"</tt> - Position error to be assigned to hits. Default: 50 mkm.<br>
93     * @param name   Name of parameter to be set
94     * @param value  Value to be assigned to the parameter.
95     * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
96     *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
97     *         and set their own parameters.
98     */
99    public void set(String name, double value) {
100     if (name.equalsIgnoreCase("DISTANCE_CUT")) {
101       distanceCut = value;
102     } else if (name.equalsIgnoreCase("BARREL_TILING")) {
103       barrelTiling = value;
104     } else if (name.equalsIgnoreCase("ENDCAP_TILING")) {
105       endcapTiling = value;
106     } else if (name.equalsIgnoreCase("SIMPLE_ERROR")) {
107       simpleError = value;
108     } else {
109       throw new NoSuchParameterException(name, this.getClass());
110     }
111   }
112   
113 // -- Processing event :  ------------------------------------------------------
114   
115   /**
116    * Process event, and put created list of <tt>GarfieldHit</tt>s into the event.
117    */
118   public void process(EventHeader event) {
119     
120     // Convert SimTrackerHit to GarfieldHit
121     
122     // endcap tracker:  a simplified geometry:
123     // even layers go along y, odd layers along x direction.
124     // xxx this needs to be made more realistic
125     
126     ArrayList<GarfieldHit> listGarfieldHits = new ArrayList<GarfieldHit>();
127     
128     double[] xx0 = new double[]{0.,0.,0.};
129     double[] xx1 = new double[]{0.,0.,0.};
130     int id = 0;
131     
132     List<List<SimTrackerHit>> collections = event.get(SimTrackerHit.class);
133     for (List<SimTrackerHit> collection : collections) {
134       String collectionName = event.getMetaData(collection).getName();
135       if (inputCollectionNames.isEmpty() || inputCollectionNames.contains(collectionName)) {
136         for (SimTrackerHit hit: collection){
137           
138           if ( (!modeUseVXD) && isVXD(hit)) continue;
139           
140           if (findAdjacentHit(hit, listGarfieldHits)) continue; // Skip if hit is too close to one of
141           // GarfieldHits that have been already created
142           
143           double[] p=hit.getPoint();
144           int hLayer = hit.getLayer();
145           int newLayerID = getGarfieldLayerID(hit);
146           
147           boolean isInEndCap = hit.getSubdetector().isEndcap();
148           
149           GarfieldHit gh;
150           if (is3D(hit)){                                           // vertex detector
151             gh = new GarfieldHit(p, simpleError, newLayerID, id);
152           } else if (isInEndCap && isEven(hLayer)){             // even endcap layer
153             xx0[0]=p[0];
154             xx0[1]=Math.ceil(p[1]/endcapTiling)*endcapTiling;
155             xx0[2]=p[2];
156             xx1[0]=p[0];
157             xx1[1]=(Math.ceil(p[1]/endcapTiling)-1)*endcapTiling;
158             xx1[2]=p[2];
159             gh = new GarfieldHit(xx0, xx1, simpleError, newLayerID, id);
160             gh.setEndcap(true);
161           } else if (isInEndCap && !isEven(hLayer)){             // odd endcap layer
162             xx0[0]=Math.ceil(p[0]/endcapTiling)*endcapTiling;
163             xx0[1]=p[1];
164             xx0[2]=p[2];
165             xx1[0]=(Math.ceil(p[0]/endcapTiling)-1)*endcapTiling;
166             xx1[1]=p[1];
167             xx1[2]=p[2];
168             gh = new GarfieldHit(xx0, xx1, simpleError, newLayerID, id);
169             gh.setEndcap(true);
170           } else {                                                 // barrel tracker
171             xx0[0]=p[0];
172             xx0[1]=p[1];
173             xx0[2]=barrelTrackerZ(p[2],0,hit.getLayer());
174             xx1[0]=p[0];
175             xx1[1]=p[1];
176             xx1[2]=barrelTrackerZ(p[2],1,hit.getLayer());
177             gh = new GarfieldHit(xx0, xx1, simpleError, newLayerID, id);
178           }
179           gh.addRawHit(hit);
180           listGarfieldHits.add(gh);
181           id++;
182         }
183       }
184     }
185     
186     // Sort the list of Garfield hits by layer number
187     
188     if (modeFromOutsideIn){
189       Collections.sort(listGarfieldHits, new Comparator() {
190         public int compare(Object o1, Object o2) {
191           return ((GarfieldHit)o2).getLayer() - ((GarfieldHit)o1).getLayer();
192         }
193       });
194     } else{
195       Collections.sort(listGarfieldHits, new Comparator() {
196         public int compare(Object o1, Object o2) {
197           return ((GarfieldHit)o1).getLayer() - ((GarfieldHit)o2).getLayer();
198         }
199       });
200     }
201     // Return Garfield hits collection (and put it into the event)
202     
203     listGarfieldHits.trimToSize();
204     event.put(outputCollectionName, listGarfieldHits);    
205   }
206   
207 // -- Private helper methods :  ------------------------------------------------
208   
209   /**
210    * Returns true if a GarfieldHit exists in the supplied <code>oldHitList</code>
211    * that is too close to the <code>newHit</code>, so the two should be merged.
212    * <code>newHit</code> is then added to the list of raw hits associated with that
213    * GarfieldHit.
214    *
215    * This is a temporary solution to get rid of multiple adjacent hits due to delta rays -
216    * should be replaced by proper digitization later.
217    */
218   private boolean findAdjacentHit(SimTrackerHit newHit, ArrayList<GarfieldHit> oldHitList) {
219     boolean tooClose = false;
220     for (GarfieldHit gHit : oldHitList) {
221       List<SimTrackerHit> rawHits = (List<SimTrackerHit>)gHit.getRawHits();
222       for (SimTrackerHit oldHit : rawHits) {
223         if ( (newHit.getLayer() == oldHit.getLayer()) && (oldHit.getSubdetector().getSystemID() == newHit.getSubdetector().getSystemID()) ) {
224           double[] p1 = newHit.getPoint();
225           double[] p2 = oldHit.getPoint();
226           double alphaZ = 1.;
227           if (oldHit.getSubdetector().isBarrel() && !isVXD(oldHit)) alphaZ = 0.0001; // Do we need this ?
228           double d = Math.sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+alphaZ*(p1[2]-p2[2])*(p1[2]-p2[2]));
229           tooClose = (d < this.distanceCut);
230         }
231         if (tooClose) {
232           gHit.addRawHit(newHit);
233           return true;
234         }
235       }
236     }
237     return false;
238   }
239   
240   /**
241    * Garfield-specific tracking layer numbering:
242    * from innermost VXD layer to outermost Tracker layer, barrels first.
243    */
244   private int getGarfieldLayerID(SimTrackerHit hit) {
245     int layer = hit.getLayer();
246     Subdetector sys = hit.getSubdetector();
247     if (sys == Const.det().VXD_BARREL.subdetector() || sys == Const.det().VXD_ENDCAP.subdetector()) {
248       layer = layer; //  EvT changed that on Sep 29th + Const.nLayers[Const.codeVXDBarrel];
249     } else if (sys == Const.det().TRACKER_BARREL.subdetector()) {
250       layer = layer + Const.det().VXD_BARREL.nLayers(); // EVT + Const.nLayers[Const.codeVXDEndcap];
251     } else if (sys == Const.det().TRACKER_ENDCAP.subdetector() || sys == Const.det().TRACKER_FORWARD.subdetector()) {
252       layer = layer + Const.det().VXD_BARREL.nLayers()
253               + Const.det().TRACKER_BARREL.nLayers(); //  EVT + Const.nLayers[Const.codeVXDEndcap]
254       // if this changes, change also GarfieldTrack::initialize
255     }
256     return layer;
257   }
258   
259   /** Very black magic */
260   private double barrelTrackerZ(double z, int end, int layer){
261     // layer as in trackerHit 0-4
262     double offset;
263     if (isEven(layer) || barrelTiling > 50.*Const.cm) offset = 0.;
264     else offset = 0.5*barrelTiling;
265     double zx = ((int) ((z-offset)/barrelTiling))*barrelTiling+offset;
266     double zy;
267     if (zx<z) zy = zx+ barrelTiling;
268     else zy = zx - barrelTiling;
269     if (end == 0) return zx;
270     else return zy;
271   }
272   
273   /**
274    * Returns true if hit supplied as an argument has information about
275    * all three coordinates (this implementation is very detector and
276    * package specific).
277    */
278   private boolean is3D(SimTrackerHit hit){
279     return Const.det().is3D(hit.getSubdetector());
280   }
281   
282   private boolean isEven(int i){return ((i % 2) == 0);}
283   
284   /** Returns true if the hit is in vertex detector. */
285   private boolean isVXD(SimTrackerHit hit) {
286     return Const.det().isVXD(hit.getSubdetector());
287   }
288   
289 // -- Private data :  ----------------------------------------------------------
290   
291   List<String> inputCollectionNames = new ArrayList<String>(4);  // Names of hit collections to be processed
292   String outputCollectionName = "GarfieldHits";
293   
294   double distanceCut = 200. * Const.micrometer;  // Hits closer to each other than this distance will be merged.
295   
296   private double barrelTiling = 10. * Const.cm;
297   private double endcapTiling = 10. * Const.cm;
298   
299   private double simpleError = 0.005 * Const.cm; // 50 micron simple error for first tests
300   
301   private boolean modeFromOutsideIn = true;
302   private boolean modeUseVXD = true;
303   
304 }