Print

Print


Commit in lcsim/src/org/lcsim/contrib/uiowa on MAIN
LocalHelixExtrapolator.java+424added 1.1
LocalHelixExtrapolationTrackClusterMatcher.java+11-3901.6 -> 1.7
LocalHelixExtrapolationTrackMIPClusterMatcher.java+2-711.2 -> 1.3
ReclusterDriver.java+3-31.16 -> 1.17
ReclusterDTreeDriver.java+13-1221.12 -> 1.13
+453-586
1 added + 4 modified, total 5 files
MJC: (contrib) Refactor helix extrapolation; remove some debug code

lcsim/src/org/lcsim/contrib/uiowa
LocalHelixExtrapolator.java added at 1.1
diff -N LocalHelixExtrapolator.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ LocalHelixExtrapolator.java	25 Mar 2008 22:46:01 -0000	1.1
@@ -0,0 +1,424 @@
+package org.lcsim.contrib.uiowa;
+
+import java.util.*;
+import hep.physics.vec.*;
+import org.lcsim.util.decision.*;
+
+import hep.physics.particle.Particle;
+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;
+import org.lcsim.event.MCParticle;
+import org.lcsim.mc.fast.tracking.ReconTrack;
+import org.lcsim.event.SimCalorimeterHit;
+import org.lcsim.recon.pfa.identifier.TrackClusterMatcher;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.mc.fast.tracking.ReconTrack;
+import org.lcsim.event.base.*;
+import org.lcsim.geometry.IDDecoder;
+
+/**
+ * Support class for local helix extrapolation, used to estimate
+ * intercept point of simulated track on an arbitrary ECAL layer.
+ * This will at some point be replaced by full tracking so it's
+ * not a good idea to depend heavily on it.
+ *
+ */
+
+public class LocalHelixExtrapolator extends Driver
+{
+
+    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 Vector<Double> m_ECAL_barrel_layering_r;
+    protected Vector<Double> m_ECAL_endcap_layering_z;
+    protected double m_ECAL_endcap_rmin;
+    protected double m_ECAL_endcap_rmax;
+    protected double[] m_fieldStrength;
+    boolean m_barrelValid = false;
+    boolean m_endcapValid = false;
+    double m_trackParam_xc = 0.0;
+    double m_trackParam_yc = 0.0;
+    double m_trackParam_radius = 0.0;
+    double m_trackParam_dz_by_dphi = 0.0;
+    double m_trackPoint_z = 0.0;
+    double m_trackPoint_phi = 0.0;
+    double m_track_z0 = 0.0;
+    double m_track_phi0 = 0.0;
+    double m_track_phi1 = 0.0;
+    EventHeader m_event = null;
+
+    /** Process this event, storing geometry info if needed. */
+    public void process(EventHeader event) {
+	m_event = event;
+	initGeometry(event);
+    }
+
+    /** Initialize geometry. This is done automatically if the class is run as a driver. */
+    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_ECAL_barrel_layering_r = new Vector<Double>();
+	for (int iLayer=0; iLayer<emb.getLayering().getLayerCount(); iLayer++) {
+	    double r = emb.getLayering().getDistanceToLayerSensorMid(iLayer);
+	    m_ECAL_barrel_layering_r.add(new Double(r));
+	}
+	m_ECAL_endcap_layering_z = new Vector<Double>();
+	for (int iLayer=0; iLayer<eme.getLayering().getLayerCount(); iLayer++) {
+	    double z = eme.getLayering().getDistanceToLayerSensorMid(iLayer);
+	    m_ECAL_endcap_layering_z.add(new Double(z));
+	}
+	m_init = true;
+    }
+
+    protected double m_cutSeparation = 30.0; // 3cm
+    public void setCutSeparation(double cutSeparation) { m_cutSeparation = cutSeparation; }
+
+    // Utility routines
+    // ----------------
+
+    // ONLY "performExtrapolation" is allowed to modify this!
+    private BasicHep3Vector m_lastInterceptPoint = null;
+
+    public BasicHep3Vector getLastInterceptPoint() {
+	if (m_lastInterceptPoint == null) {
+	    return null;
+	} else {
+	    return new BasicHep3Vector(m_lastInterceptPoint.x(), m_lastInterceptPoint.y(), m_lastInterceptPoint.z());
+	}
+    }
+
+    public Hep3Vector performExtrapolation(Track tr) {
+	// Find hits. For now these are SimTrackerHits because
+	// of the inability to get hold of TrackerHits.
+	Collection<SimTrackerHit> trackerHits = findHits(tr);
+
+	if (trackerHits.size() < 3) { 
+	    // Need at least 3 hits to make a helix.
+	    m_lastInterceptPoint = null;
+	    return m_lastInterceptPoint;
+	}
+	// Hit 0 is the closest to the calorimeter (confusing!)
+	SimTrackerHit hit0 = null;
+	SimTrackerHit hit1 = null;
+	SimTrackerHit hit2 = null;
+	for (SimTrackerHit hit : trackerHits) {
+	    if (hit0==null || Math.abs(hit.getPoint()[2])>Math.abs(hit0.getPoint()[2])) {
+		hit2 = hit1;
+		hit1 = hit0;
+		hit0 = hit;
+	    } else if (hit1==null || Math.abs(hit.getPoint()[2])>Math.abs(hit1.getPoint()[2])) {
+		hit2 = hit1;
+		hit1 = hit;
+	    } else if (hit2==null || Math.abs(hit.getPoint()[2])>Math.abs(hit2.getPoint()[2])) {
+		hit2 = hit;
+	    }
+	}
+
+	// First look at the xy (circle) projection
+	double x0 = hit0.getPoint()[0];
+	double x1 = hit1.getPoint()[0];
+	double x2 = hit2.getPoint()[0];
+	double y0 = hit0.getPoint()[1];
+	double y1 = hit1.getPoint()[1];
+	double y2 = hit2.getPoint()[1];
+	double a1 = 2.0 * (x1-x0);
+	double a2 = 2.0 * (x2-x0);
+	double b1 = 2.0 * (y1-y0);
+	double b2 = 2.0 * (y2-y0);
+	double c1 = -x0*x0 -y0*y0 +x1*x1 +y1*y1;
+	double c2 = -x0*x0 -y0*y0 +x2*x2 +y2*y2;
+	// Circle center is at (x_c, y_c)
+	double x_c = (c1*b2-c2*b1)/(a1*b2-a2*b1);
+	double y_c = (c1*a2-c2*a1)/(b1*a2-b2*a1);
+	// Circle radius
+	double radiusSquared = (x_c-x0)*(x_c-x0) + (y_c-y0)*(y_c-y0);
+	double radius = Math.sqrt(radiusSquared);
+	// Now look at z/phi projection
+	// Watch out, this is phi around the circle, not the azimuthal angle phi
+	double z0 = hit0.getPoint()[2];
+	double z1 = hit1.getPoint()[2];
+	double z2 = hit2.getPoint()[2];
+	double phi0 = Math.atan2(y0-y_c, x0-x_c); // in the range -pi through +pi
+	double phi1 = Math.atan2(y1-y_c, x1-x_c);
+	double phi2 = Math.atan2(y2-y_c, x2-x_c);
+	double dz = (z0-z1);
+	double dphi = (phi0-phi1);
+	while (dphi < -Math.PI) { dphi += 2.0*Math.PI; }
+	while (dphi > Math.PI) { dphi -= 2.0*Math.PI; }
+	double dz_by_dphi = dz/dphi;
+	// Now, try to project along to the endcaps (fairly straightforward)
+	double dz_to_endcap = Math.abs(m_ECAL_endcap_z) - z0;
+	if (z0 < 0) {
+	    dz_to_endcap = -Math.abs(m_ECAL_endcap_z) - z0;
+	}
+	double dphi_to_endcap = dz_to_endcap / dz_by_dphi;
+	double found_endcap_z = z0 + dz_to_endcap;
+	double found_endcap_phi = phi0 + dphi_to_endcap;
+	double found_endcap_x = x_c + radius * Math.cos(found_endcap_phi);
+	double found_endcap_y = y_c + radius * Math.sin(found_endcap_phi);
+	double found_endcap_polar_r = Math.sqrt(found_endcap_x*found_endcap_x + found_endcap_y*found_endcap_y);
+	double found_endcap_polar_phi = Math.atan2(found_endcap_y, found_endcap_x);
+	m_endcapValid = (found_endcap_polar_r >= m_ECAL_endcap_rmin-m_cutSeparation && found_endcap_polar_r <= m_ECAL_endcap_rmax+m_cutSeparation);
+	// Now project along to the barrel (harder!)
+	// We have phi such that (x-x_c)=a*cos(phi), (y-y_c)=a*sin(phi)
+	// Define theta such that x_c = b*cos(theta), y_c = b*sin(theta)
+	double a = radius;
+	double b = Math.sqrt(x_c*x_c + y_c*y_c);
+	double r = m_ECAL_barrel_r; // barrel radius
+	double cos_phi_minus_theta = (r*r - a*a - b*b) / (2.0*a*b); // Obviously, this blows up if a or b is zero
+	double theta = Math.atan2(y_c, x_c); // in the range (-pi, +pi)
+	double dphi_to_barrel = 0.0;
+	m_barrelValid = false;
+	if (cos_phi_minus_theta < -1.0) {
+	    // No solution
+	} else if (cos_phi_minus_theta == -1.0) {
+	    // Unique solution: phi = theta + pi
+	    dphi_to_barrel = theta + Math.PI - phi0;
+	    while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
+	    while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }
+	    m_barrelValid = true;
+	} else if (cos_phi_minus_theta == 1.0) {
+	    // Unique solution: phi = theta
+	    dphi_to_barrel = theta - phi0;
+	    while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
+	    while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }
+	    m_barrelValid = true;
+	} else if (cos_phi_minus_theta > 1.0) {
+	    // No solution
+	} else {
+	    // Two solutions
+	    double phi_minus_theta_first_solution = Math.acos(cos_phi_minus_theta); // in the range 0 through pi
+	    double phi_minus_theta_second_solution = -phi_minus_theta_first_solution; // in the range -pi through 0
+	    double phi_first_solution = phi_minus_theta_first_solution + theta; // in the range (-pi, 2pi)
+	    double phi_second_solution = phi_minus_theta_second_solution + theta; // in the range (-2pi, pi)
+	    double dphi_to_barrel_firstSolution = phi_first_solution - phi0;
+	    double dphi_to_barrel_secondSolution = phi_second_solution - phi0;
+	    while (dphi_to_barrel_firstSolution < -Math.PI) { dphi_to_barrel_firstSolution += 2.0*Math.PI; }
+	    while (dphi_to_barrel_secondSolution < -Math.PI) { dphi_to_barrel_secondSolution += 2.0*Math.PI; }
+	    while (dphi_to_barrel_firstSolution > Math.PI) { dphi_to_barrel_firstSolution -= 2.0*Math.PI; }
+	    while (dphi_to_barrel_secondSolution > Math.PI) { dphi_to_barrel_secondSolution -= 2.0*Math.PI; }
+	    // OK, now which of the two solutions is better?
+	    double test_dphi1 = dphi_to_barrel_firstSolution * dphi;
+	    double test_dphi2 = dphi_to_barrel_secondSolution * dphi;
+	    while (test_dphi1 < 0) { test_dphi1 += 2.0*Math.PI; }
+	    while (test_dphi2 < 0) { test_dphi2 += 2.0*Math.PI; }
+	    if (test_dphi1 < test_dphi2) {
+		dphi_to_barrel = dphi_to_barrel_firstSolution;
+	    } else {
+		dphi_to_barrel = dphi_to_barrel_secondSolution;
+	    }
+	    while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
+	    while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }		    
+	    m_barrelValid = true;
+	}
+	double found_barrel_z = z0 + dz_by_dphi * dphi_to_barrel;
+	double found_barrel_phi = phi0 + dphi_to_barrel;
+	double found_barrel_x = x_c + radius * Math.cos(found_barrel_phi);
+	double found_barrel_y = y_c + radius * Math.sin(found_barrel_phi);
+	double found_barrel_polar_r = Math.sqrt(found_barrel_x*found_barrel_x + found_barrel_y*found_barrel_y);
+	double found_barrel_polar_phi = Math.atan2(found_barrel_y, found_barrel_x);
+	m_barrelValid = m_barrelValid && (found_barrel_z >= m_ECAL_barrel_zmin-m_cutSeparation && found_barrel_z <= m_ECAL_barrel_zmax+m_cutSeparation);
+	
+	if (m_barrelValid && m_endcapValid) {
+	    // Weird case: two possible solutions
+	    // Look at which is closer to last tracker hit.
+	    double distanceToBarrelSq = (x0-found_barrel_x)*(x0-found_barrel_x) + (y0-found_barrel_y)*(y0-found_barrel_y) + (z0-found_barrel_z)*(z0-found_barrel_z);
+	    double distanceToEndcapSq = (x0-found_endcap_x)*(x0-found_endcap_x) + (y0-found_endcap_y)*(y0-found_endcap_y) + (z0-found_endcap_z)*(z0-found_endcap_z);
+	    if (distanceToBarrelSq<distanceToEndcapSq) {
+		m_endcapValid = false;
+	    } else {
+		m_barrelValid = false;
+	    }
+	}
+
+	m_trackParam_xc = x_c;
+	m_trackParam_yc = y_c;
+	m_trackParam_radius = radius;
+	m_trackParam_dz_by_dphi = dz_by_dphi;
+	m_track_phi0 = phi0;
+	m_track_phi1 = phi1;
+	m_track_z0 = z0;
+	if (m_endcapValid) {
+	    m_trackPoint_z = found_endcap_z;
+	    m_trackPoint_phi = found_endcap_phi;
+	    m_lastInterceptPoint = new BasicHep3Vector(found_endcap_x, found_endcap_y, found_endcap_z);
+	    return m_lastInterceptPoint;
+	}
+	if (m_barrelValid) {
+	    m_trackPoint_z = found_barrel_z;
+	    m_trackPoint_phi = found_barrel_phi;
+	    m_lastInterceptPoint = new BasicHep3Vector(found_barrel_x, found_barrel_y, found_barrel_z);
+	    return m_lastInterceptPoint;
+	}
+
+	// No solution
+	m_lastInterceptPoint = null;
+	return m_lastInterceptPoint;
+    }
+
+    private Collection<SimTrackerHit> findHits(Track tr) {
+	// Find truth particle of track:
+	MCParticle truth = null;
+	if (tr instanceof org.lcsim.mc.fast.tracking.ReconTrack) {
+	    org.lcsim.mc.fast.tracking.ReconTrack reconTr = (org.lcsim.mc.fast.tracking.ReconTrack) (tr);
+	    truth = (MCParticle)(reconTr.getMCParticle());
+	} else if (tr instanceof BaseTrackMC) {
+	    truth = ((BaseTrackMC)(tr)).getMCParticle();
+	}
+	// Look up all hits in event:
+	List<SimTrackerHit> trackerHits = new Vector<SimTrackerHit>();
+	trackerHits.addAll(m_event.get(org.lcsim.event.SimTrackerHit.class, "TkrBarrHits"));
+	trackerHits.addAll(m_event.get(org.lcsim.event.SimTrackerHit.class, "TkrEndcapHits"));
+	// Find hits that match track:
+	List<SimTrackerHit> hitsMatched = new Vector<org.lcsim.event.SimTrackerHit>();
+	for (SimTrackerHit hit : trackerHits) {
+	    if (hit.getMCParticle() == truth) {
+		hitsMatched.add(hit);
+	    }
+	}
+	return hitsMatched;
+    }
+
+    public Long extendToECALLayerAndFindCell(int layer) {
+	Hep3Vector point = extendToECALLayer(layer);
+	IDDecoder id = null;
+	if (m_barrelValid) {
+	    id = m_event.getDetector().getDecoder("EcalBarrHits");
+	    if (id == null) { throw new AssertionError("Failed to find barrel ID"); }
+	} else if (m_endcapValid) {
+	    id = m_event.getDetector().getDecoder("EcalEndcapHits");
+	    if (id == null) { throw new AssertionError("Failed to find endcap ID"); }
+	}
+	if (id != null) {
+	    long cell = id.findCellContainingXYZ(point);
+	    id.setID(cell);
+	    Hep3Vector cellCenter = id.getPositionVector();
+	    return new Long(cell);
+	} else {
+	    return null;
+	}
+    }
+
+    /** Assumes extrapolation has already been done. */
+    public Hep3Vector getTangent() {
+	double dphi = 0.01;
+	double dx = m_trackParam_radius * ( Math.cos(m_trackPoint_phi+dphi) - Math.cos(m_trackPoint_phi) );
+	double dy = m_trackParam_radius * ( Math.sin(m_trackPoint_phi+dphi) - Math.sin(m_trackPoint_phi) );
+	double dz = m_trackParam_dz_by_dphi * dphi;
+	Hep3Vector tangent = VecOp.unit(new BasicHep3Vector(dx,dy,dz));
+	return tangent;
+    }
+
+    /** Assumes extrapolation has already been done. */
+    public Hep3Vector extendToECALLayer(int layer) {
+	double dphi = (m_track_phi0 - m_track_phi1);
+	while (dphi < -Math.PI) { dphi += 2.0*Math.PI; }
+	while (dphi > Math.PI) { dphi -= 2.0*Math.PI; }
+	double x_c = m_trackParam_xc;
+	double y_c = m_trackParam_yc;
+	double radius = m_trackParam_radius;
+	double dz_by_dphi = m_trackParam_dz_by_dphi;
+
+	if (m_barrelValid) {
+	    double a = radius;
+	    double b = Math.sqrt(x_c*x_c + y_c*y_c);
+	    double r =  m_ECAL_barrel_layering_r.get(layer);
+	    double cos_phi_minus_theta = (r*r - a*a - b*b) / (2.0*a*b); // Obviously, this blows up if a or b is zero
+	    double theta = Math.atan2(y_c, x_c); // in the range (-pi, +pi)
+	    double dphi_to_barrel = 0.0;
+	    if (cos_phi_minus_theta < -1.0) {
+		// No solution
+		return null;
+	    } else if (cos_phi_minus_theta == -1.0) {
+		// Unique solution: phi = theta + pi
+		dphi_to_barrel = theta + Math.PI - m_track_phi0;
+		while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
+		while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }
+	    } else if (cos_phi_minus_theta == 1.0) {
+		// Unique solution: phi = theta
+		dphi_to_barrel = theta - m_track_phi0;
+		while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
+		while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }
+	    } else if (cos_phi_minus_theta > 1.0) {
+		// No solution
+		return null;
+	    } else {
+		// Two solutions
+		double phi_minus_theta_first_solution = Math.acos(cos_phi_minus_theta); // in the range 0 through pi
+		double phi_minus_theta_second_solution = -phi_minus_theta_first_solution; // in the range -pi through 0
+		double phi_first_solution = phi_minus_theta_first_solution + theta; // in the range (-pi, 2pi)
+		double phi_second_solution = phi_minus_theta_second_solution + theta; // in the range (-2pi, pi)
+		double dphi_to_barrel_firstSolution = phi_first_solution - m_track_phi0;
+		double dphi_to_barrel_secondSolution = phi_second_solution - m_track_phi0;
+		while (dphi_to_barrel_firstSolution < -Math.PI) { dphi_to_barrel_firstSolution += 2.0*Math.PI; }
+		while (dphi_to_barrel_secondSolution < -Math.PI) { dphi_to_barrel_secondSolution += 2.0*Math.PI; }
+		while (dphi_to_barrel_firstSolution > Math.PI) { dphi_to_barrel_firstSolution -= 2.0*Math.PI; }
+		while (dphi_to_barrel_secondSolution > Math.PI) { dphi_to_barrel_secondSolution -= 2.0*Math.PI; }
+		// OK, now which of the two solutions is better?
+		double test_dphi1 = dphi_to_barrel_firstSolution * dphi;
+		double test_dphi2 = dphi_to_barrel_secondSolution * dphi;
+		while (test_dphi1 < 0) { test_dphi1 += 2.0*Math.PI; }
+		while (test_dphi2 < 0) { test_dphi2 += 2.0*Math.PI; }
+		if (test_dphi1 < test_dphi2) {
+		    dphi_to_barrel = dphi_to_barrel_firstSolution;
+		} else {
+		    dphi_to_barrel = dphi_to_barrel_secondSolution;
+		}
+		while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
+		while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }		    
+	    }
+	    double found_barrel_z = m_track_z0 + dz_by_dphi * dphi_to_barrel;
+	    double found_barrel_phi = m_track_phi0 + dphi_to_barrel;
+	    double found_barrel_x = x_c + radius * Math.cos(found_barrel_phi);
+	    double found_barrel_y = y_c + radius * Math.sin(found_barrel_phi);
+	    double found_barrel_polar_r = Math.sqrt(found_barrel_x*found_barrel_x + found_barrel_y*found_barrel_y);
+	    double found_barrel_polar_phi = Math.atan2(found_barrel_y, found_barrel_x);
+	    boolean validSolution =(found_barrel_z >= m_ECAL_barrel_zmin-m_cutSeparation && found_barrel_z <= m_ECAL_barrel_zmax+m_cutSeparation);
+	    if (validSolution) {
+		return new BasicHep3Vector(found_barrel_x, found_barrel_y, found_barrel_z);
+	    } else {
+		return null;
+	    }
+	} else if (m_endcapValid) {
+	    double previous_z = m_trackPoint_z;
+	    double new_z = Math.abs(m_ECAL_endcap_layering_z.get(layer));
+	    if (previous_z < 0) { new_z = -new_z; }
+	    double dz = new_z - previous_z;
+	    double deltaPhi = dz / m_trackParam_dz_by_dphi;
+	    double phi = m_trackPoint_phi + deltaPhi;
+	    double found_endcap_x = x_c + radius * Math.cos(phi);
+	    double found_endcap_y = y_c + radius * Math.sin(phi);
+	    double found_endcap_z = new_z;
+	    double found_endcap_polar_r = Math.sqrt(found_endcap_x*found_endcap_x + found_endcap_y*found_endcap_y);
+	    boolean validSolution = (found_endcap_polar_r >= m_ECAL_endcap_rmin-m_cutSeparation && found_endcap_polar_r <= m_ECAL_endcap_rmax+m_cutSeparation);
+	    if (validSolution) {
+		return new BasicHep3Vector(found_endcap_x, found_endcap_y, found_endcap_z);
+	    } else {
+		return null;
+	    }
+	} else {
+	    // No solution
+	    return null;
+	}
+    }
+}

lcsim/src/org/lcsim/contrib/uiowa
LocalHelixExtrapolationTrackClusterMatcher.java 1.6 -> 1.7
diff -u -r1.6 -r1.7
--- LocalHelixExtrapolationTrackClusterMatcher.java	8 Mar 2008 20:51:30 -0000	1.6
+++ LocalHelixExtrapolationTrackClusterMatcher.java	25 Mar 2008 22:46:01 -0000	1.7
@@ -39,12 +39,15 @@
     /** Simple constructor. */
     public LocalHelixExtrapolationTrackClusterMatcher() {
 	super();
+	m_extrap= new LocalHelixExtrapolator();
     }
 
     /** Constructor, specifying additional cut to apply. */
     public LocalHelixExtrapolationTrackClusterMatcher(DecisionMakerPair<Track,Cluster> extraCut) { 
 	super();
 	m_extraCut = extraCut; 
+	m_extrap= new LocalHelixExtrapolator();
+	add(m_extrap);
     }
 
     /** Another way to specify the additional cut. */
@@ -55,7 +58,8 @@
     /** Process this event, storing geometry info if needed. */
     public void process(EventHeader event) {
 	m_event = event;
-	initGeometry(event);
+	m_extrap.process(event);
+
     }
 
     /**
@@ -65,7 +69,7 @@
       */
     public Cluster matchTrackToCluster(Track tr, List<Cluster> clusters) {
 	if (m_debug) { System.out.println("DEBUG: "+this.getClass().getName()+" trying to match track with p="+(new BasicHep3Vector(tr.getMomentum())).magnitude()+" to a list of "+clusters.size()+" clusters."); }
-	Hep3Vector point = performExtrapolation(tr);
+	Hep3Vector point = m_extrap.performExtrapolation(tr);
 	if (point != null) {
 	    // Extrapolated to ECAL OK.
 	    if (m_debug) { System.out.println("DEBUG: "+this.getClass().getName()+": extrapolated track with p="+(new BasicHep3Vector(tr.getMomentum())).magnitude()+" to r="+(Math.sqrt(point.x()*point.x()+point.y()*point.y()))+", z="+point.z()); }
@@ -104,270 +108,21 @@
 	return null;
     }
 
-    /** Initialize geometry. This is done automatically if the class is run as a driver. */
-    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_ECAL_barrel_layering_r = new Vector<Double>();
-	for (int iLayer=0; iLayer<emb.getLayering().getLayerCount(); iLayer++) {
-	    double r = emb.getLayering().getDistanceToLayerSensorMid(iLayer);
-	    m_ECAL_barrel_layering_r.add(new Double(r));
-	}
-	m_ECAL_endcap_layering_z = new Vector<Double>();
-	for (int iLayer=0; iLayer<eme.getLayering().getLayerCount(); iLayer++) {
-	    double z = eme.getLayering().getDistanceToLayerSensorMid(iLayer);
-	    m_ECAL_endcap_layering_z.add(new Double(z));
-	}
-	m_init = true;
-    }
-
-    /**
-     * Perform track matching.
-     *
-     * Return value is the associated cluster.
-     *
-     * The argumets <code>tr</code> and <code>clusters</code> are inputs.
-     *
-     * The argument <code>interceptPoint</code> will be changed to the (x,y,z)
-     * co-ordinates of the estimated intercept point of the track on the calorimeter
-     * surface. If no intercept point is found, the intercept point will be set
-     * to (NaN, NaN, NaN). If a null <code>interceptPoint</code> is supplied by
-     * the caller, this will cause a null pointer exception.
-     */
-    public Cluster matchTrackToClusterQuotingInterceptPoint(Track tr, List<Cluster> clusters, BasicHep3Vector interceptPoint) {
-	Cluster clus = matchTrackToCluster(tr, clusters);
-	BasicHep3Vector foundInterceptPoint = getLastInterceptPoint();
-	if (foundInterceptPoint != null) {
-	    interceptPoint.setV(foundInterceptPoint.x(), foundInterceptPoint.y(), foundInterceptPoint.z());
-	} else {
-	    interceptPoint.setV(Double.NaN, Double.NaN, Double.NaN);
-	}
-	return clus;
-    }
-
-    public void setCutSeparation(double cutSeparation) { m_cutSeparation = cutSeparation; }
+    public void setCutSeparation(double cutSeparation) { m_cutSeparation = cutSeparation; m_extrap.setCutSeparation(cutSeparation); }
     public void setCutFirstLayer(int cutFirstLayer) { m_cutFirstLayer = cutFirstLayer; }
 
+    public LocalHelixExtrapolator getExtrapolator() { return m_extrap; }
+    public void setExtrapolator(LocalHelixExtrapolator extrap) { m_extrap = extrap; }
+
     protected DecisionMakerPair<Track,Cluster> m_extraCut = null;
     protected double m_cutSeparation = 30.0; // 3cm
     protected int    m_cutFirstLayer = 5; // Cluster must have a hit in in layer 0,1,2,3, or 4.
     protected EventHeader m_event;
-    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 Vector<Double> m_ECAL_barrel_layering_r;
-    protected Vector<Double> m_ECAL_endcap_layering_z;
-    protected double m_ECAL_endcap_rmin;
-    protected double m_ECAL_endcap_rmax;
-    protected double[] m_fieldStrength;
-    // Cache some geometry information for subclasses
-    boolean m_barrelValid = false;
-    boolean m_endcapValid = false;
-    double m_trackParam_xc = 0.0;
-    double m_trackParam_yc = 0.0;
-    double m_trackParam_radius = 0.0;
-    double m_trackParam_dz_by_dphi = 0.0;
-    double m_trackPoint_z = 0.0;
-    double m_trackPoint_phi = 0.0;
-    double m_track_z0 = 0.0;
-    double m_track_phi0 = 0.0;
-    double m_track_phi1 = 0.0;
+    protected LocalHelixExtrapolator m_extrap = null;
 
     // Utility routines
     // ----------------
 
-
-    // ONLY "performExtrapolation" is allowed to modify this!
-    private BasicHep3Vector m_lastInterceptPoint = null;
-    // Don't make this public!
-    protected BasicHep3Vector getLastInterceptPoint() {
-	if (m_lastInterceptPoint == null) {
-	    return null;
-	} else {
-	    return new BasicHep3Vector(m_lastInterceptPoint.x(), m_lastInterceptPoint.y(), m_lastInterceptPoint.z());
-	}
-    }
-
-    protected Hep3Vector performExtrapolation(Track tr) {
-	// Find hits. For now these are SimTrackerHits because
-	// of the inability to get hold of TrackerHits.
-	Collection<SimTrackerHit> trackerHits = findHits(tr);
-
-	if (trackerHits.size() < 3) { 
-	    // Need at least 3 hits to make a helix.
-	    m_lastInterceptPoint = null;
-	    return m_lastInterceptPoint;
-	}
-	// Hit 0 is the closest to the calorimeter (confusing!)
-	SimTrackerHit hit0 = null;
-	SimTrackerHit hit1 = null;
-	SimTrackerHit hit2 = null;
-	for (SimTrackerHit hit : trackerHits) {
-	    if (hit0==null || Math.abs(hit.getPoint()[2])>Math.abs(hit0.getPoint()[2])) {
-		hit2 = hit1;
-		hit1 = hit0;
-		hit0 = hit;
-	    } else if (hit1==null || Math.abs(hit.getPoint()[2])>Math.abs(hit1.getPoint()[2])) {
-		hit2 = hit1;
-		hit1 = hit;
-	    } else if (hit2==null || Math.abs(hit.getPoint()[2])>Math.abs(hit2.getPoint()[2])) {
-		hit2 = hit;
-	    }
-	}
-
-	// First look at the xy (circle) projection
-	double x0 = hit0.getPoint()[0];
-	double x1 = hit1.getPoint()[0];
-	double x2 = hit2.getPoint()[0];
-	double y0 = hit0.getPoint()[1];
-	double y1 = hit1.getPoint()[1];
-	double y2 = hit2.getPoint()[1];
-	double a1 = 2.0 * (x1-x0);
-	double a2 = 2.0 * (x2-x0);
-	double b1 = 2.0 * (y1-y0);
-	double b2 = 2.0 * (y2-y0);
-	double c1 = -x0*x0 -y0*y0 +x1*x1 +y1*y1;
-	double c2 = -x0*x0 -y0*y0 +x2*x2 +y2*y2;
-	// Circle center is at (x_c, y_c)
-	double x_c = (c1*b2-c2*b1)/(a1*b2-a2*b1);
-	double y_c = (c1*a2-c2*a1)/(b1*a2-b2*a1);
-	// Circle radius
-	double radiusSquared = (x_c-x0)*(x_c-x0) + (y_c-y0)*(y_c-y0);
-	double radius = Math.sqrt(radiusSquared);
-	// Now look at z/phi projection
-	// Watch out, this is phi around the circle, not the azimuthal angle phi
-	double z0 = hit0.getPoint()[2];
-	double z1 = hit1.getPoint()[2];
-	double z2 = hit2.getPoint()[2];
-	double phi0 = Math.atan2(y0-y_c, x0-x_c); // in the range -pi through +pi
-	double phi1 = Math.atan2(y1-y_c, x1-x_c);
-	double phi2 = Math.atan2(y2-y_c, x2-x_c);
-	double dz = (z0-z1);
-	double dphi = (phi0-phi1);
-	while (dphi < -Math.PI) { dphi += 2.0*Math.PI; }
-	while (dphi > Math.PI) { dphi -= 2.0*Math.PI; }
-	double dz_by_dphi = dz/dphi;
-	// Now, try to project along to the endcaps (fairly straightforward)
-	double dz_to_endcap = Math.abs(m_ECAL_endcap_z) - z0;
-	if (z0 < 0) {
-	    dz_to_endcap = -Math.abs(m_ECAL_endcap_z) - z0;
-	}
-	double dphi_to_endcap = dz_to_endcap / dz_by_dphi;
-	double found_endcap_z = z0 + dz_to_endcap;
-	double found_endcap_phi = phi0 + dphi_to_endcap;
-	double found_endcap_x = x_c + radius * Math.cos(found_endcap_phi);
-	double found_endcap_y = y_c + radius * Math.sin(found_endcap_phi);
-	double found_endcap_polar_r = Math.sqrt(found_endcap_x*found_endcap_x + found_endcap_y*found_endcap_y);
-	double found_endcap_polar_phi = Math.atan2(found_endcap_y, found_endcap_x);
-	m_endcapValid = (found_endcap_polar_r >= m_ECAL_endcap_rmin-m_cutSeparation && found_endcap_polar_r <= m_ECAL_endcap_rmax+m_cutSeparation);
-	// Now project along to the barrel (harder!)
-	// We have phi such that (x-x_c)=a*cos(phi), (y-y_c)=a*sin(phi)
-	// Define theta such that x_c = b*cos(theta), y_c = b*sin(theta)
-	double a = radius;
-	double b = Math.sqrt(x_c*x_c + y_c*y_c);
-	double r = m_ECAL_barrel_r; // barrel radius
-	double cos_phi_minus_theta = (r*r - a*a - b*b) / (2.0*a*b); // Obviously, this blows up if a or b is zero
-	double theta = Math.atan2(y_c, x_c); // in the range (-pi, +pi)
-	double dphi_to_barrel = 0.0;
-	m_barrelValid = false;
-	if (cos_phi_minus_theta < -1.0) {
-	    // No solution
-	} else if (cos_phi_minus_theta == -1.0) {
-	    // Unique solution: phi = theta + pi
-	    dphi_to_barrel = theta + Math.PI - phi0;
-	    while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
-	    while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }
-	    m_barrelValid = true;
-	} else if (cos_phi_minus_theta == 1.0) {
-	    // Unique solution: phi = theta
-	    dphi_to_barrel = theta - phi0;
-	    while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
-	    while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }
-	    m_barrelValid = true;
-	} else if (cos_phi_minus_theta > 1.0) {
-	    // No solution
-	} else {
-	    // Two solutions
-	    double phi_minus_theta_first_solution = Math.acos(cos_phi_minus_theta); // in the range 0 through pi
-	    double phi_minus_theta_second_solution = -phi_minus_theta_first_solution; // in the range -pi through 0
-	    double phi_first_solution = phi_minus_theta_first_solution + theta; // in the range (-pi, 2pi)
-	    double phi_second_solution = phi_minus_theta_second_solution + theta; // in the range (-2pi, pi)
-	    double dphi_to_barrel_firstSolution = phi_first_solution - phi0;
-	    double dphi_to_barrel_secondSolution = phi_second_solution - phi0;
-	    while (dphi_to_barrel_firstSolution < -Math.PI) { dphi_to_barrel_firstSolution += 2.0*Math.PI; }
-	    while (dphi_to_barrel_secondSolution < -Math.PI) { dphi_to_barrel_secondSolution += 2.0*Math.PI; }
-	    while (dphi_to_barrel_firstSolution > Math.PI) { dphi_to_barrel_firstSolution -= 2.0*Math.PI; }
-	    while (dphi_to_barrel_secondSolution > Math.PI) { dphi_to_barrel_secondSolution -= 2.0*Math.PI; }
-	    // OK, now which of the two solutions is better?
-	    double test_dphi1 = dphi_to_barrel_firstSolution * dphi;
-	    double test_dphi2 = dphi_to_barrel_secondSolution * dphi;
-	    while (test_dphi1 < 0) { test_dphi1 += 2.0*Math.PI; }
-	    while (test_dphi2 < 0) { test_dphi2 += 2.0*Math.PI; }
-	    if (test_dphi1 < test_dphi2) {
-		dphi_to_barrel = dphi_to_barrel_firstSolution;
-	    } else {
-		dphi_to_barrel = dphi_to_barrel_secondSolution;
-	    }
-	    while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
-	    while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }		    
-	    m_barrelValid = true;
-	}
-	double found_barrel_z = z0 + dz_by_dphi * dphi_to_barrel;
-	double found_barrel_phi = phi0 + dphi_to_barrel;
-	double found_barrel_x = x_c + radius * Math.cos(found_barrel_phi);
-	double found_barrel_y = y_c + radius * Math.sin(found_barrel_phi);
-	double found_barrel_polar_r = Math.sqrt(found_barrel_x*found_barrel_x + found_barrel_y*found_barrel_y);
-	double found_barrel_polar_phi = Math.atan2(found_barrel_y, found_barrel_x);
-	m_barrelValid = m_barrelValid && (found_barrel_z >= m_ECAL_barrel_zmin-m_cutSeparation && found_barrel_z <= m_ECAL_barrel_zmax+m_cutSeparation);
-	
-	if (m_barrelValid && m_endcapValid) {
-	    // Weird case: two possible solutions
-	    // Look at which is closer to last tracker hit.
-	    double distanceToBarrelSq = (x0-found_barrel_x)*(x0-found_barrel_x) + (y0-found_barrel_y)*(y0-found_barrel_y) + (z0-found_barrel_z)*(z0-found_barrel_z);
-	    double distanceToEndcapSq = (x0-found_endcap_x)*(x0-found_endcap_x) + (y0-found_endcap_y)*(y0-found_endcap_y) + (z0-found_endcap_z)*(z0-found_endcap_z);
-	    if (distanceToBarrelSq<distanceToEndcapSq) {
-		m_endcapValid = false;
-	    } else {
-		m_barrelValid = false;
-	    }
-	}
-
-	m_trackParam_xc = x_c;
-	m_trackParam_yc = y_c;
-	m_trackParam_radius = radius;
-	m_trackParam_dz_by_dphi = dz_by_dphi;
-	m_track_phi0 = phi0;
-	m_track_phi1 = phi1;
-	m_track_z0 = z0;
-	if (m_endcapValid) {
-	    m_trackPoint_z = found_endcap_z;
-	    m_trackPoint_phi = found_endcap_phi;
-	    m_lastInterceptPoint = new BasicHep3Vector(found_endcap_x, found_endcap_y, found_endcap_z);
-	    return m_lastInterceptPoint;
-	}
-	if (m_barrelValid) {
-	    m_trackPoint_z = found_barrel_z;
-	    m_trackPoint_phi = found_barrel_phi;
-	    m_lastInterceptPoint = new BasicHep3Vector(found_barrel_x, found_barrel_y, found_barrel_z);
-	    return m_lastInterceptPoint;
-	}
-
-	// No solution
-	m_lastInterceptPoint = null;
-	return m_lastInterceptPoint;
-    }
-
     protected List<Cluster> findNearestClusters(Hep3Vector point, List<Cluster> clusterList) {
 	Map<Cluster,Double> mapClusterToDistance = new HashMap<Cluster, Double>();
 	List<Cluster> sortedListOfClusters = new Vector<Cluster>();
@@ -446,142 +201,8 @@
 	Map<T,Double> m_map;
     }
 
-    protected Collection<SimTrackerHit> findHits(Track tr) {
-	// Find truth particle of track:
-	MCParticle truth = null;
-	if (tr instanceof org.lcsim.mc.fast.tracking.ReconTrack) {
-	    org.lcsim.mc.fast.tracking.ReconTrack reconTr = (org.lcsim.mc.fast.tracking.ReconTrack) (tr);
-	    truth = (MCParticle)(reconTr.getMCParticle());
-	} else if (tr instanceof BaseTrackMC) {
-	    truth = ((BaseTrackMC)(tr)).getMCParticle();
-	}
-	// Look up all hits in event:
-	List<SimTrackerHit> trackerHits = new Vector<SimTrackerHit>();
-	trackerHits.addAll(m_event.get(org.lcsim.event.SimTrackerHit.class, "TkrBarrHits"));
-	trackerHits.addAll(m_event.get(org.lcsim.event.SimTrackerHit.class, "TkrEndcapHits"));
-	// Find hits that match track:
-	List<SimTrackerHit> hitsMatched = new Vector<org.lcsim.event.SimTrackerHit>();
-	for (SimTrackerHit hit : trackerHits) {
-	    if (hit.getMCParticle() == truth) {
-		hitsMatched.add(hit);
-	    }
-	}
-	return hitsMatched;
-    }
-
     protected boolean m_debug = false;
     public void setDebug(boolean debug) { m_debug = debug ; }
 
-    protected Long extendToLayerAndFindCell(int layer) {
-	Hep3Vector point = extendToLayer(layer);
-	IDDecoder id = null;
-	if (m_barrelValid) {
-	    id = m_event.getDetector().getDecoder("EcalBarrHits");
-	    if (id == null) { throw new AssertionError("Failed to find barrel ID"); }
-	} else if (m_endcapValid) {
-	    id = m_event.getDetector().getDecoder("EcalEndcapHits");
-	    if (id == null) { throw new AssertionError("Failed to find endcap ID"); }
-	}
-	if (id != null) {
-	    long cell = id.findCellContainingXYZ(point);
-	    id.setID(cell);
-	    Hep3Vector cellCenter = id.getPositionVector();
-	    return new Long(cell);
-	} else {
-	    return null;
-	}
-    }
-
-    protected Hep3Vector extendToLayer(int layer) {
-	double dphi = (m_track_phi0 - m_track_phi1);
-	while (dphi < -Math.PI) { dphi += 2.0*Math.PI; }
-	while (dphi > Math.PI) { dphi -= 2.0*Math.PI; }
-	double x_c = m_trackParam_xc;
-	double y_c = m_trackParam_yc;
-	double radius = m_trackParam_radius;
-	double dz_by_dphi = m_trackParam_dz_by_dphi;
-
-	if (m_barrelValid) {
-	    double a = radius;
-	    double b = Math.sqrt(x_c*x_c + y_c*y_c);
-	    double r =  m_ECAL_barrel_layering_r.get(layer);
-	    double cos_phi_minus_theta = (r*r - a*a - b*b) / (2.0*a*b); // Obviously, this blows up if a or b is zero
-	    double theta = Math.atan2(y_c, x_c); // in the range (-pi, +pi)
-	    double dphi_to_barrel = 0.0;
-	    if (cos_phi_minus_theta < -1.0) {
-		// No solution
-		return null;
-	    } else if (cos_phi_minus_theta == -1.0) {
-		// Unique solution: phi = theta + pi
-		dphi_to_barrel = theta + Math.PI - m_track_phi0;
-		while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
-		while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }
-	    } else if (cos_phi_minus_theta == 1.0) {
-		// Unique solution: phi = theta
-		dphi_to_barrel = theta - m_track_phi0;
-		while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
-		while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }
-	    } else if (cos_phi_minus_theta > 1.0) {
-		// No solution
-		return null;
-	    } else {
-		// Two solutions
-		double phi_minus_theta_first_solution = Math.acos(cos_phi_minus_theta); // in the range 0 through pi
-		double phi_minus_theta_second_solution = -phi_minus_theta_first_solution; // in the range -pi through 0
-		double phi_first_solution = phi_minus_theta_first_solution + theta; // in the range (-pi, 2pi)
-		double phi_second_solution = phi_minus_theta_second_solution + theta; // in the range (-2pi, pi)
-		double dphi_to_barrel_firstSolution = phi_first_solution - m_track_phi0;
-		double dphi_to_barrel_secondSolution = phi_second_solution - m_track_phi0;
-		while (dphi_to_barrel_firstSolution < -Math.PI) { dphi_to_barrel_firstSolution += 2.0*Math.PI; }
-		while (dphi_to_barrel_secondSolution < -Math.PI) { dphi_to_barrel_secondSolution += 2.0*Math.PI; }
-		while (dphi_to_barrel_firstSolution > Math.PI) { dphi_to_barrel_firstSolution -= 2.0*Math.PI; }
-		while (dphi_to_barrel_secondSolution > Math.PI) { dphi_to_barrel_secondSolution -= 2.0*Math.PI; }
-		// OK, now which of the two solutions is better?
-		double test_dphi1 = dphi_to_barrel_firstSolution * dphi;
-		double test_dphi2 = dphi_to_barrel_secondSolution * dphi;
-		while (test_dphi1 < 0) { test_dphi1 += 2.0*Math.PI; }
-		while (test_dphi2 < 0) { test_dphi2 += 2.0*Math.PI; }
-		if (test_dphi1 < test_dphi2) {
-		    dphi_to_barrel = dphi_to_barrel_firstSolution;
-		} else {
-		    dphi_to_barrel = dphi_to_barrel_secondSolution;
-		}
-		while (dphi_to_barrel < -Math.PI) { dphi_to_barrel += 2.0*Math.PI; }
-		while (dphi_to_barrel > Math.PI) { dphi_to_barrel -= 2.0*Math.PI; }		    
-	    }
-	    double found_barrel_z = m_track_z0 + dz_by_dphi * dphi_to_barrel;
-	    double found_barrel_phi = m_track_phi0 + dphi_to_barrel;
-	    double found_barrel_x = x_c + radius * Math.cos(found_barrel_phi);
-	    double found_barrel_y = y_c + radius * Math.sin(found_barrel_phi);
-	    double found_barrel_polar_r = Math.sqrt(found_barrel_x*found_barrel_x + found_barrel_y*found_barrel_y);
-	    double found_barrel_polar_phi = Math.atan2(found_barrel_y, found_barrel_x);
-	    boolean validSolution =(found_barrel_z >= m_ECAL_barrel_zmin-m_cutSeparation && found_barrel_z <= m_ECAL_barrel_zmax+m_cutSeparation);
-	    if (validSolution) {
-		return new BasicHep3Vector(found_barrel_x, found_barrel_y, found_barrel_z);
-	    } else {
-		return null;
-	    }
-	} else if (m_endcapValid) {
-	    double previous_z = m_trackPoint_z;
-	    double new_z = Math.abs(m_ECAL_endcap_layering_z.get(layer));
-	    if (previous_z < 0) { new_z = -new_z; }
-	    double dz = new_z - previous_z;
-	    double deltaPhi = dz / m_trackParam_dz_by_dphi;
-	    double phi = m_trackPoint_phi + deltaPhi;
-	    double found_endcap_x = x_c + radius * Math.cos(phi);
-	    double found_endcap_y = y_c + radius * Math.sin(phi);
-	    double found_endcap_z = new_z;
-	    double found_endcap_polar_r = Math.sqrt(found_endcap_x*found_endcap_x + found_endcap_y*found_endcap_y);
-	    boolean validSolution = (found_endcap_polar_r >= m_ECAL_endcap_rmin-m_cutSeparation && found_endcap_polar_r <= m_ECAL_endcap_rmax+m_cutSeparation);
-	    if (validSolution) {
-		return new BasicHep3Vector(found_endcap_x, found_endcap_y, found_endcap_z);
-	    } else {
-		return null;
-	    }
-	} else {
-	    // No solution
-	    return null;
-	}
-    }
 }
 

lcsim/src/org/lcsim/contrib/uiowa
LocalHelixExtrapolationTrackMIPClusterMatcher.java 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- LocalHelixExtrapolationTrackMIPClusterMatcher.java	19 Nov 2007 21:04:42 -0000	1.2
+++ LocalHelixExtrapolationTrackMIPClusterMatcher.java	25 Mar 2008 22:46:01 -0000	1.3
@@ -26,83 +26,14 @@
     }
 
     public Cluster matchTrackToCluster(Track tr, List<Cluster> clusters) {
-	Hep3Vector point = performExtrapolation(tr);
+	Hep3Vector point = m_extrap.performExtrapolation(tr);
 	if (point != null) {
 	    // Extrapolated to ECAL OK.
 	    // Now, what is the tangent at that point?
-	    double dphi = 0.01;
-	    double dx = m_trackParam_radius * ( Math.cos(m_trackPoint_phi+dphi) - Math.cos(m_trackPoint_phi) );
-	    double dy = m_trackParam_radius * ( Math.sin(m_trackPoint_phi+dphi) - Math.sin(m_trackPoint_phi) );
-	    double dz = m_trackParam_dz_by_dphi * dphi;
-	    Hep3Vector tangent = VecOp.unit(new BasicHep3Vector(dx,dy,dz));
+	    Hep3Vector tangent = m_extrap.getTangent();
 	    // Look through clusters, starting with the nearest ones:
 	    List<Cluster> nearestClusters = findNearestClusters(point, clusters);
 	    for (Cluster nearbyCluster : nearestClusters) {
-		if (m_debug) { 
-		    double debug_separation = proximity(point, nearbyCluster);
-		    int debug_layer = -1; 
-		    CalorimeterHit debug_firstHitInECAL = findInnermostHitInECAL(nearbyCluster);
-		    if (debug_firstHitInECAL != null) { 
-			debug_layer = getLayer(debug_firstHitInECAL);
-		    }
-		    double debug_unitDotProduct = findUnitDotProduct(tangent, nearbyCluster);
-		    System.out.println("DEBUG: LocalHelixExtrapolationTrackMIPClusterMatcher: trying to connect a track to a MIP ("+nearbyCluster.getCalorimeterHits().size()+" hits) with separation="+debug_separation+" and first ECAL layer="+debug_layer+" and unit dot product="+debug_unitDotProduct);
-		    System.out.println("DEBUG: LocalHelixExtrapolationTrackMIPClusterMatcher: Extrapolated point = ("+point.x()+", "+point.y()+", "+point.z()+")");
-		    System.out.println("DEBUG: LocalHelixExtrapolationTrackMIPClusterMatcher: Cross-check: point = ("+
-				       (m_trackParam_xc + m_trackParam_radius * Math.cos(m_trackPoint_phi))+", "+
-				       (m_trackParam_yc + m_trackParam_radius * Math.sin(m_trackPoint_phi))+", "+
-				       m_trackPoint_z+")");
-		    System.out.println("DEBUG: LocalHelixExtrapolationTrackMIPClusterMatcher: ... since xc="+m_trackParam_xc+" and yc="+m_trackParam_yc+" and radius="+m_trackParam_radius+" and phi="+m_trackPoint_phi);
-		    Collection<SimTrackerHit> trackerHits = findHits(tr);
-		    SimTrackerHit hit0 = null;
-		    SimTrackerHit hit1 = null;
-		    SimTrackerHit hit2 = null;
-		    for (SimTrackerHit hit : trackerHits) {
-			if (hit0==null || Math.abs(hit.getPoint()[2])>Math.abs(hit0.getPoint()[2])) {
-			    hit2 = hit1;
-			    hit1 = hit0;
-			    hit0 = hit;
-			} else if (hit1==null || Math.abs(hit.getPoint()[2])>Math.abs(hit1.getPoint()[2])) {
-			    hit2 = hit1;
-			    hit1 = hit;
-			} else if (hit2==null || Math.abs(hit.getPoint()[2])>Math.abs(hit2.getPoint()[2])) {
-			    hit2 = hit;
-			}
-		    }
-		    List<SimTrackerHit> otherHits = new Vector<SimTrackerHit>();
-		    List<SimTrackerHit> tmpHits = new Vector<SimTrackerHit>();
-		    tmpHits.add(hit0);
-		    tmpHits.add(hit1);
-		    tmpHits.add(hit2);
-		    for (SimTrackerHit hit : trackerHits) {
-			if (hit==hit0 || hit==hit1 || hit==hit2) {
-			    // ...
-			} else {
-			    otherHits.add(hit);
-			}
-		    }
-		    for (SimTrackerHit hit : tmpHits) {
-			double x = hit.getPoint()[0];
-			double y = hit.getPoint()[1];
-			double z = hit.getPoint()[2];
-			double r = Math.sqrt(x*x + y*y);
-			System.out.println("DEBUG: LocalHelixExtrapolationTrackMIPClusterMatcher: SimHit at x="+x+", y="+y+", z="+z+", r="+r);
-		    }
-		    for (SimTrackerHit hit : otherHits) {
-			double x = hit.getPoint()[0];
-			double y = hit.getPoint()[1];
-			double z = hit.getPoint()[2];
-			double r = Math.sqrt(x*x + y*y);
-			System.out.println("DEBUG: LocalHelixExtrapolationTrackMIPClusterMatcher: SimHit at x="+x+", y="+y+", z="+z+", r="+r+" [extra]");
-		    }
-		    if (new Double(debug_unitDotProduct).isNaN()) {
-			System.out.println("DEBUG: Dot product is NaN => dumping hits...");
-			for (CalorimeterHit hit : nearbyCluster.getCalorimeterHits()) {
-			    double[] pos = hit.getPosition();
-			    System.out.println("DEBUG:     Layer "+getLayer(hit)+", x="+pos[0]+", y="+pos[1]+", z="+pos[2]);
-			}
-		    }
-		}
 		double separation = proximity(point, nearbyCluster);
 		if (separation > m_cutSeparation) {
 		    // This cluster (and therefore all subsequent ones) are too far away to pass

lcsim/src/org/lcsim/contrib/uiowa
ReclusterDriver.java 1.16 -> 1.17
diff -u -r1.16 -r1.17
--- ReclusterDriver.java	8 Mar 2008 20:51:30 -0000	1.16
+++ ReclusterDriver.java	25 Mar 2008 22:46:01 -0000	1.17
@@ -32,7 +32,7 @@
   *
   * This version is PRELIMINARY.
   *
-  * @version $Id: ReclusterDriver.java,v 1.16 2008/03/08 20:51:30 mcharles Exp $
+  * @version $Id: ReclusterDriver.java,v 1.17 2008/03/25 22:46:01 mcharles Exp $
   * @author Mat Charles
   */
 
@@ -2744,7 +2744,7 @@
 	    double pt = Math.sqrt(px*px + py*py);
 	    double cosTheta = pz/pmag;
 	    String printme = new String("Track with p="+p.magnitude()+" (cosTheta="+cosTheta+")");
-	    LocalHelixExtrapolationTrackClusterMatcher extrap = new LocalHelixExtrapolationTrackClusterMatcher();
+	    LocalHelixExtrapolator extrap = new LocalHelixExtrapolator();
 	    extrap.process(m_event);
 	    Hep3Vector point = extrap.performExtrapolation(tr);
 	    if (point == null) {
@@ -2842,7 +2842,7 @@
 	    }
 	    printme += " (dominant particle: "+maxParticle.getType().getPDGID()+" with "+clusterTruth.get(maxParticle).size()+" hits)";
 	    
-	    LocalHelixExtrapolationTrackClusterMatcher extrap = new LocalHelixExtrapolationTrackClusterMatcher();
+	    LocalHelixExtrapolator extrap = new LocalHelixExtrapolator();
 	    extrap.process(m_event);
 	    Hep3Vector point = extrap.performExtrapolation(tr);
 	    printme += " -- extrap point is ";

lcsim/src/org/lcsim/contrib/uiowa
ReclusterDTreeDriver.java 1.12 -> 1.13
diff -u -r1.12 -r1.13
--- ReclusterDTreeDriver.java	20 Mar 2008 02:29:18 -0000	1.12
+++ ReclusterDTreeDriver.java	25 Mar 2008 22:46:01 -0000	1.13
@@ -259,7 +259,6 @@
 		    clustersMatchedToTracks.put(clus, tracksOfThisCluster);
 		    tracksMatchedToClusters.put(tr, clus);
 		    if (m_photonDebug) { 
-			debugTestPhoton(tr, clus); 
 			double radius50 = radiusToCoverFractionOfPhoton(clus, 0.5);
 			double radius67 = radiusToCoverFractionOfPhoton(clus, 0.67);
 			double radius90 = radiusToCoverFractionOfPhoton(clus, 0.9);
@@ -588,7 +587,7 @@
 		// In any case, it clearly pointed to the calorimeter so we shouldn't
 		// add on the track momentum (that would be double-counting)
 	    } else {
-		Hep3Vector interceptPoint = debugTrackMatch.extendToLayer(0);
+		Hep3Vector interceptPoint = debugTrackMatch.getExtrapolator().extendToECALLayer(0);
 		if (interceptPoint == null) {
 		    // No valid extrap to calorimeter
 		    unmatchedTracksThatDontReachCalorimeter.add(tr);
@@ -2396,105 +2395,6 @@
 	}
     }
 
-    private void debugTestPhoton(Track tr, Cluster matchedCluster) {
-	List<CalorimeterHit> allHitsEcalBarrel = m_event.get(CalorimeterHit.class, "EcalBarrDigiHits");
-	List<CalorimeterHit> allHitsEcalEndcap = m_event.get(CalorimeterHit.class, "EcalEndcapDigiHits");
-	Set<Long> allHitsEcal = new HashSet<Long>();
-	for (CalorimeterHit hit : allHitsEcalBarrel) { allHitsEcal.add(hit.getCellID()); }
-	for (CalorimeterHit hit : allHitsEcalEndcap) { allHitsEcal.add(hit.getCellID()); }
-	PhotonClusterEnergyCalculator ronPhotonCalib = new PhotonClusterEnergyCalculator();
-	LocalHelixExtrapolationTrackClusterMatcher debugTrackMatch = new LocalHelixExtrapolationTrackClusterMatcher();
-	debugTrackMatch.process(m_event);
-	List<Cluster> tmpList = new Vector<Cluster>();
-	tmpList.add(matchedCluster);
-	Cluster tmpMatchedCluster = debugTrackMatch.matchTrackToCluster(tr, tmpList);
-	Hep3Vector interceptPoint = debugTrackMatch.extendToLayer(0);
-	BaseTrackMC mctr = (BaseTrackMC)(tr);
-	System.out.println("DEBUG: Matched track (ID="+mctr.getMCParticle().getType()+") with p="+mctr.getMCParticle().getMomentum().magnitude()+" to photon cluster with "+matchedCluster.getCalorimeterHits().size()+" hits E = "+ronPhotonCalib.getEnergy(matchedCluster));
-	Map<MCParticle, List<SimCalorimeterHit>> truthMap = truthFromCluster(matchedCluster);
-	for (MCParticle truthPart : truthMap.keySet()) {
-	    List<SimCalorimeterHit> hitsOfTruthPart = truthMap.get(truthPart);
-	    System.out.println("DEBUG:   * Contribution of "+hitsOfTruthPart.size()+" hits from truth particle (ID="+truthPart.getType()+") with p = "+truthPart.getMomentum().magnitude());
-	}
-	Cluster coreSubCluster = matchedCluster.getClusters().get(0);
-	{
-	    BasicCluster copyOfCoreSubCluster = new BasicCluster();
-	    copyOfCoreSubCluster.addCluster(coreSubCluster);
-	    TensorClusterPropertyCalculator calc = new TensorClusterPropertyCalculator();
-	    copyOfCoreSubCluster.setPropertyCalculator(calc);
-	    copyOfCoreSubCluster.calculateProperties();
-	    double[][]axes = calc.getPrincipleAxis();
-	    Hep3Vector coreDirection = new BasicHep3Vector(axes[0][0], axes[0][1], axes[0][2]);
-	    Hep3Vector corePosition = new BasicHep3Vector(calc.getPosition());
-	    Line line = new Line(corePosition, coreDirection);
-	    if (interceptPoint != null) {
-		double s = line.getDistanceToPoint(interceptPoint);
-		Hep3Vector poca = line.getPointAtDistance(s);
-		double doca = VecOp.sub(poca, interceptPoint).magnitude();
-		System.out.println("DEBUG: Distance from core centroid to intercept point: "+doca);
-	    }
-	    Hep3Vector origin = new BasicHep3Vector(0,0,0);
-	    double sOrigin = line.getDistanceToPoint(origin);
-	    Hep3Vector pocaToOrigin = line.getPointAtDistance(sOrigin);
-	    double docaToOrigin = VecOp.sub(pocaToOrigin, origin).magnitude();
-	    System.out.println("DEBUG: Impact parameter of photon core to origin: "+docaToOrigin);
-	}
-	Map<MCParticle, List<SimCalorimeterHit>> truthMapCore = truthFromCluster(coreSubCluster);
-	for (MCParticle truthPart : truthMapCore.keySet()) {
-	    List<SimCalorimeterHit> hitsOfTruthPart = truthMapCore.get(truthPart);
-	    System.out.println("DEBUG:   * CORE: Contribution of "+hitsOfTruthPart.size()+" hits from truth particle (ID="+truthPart.getType()+") with p = "+truthPart.getMomentum().magnitude());
-	}
-	Clusterer oldMipfinder = new TrackClusterDriver();
-	List<Cluster> mipClustersInsidePhoton = oldMipfinder.createClusters(matchedCluster.getCalorimeterHits());
-	System.out.println("DEBUG:   * Found "+mipClustersInsidePhoton.size()+" MIPs inside photon:");
-	for (Cluster clus : mipClustersInsidePhoton) {
-	    double energySum = 0.0;
-	    double hitCount = 0.0;
-	    int outerLayer=-1;
-	    int innerLayer=-1;
-	    boolean firstHit = true;
-	    for (CalorimeterHit hit : clus.getCalorimeterHits()) {
-		energySum += hit.getCorrectedEnergy();
-		hitCount++;
-		int layer = getLayer(hit);
-		if (firstHit) {
-		    outerLayer = layer;
-		    innerLayer = layer;
-		    firstHit = false;
-		} else {
-		    if (layer > outerLayer) { 
-			outerLayer = layer;
-		    }
-		    if (layer < innerLayer) { 
-			innerLayer = layer;
-		    }
-		}
-	    }
-	    double meanEnergyPerHit = energySum / hitCount;
-	    System.out.println("DEBUG:      * "+clus.getCalorimeterHits().size()+" hits ("+innerLayer+"-"+outerLayer+") with mean energy "+meanEnergyPerHit);
-	}
-	Set<Long> allClusterHits = new HashSet<Long>();
-	Set<Long> allCoreHits = new HashSet<Long>();
-	for (CalorimeterHit hit : coreSubCluster.getCalorimeterHits()) {
-	    allCoreHits.add(hit.getCellID());
-	}
-	for (CalorimeterHit hit : matchedCluster.getCalorimeterHits()) {
-	    allClusterHits.add(hit.getCellID());
-	}
-	for (int iLayer=0; iLayer<5; iLayer++) {
-	    Long cellID = debugTrackMatch.extendToLayerAndFindCell(iLayer);
-	    if (allCoreHits.contains(cellID)) {
-		System.out.println("DEBUG:    * Extrap hit from layer "+iLayer+" in core");
-	    } else if (allClusterHits.contains(cellID)) {
-		System.out.println("DEBUG:    * Extrap hit from layer "+iLayer+" in cluster but not core");
-	    } else if (allHitsEcal.contains(cellID)) {
-		System.out.println("DEBUG:    * Extrap hit from layer "+iLayer+" not in cluster (but in ECAL)");
-	    } else {
-		System.out.println("DEBUG:    * Extrap hit from layer "+iLayer+" missing");
-	    }
-	}
-    }
-
     private double electronEnergyNormalizedResidual(Track tr, Cluster clus) {
 	double energyAssumingElectron = energy(clus, m_photonCalib);
 	double trackMomentum = (new BasicHep3Vector(tr.getMomentum())).magnitude();
@@ -2508,18 +2408,15 @@
     }
 
     private int countHitsInClusterInFirstLayers(Track tr, Cluster clus, int nLayers) {
-	LocalHelixExtrapolationTrackClusterMatcher debugTrackMatch = new LocalHelixExtrapolationTrackClusterMatcher();
-	debugTrackMatch.process(m_event);
-	List<Cluster> tmpList = new Vector<Cluster>();
-	tmpList.add(clus);
-	Cluster tmpMatchedCluster = debugTrackMatch.matchTrackToCluster(tr, tmpList);
+	LocalHelixExtrapolator extrap = new LocalHelixExtrapolator();
+	extrap.process(m_event);
 	Set<Long> allClusterHits = new HashSet<Long>();
 	for (CalorimeterHit hit : clus.getCalorimeterHits()) {
 	    allClusterHits.add(hit.getCellID());
 	}
 	int countMatches = 0;
 	for (int iLayer=0; iLayer<nLayers; iLayer++) {
-	    Long cellID = debugTrackMatch.extendToLayerAndFindCell(iLayer);
+	    Long cellID = extrap.extendToECALLayerAndFindCell(iLayer);
 	    if (allClusterHits.contains(cellID)) {
 		countMatches++;
 	    }
@@ -2528,18 +2425,15 @@
     }
 
     private int countHitsInCoreInFirstLayers(Track tr, Cluster clus, int nLayers) {
-	LocalHelixExtrapolationTrackClusterMatcher debugTrackMatch = new LocalHelixExtrapolationTrackClusterMatcher();
-	debugTrackMatch.process(m_event);
-	List<Cluster> tmpList = new Vector<Cluster>();
-	tmpList.add(clus);
-	Cluster tmpMatchedCluster = debugTrackMatch.matchTrackToCluster(tr, tmpList);
+	LocalHelixExtrapolator extrap = new LocalHelixExtrapolator();
+	extrap.process(m_event);
 	Set<Long> coreClusterHits = new HashSet<Long>();
 	for (CalorimeterHit hit : clus.getClusters().get(0).getCalorimeterHits()) {
 	    coreClusterHits.add(hit.getCellID());
 	}
 	int countMatches = 0;
 	for (int iLayer=0; iLayer<nLayers; iLayer++) {
-	    Long cellID = debugTrackMatch.extendToLayerAndFindCell(iLayer);
+	    Long cellID = extrap.extendToECALLayerAndFindCell(iLayer);
 	    if (coreClusterHits.contains(cellID)) {
 		countMatches++;
 	    }
@@ -2566,12 +2460,9 @@
     }
 
     private double distanceFromTrackToPhotonCore(Track tr, Cluster clus) {
-	LocalHelixExtrapolationTrackClusterMatcher debugTrackMatch = new LocalHelixExtrapolationTrackClusterMatcher();
-	debugTrackMatch.process(m_event);
-	List<Cluster> tmpList = new Vector<Cluster>();
-	tmpList.add(clus);
-	Cluster tmpMatchedCluster = debugTrackMatch.matchTrackToCluster(tr, tmpList);
-	Hep3Vector interceptPoint = debugTrackMatch.extendToLayer(0);
+	LocalHelixExtrapolator extrap = new LocalHelixExtrapolator();
+	extrap.process(m_event);
+	Hep3Vector interceptPoint = extrap.performExtrapolation(tr);
 	if (interceptPoint != null) {
 	    Cluster coreSubCluster = clus.getClusters().get(0);
 	    BasicCluster copyOfCoreSubCluster = new BasicCluster();
@@ -2913,9 +2804,9 @@
 	    }
 	    Cluster seedClusToUse = null;
 	    Cluster tmpMatchedClusterLayer0 = debugTrackMatch.matchTrackToCluster(tr, tmpListLayer0);
+	    Hep3Vector interceptPointLayer0 = debugTrackMatch.getExtrapolator().extendToECALLayer(0);
 	    Cluster tmpMatchedClusterLayer1 = debugTrackMatch.matchTrackToCluster(tr, tmpListLayer1);
-	    Hep3Vector interceptPointLayer0 = debugTrackMatch.extendToLayer(0);
-	    Hep3Vector interceptPointLayer1 = debugTrackMatch.extendToLayer(1);
+	    Hep3Vector interceptPointLayer1 = debugTrackMatch.getExtrapolator().extendToECALLayer(1);
 	    if (tmpMatchedClusterLayer0 == null && tmpMatchedClusterLayer1 == null) {
 		// No seed found for this track -- maybe extrapolation is too imprecise.
 		// Handle it the usual way.
@@ -2943,7 +2834,7 @@
 		seedHitToUse = seedClusToUse.getCalorimeterHits().iterator().next();
 		// Require within a certain distance (sanity check)
 		Hep3Vector positionOfSeedHit = new BasicHep3Vector(seedHitToUse.getPosition());
-		Hep3Vector trackExtrapPointInLayer = debugTrackMatch.extendToLayer(getLayer(seedHitToUse));
+		Hep3Vector trackExtrapPointInLayer = debugTrackMatch.getExtrapolator().extendToECALLayer(getLayer(seedHitToUse));
 		double distForCut = VecOp.sub(positionOfSeedHit, trackExtrapPointInLayer).magnitude();
 		if (distForCut < 10.0) {
 		    // Within 1cm
CVSspam 0.2.8