Print

Print


Commit in lcsim/src/org/lcsim/recon/pfa/identifier on MAIN
TrackClusterMatcher.java+28added 1.1
SimpleTrackClusterMatcher.java+273added 1.1
SimpleTrackMIPClusterMatcher.java+59added 1.1
+360
3 added files
Interface for track-cluster matching

lcsim/src/org/lcsim/recon/pfa/identifier
TrackClusterMatcher.java added at 1.1
diff -N TrackClusterMatcher.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ TrackClusterMatcher.java	10 Aug 2006 22:57:02 -0000	1.1
@@ -0,0 +1,28 @@
+package org.lcsim.recon.pfa.identifier;
+
+import java.util.*;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.Track;
+
+/**
+  * Interface for matching Tracks to Clusters
+  *
+  * @version $Id: TrackClusterMatcher.java,v 1.1 2006/08/10 22:57:02 mcharles Exp $
+  */
+
+public interface TrackClusterMatcher
+{
+    /**
+     * Attempt to match a Track <code>tr</code> to a Cluster 
+     * from the list <code>clusters</code>. The return value
+     * is the matched Cluster, or null if there is no acceptable
+     * match found.
+     *
+     * Implementations typically return a cluster from the list supplied.
+     * They may also return a new cluster which contains clusters 
+     * (via Cluster.getClusters()) from this list (and no other hits/clusters). 
+     *
+     * @version $Id: TrackClusterMatcher.java,v 1.1 2006/08/10 22:57:02 mcharles Exp $
+     */
+    public Cluster matchTrackToCluster(Track tr, List<Cluster> clusters);
+}

lcsim/src/org/lcsim/recon/pfa/identifier
SimpleTrackClusterMatcher.java added at 1.1
diff -N SimpleTrackClusterMatcher.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SimpleTrackClusterMatcher.java	10 Aug 2006 22:57:02 -0000	1.1
@@ -0,0 +1,273 @@
+package org.lcsim.recon.pfa.identifier;
+
+import java.util.*;
+import hep.physics.vec.*;
+
+import org.lcsim.util.swim.HelixSwimmer;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.geometry.subdetector.CylindricalCalorimeter;
+import org.lcsim.geometry.Detector;
+import org.lcsim.recon.cluster.util.BasicCluster;
+import org.lcsim.recon.cluster.util.TensorClusterPropertyCalculator;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.Track;
+import org.lcsim.util.Driver;
+
+/**
+ * Attempt to match a Track to a Cluster, based on the intercept point
+ * on the ECAL inner surface.
+ *
+ * @version $Id: SimpleTrackClusterMatcher.java,v 1.1 2006/08/10 22:57:02 mcharles Exp $ 
+ */
+
+public class SimpleTrackClusterMatcher extends Driver implements TrackClusterMatcher
+{
+
+    /**
+      * Match this track to a cluster from the list supplied.
+      */
+    public Cluster matchTrackToCluster(Track tr, List<Cluster> clusters)
+    {
+	// Make a HelixSwimmer to propagate the track
+	HelixSwimmer swimmer = new HelixSwimmer(m_fieldStrength[2]);
+	swimmer.setTrack(tr);
+
+	// Try swimming to the barrel:
+	double  alphaBarrel = swimToBarrel(swimmer);
+	boolean validBarrel = false;
+	// Try swimming to the endcap:
+	double  alphaEndcap = swimToEndcap(swimmer);
+	boolean validEndcap = false;
+
+	// Fixme: Here we should check that the track really does go all the
+	// way to the ECAL instead of stopping/decaying/interacting earlier.
+	double alpha = Double.NaN; 
+	if (isValidBarrelIntercept(swimmer, alphaBarrel)) {
+	    alpha = alphaBarrel;
+	    validBarrel = true;
+	} else if (isValidEndcapIntercept(swimmer, alphaEndcap)) {
+	    alpha = alphaEndcap;
+	    validEndcap = true;
+	}
+
+	// Did we make a successful extrapolation?
+	if (Double.isNaN(alpha)) {
+	    // No -- failed
+	    return null;
+	}
+	if ( !(validEndcap || validBarrel) ) {
+	    // Invalid state
+	    throw new AssertionError("Invalid state: alpha is not NaN, but not a valid barrel or endcap intercept");
+	}
+	if ( validEndcap && validBarrel ) {
+	    throw new AssertionError("Invalid state: barrel="+validBarrel+", endcap="+validEndcap);
+	}
+
+	// If we reach here, we extrapolated to the barrel or
+	// to the endcap successfully.
+	
+	Cluster matchedCluster = findMatchedCluster(tr, swimmer, alpha, clusters);
+	if (matchedCluster != null) {
+	    // Matched OK
+	    if (m_debug) { 
+		Hep3Vector momentumVec = new BasicHep3Vector(tr.getMomentum());
+		System.out.println("DEBUG: Extrapolated track to cluster (momentum = "+momentumVec.magnitude()+")"); 
+	    }
+	    return matchedCluster;
+	} else {
+	    // No match found
+	    if (m_debug) { 
+		Hep3Vector momentumVec = new BasicHep3Vector(tr.getMomentum());
+		System.out.println("DEBUG: Failed to extrapolate track (momentum = "+momentumVec.magnitude()+")"); 
+	    }
+	    return null;
+	}
+    }
+
+    protected double swimToBarrel(HelixSwimmer swimmer) {
+	// Look for a hit in the first layer of the ECAL barrel
+	return swimmer.getDistanceToRadius(m_ECAL_barrel_r);
+    }
+    protected double swimToEndcap(HelixSwimmer swimmer) {
+	// Look for a hit in the first layer of the ECAL endcap
+	return swimmer.getDistanceToZ(m_ECAL_endcap_z);
+    }
+    protected boolean isValidBarrelIntercept(HelixSwimmer swimmer, double alpha) {
+	// Must have -m_ECAL_barrel_z <= z <= +m_ECAL_barrel_z
+	Hep3Vector intercept = swimmer.getPointAtDistance(alpha);
+	double z = intercept.z();
+	boolean zInRange = (z >= m_ECAL_barrel_zmin && z <= m_ECAL_barrel_zmax);
+	return zInRange;
+    }
+    protected boolean isValidEndcapIntercept(HelixSwimmer swimmer, double alpha) {
+	// Must have m_ECAL_endcap_rmin <= r <= m_ECAL_endcap_rmax
+	Hep3Vector intercept = swimmer.getPointAtDistance(alpha);
+	double r = Math.sqrt(intercept.x()*intercept.x() + intercept.y()*intercept.y());
+	boolean rInRange = (r >= m_ECAL_endcap_rmin && r <= m_ECAL_endcap_rmax);
+	return rInRange;
+    }
+
+    protected Cluster findMatchedCluster(Track tr, HelixSwimmer swimmer, double alpha, List<Cluster> clusters) 
+    {
+	// Find the track intercept and direction
+	swimmer.setTrack(tr);
+	Hep3Vector trackPoint = swimmer.getPointAtDistance(alpha);
+	
+	List<Cluster> nearestClusters = findNearestClusters(trackPoint, clusters);
+	for (Cluster nearbyCluster : nearestClusters) {
+	    // Obtain geometrical info:
+	    CalorimeterHit nearestHit = findNearestHit(trackPoint, nearbyCluster);
+	    double separation = proximity(trackPoint, nearestHit);
+	    int firstLayerHit = getLayer(nearestHit);
+	    org.lcsim.geometry.Subdetector subdet = nearestHit.getSubdetector();
+	    // Make cuts:
+	    boolean goodSubDet = (subdet.getName().compareTo("EMBarrel")==0) || (subdet.getName().compareTo("EMEndcap")==0);
+	    boolean goodFirstLayer = (firstLayerHit < 5);
+	    boolean goodSeparation = (separation < 30.0);
+	    boolean foundMatch = goodSubDet && goodFirstLayer && goodSeparation;
+	    if (foundMatch) {
+		// Geometrically, it looks good.
+		// Is it sensible in terms of energy?
+		
+		// // FIXME: Farm the calibration out to an external class properly
+		// double estimatedClusterEnergy = SimpleNeutralParticleMaker.estimateClusterEnergy(clus);
+		// // We don't expect an exact match due to resolution, energy lost
+		// // to fragments etc., but a good portion of the energy should be
+		// // in the cluster
+		// double[] trackMomentum = tr.getMomentum();
+		// double trackMomentumMag = Math.sqrt(trackMomentum[0]*trackMomentum[0] + trackMomentum[1]*trackMomentum[1] + trackMomentum[2]*trackMomentum[2]);
+		// boolean fractionEnergyOK = estimatedClusterEnergy > 0.5*trackMomentumMag;
+		// boolean absoluteEnergyOK = (trackMomentumMag - estimatedClusterEnergy < 0.2); // deliberately one-sided
+		// boolean energyOK = fractionEnergyOK || absoluteEnergyOK;
+		boolean energyOK = true; // For now, always pass
+
+		if (energyOK) {
+		    // Matches OK
+		    return nearbyCluster;
+		} else {
+		    // This cluster isn't a good match -- ignore it.
+		}
+	    }
+	}
+	// No match
+	return null;
+    }
+
+    protected List<Cluster> findNearestClusters(Hep3Vector point, List<Cluster> clusterList)
+    {
+	Map<Cluster,Double> mapClusterToDistance = new HashMap<Cluster, Double>();
+	List<Cluster> sortedListOfClusters = new Vector<Cluster>();
+	for (Cluster clus : clusterList) {
+	    double dist = proximity(point, clus);
+	    mapClusterToDistance.put(clus, new Double(dist));
+	    sortedListOfClusters.add(clus);
+	}
+	Comparator<Cluster> comp = new CompareMapping<Cluster>(mapClusterToDistance);
+	Collections.sort(sortedListOfClusters, comp);
+	return sortedListOfClusters;
+    }
+    protected CalorimeterHit findNearestHit(Hep3Vector point, Cluster clus) 
+    {
+	CalorimeterHit nearest = null;
+	double minDist = 0;
+	for (CalorimeterHit hit : clus.getCalorimeterHits()) {
+	    Hep3Vector hitPosition = new BasicHep3Vector(hit.getPosition());
+	    double distance = VecOp.sub(hitPosition, point).magnitude();
+	    if (distance<minDist || nearest==null) {
+		nearest = hit;
+	    }
+	}
+	return nearest;
+    }
+
+    protected double proximity(Hep3Vector point, Cluster clus) {
+	CalorimeterHit nearestHit = findNearestHit(point, clus);
+	return proximity(point, nearestHit);
+    }
+    protected double proximity(Hep3Vector point, CalorimeterHit hit) {
+	Hep3Vector hitPosition = new BasicHep3Vector(hit.getPosition());
+	double distance = VecOp.sub(hitPosition, point).magnitude();
+	return distance;
+    }
+
+    protected double findUnitDotProduct(Hep3Vector tangent, Cluster clus) 
+    {
+	// Find the cluster direction
+	BasicCluster copy = new BasicCluster();
+	copy.addCluster(clus);
+	TensorClusterPropertyCalculator calc = new TensorClusterPropertyCalculator();
+	copy.setPropertyCalculator(calc);
+	copy.calculateProperties();
+	double[][]axes = calc.getPrincipleAxis();
+	Hep3Vector clusterDir = new BasicHep3Vector(axes[0][0], axes[0][1], axes[0][2]);
+	// Get the dot product:
+	double unitDotProduct = VecOp.dot(tangent, clusterDir) / (tangent.magnitude() * clusterDir.magnitude());
+	return unitDotProduct;
+    }
+    protected int getLayer(CalorimeterHit hit) {
+	org.lcsim.geometry.IDDecoder id = hit.getIDDecoder();
+	id.setID(hit.getCellID());
+	int layer = id.getLayer();
+	return layer;
+    }
+
+    public void process(EventHeader event) {
+	initGeometry(event);
+    }
+
+    public void initGeometry(EventHeader event) 
+    {
+	Detector det = event.getDetector();
+	CylindricalCalorimeter emb = ((CylindricalCalorimeter) det.getSubdetectors().get("EMBarrel"));
+	CylindricalCalorimeter eme = ((CylindricalCalorimeter) det.getSubdetectors().get("EMEndcap"));
+	m_ECAL_barrel_zmin = emb.getZMin();
+	m_ECAL_barrel_zmax = emb.getZMax();
+	m_ECAL_barrel_r = emb.getLayering().getDistanceToLayerSensorMid(0);
+	m_ECAL_endcap_z = eme.getLayering().getDistanceToLayerSensorMid(0);
+	m_ECAL_endcap_rmin = eme.getInnerRadius();
+	m_ECAL_endcap_rmax = eme.getOuterRadius();
+	double[] zero = {0, 0, 0};
+	m_fieldStrength = det.getFieldMap().getField(zero);
+	m_init = true;
+	if (m_debug) {
+	    System.out.println(this.getClass().getName()+": Init: ECAL barrel zmin="+m_ECAL_barrel_zmin);
+	    System.out.println(this.getClass().getName()+": Init: ECAL barrel zmax="+m_ECAL_barrel_zmax);
+	    System.out.println(this.getClass().getName()+": Init: ECAL barrel r="+m_ECAL_barrel_r);
+	    System.out.println(this.getClass().getName()+": Init: ECAL endcap z="+m_ECAL_endcap_z);
+	    System.out.println(this.getClass().getName()+": Init: ECAL endcap rmin="+m_ECAL_endcap_rmin);
+	    System.out.println(this.getClass().getName()+": Init: ECAL endcap rmax="+m_ECAL_endcap_rmax);
+	}
+    }
+
+    protected boolean m_init = false;
+    protected double m_ECAL_barrel_zmin;
+    protected double m_ECAL_barrel_zmax;
+    protected double m_ECAL_barrel_r;
+    protected double m_ECAL_endcap_z;
+    protected double m_ECAL_endcap_rmin;
+    protected double m_ECAL_endcap_rmax;
+    protected boolean m_debug = false;
+    protected double[] m_fieldStrength;
+
+    private class CompareMapping<T> implements Comparator<T> {
+	public CompareMapping(Map<T,Double> map) {
+	    m_map = map;
+	}
+	public int compare(Object o1, Object o2) {
+	    Cluster c1 = (Cluster) o1;
+	    Cluster c2 = (Cluster) o2;
+	    Double D1 = m_map.get(c1);
+	    Double D2 = m_map.get(c2);
+	    if (D1.equals(D2)) {
+		// Equal
+		return 0;
+	    } else if (D1.doubleValue() < D2.doubleValue()) {
+		return -1;
+	    } else {
+		return +1;
+	    }
+	}
+	Map<T,Double> m_map;
+    }
+}

lcsim/src/org/lcsim/recon/pfa/identifier
SimpleTrackMIPClusterMatcher.java added at 1.1
diff -N SimpleTrackMIPClusterMatcher.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SimpleTrackMIPClusterMatcher.java	10 Aug 2006 22:57:02 -0000	1.1
@@ -0,0 +1,59 @@
+package org.lcsim.recon.pfa.identifier;
+
+import java.util.*;
+import hep.physics.vec.*;
+
+import org.lcsim.util.swim.HelixSwimmer;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.geometry.subdetector.CylindricalCalorimeter;
+import org.lcsim.geometry.Detector;
+import org.lcsim.recon.cluster.util.BasicCluster;
+import org.lcsim.recon.cluster.util.TensorClusterPropertyCalculator;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.Track;
+
+/**
+ * Attempt to match a Track to a MIP-like Cluster, based on the intercept point
+ * on the ECAL inner surface and on the direction of the track at the
+ * intercept point.
+ *
+ * @version $Id: SimpleTrackMIPClusterMatcher.java,v 1.1 2006/08/10 22:57:02 mcharles Exp $ 
+ */
+
+public class SimpleTrackMIPClusterMatcher extends SimpleTrackClusterMatcher
+{
+    protected Cluster findMatchedCluster(Track tr, HelixSwimmer swimmer, double alpha, List<Cluster> mips)     
+    {
+	// Find the track intercept and direction
+	swimmer.setTrack(tr);
+	Hep3Vector trackPoint = swimmer.getPointAtDistance(alpha);
+	// Obtain the unit vector giving the tangent:
+	double delta = 0.1;
+	if (alpha < 0) { delta *= -1.0; }
+	Hep3Vector aLittleFurther = swimmer.getPointAtDistance(alpha+delta);
+	Hep3Vector tangent = VecOp.unit(VecOp.sub(aLittleFurther, trackPoint));
+
+	List<Cluster> nearestMIPs = findNearestClusters(trackPoint, mips);
+	for (Cluster nearbyMIP : nearestMIPs) {
+	    // Obtain geometrical info:
+	    CalorimeterHit nearestHit = findNearestHit(trackPoint, nearbyMIP);
+	    double separation = proximity(trackPoint, nearestHit);
+	    int firstLayerHit = getLayer(nearestHit);
+	    double unitDotProduct = findUnitDotProduct(tangent, nearbyMIP);
+	    org.lcsim.geometry.Subdetector subdet = nearestHit.getSubdetector();
+	    // Make cuts:
+	    boolean goodSubDet = (subdet.getName().compareTo("EMBarrel")==0) || (subdet.getName().compareTo("EMEndcap")==0);
+	    boolean goodFirstLayer = (firstLayerHit < 5);
+	    boolean goodDotProduct = (Math.abs(unitDotProduct) > 0.85);
+	    boolean goodSeparation = (separation < 50.0);
+	    boolean foundMatch = goodSubDet && goodFirstLayer && goodDotProduct && goodSeparation;
+	    if (foundMatch) {
+		// OK, made a good match
+		return nearbyMIP;
+	    }
+	}
+	// No match
+	return null;
+    }
+}
CVSspam 0.2.8