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 }