View Javadoc

1   package org.lcsim.recon.tracking.vsegment.hitmaking;
2   
3   import java.util.*;
4   
5   import hep.aida.*;
6   import org.lcsim.util.aida.AIDA;
7   
8   import hep.physics.matrix.SymmetricMatrix;
9   import hep.physics.vec.BasicHep3Vector;
10  import hep.physics.vec.Hep3Vector;
11  import hep.physics.vec.VecOp;
12  import org.lcsim.event.EventHeader;
13  import org.lcsim.recon.cat.util.NoSuchParameterException;
14  import org.lcsim.spacegeom.SpacePointVector;
15  import org.lcsim.util.Driver;
16  
17  import org.lcsim.recon.tracking.vsegment.geom.RegionSegmenter;
18  import org.lcsim.recon.tracking.vsegment.geom.SegmentationManager;
19  import org.lcsim.recon.tracking.vsegment.geom.Sensor;
20  import org.lcsim.recon.tracking.vsegment.geom.SensorType;
21  import org.lcsim.recon.tracking.vsegment.hit.TrackerCluster;
22  import org.lcsim.recon.tracking.vsegment.hit.TrackerHit;
23  import org.lcsim.recon.tracking.vsegment.hitmaking.hitmakers.TrackerHitMakerBasic;
24  
25  /**
26   * Driver that converts a collection of {@link TrackerCluster} or {@link TrackerHit}
27   * objects into a collection of org.lcsim.event.{@link TrackerHit} objects.
28   * <p>
29   * See the description of {@link #set} method for details on how to specify input and
30   * output collections. If this Driver is run on <tt>TrackerClusters</tt>, it first generates
31   * <tt>TrackerHits</tt> internally, using the {@link TrackerHitMaker} set through a call to 
32   * <tt>set("HIT_MAKER", hitMaker)</tt>, and then converts them into <tt>OldTrackerHits</tt>.
33   * <p>
34   * Creation of <tt>OldTrackerHit</tt> objects is done either by {@link #convert(TrackerHit hit)}
35   * (for pixels and sensors for which <tt>getStereoPartners(Sensor)</tt> method of the 
36   * corresponding <tt>Segmenter</tt> returns <tt>null</tt>) or by
37   * {@link #cross(TrackerHit hit1, TrackerHit hit2)} method. A user can override either of these
38   * methods to control what position and covariance matrix are assigned to newly created
39   * <tt>OldTrackerHits</tt>.
40   * <p>
41   * If <tt>getStereoPartners(Sensor)</tt> method returns an empty list (default behavior
42   * of {@link RegionSegmenter}) for a given <tt>Sensor</tt> object, and that Sensor contains
43   * strips, no <tt>OldTrackerHits</tt> will be produced from clusters on that sensor.
44   *
45   * @author D. Onoprienko
46   * @version $Id: TrackerHitConverter.java,v 1.1 2008/12/06 21:53:44 onoprien Exp $
47   */
48  public class TrackerHitConverter extends Driver {
49    
50  // -- Constructors :  ----------------------------------------------------------
51    
52    public TrackerHitConverter() {
53      _notInit = true;
54      _hitMapName = null;
55      _clusterMapName = "TrackerClusters";
56      _outListName = "StandardTrackerHits";
57    }
58    
59    private void init(EventHeader event) {
60      _notInit = false;
61      if (_segMan == null) _segMan = (SegmentationManager) event.get("SegmentationManager");
62      if (_clusterMapName != null) {
63        List<Driver> drivers = drivers();
64        ListIterator<Driver> it = drivers.listIterator();
65        while (it.hasNext()) {
66          if (it.next() instanceof HitMakingDriver) it.remove();
67        }
68        if (_hitMaker == null) _hitMaker = new TrackerHitMakerBasic();
69        HitMakingDriver hitMakingDriver = new HitMakingDriver(_hitMaker);
70        hitMakingDriver.set("INPUT_MAP_NAME",_clusterMapName);
71        hitMakingDriver.set("OUTPUT_MAP_NAME", (_hitMapName == null) ? "_temporary_" : _hitMapName);
72        add(hitMakingDriver);
73      }
74      
75    }
76  
77  // -- Setters :  ---------------------------------------------------------------
78  
79    /**
80     * Set any <tt>String</tt> parameter. 
81     * The following parameters can be set with this method:
82     * <p><dl>
83     * <dt>"INPUT_HIT_MAP_NAME"</dt> <dd>Name of input collection of tracker hits
84     *             (type <tt>HashMap&lt;Sensor, ArrayList&lt;TrackerHit&gt;&gt;</tt>). 
85     *             <br>Default: not set - clusters will be used as input.</dd>
86     * <dt>"INPUT_CLUSTER_MAP_NAME"</dt> <dd>Name of input collection of tracker clusters
87     *             (type <tt>HashMap&lt;Sensor, ArrayList&lt;TrackerCluster&gt;&gt;</tt>).
88     *             If both input hit map name and input cluster map name are set, 
89     *             a map of <tt>TrackerHits</tt> will be produced and saved into the event
90     *             under the given name.
91     *             <br>Default: "TrackerClusters".</dd>
92     * <dt>"OUTPUT_HIT_LIST_NAME"</dt> <dd>Name of output collection of tracker hits
93     *             (type <tt>List&lt;org.lcsim.event.TrackerHit&gt;</tt>). 
94     *             <br>Default: "StandardTrackerHits".</dd>
95     * <dt>"HIT_MAKER"</dt> <dd>{@link TrackerHitMaker} object to be used by this converter. 
96     *             <br>Default: New instance of {@link TrackerHitMakerBasic} will be used
97     *             if the hit maker is not set explicitly.</dd></dl>
98     * 
99     * @param name   Name of parameter to be set. Case is ignored.
100    * @param value  Value to be assigned to the parameter.
101    * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
102    *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
103    *         and set their own parameters.
104    */
105   public void set(String name, Object value) {
106     try {
107       if (name.equalsIgnoreCase("INPUT_HIT_MAP_NAME")) {
108         _hitMapName = (String) value;
109       } else if (name.equalsIgnoreCase("INPUT_CLUSTER_MAP_NAME")) {
110         _clusterMapName = (String) value;
111       } else if (name.equalsIgnoreCase("OUTPUT_HIT_LIST_NAME")) {
112         _outListName = (String) value;
113       } else if (name.equalsIgnoreCase("HIT_MAKER")) {
114         _hitMaker = (TrackerHitMaker) value;
115       } else {
116         throw new NoSuchParameterException(name, this.getClass());
117       }
118     } catch (ClassCastException x) {
119       throw new IllegalArgumentException("Value of incompatible type", x);
120     }
121   }
122   
123 // -- Event processing :  ------------------------------------------------------
124   
125   public void process(EventHeader event) {
126     
127     if (_notInit) init(event);
128     
129 //    System.out.println(" ");
130 //    System.out.println("Starting conversion of TrackerHits into TrackerHits");
131     
132     super.process(event);
133 
134     String hitMapName = (_hitMapName == null) ? "_temporary_" : _hitMapName;
135     HashMap<Sensor, ArrayList<TrackerHit>> hitMap = (HashMap<Sensor, ArrayList<TrackerHit>>) event.get(hitMapName);
136     ArrayList<OldTrackerHit> out = new ArrayList<OldTrackerHit>(1000);
137     ArrayList<Sensor> processedSensors = new ArrayList<Sensor>(hitMap.size());
138     
139     for (Sensor sensor : hitMap.keySet()) {
140       
141       List<TrackerHit> hitsOnSensor = hitMap.get(sensor);
142       int hitDimension = sensor.getType().getHitDimension();
143       
144       if (hitDimension == 1) { // Strips
145         List<Sensor> partners = _segMan.getStereoPartners(sensor);
146         if (partners == null) {
147           for (TrackerHit hit : hitsOnSensor) {
148             OldTrackerHit oHit = convert(hit);
149             if (oHit != null) out.add(oHit);
150           }
151         } else {
152           for (Sensor partner : partners) {
153             Hep3Vector shift = VecOp.sub(sensor.getTranslation(), partner.getTranslation());
154             if (! processedSensors.contains(partner)) {
155               List<TrackerHit>  hitsOnPartner = hitMap.get(partner);
156               if (hitsOnPartner != null) {
157                 for (TrackerHit hitOnSensor : hitsOnSensor) {
158                   for (TrackerHit hitOnPartner : hitsOnPartner) {
159                     OldTrackerHit hit = cross(hitOnSensor, hitOnPartner);
160                     if (hit != null) out.add(hit);
161                   }
162                 }
163               }
164             }
165           }
166           processedSensors.add(sensor);
167         }
168       } else if (hitDimension == 2) { // Pixels
169         for (TrackerHit hit : hitsOnSensor) {
170           OldTrackerHit oHit = convert(hit);
171           if (oHit != null) out.add(oHit);
172         }
173       } else {
174         throw new RuntimeException("Unknown hit dimension " + hitDimension);
175       }
176     }
177     
178     out.trimToSize();
179     if (_hitMapName == null) event.remove("_temporary_");
180     event.put(_outListName, out);
181   }
182   
183   /**
184    * Creates a new <tt>OldTrackerHit</tt> from a pair of <tt>TrackerHits</tt> in stereo layers.
185    * <p>
186    * The implementation assumes that hits provided as arguments are both segment-like, and 
187    * belong to parallel <tt>Sensors</tt> (local reference frame W axes parallel) 
188    * with non-parallel strips (U axes are not parallel). If any of these assumptions is
189    * not true, <tt>null</tt> will be returned and error message printed. Otherwise, the
190    * method will try to find an intersection in U,V plane (ignoring W difference between 
191    * the sensors). If successful, the returned <tt>OldTrackerHit</tt> will have U and V
192    * coordinates corresponding to that intersection, and W coordinate will be half way
193    * between sensor planes. If hits do not cross, the method returns <tt>null</tt>.
194    */
195   protected OldTrackerHit cross(TrackerHit hit1, TrackerHit hit2) {
196     
197     Sensor sensor1 = hit1.getSensor();
198     double tolerance = _stereoTolerance * hit2.getLength();
199     
200     SpacePointVector globSegment2 = hit2.getSegment();
201     Hep3Vector locStart2 = sensor1.globalToLocal(globSegment2.getStartPoint());
202     Hep3Vector locEnd2 = sensor1.globalToLocal(globSegment2.getEndPoint());
203     SpacePointVector locSegment1 = hit1.getLocalSegment();
204     Hep3Vector locStart1 = locSegment1.getStartPoint();
205     Hep3Vector locEnd1 = locSegment1.getEndPoint();
206     
207     double du = locEnd2.x() - locStart2.x();
208     double dw = Math.abs(locEnd2.z() - locStart2.z());
209     if (Math.abs(du) < tolerance) {
210       System.out.println("Shallow stereo angle");
211       return null;
212     } else if (dw > tolerance ) {
213       System.out.println("Non-parallel stereo partners");
214       return null;
215     }
216     double u = locStart1.x();
217     double v = locStart2.y() - ((locStart2.x()-u) * (locEnd2.y()-locStart2.y())) / du;
218     
219     if (((v - locStart1.y()) * (v - locEnd1.y())) > 0.) return null;  // not intersecting
220    
221     Hep3Vector locPos = new BasicHep3Vector(u, v, (locEnd2.z() + locEnd1.z())/2.);
222     
223     Hep3Vector locUnitU2 = sensor1.globalToLocal(hit2.getSensor().localToGlobal(unitU));
224     double a = locUnitU2.x();
225     double b = locUnitU2.y();
226     double sigma1 = hit1.getCovMatrix().diagonal(0);
227     double sigma2 = hit2.getCovMatrix().diagonal(0);
228     double[] cov = new double[]{sigma1+a*a*sigma2, a*b*sigma2, b*b*sigma2, 0., 0., _errFlat*dw};
229     double s1 = hit1.getSignal();
230     double s2 = hit2.getSignal();
231     double signal = s1 + s2;
232     double time = (s1*hit1.getTime() + s2*hit2.getTime()) / signal;
233     ArrayList<TrackerCluster> parents = new ArrayList<TrackerCluster>(2);
234     parents.add(hit1.getCluster());
235     parents.add(hit2.getCluster());
236     
237     return new OldTrackerHit(sensor1.localToGlobal(locPos), new SymmetricMatrix(3,cov,true), signal, time, 0, parents);
238   }
239   
240   /**
241    * Creates a new <tt>OldTrackerHit</tt> given <tt>TrackerHit</tt>.
242    * Position and covariance matrix of the created <tt>OldTrackerHit</tt> are
243    * global position and covariance matrix of the <tt>TrackerHit</tt> (if the 
244    * supplied <tt>TrackerHit</tt> is segment-like, that places the newly created
245    * <tt>TrackerHit</tt> at the center of the segment. 
246    */
247   protected OldTrackerHit convert(TrackerHit hit) {
248     ArrayList<TrackerCluster> parents = new ArrayList<TrackerCluster>(1);
249     parents.add(hit.getCluster());
250     return new OldTrackerHit(hit.getPosition(), hit.getCovMatrix(), hit.getSignal(), hit.getTime(), 0, parents);
251   }
252   
253 // -- Private parts :  ---------------------------------------------------------
254   
255   private boolean _notInit;
256 
257   private String _hitMapName;
258   private String _clusterMapName;
259   private String _outListName;
260   
261   protected SegmentationManager _segMan;
262   private TrackerHitMaker _hitMaker;
263   
264   private double _stereoTolerance = 0.01;
265   
266   private double _errFlat = 1./Math.sqrt(12.);
267   private Hep3Vector unitU = new BasicHep3Vector(1., 0., 0.);  
268 }