Print

Print


Commit in lcsim/src/org/lcsim/contrib/uiowa on MAIN
AmbiguousTrackToClusterMapMaker.java+119added 1.1
TrackToClusterMapMaker.java+26added 1.1
TrackToElectronMapMaker.java+186added 1.1
TrackToGenericClusterMapMaker.java+112added 1.1
TrackToMipClusterMapMaker.java+102added 1.1
TrackToPreShowerMipMapMaker.java+165added 1.1
+710
6 added files
MJC: (contrib) Refactor PFA track-cluster matchers

lcsim/src/org/lcsim/contrib/uiowa
AmbiguousTrackToClusterMapMaker.java added at 1.1
diff -N AmbiguousTrackToClusterMapMaker.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ AmbiguousTrackToClusterMapMaker.java	15 Oct 2008 22:15:03 -0000	1.1
@@ -0,0 +1,119 @@
+package org.lcsim.contrib.uiowa;
+
+import java.util.*; 
+import hep.physics.vec.*;
+import org.lcsim.util.*;
+import org.lcsim.event.*;
+import org.lcsim.event.util.*;
+import org.lcsim.recon.pfa.identifier.*;
+
+public class AmbiguousTrackToClusterMapMaker extends TrackToClusterMapMaker {
+    protected HelixExtrapolator m_findCluster;
+    public AmbiguousTrackToClusterMapMaker(HelixExtrapolator findCluster, String inputTrackList, String outputMap, String outputUnmatchedTrackList) {
+	super(inputTrackList, outputMap, outputUnmatchedTrackList);
+	m_findCluster = findCluster;
+    }
+
+    protected Map<String,String> m_mapInputNameToMatchedOutputName = new HashMap<String,String>();
+    protected Map<String,String> m_mapInputNameToUnmatchedOutputName = new HashMap<String,String>();
+    public void addInputList(String inputName, String matchedOutputName, String unmatchedOutputName) {
+	m_mapInputNameToMatchedOutputName.put(inputName, matchedOutputName);
+	m_mapInputNameToUnmatchedOutputName.put(inputName, unmatchedOutputName);
+    }
+
+    protected Map<Track,Cluster> makeMap(EventHeader event) {
+	// Read in inputs
+	List<Track> trackList = event.get(Track.class, m_inputTrackListName);
+	Map<String, List<Cluster>> inputLists = new HashMap<String, List<Cluster>>();
+	for (String str : m_mapInputNameToMatchedOutputName.keySet()) {
+	    List<Cluster> currentList = event.get(Cluster.class, str);
+	    inputLists.put(str, currentList);
+	}
+	if (inputLists.size() != m_mapInputNameToMatchedOutputName.size()) { throw new AssertionError("Book-keeping error"); }
+	if (inputLists.size() != m_mapInputNameToUnmatchedOutputName.size()) { throw new AssertionError("Book-keeping error"); }
+
+	// Set up matching
+	LocalHelixExtrapolationTrackMIPClusterMatcher mipMatch = new LocalHelixExtrapolationTrackMIPClusterMatcher(m_findCluster);
+	LocalHelixExtrapolationTrackClusterMatcher genMatch = new LocalHelixExtrapolationTrackClusterMatcher(m_findCluster);
+	DualActionTrackClusterMatcher dualMatch = new DualActionTrackClusterMatcher(mipMatch, genMatch);
+	mipMatch.process(event);
+	genMatch.process(event);
+	List<Cluster> allMatchableClusters = new Vector<Cluster>();
+	for (List<Cluster> inputList : inputLists.values()) {
+	    allMatchableClusters.addAll(inputList);
+	}
+
+	// Do matching
+	Map<Track,Cluster> tracksMatchedToClusters = new HashMap<Track,Cluster>();
+	Map<Cluster, List<Track>> clustersMatchedToTracks = new HashMap<Cluster, List<Track>>();
+	for (Track tr : trackList) {
+	    Cluster matchedCluster = dualMatch.matchTrackToCluster(tr, allMatchableClusters);
+	    if (matchedCluster != null) {
+		// Found a match
+		// Optionally, handle these cases:
+		//   * Match is to a teeny cluster piece (leftoverHitClusters) but there is structure nearby inside same DTree
+		//   * Match is to a photon (try to split up)
+		//   * Match is to a cluster with E>>p (try to split up)
+		// ... but those don't really apply here (they aren't MIPs)
+		tracksMatchedToClusters.put(tr, matchedCluster);
+		List<Track> clusTrList = clustersMatchedToTracks.get(matchedCluster);
+		if (clusTrList == null) { 
+		    clusTrList = new Vector<Track>(); 
+		    clustersMatchedToTracks.put(matchedCluster, clusTrList); 
+		}
+		clusTrList.add(tr);
+	    }
+	}
+
+	// In this case, we don't forbid ambiguous matches where more than one track points to a single cluster.
+	// But we do need to identify them. For now, describe them as a MultipleTrackTrack. We may want to
+	// revisit this later.
+	Map<Track,Cluster> outputMap = new HashMap<Track,Cluster>();
+	Set<Track> matchedTracks = new HashSet<Track>();
+	for (Cluster clus : clustersMatchedToTracks.keySet()) {
+	    if (clus == null) { throw new AssertionError("Null cluster!"); }
+	    List<Track> tracksOfMatchedClus = clustersMatchedToTracks.get(clus);
+	    if (tracksOfMatchedClus == null) { throw new AssertionError("Book-keeping error!"); }
+	    if (tracksOfMatchedClus.size()==0) {
+		throw new AssertionError("Book-keeping error!");
+	    } else if (tracksOfMatchedClus.size()==1) {
+		// Unique match -- OK
+		Track tr = tracksOfMatchedClus.get(0);
+		outputMap.put(tr, clus);
+	    } else {
+		// Ambiguous match -- also OK
+		ReclusterDriver tmp = new ReclusterDriver();
+		Track mergedTrack = tmp.makeMultipleTrackTrack(tracksOfMatchedClus);
+		outputMap.put(mergedTrack, clus);
+	    }
+	    matchedTracks.addAll(tracksOfMatchedClus);
+	}
+	
+	// Identify unmatched tracks
+	List<Track> unmatchedTracks = new Vector<Track>();
+	unmatchedTracks.addAll(trackList);
+	unmatchedTracks.removeAll(matchedTracks);
+
+	// Separate out lists of matched & unmatched clusters
+	for (String str : m_mapInputNameToMatchedOutputName.keySet()) {
+	    List<Cluster> inputList = inputLists.get(str);
+	    List<Cluster> outputListMatched = new Vector<Cluster>();
+	    List<Cluster> outputListUnmatched = new Vector<Cluster>();
+	    String matchedOutputName = m_mapInputNameToMatchedOutputName.get(str);
+	    String unmatchedOutputName = m_mapInputNameToUnmatchedOutputName.get(str);
+	    for (Cluster clus : inputList) {
+		if (outputMap.values().contains(clus)) {
+		    outputListMatched.add(clus);
+		} else {
+		    outputListUnmatched.add(clus);
+		}
+	    }
+	    event.put(matchedOutputName, outputListMatched);
+	    event.put(unmatchedOutputName, outputListUnmatched);
+	}
+
+	// All done
+	event.put(m_outputUnmatchedTrackListName, unmatchedTracks);
+	return outputMap;
+    }
+}

lcsim/src/org/lcsim/contrib/uiowa
TrackToClusterMapMaker.java added at 1.1
diff -N TrackToClusterMapMaker.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ TrackToClusterMapMaker.java	15 Oct 2008 22:15:03 -0000	1.1
@@ -0,0 +1,26 @@
+package org.lcsim.contrib.uiowa;
+
+import java.util.*; 
+import org.lcsim.util.*;
+import org.lcsim.event.*;
+import org.lcsim.event.util.*;
+
+public abstract class TrackToClusterMapMaker extends Driver {
+
+    abstract protected Map<Track,Cluster> makeMap(EventHeader event);
+
+    String m_inputTrackListName;
+    String m_outputMapName;
+    String m_outputUnmatchedTrackListName;
+    public TrackToClusterMapMaker(String inputTrackList, String outputMap, String outputUnmatchedTrackList) {
+	super();
+	m_inputTrackListName = inputTrackList;
+	m_outputMapName = outputMap;
+	m_outputUnmatchedTrackListName = outputUnmatchedTrackList;
+    }
+
+    public void process(EventHeader event) {
+	Map<Track,Cluster> output = makeMap(event);
+	event.put(m_outputMapName, output);
+    }
+}

lcsim/src/org/lcsim/contrib/uiowa
TrackToElectronMapMaker.java added at 1.1
diff -N TrackToElectronMapMaker.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ TrackToElectronMapMaker.java	15 Oct 2008 22:15:03 -0000	1.1
@@ -0,0 +1,186 @@
+package org.lcsim.contrib.uiowa;
+
+import java.util.*;
+import hep.physics.vec.*;
+import org.lcsim.util.*;
+import org.lcsim.event.*;
+import org.lcsim.event.util.*;
+import org.lcsim.recon.pfa.identifier.*;
+import org.lcsim.recon.cluster.util.*;
+import org.lcsim.util.swim.Line;
+
+public class TrackToElectronMapMaker extends TrackToClusterMapMaker {
+
+    protected String m_outputElectronClusterListName;
+    protected String m_inputPhotonListName;
+    protected ClusterEnergyCalculator m_photonCalib;
+    protected HelixExtrapolator m_findCluster;
+    public TrackToElectronMapMaker(HelixExtrapolator findCluster, String inputPhotonList, String inputTrackList, String outputTrackClusterMap, String outputUnmatchedTrackList, String outputElectronClusterList) {
+	super(inputTrackList, outputTrackClusterMap, outputUnmatchedTrackList);
+	m_outputElectronClusterListName = outputElectronClusterList;
+	m_inputPhotonListName = inputPhotonList;
+	m_findCluster = findCluster;
+	m_photonCalib = new QNeutralHadronClusterEnergyCalculator();
+    }
+
+
+
+    protected Map<Track,Cluster> makeMap(EventHeader event) {
+	// Read in inputs
+	List<Track> trackList = event.get(Track.class, m_inputTrackListName);
+	List<Cluster> photons = event.get(Cluster.class, m_inputPhotonListName);
+	
+	// The output
+	Map<Track,Cluster> outputMap = new HashMap<Track,Cluster>();
+
+	// Extrapolation utility
+	LocalHelixExtrapolationTrackClusterMatcher genMatch = new LocalHelixExtrapolationTrackClusterMatcher(m_findCluster);
+
+	// Loop over tracks, looking for a good match to a photon
+	Map<Track,Cluster> electronCandidateMap = new HashMap<Track,Cluster>();
+	Set<Cluster> electronCandidateClusters = new HashSet<Cluster>();
+	Set<Cluster> vetoedElectronCandidateClusters = new HashSet<Cluster>();
+	List<Cluster> electronClusters = new Vector<Cluster>();
+	List<Track> electronTracks = new Vector<Track>();
+	for (Track tr : trackList) {
+	    Cluster matchedCluster = genMatch.matchTrackToCluster(tr, photons);
+	    if (matchedCluster != null) {
+		if (photons.contains(matchedCluster)) {
+		    // Electron candidate
+		    if (electronCandidateClusters.contains(matchedCluster)) {
+			// Multiple track matches => veto
+			vetoedElectronCandidateClusters.add(matchedCluster);
+		    }
+		    electronCandidateClusters.add(matchedCluster);
+		    // Now, are we confident that it's an electron?
+		    double electronResid = electronEnergyNormalizedResidual(tr, matchedCluster);
+		    int hitsInCluster = countHitsInClusterInFirstLayers(tr, matchedCluster, 5);
+		    int hitsInCore = countHitsInCoreInFirstLayers(tr, matchedCluster, 5);
+		    double originIP = impactParameterFromPhotonCoreToOrigin(matchedCluster);
+		    double trackIP = distanceFromTrackToPhotonCore(tr, matchedCluster);
+		    if (electronResid > -2.0 && electronResid < 2.0 && trackIP < 7.0 && hitsInCore > 1) {
+			// Accept as electron
+			electronCandidateMap.put(tr, matchedCluster);
+		    }
+		}
+	    }
+	}
+	
+	// Now, did we accept any of those?
+	for (Track tr : electronCandidateMap.keySet()) {
+	    Cluster clus = electronCandidateMap.get(tr);
+	    if (!electronCandidateClusters.contains(clus)) { throw new AssertionError("Book-keeping failure"); }
+	    if (!vetoedElectronCandidateClusters.contains(clus)) {
+		// We accepted it and didn't veto it => electron
+		if (electronClusters.contains(clus)) { throw new AssertionError("Book-keeping failure"); }
+		electronClusters.add(clus);
+		electronTracks.add(tr);
+	    }
+	}
+
+	// Unmatched tracks
+	List<Track> unmatchedTracks = new Vector<Track>();
+	unmatchedTracks.addAll(trackList);
+	unmatchedTracks.removeAll(electronTracks);
+
+	// Outputs
+	event.put(m_outputUnmatchedTrackListName, unmatchedTracks);
+	event.put(m_outputElectronClusterListName, electronClusters);
+	return outputMap;
+    }
+
+    // Utility routines
+
+    private double electronEnergyNormalizedResidual(Track tr, Cluster clus) {
+	double energyAssumingElectron = m_photonCalib.getEnergy(clus);
+	double trackMomentum = (new BasicHep3Vector(tr.getMomentum())).magnitude();
+	double residual = trackMomentum - energyAssumingElectron;
+	double estimatedError = 0.2 * Math.sqrt(trackMomentum);
+	if (trackMomentum < 1.0) { 
+	    // Don't shrink the error too much.
+	    estimatedError = 0.2; 
+	}
+	return (residual/estimatedError);
+    }
+
+    private int countHitsInClusterInFirstLayers(Track tr, Cluster clus, int nLayers) {
+	Set<Long> allClusterHits = new HashSet<Long>();
+	for (CalorimeterHit hit : clus.getCalorimeterHits()) {
+	    allClusterHits.add(hit.getCellID());
+	}
+	int countMatches = 0;
+	HelixExtrapolationResult result = m_findCluster.performExtrapolation(tr);
+	if (result != null) {
+	    for (int iLayer=0; iLayer<nLayers; iLayer++) {
+		Long cellID = result.extendToECALLayerAndFindCell(iLayer);
+		if (cellID != null && allClusterHits.contains(cellID)) {
+		    countMatches++;
+		}
+	    }
+	}
+	return countMatches;
+    }
+
+    private int countHitsInCoreInFirstLayers(Track tr, Cluster clus, int nLayers) {
+	Set<Long> coreClusterHits = new HashSet<Long>();
+	for (CalorimeterHit hit : clus.getClusters().get(0).getCalorimeterHits()) {
+	    coreClusterHits.add(hit.getCellID());
+	}
+	int countMatches = 0;
+	HelixExtrapolationResult result = m_findCluster.performExtrapolation(tr);
+	if (result != null) {
+	    for (int iLayer=0; iLayer<nLayers; iLayer++) {
+		Long cellID = result.extendToECALLayerAndFindCell(iLayer);
+		if (cellID != null && coreClusterHits.contains(cellID)) {
+		    countMatches++;
+		}
+	    }
+	}
+	return countMatches;
+    }
+
+    private double impactParameterFromPhotonCoreToOrigin(Cluster clus) {
+	Cluster coreSubCluster = clus.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);
+	Hep3Vector origin = new BasicHep3Vector(0,0,0);
+	double sOrigin = line.getDistanceToPoint(origin);
+	Hep3Vector pocaToOrigin = line.getPointAtDistance(sOrigin);
+	double docaToOrigin = VecOp.sub(pocaToOrigin, origin).magnitude();
+	return docaToOrigin;
+    }
+
+    private double distanceFromTrackToPhotonCore(Track tr, Cluster clus) {
+	HelixExtrapolationResult result = m_findCluster.performExtrapolation(tr);
+	Hep3Vector interceptPoint = null;
+	if (result != null) {
+	    interceptPoint = result.getInterceptPoint();
+	}
+	if (interceptPoint != null) {
+	    Cluster coreSubCluster = clus.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);
+	    double s = line.getDistanceToPoint(interceptPoint);
+	    Hep3Vector poca = line.getPointAtDistance(s);
+	    double doca = VecOp.sub(poca, interceptPoint).magnitude();
+	    return doca;
+	} else {
+	    return Double.NaN;
+	}
+    }
+
+}

lcsim/src/org/lcsim/contrib/uiowa
TrackToGenericClusterMapMaker.java added at 1.1
diff -N TrackToGenericClusterMapMaker.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ TrackToGenericClusterMapMaker.java	15 Oct 2008 22:15:03 -0000	1.1
@@ -0,0 +1,112 @@
+package org.lcsim.contrib.uiowa;
+
+import java.util.*; 
+import org.lcsim.util.*;
+import org.lcsim.event.*;
+import org.lcsim.event.util.*;
+import org.lcsim.recon.pfa.identifier.*;
+
+public class TrackToGenericClusterMapMaker extends TrackToClusterMapMaker {
+
+    protected HelixExtrapolator m_findCluster;
+    public TrackToGenericClusterMapMaker(HelixExtrapolator findCluster, String inputTrackList, String outputMap, String outputUnmatchedTrackList) {
+	super(inputTrackList, outputMap, outputUnmatchedTrackList);
+	m_findCluster = findCluster;
+    }
+
+    protected Map<String,String> m_mapInputNameToMatchedOutputName = new HashMap<String,String>();
+    protected Map<String,String> m_mapInputNameToUnmatchedOutputName = new HashMap<String,String>();
+    public void addInputList(String inputName, String matchedOutputName, String unmatchedOutputName) {
+	m_mapInputNameToMatchedOutputName.put(inputName, matchedOutputName);
+	m_mapInputNameToUnmatchedOutputName.put(inputName, unmatchedOutputName);
+    }
+
+    protected Map<Track,Cluster> makeMap(EventHeader event) {
+	// Read in inputs
+	List<Track> trackList = event.get(Track.class, m_inputTrackListName);
+	Map<String, List<Cluster>> inputLists = new HashMap<String, List<Cluster>>();
+	for (String str : m_mapInputNameToMatchedOutputName.keySet()) {
+	    List<Cluster> currentList = event.get(Cluster.class, str);
+	    inputLists.put(str, currentList);
+	}
+	if (inputLists.size() != m_mapInputNameToMatchedOutputName.size()) { throw new AssertionError("Book-keeping error"); }
+	if (inputLists.size() != m_mapInputNameToUnmatchedOutputName.size()) { throw new AssertionError("Book-keeping error"); }
+
+	// Set up matching
+	LocalHelixExtrapolationTrackMIPClusterMatcher mipMatch = new LocalHelixExtrapolationTrackMIPClusterMatcher(m_findCluster);
+	LocalHelixExtrapolationTrackClusterMatcher genMatch = new LocalHelixExtrapolationTrackClusterMatcher(m_findCluster);
+	DualActionTrackClusterMatcher dualMatch = new DualActionTrackClusterMatcher(mipMatch, genMatch);
+	mipMatch.process(event);
+	genMatch.process(event);
+	List<Cluster> allMatchableClusters = new Vector<Cluster>();
+	for (List<Cluster> inputList : inputLists.values()) {
+	    allMatchableClusters.addAll(inputList);
+	}
+
+	// Do matching
+	Map<Track,Cluster> tracksMatchedToClusters = new HashMap<Track,Cluster>();
+	Map<Cluster, List<Track>> clustersMatchedToTracks = new HashMap<Cluster, List<Track>>();
+	for (Track tr : trackList) {
+	    Cluster matchedCluster = dualMatch.matchTrackToCluster(tr, allMatchableClusters);
+	    if (matchedCluster != null) {
+		// Found a match
+		// Optionally, handle these cases:
+		//   * Match is to a teeny cluster piece (leftoverHitClusters) but there is structure nearby inside same DTree
+		//   * Match is to a photon (try to split up)
+		//   * Match is to a cluster with E>>p (try to split up)
+		// ... but those don't really apply here (they aren't MIPs)
+		tracksMatchedToClusters.put(tr, matchedCluster);
+		List<Track> clusTrList = clustersMatchedToTracks.get(matchedCluster);
+		if (clusTrList == null) { 
+		    clusTrList = new Vector<Track>(); 
+		    clustersMatchedToTracks.put(matchedCluster, clusTrList); 
+		}
+		clusTrList.add(tr);
+	    }
+	}
+
+	// Flag unique matches to be written out:
+	Map<Track,Cluster> outputMap = new HashMap<Track,Cluster>();
+	for (Track tr : tracksMatchedToClusters.keySet()) {
+	    Cluster matchedClus = tracksMatchedToClusters.get(tr);
+	    List<Track> tracksOfMatchedClus = clustersMatchedToTracks.get(matchedClus);
+	    if (tracksOfMatchedClus == null) { throw new AssertionError("Book-keeping error!"); }
+	    if (tracksOfMatchedClus.size()==0) {
+		throw new AssertionError("Book-keeping error!");
+	    } else if (tracksOfMatchedClus.size()==1) {
+		// Unique match -- OK
+		outputMap.put(tr, matchedClus);
+	    } else {
+		// Ambiguous match -- ignore for now
+	    }
+	}
+
+	// Identify unmatched tracks
+	List<Track> unmatchedTracks = new Vector<Track>();
+	unmatchedTracks.addAll(trackList);
+	unmatchedTracks.removeAll(outputMap.keySet());
+
+	// Separate out lists of matched & unmatched clusters
+	for (String str : m_mapInputNameToMatchedOutputName.keySet()) {
+	    List<Cluster> inputList = inputLists.get(str);
+	    List<Cluster> outputListMatched = new Vector<Cluster>();
+	    List<Cluster> outputListUnmatched = new Vector<Cluster>();
+	    String matchedOutputName = m_mapInputNameToMatchedOutputName.get(str);
+	    String unmatchedOutputName = m_mapInputNameToUnmatchedOutputName.get(str);
+	    for (Cluster clus : inputList) {
+		if (outputMap.values().contains(clus)) {
+		    outputListMatched.add(clus);
+		} else {
+		    outputListUnmatched.add(clus);
+		}
+	    }
+	    event.put(matchedOutputName, outputListMatched);
+	    event.put(unmatchedOutputName, outputListUnmatched);
+	}
+
+	// All done
+	event.put(m_outputUnmatchedTrackListName, unmatchedTracks);
+	return outputMap;
+    }
+}
+

lcsim/src/org/lcsim/contrib/uiowa
TrackToMipClusterMapMaker.java added at 1.1
diff -N TrackToMipClusterMapMaker.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ TrackToMipClusterMapMaker.java	15 Oct 2008 22:15:03 -0000	1.1
@@ -0,0 +1,102 @@
+package org.lcsim.contrib.uiowa;
+
+import java.util.*; 
+import org.lcsim.util.*;
+import org.lcsim.event.*;
+import org.lcsim.event.util.*;
+import org.lcsim.recon.pfa.identifier.*;
+
+public class TrackToMipClusterMapMaker extends TrackToClusterMapMaker {
+    protected HelixExtrapolator m_findCluster;
+    public TrackToMipClusterMapMaker(HelixExtrapolator findCluster, String inputTrackList, String outputMap, String outputUnmatchedTrackList) {
+	super(inputTrackList, outputMap, outputUnmatchedTrackList);
+	m_findCluster = findCluster;
+    }
+
+    protected Map<String,String> m_mapInputNameToMatchedOutputName = new HashMap<String,String>();
+    protected Map<String,String> m_mapInputNameToUnmatchedOutputName = new HashMap<String,String>();
+    public void addInputList(String inputName, String matchedOutputName, String unmatchedOutputName) {
+	m_mapInputNameToMatchedOutputName.put(inputName, matchedOutputName);
+	m_mapInputNameToUnmatchedOutputName.put(inputName, unmatchedOutputName);
+    }
+
+    protected Map<Track,Cluster> makeMap(EventHeader event) {
+	// Read in inputs
+	List<Track> trackList = event.get(Track.class, m_inputTrackListName);
+	Map<String, List<Cluster>> inputLists = new HashMap<String, List<Cluster>>();
+	for (String str : m_mapInputNameToMatchedOutputName.keySet()) {
+	    List<Cluster> currentList = event.get(Cluster.class, str);
+	    inputLists.put(str, currentList);
+	}
+	if (inputLists.size() != m_mapInputNameToMatchedOutputName.size()) { throw new AssertionError("Book-keeping error"); }
+	if (inputLists.size() != m_mapInputNameToUnmatchedOutputName.size()) { throw new AssertionError("Book-keeping error"); }
+
+	// Set up matching
+	LocalHelixExtrapolationTrackMIPClusterMatcher mipMatch = new LocalHelixExtrapolationTrackMIPClusterMatcher(m_findCluster);
+	mipMatch.process(event);
+	List<Cluster> allMatchableClusters = new Vector<Cluster>();
+	for (List<Cluster> inputList : inputLists.values()) {
+	    allMatchableClusters.addAll(inputList);
+	}
+
+	// Do matching
+	Map<Track,Cluster> tracksMatchedToClusters = new HashMap<Track,Cluster>();
+	Map<Cluster, List<Track>> clustersMatchedToTracks = new HashMap<Cluster, List<Track>>();
+	for (Track tr : trackList) {
+	    Cluster matchedCluster = mipMatch.matchTrackToCluster(tr, allMatchableClusters);
+	    if (matchedCluster != null) {
+		// Found a match
+		tracksMatchedToClusters.put(tr, matchedCluster);
+		List<Track> clusTrList = clustersMatchedToTracks.get(matchedCluster);
+		if (clusTrList == null) { 
+		    clusTrList = new Vector<Track>(); 
+		    clustersMatchedToTracks.put(matchedCluster, clusTrList); 
+		}
+		clusTrList.add(tr);
+	    }
+	}
+
+	// Flag unique matches to be written out:
+	Map<Track,Cluster> outputMap = new HashMap<Track,Cluster>();
+	for (Track tr : tracksMatchedToClusters.keySet()) {
+	    Cluster matchedClus = tracksMatchedToClusters.get(tr);
+	    List<Track> tracksOfMatchedClus = clustersMatchedToTracks.get(matchedClus);
+	    if (tracksOfMatchedClus == null) { throw new AssertionError("Book-keeping error!"); }
+	    if (tracksOfMatchedClus.size()==0) {
+		throw new AssertionError("Book-keeping error!");
+	    } else if (tracksOfMatchedClus.size()==1) {
+		// Unique match -- OK
+		outputMap.put(tr, matchedClus);
+	    } else {
+		// Ambiguous match -- ignore for now
+	    }
+	}
+
+	// Identify unmatched tracks
+	List<Track> unmatchedTracks = new Vector<Track>();
+	unmatchedTracks.addAll(trackList);
+	unmatchedTracks.removeAll(outputMap.keySet());
+
+	// Separate out lists of matched & unmatched clusters
+	for (String str : m_mapInputNameToMatchedOutputName.keySet()) {
+	    List<Cluster> inputList = inputLists.get(str);
+	    List<Cluster> outputListMatched = new Vector<Cluster>();
+	    List<Cluster> outputListUnmatched = new Vector<Cluster>();
+	    String matchedOutputName = m_mapInputNameToMatchedOutputName.get(str);
+	    String unmatchedOutputName = m_mapInputNameToUnmatchedOutputName.get(str);
+	    for (Cluster clus : inputList) {
+		if (outputMap.values().contains(clus)) {
+		    outputListMatched.add(clus);
+		} else {
+		    outputListUnmatched.add(clus);
+		}
+	    }
+	    event.put(matchedOutputName, outputListMatched);
+	    event.put(unmatchedOutputName, outputListUnmatched);
+	}
+
+	// All done
+	event.put(m_outputUnmatchedTrackListName, unmatchedTracks);
+	return outputMap;
+    }
+}

lcsim/src/org/lcsim/contrib/uiowa
TrackToPreShowerMipMapMaker.java added at 1.1
diff -N TrackToPreShowerMipMapMaker.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ TrackToPreShowerMipMapMaker.java	15 Oct 2008 22:15:03 -0000	1.1
@@ -0,0 +1,165 @@
+package org.lcsim.contrib.uiowa;
+
+import java.util.*; 
+import org.lcsim.util.*;
+import org.lcsim.event.*;
+import org.lcsim.event.util.*;
+import org.lcsim.recon.cluster.util.BasicCluster;
+
+public class TrackToPreShowerMipMapMaker extends TrackToClusterMapMaker {
+
+    String m_inputMapTrkToMIP;
+    String m_outputMips;
+    String m_outputSmallClusters;
+    String m_outputBlocks;
+    public TrackToPreShowerMipMapMaker(String inputMapTrkToMIP, String inputTrackList, String outputMap, String outputUnmatchedTrackList, String outputMips, String outputSmallClusters, String outputBlocks) {
+	super(inputTrackList, outputMap, outputUnmatchedTrackList);
+	m_inputMapTrkToMIP = inputMapTrkToMIP;
+	m_outputMips = outputMips;
+	m_outputSmallClusters = outputSmallClusters;
+	m_outputBlocks = outputBlocks;
+    }
+
+    protected Map<Track,Cluster> makeMap(EventHeader event) {
+	// The output
+	Map<Track,Cluster> outputMap = new HashMap<Track,Cluster>();
+	List<Cluster> outputClustersMips = new Vector<Cluster>();
+	List<Cluster> outputClustersBlocks = new Vector<Cluster>();
+	List<Cluster> outputClustersSmall = new Vector<Cluster>();
+
+	// Read in MIP connections
+	List<Track> inputTrackList = event.get(Track.class, m_inputTrackListName);
+	Map<Track,BasicCluster> MapTrkToMIP = (Map<Track,BasicCluster>)(event.get(m_inputMapTrkToMIP));
+	
+	// Now, each track is connected to a MIP. But some of these MIP clusters
+	// may overlap. We need to identify the cases when that happens and then
+	//   * produce a merged cluster
+	//   * have each of the tracks pointing to the same merged cluster
+	// First, check for overlaps...
+	Map<Cluster,Track> mapMipToTrack = new HashMap<Cluster,Track>();
+	Map<Cluster,Cluster> mapMipToMergedCluster = new HashMap<Cluster,Cluster>();
+	Map<Cluster,List<Track>> mapMergedClusterToTracks = new HashMap<Cluster,List<Track>>();
+
+	// Find hits for each MIP & which clusters they're inside
+	Map<CalorimeterHit,Set<Cluster>> hitMipMap = new HashMap<CalorimeterHit,Set<Cluster>>();
+	for (Track tr : MapTrkToMIP.keySet()) {
+	    if (!inputTrackList.contains(tr)) { throw new AssertionError("Book-keeping error"); }
+	    BasicCluster mip = MapTrkToMIP.get(tr);
+	    mapMipToTrack.put(mip,tr);
+	    for (CalorimeterHit hit : mip.getCalorimeterHits()) {
+		Set<Cluster> mipsOfHit = hitMipMap.get(hit);
+		if (mipsOfHit == null) {
+		    mipsOfHit= new HashSet<Cluster>();
+		    hitMipMap.put(hit, mipsOfHit);
+		}
+		mipsOfHit.add(mip);
+	    }
+	}
+
+	// Look for groups of mips such that
+	//  * Every MIP in a group is connected (directly or indirectly)
+	//    to every other MIP in the group.
+	//  * Every MIP appears in exactly one group.
+	List<Set<Cluster>> mipOverlapSets = new Vector<Set<Cluster>>();
+	for (CalorimeterHit hit : hitMipMap.keySet()) {
+	    Set<Cluster> touchedClusters = hitMipMap.get(hit);
+	    Set<Set<Cluster>> oldLinkedClusterSets = new HashSet<Set<Cluster>>();
+	    for (Cluster clus : touchedClusters) {
+		for (Set<Cluster> currentSet : mipOverlapSets) {
+		    if (currentSet.contains(clus)) {
+			oldLinkedClusterSets.add(currentSet);
+		    }
+		}
+	    }
+	    Set<Cluster> newLinkedClusterSet = new HashSet<Cluster>();
+	    newLinkedClusterSet.addAll(touchedClusters);
+	    for (Set<Cluster> oldSet : oldLinkedClusterSets) {
+		newLinkedClusterSet.addAll(oldSet);
+		mipOverlapSets.remove(oldSet);
+	    }
+	    mipOverlapSets.add(newLinkedClusterSet);
+	}
+
+	// Verify that each cluster appears in exactly one set
+	List<Cluster> countedClusterList = new Vector<Cluster>();
+	Set<Cluster> countedClusterSet = new HashSet<Cluster>();
+	for (Set<Cluster> currentSet : mipOverlapSets) {
+	    countedClusterList.addAll(currentSet);
+	    countedClusterSet.addAll(currentSet);
+	}
+	if (countedClusterList.size() != MapTrkToMIP.size()) { throw new AssertionError("Book-keeping error"); }
+	if (countedClusterSet.size() != MapTrkToMIP.size()) { throw new AssertionError("Book-keeping error"); }
+
+	// Do the merge of overlapping MIPs
+	for (Set<Cluster> currentSet : mipOverlapSets) {
+	    if (currentSet.size()==0) {
+		throw new AssertionError("Empty set!");
+	    } else if (currentSet.size()==1) {
+		Cluster mip = currentSet.iterator().next();
+		mapMipToMergedCluster.put(mip,mip);
+		Track tr = mapMipToTrack.get(mip);
+		List<Track> mergedTracks = new Vector<Track>();
+		mergedTracks.add(tr);
+		mapMergedClusterToTracks.put(mip, mergedTracks);
+	    } else {
+		BasicCluster mergedMip = new BasicCluster();
+		List<Track> mergedTracks = new Vector<Track>();
+		Set<CalorimeterHit> mergedHits = new HashSet<CalorimeterHit>();
+		for (Cluster mip : currentSet) {
+		    mergedHits.addAll(mip.getCalorimeterHits());
+		    Track tr = mapMipToTrack.get(mip);
+		    mergedTracks.add(tr);
+		}
+		for (CalorimeterHit hit : mergedHits) {
+		    mergedMip.addHit(hit);
+		}
+		for (Cluster clus : currentSet) {
+		    mapMipToMergedCluster.put(clus, mergedMip);
+		    mapMergedClusterToTracks.put(mergedMip, mergedTracks);
+		}
+	    }
+	}
+
+	// Assign MIPs to tracks, taking overlaps into account
+	for (Cluster mergedMip : mapMergedClusterToTracks.keySet()) {
+	    List<Track> tracks = mapMergedClusterToTracks.get(mergedMip);
+	    if (tracks == null) { throw new AssertionError("Null tracks!"); }
+	    if (tracks.size()==0) { 
+		throw new AssertionError("Empty track list!"); 
+	    } else if (tracks.size()==1) {
+		// Unique
+		Track tr = tracks.get(0);
+		if (mergedMip.getCalorimeterHits().size() > 5) {
+		    // Found a good MIP
+		    System.out.println("DEBUG: Good pre-shower MIP with "+mergedMip.getCalorimeterHits().size()+" hits -- adding...");
+		    outputMap.put(tr, mergedMip);
+		    outputClustersMips.add(mergedMip);
+		} else {
+		    // Didn't find a good mip
+		    System.out.print("DEBUG: Dodgy pre-shower MIP with only "+mergedMip.getCalorimeterHits().size()+" hits -- not adding. Hits were:");
+		    for (CalorimeterHit hit : mergedMip.getCalorimeterHits()) {
+			System.out.print("  "+hit.getCellID());
+		    }
+		    System.out.println();
+		    outputClustersSmall.add(mergedMip);
+		}
+	    } else {
+		// Overlap -- can't treat it as a MIP.
+		System.out.println("DEBUG: Overlapping pre-shower MIP with "+mergedMip.getCalorimeterHits().size()+" hits matched to "+tracks.size()+" tracks.");
+		outputClustersBlocks.add(mergedMip);
+	    }
+	}
+
+	// Identify unmatched tracks
+	List<Track> unmatchedTracks = new Vector<Track>();
+	unmatchedTracks.addAll(inputTrackList);
+	unmatchedTracks.removeAll(outputMap.keySet());
+
+	// All done
+	event.put(m_outputMips, outputClustersMips);
+	event.put(m_outputBlocks, outputClustersBlocks);
+	event.put(m_outputSmallClusters, outputClustersSmall);
+	event.put(m_outputUnmatchedTrackListName, unmatchedTracks);
+	return outputMap;
+    }
+}
CVSspam 0.2.8