View Javadoc

1   package org.lcsim.recon.tracking.trfcyl;
2   
3   import java.util.Map;
4   import java.util.HashMap;
5   import java.util.TreeMap;
6   import java.util.SortedMap;
7   
8   import java.util.List;
9   import java.util.LinkedList;
10  import java.util.ArrayList;
11  import java.util.Iterator;
12  import java.util.ListIterator;
13  
14  import org.lcsim.recon.tracking.trfutil.Assert;
15  import org.lcsim.recon.tracking.trfutil.TRFMath;
16  
17  import org.lcsim.recon.tracking.trfbase.Cluster;
18  import org.lcsim.recon.tracking.trfbase.Hit;
19  import org.lcsim.recon.tracking.trfbase.Surface;
20  import org.lcsim.recon.tracking.trfbase.ETrack;
21  
22  import org.lcsim.recon.tracking.trflayer.ClusterFindManager;
23  
24  /**
25  * Cluster finder for a cylindrical layer.  It maintains a map of
26  * clusters of type HitCylPhi or HitCylPhiZ indexed by position so
27  * the clusters near a track can be retrieved quickly.
28  *<p>
29   * A track is defined to be near a cluster if the chi-square difference
30   * between the corresponding hit measurement and prediction is less
31   * than _max_chsq_diff.
32   *
33   *
34   *@author Norman A. Graf
35   *@version 1.0
36   *
37   */
38  public class ClusterFindCyl extends ClusterFindManager
39  {
40      
41      // static methods
42      
43      //
44      
45      /**
46       *Return a String representation of the class' type name.
47       *Included for completeness with the C++ version.
48       *
49       * @return   A String representation of the class' type name.
50       */
51      public static String typeName()
52      { return "ClusterFindCyl";
53      }
54      
55      //
56      
57      /**
58       *Return a String representation of the class' type name.
59       *Included for completeness with the C++ version.
60       *
61       * @return   A String representation of the class' type name.
62       */
63      public static String staticType()
64      { return typeName();
65      }
66      
67      // attributes
68      
69      // surface
70      private SurfCylinder _scy;
71      
72      // stereo angle
73      private double _stereo;
74      
75      // maximum allowed chi-square difference
76      private double _max_chsq_diff;
77      
78      // clusters
79      private TreeMap _clusters;
80      
81      
82      // methods
83      
84      //
85      
86      /**
87       *Construct an instance from the cylindrical radius, the stereo angle, and the maximum chi-square
88       *difference which defines the nearness of a hit to a track.
89       *
90       * @param   radius The radius of the cylinder.
91       * @param   stereo The stereo angle of the measurement (0 if axial only measurements).
92       * @param   max_chsq_diff The maximum chi-square for a track-hit association.
93       */
94      public ClusterFindCyl(double radius, double stereo,
95      double max_chsq_diff)
96      {
97          //	_clusters = new HashMap();
98          _clusters = new TreeMap(); //use a TreeMap to automatically sort in phi
99          _scy = new SurfCylinder(radius);
100         _stereo = stereo;
101         _max_chsq_diff = max_chsq_diff;
102     }
103     
104     //
105     
106     /**
107      *Return a String representation of the class' type name.
108      *Included for completeness with the C++ version.
109      *
110      * @return   A String representation of the class' type name.
111      */
112     public String type()
113     { return staticType();
114     }
115     
116     //
117     
118     /**
119      *Return the radius of the cylinder.
120      *
121      * @return The radius of this cylinder.
122      */
123     public double radius()
124     { return _scy.radius();
125     }
126     
127     //
128     
129     /**
130      *Return the stereo slope.
131      *
132      * @return The stereo angle.
133      */
134     public double stereo()
135     { return _stereo;
136     }
137     
138     //
139     
140     /**
141      * Return the maximum chi-square difference which defines a hit to be near a track.
142      *
143      * @return  The maximum chi-square for a track-hit association.
144      */
145     public double maxChsqDiff()
146     { return _max_chsq_diff;
147     }
148     
149     //
150     
151     /**
152      *Add a cluster to this ClusterFindManager.
153      * The cluster must be of type ClusCylPhi or ClusCylPhiZ.
154      *
155      * @param   clus The Cluster to add.
156      * @return  0 if successful.
157      */
158     public int addCluster( Cluster clus )
159     {
160         // declare the key value
161         double keyval = 0.;
162         
163         // Extract the cluster position depending on type
164         if ( clus.type().equals(ClusCylPhi.staticType()) )
165         {
166             ClusCylPhi clu = (  ClusCylPhi) clus;
167             Assert.assertTrue( clu.surface().equals(_scy) );
168             Assert.assertTrue( _stereo == 0.0 );
169             keyval = clu.phi();
170         }
171         else if ( clus.type().equals(ClusCylPhiZ.staticType()) )
172         {
173             ClusCylPhiZ clu = ( ClusCylPhiZ) clus;
174             Assert.assertTrue( clu.surface().equals(_scy) );
175             Assert.assertTrue( clu.stereo() == _stereo );
176             keyval = clu.phiZ();
177         }
178         else if ( clus.type().equals(ClusCylPhiZ2D.staticType()) )
179         {
180             ClusCylPhiZ2D clu = ( ClusCylPhiZ2D ) clus;
181             Assert.assertTrue( clu.surface().equals(_scy) );
182 //            Assert.assertTrue( clu.stereo() == _stereo );
183             keyval = clu.phi();
184         }        
185         else
186         {
187             Assert.assertTrue(false);
188             System.exit(1);
189         }
190         
191         // Put value in range (0,2pi)
192         keyval = TRFMath.fmod1( keyval, TRFMath.TWOPI );
193         Double key = new Double(keyval);
194         // Check there is no other cluster at this position.
195         if ( _clusters.containsKey(key))
196         {
197             Assert.assertTrue(false);
198             System.exit(2);
199         }
200         
201         // Store the cluster.
202         _clusters.put(key, clus);
203         return 0;
204         
205     }
206     
207     //
208     
209     /**
210      *Drop all clusters from this manager.
211      *
212      */
213     public void dropClusters()
214     {
215         _clusters.clear();
216     }
217     
218     //
219     
220     /**
221      *Return the surface.
222      *
223      * @return The Surface associated to this manager.
224      */
225     public   Surface surface()
226     { return _scy;
227     }
228     
229     //
230     
231     /**
232      *Return all the clusters.
233      *
234      * @return The list of clusters managed by this manager.
235      */
236     public  List clusters()
237     {
238         // Create the list of clusters.
239         List clusters = new ArrayList();
240         
241         // Loop over clusters and add to output list.
242         
243         for ( Iterator iclu=_clusters.values().iterator();  iclu.hasNext(); )
244             clusters.add( iclu.next() );
245         
246         return clusters;
247         
248     }
249     
250     //
251     
252     
253     /**
254      *Return all the clusters near a track at the surface. Nearness is delimited by the
255      *maximum chi-squared between the track prediction and the cluster measurement.
256      *
257      * Clusters have been ordered by phi or phiz in range (0,2pi). need to check!
258      * The nearby subset is returned in the same order.
259      *
260      * @param   tre The ETrack for which to return clusters.
261      * @return  A list of clusters near the track tre.
262      */
263     public  List clusters(  ETrack tre)
264     {
265         
266         // Create the list of clusters.
267         List clusters = new ArrayList();
268         
269         // Check the track surface.
270         if ( !tre.surface().equals(_scy) )
271         {
272             Assert.assertTrue(false);
273             return clusters;
274         }
275         
276         // If there are no clusters, return the empty list.
277         if ( _clusters.size() == 0 )
278         {
279             return clusters;
280         }
281         
282         // Fetch the predicted position.
283         double value = tre.vector(0) + _stereo*tre.vector(1);
284         value = TRFMath.fmod1( value, TRFMath.TWOPI );
285         
286         //for time being loop over all the clusters.
287         // need to be smarter later
288         
289         for(Iterator it = _clusters.values().iterator(); it.hasNext(); )
290         {
291             //get the cluster
292             Cluster clu = (Cluster) it.next();
293             // is cluster within range?
294             if (chsqDiff(clu,tre) < _max_chsq_diff )
295             {
296                 // if so add it to the list
297                 clusters.add( clu );
298             }
299         }
300         
301 /*
302   // Fetch first cluster after the prediction.
303   // If there is none, wrap around to the first.
304   SortedMap sm = _clusters.tailMap( new Double(value) );
305  
306   // Loop over clusters from this and above.
307   // If cluster is close, add it to the list; otherwise exit loop.
308  
309   Iterator it = sm.values().iterator();
310  
311 while(true)
312   {
313         //get the cluster
314                 Cluster clu = (Cluster) it.next();
315         // is cluster within range?
316         if(chsq_diff(clu,tre) > _max_chsq_diff ) break;
317         // if so add it to the list
318         clusters.add( clu );
319         // if we get to end of tailMap (and therefore end of cluster map)
320         // continue at beginning of cluster map.
321         // needed because of phi-wrap in cylindrical detector
322         if(!it.hasNext()) it = _clusters.values().iterator();
323         //have we gotten all the way back to the beginning of the tailMap?
324         //if so break out of the loop. (shouldn't happen, but check anyway)
325         if(it == sm.values().iterator()) break;
326   }
327  */
328   /*
329   ClusterMap::const_iterator iclu = iclu1;
330   ClusterMap::const_iterator iclu2;
331   while ( true ) {
332     ClusterPtr pclu = (*iclu).second;
333     iclu2 = iclu;
334     if ( chsq_diff(pclu,tre) > _max_chsq_diff ) break;
335     clusters.push_back( pclu );
336     // increment iterator; loop from end back to beginning
337     if ( ++iclu == _clusters.end() ) iclu = _clusters.begin();
338     // Exit if we are back at the beginning.
339     if ( iclu == iclu1 ) break;
340   }
341    */
342 /*
343   // We have checked all clusters in the (circular) range greater than
344   // the prediction.
345   // Now loop back, again accounting for the phi-wrap problem
346   // Need to find out how to get a generic collection reverse iterator.
347   // Until then copy the sorted map into a LinkedList.
348   SortedMap sm2 = _clusters.headMap( new Double(value) );
349   LinkedList ll = new LinkedList(sm2.values());
350   ListIterator it2 = ll.listIterator(ll.size());
351  */
352   /*
353   iclu = iclu1;
354   if ( iclu == _clusters.begin() ) iclu = _clusters.end();
355   while ( --iclu != iclu2 ) {
356     ClusterPtr pclu = (*iclu).second;
357     if ( chsq_diff(pclu,tre) > _max_chsq_diff ) break;
358     clusters.push_front( pclu );
359     // decrement iterator; loop from beginning back to end
360     if ( iclu == _clusters.begin() ) iclu = _clusters.end();
361   }
362    
363   // Return the nearby clusters.
364    
365    */
366         return clusters;
367         
368     }
369     
370     
371     
372     /**
373      *output stream
374      *
375      * @return A String representation of this instance.
376      */
377     public String toString()
378     {
379         
380         StringBuffer sb = new StringBuffer("Cluster finder for " + _scy + ".\n");
381         sb.append( "Stereo angle is " + _stereo + "." + ".\n");
382         sb.append( "Maximum chi-square difference is "
383         + _max_chsq_diff + "." + ".\n");
384         int count = _clusters.size();
385         if ( count>0 )
386         {
387             sb.append( "Finder has " + count + " cluster");
388             if ( count > 1 ) sb.append( "s");
389             sb.append( ": \n");
390             for (Iterator i=_clusters.entrySet().iterator(); i.hasNext(); )
391             {
392                 Map.Entry e = (Map.Entry) i.next();
393                 sb.append(e.getKey() + ": " + e.getValue() + "\n");
394             }
395         }
396         else
397         {
398             sb.append( "Finder has no clusters.");
399         }
400         return sb.toString();
401     }
402     
403     //**********************************************************************
404     // Helper functions.
405     //**********************************************************************
406     
407     // Calculate the chi-square difference between and cluster and a track.
408     // It is assumed the cluster generates exactly one prediction and that
409     // this prediction has one dimension.
410     
411     private static double chsqDiff( Cluster clu,   ETrack tre)
412     {
413         
414         // Fetch the hit predictions.
415         List hits = clu.predict(tre,clu);
416         
417         // Check there is one hit.
418         Assert.assertTrue( hits.size() == 1 );
419         
420         // Fetch the hit.
421         Hit hit = (Hit) hits.get(0);
422         
423         // Check the hit dimension.
424         Assert.assertTrue( hit.size() == 1 );
425         
426         // Fetch the difference between prediction and measurement.
427         double diff = hit.differenceVector().get(0);
428         
429         // Fetch the measurement error and the prediction error.
430         double emeas = hit.measuredError().get(0,0);
431         double epred = hit.predictedError().get(0,0);
432         
433         // Calculate and return chi-square difference.
434         return diff*diff/(emeas+epred);
435         
436     }
437 }