Commit in lcsim/src/org/lcsim/contrib/uiowa/util on MAIN
Associator.java+50added 1.1
BasicObjectToClusterWrapper.java+81added 1.1
EnergyAssociator.java+249added 1.1
ObjectToClusterWrapper.java+32added 1.1
UnwrappableObjectException.java+8added 1.1
decision/DecisionMakerPair.java+10added 1.1
        /DecisionMakerSingle.java+11added 1.1
        /ListFilter.java+26added 1.1
+467
8 added files
Preliminary version of various small utility classes

lcsim/src/org/lcsim/contrib/uiowa/util
Associator.java added at 1.1
diff -N Associator.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Associator.java	29 Sep 2005 21:05:36 -0000	1.1
@@ -0,0 +1,50 @@
+package util;
+
+import java.util.List;
+import org.lcsim.event.ReconstructedParticle;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.SimCalorimeterHit;
+import org.lcsim.event.Track;
+import org.lcsim.event.EventHeader;
+
+/**
+ * Truth association.
+ * This interface allows you to map between reco and sim
+ * objects. In general, this is not a 1:1 mapping -- for
+ * example, a reconstructed cluster can have contributions
+ * from several MC particles, and a single MC particle can
+ * contribute to several different clusters. To allow for
+ * this, the methods return an ordered list of matches
+ * (so that the first item in the list is the best match,
+ * and the last is the worst match). The metric used to
+ * determine which is "best" is implementation-defined,
+ * but should have a strict total ordering.
+ *
+ * One common use case is to need the best available
+ * 1:1 mapping. This is provided by the bestAssoc methods.
+ * Since this can fail, these methods are allowed to throw
+ * an AssociationFailedException. How the match is made
+ * and what constitutes failure are implementation-defined,
+ * but a minimum sanity requirement is that, when successful,
+ *   bestAssoc(x) == assoc(x).first
+ *
+ * If these routines are somehow called when analysing
+ * experimental data, they should throw an AssertionError.
+ */
+
+public interface Associator
+{
+    public List<MCParticle>            associateHitToMCParticles(SimCalorimeterHit hit);
+    public List<SimCalorimeterHit>     associateMCParticleToHits(MCParticle part);
+    
+    public List<MCParticle>            associateClusterToMCParticles(Cluster clus);
+    public List<Cluster>               associateMCParticleToClusters(MCParticle part);
+    
+    public List<MCParticle>            associateTrackToMCParticles(Track track);
+    public List<Track>                 associateMCParticleToTracks(MCParticle part);
+
+    public List<MCParticle>            associateParticleToMCParticles(ReconstructedParticle part);
+    public List<ReconstructedParticle> associateMCParticleToParticles(MCParticle part);
+}

lcsim/src/org/lcsim/contrib/uiowa/util
BasicObjectToClusterWrapper.java added at 1.1
diff -N BasicObjectToClusterWrapper.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ BasicObjectToClusterWrapper.java	29 Sep 2005 21:05:36 -0000	1.1
@@ -0,0 +1,81 @@
+package util; // package org.lcsim.recon.cluster.util;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import org.lcsim.recon.cluster.util.BasicCluster; 
+import org.lcsim.event.CalorimeterHit; 
+import org.lcsim.event.Cluster;
+
+/**
+  * Interface describing a class that takes an object and turns it
+  * into a cluster (or takes a list of objects and turns it
+  * into a list of clusters). If it can't handle an object, it throws
+  * an UnwrappableObjectException. In this implementation, the
+  * input objects must be instances of Cluster or CalorimeterHit.
+  */
+
+public class BasicObjectToClusterWrapper implements ObjectToClusterWrapper
+{
+    /**
+      * Simple constructor
+      */
+    public BasicObjectToClusterWrapper() {}
+
+    /**
+      * Wrap one object (Cluster or CalorimeterHit) into a Cluster
+      */
+    public Cluster wrapObject(Object obj) throws UnwrappableObjectException
+    {
+      if (obj instanceof Cluster) {
+        // Already a cluster
+        Cluster clus = (Cluster) obj;
+        return clus;
+      } else if (obj instanceof CalorimeterHit) {
+        CalorimeterHit hit = (CalorimeterHit) obj;
+        return wrapCalorimeterHit(hit);
+      } else {
+        throw new UnwrappableObjectException("Don't knowhow to wrap class "+obj.getClass().getName());
+      }
+    }
+
+    /**
+      * Wrap a list of objects (Cluster or CalorimeterHit) into a newly
+      * created list of Clusters.
+      */
+    public List<Cluster> wrapListOfObjects(List inputList) throws UnwrappableObjectException {
+      List<Cluster> emptyList = new ArrayList<Cluster>();
+      try {
+        return wrapListOfObjects(inputList, emptyList);
+      } catch (UnwrappableObjectException x) { 
+        throw x;
+      }
+    }
+
+    /**
+      * Wrap a list of objects into a list of clusters, allowing user to
+      * specify the empty list (outputList) which will hold the clusters.
+      */
+    public List<Cluster> wrapListOfObjects(List inputList, List<Cluster> outputList) throws UnwrappableObjectException {
+      outputList.clear();
+      if (!outputList.isEmpty()) { throw new AssertionError("Non-empty output list at start of method."); }
+      for (Object obj : inputList) {
+        try {
+          Cluster clus = wrapObject(obj);
+          outputList.add(clus);
+        } catch (UnwrappableObjectException x) { 
+          throw x;
+        }
+      }
+      return outputList;
+    }
+
+    /**
+      * Internal utility routine to wrap a CalorimeterHit into a Cluster
+      */
+    protected Cluster wrapCalorimeterHit(CalorimeterHit hit) {
+        BasicCluster clus = new BasicCluster();
+        clus.addHit(hit);
+        return clus;
+    }
+}

lcsim/src/org/lcsim/contrib/uiowa/util
EnergyAssociator.java added at 1.1
diff -N EnergyAssociator.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EnergyAssociator.java	29 Sep 2005 21:05:36 -0000	1.1
@@ -0,0 +1,249 @@
+package util;
+
+import java.util.List;
+import java.util.Vector;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Comparator;
+import java.util.Collections;
+
+import org.lcsim.event.ReconstructedParticle;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.TrackerHit;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.SimCalorimeterHit;
+import org.lcsim.event.Track;
+import org.lcsim.event.EventHeader;
+
+/**
+ * A truth associator that works by comparing energy
+ * deposits. The match with the greatest amount or
+ * proportion of matched energy (after correcting
+ * by the sampling fraction) is the best.
+ */
+
+class EnergyAssociator implements Associator
+{
+    protected List<SimCalorimeterHit> m_hits;
+    protected List<MCParticle>         m_mcParticles;
+    protected List<Track>              m_tracks;
+    protected List<Cluster>            m_clusters;
+    protected List<ReconstructedParticle> m_reconParticles;
+    protected EventHeader                 m_event;
+
+    public EnergyAssociator(EventHeader event)
+    {
+	// Initially, use defaults that people will expect:
+	// Calorimeter hits:
+	List<SimCalorimeterHit> newList = new Vector<SimCalorimeterHit>();
+	newList.addAll(event.getSimCalorimeterHits("EcalBarrHits"));
+	newList.addAll(event.getSimCalorimeterHits("HcalBarrHits"));
+	newList.addAll(event.getSimCalorimeterHits("EcalEndcapHits"));
+	newList.addAll(event.getSimCalorimeterHits("HcalEndcapHits"));
+	setCalorimeterHits(newList);
+	// MC Particles
+	setMCParticles(event.getMCParticles());
+	// Tracks
+	setTracks(event.getTracks());
+	// Reconstructed particles
+	setReconstructedParticles(event.get(ReconstructedParticle.class, event.MCFASTRECONSTRUCTEDPARTICLES));
+
+	m_event = event;
+    }
+
+    public void setCalorimeterHits(List<SimCalorimeterHit> hits) { m_hits = hits; }
+    public void setMCParticles(List<MCParticle> particles) { m_mcParticles = particles; }
+    public void setTracks(List<Track> tracks) { m_tracks = tracks; }
+    public void setClusters(List<Cluster> clusters) { m_clusters = clusters; }
+    public void setReconstructedParticles(List<ReconstructedParticle> particles) { m_reconParticles = particles; }
+    public List<SimCalorimeterHit> getCalorimeterHits() { return m_hits; }
+    public List<MCParticle> getMCParticles() { return m_mcParticles; }
+    public List<Track> getTracks() { return m_tracks; }
+    public List<Cluster> getClusters() { return m_clusters; }
+    public List<ReconstructedParticle> getReconstructedParticles() { return m_reconParticles; }
+
+    /**
+     * Given a SimCalorimeterHit, returns a list of all MCParticles that
+     * contributed, sorted by amount of energy contributed.
+     */
+    public List<MCParticle>            associateHitToMCParticles(SimCalorimeterHit hit)
+    {
+	SortMCList comp = new SortMCList(hit);
+	List<MCParticle> output = comp.contributingMCParticles();
+	Collections.sort(output, comp);
+	return output;
+    }
+    /**
+     * Given an MCParticle, returns a list of all SimCalorimeterHits to
+     * which it contributes, sorted by purity.
+     */
+    public List<SimCalorimeterHit>      associateMCParticleToHits(MCParticle part)
+    {
+	if (m_mapMCParticlesToHits == null) { makeMapMCParticlesToHits(); }
+	// Clone it, to make sure our internals don't get messed up by an enthusiastic user
+	ArrayList<SimCalorimeterHit> internalHits = m_mapMCParticlesToHits.get(part);
+	ArrayList<SimCalorimeterHit> hits = new ArrayList<SimCalorimeterHit>(internalHits);
+	SortHitList comp = new SortHitList(part);
+	Collections.sort(hits, comp);
+	return hits;
+    }
+
+    /**
+     * Given a Cluster, returns a list of all MCParticles that
+     * contributed, sorted by amount of energy contributed.
+     */
+    public List<MCParticle>            associateClusterToMCParticles(Cluster clus)
+    {
+	// Use hits. They have to be cast to SimCalorimeterHit objects first...
+	List<CalorimeterHit> hits = clus.getCalorimeterHits();
+	List<SimCalorimeterHit> simHits = new Vector<SimCalorimeterHit>();
+	for (CalorimeterHit hit : hits) {
+	    SimCalorimeterHit simHit = (SimCalorimeterHit) hit;
+	    simHits.add(simHit);
+	}
+	// Now do the sort/extraction
+	SortMCList comp = new SortMCList(simHits);
+	List<MCParticle> output = comp.contributingMCParticles();
+	Collections.sort(output, comp);
+	return output;
+    }
+
+    /**
+     * Given an MCParticle, returns a list of all Clusters to which it
+     * contributes, sorted by amount of energy contributed.
+     */
+    public List<Cluster>               associateMCParticleToClusters(MCParticle part)
+    {
+	throw new AssertionError("Not yet implemented");
+    }
+    
+    public List<MCParticle>            associateTrackToMCParticles(Track track)
+    {
+	List<TrackerHit> hits = track.getTrackerHits();
+	throw new AssertionError("Not yet implemented");
+    }
+    public List<Track>                 associateMCParticleToTracks(MCParticle part)
+    {
+	throw new AssertionError("Not yet implemented");
+    }
+
+    public List<MCParticle>            associateParticleToMCParticles(ReconstructedParticle part)
+    {
+	throw new AssertionError("Not yet implemented");
+    }
+    public List<ReconstructedParticle> associateMCParticleToParticles(MCParticle part)
+    {
+	throw new AssertionError("Not yet implemented");
+    }
+
+    class SortHitList implements Comparator<SimCalorimeterHit>
+    {
+	MCParticle m_part;
+	public SortHitList(MCParticle part) {
+	    m_part = part;
+	}
+	public int compare(SimCalorimeterHit hit1, SimCalorimeterHit hit2) {
+	    // Compute purity in each
+	    double purity1 = getPurity(hit1);
+	    double purity2 = getPurity(hit2);
+	    if (purity1 > purity2) {
+		return +1;
+	    } else if (purity1 < purity2) {
+		return -1;
+	    } else if (purity1 == purity2) {
+		return 0;
+	    } else {
+		// NaN or similar
+		throw new AssertionError("Hits "+hit1+","+hit2+": an purity is undefined. Purities: "+purity1+","+purity2);
+	    }
+	}
+	protected double getPurity(SimCalorimeterHit hit) {
+	    double partEnergy = 0.0;
+	    double totalEnergy = 0.0;
+	    int nContributingParticles = hit.getMCParticleCount();
+	    for (int i=0; i<nContributingParticles; i++) {
+		MCParticle part = hit.getMCParticle(i);
+		double energy = hit.getContributedEnergy(i);
+		totalEnergy += energy;
+		if (part == m_part) {
+		    partEnergy += energy;
+		}
+	    }
+	    return partEnergy / totalEnergy;
+	}
+    }
+
+    class SortMCList implements Comparator<MCParticle> 
+    {
+	protected Map<MCParticle, Double> m_mapParticleToEnergy = null;
+
+	public SortMCList(SimCalorimeterHit hit) {
+	    m_mapParticleToEnergy = new HashMap<MCParticle, Double> ();
+	    int nContributingParticles = hit.getMCParticleCount();
+	    for (int i=0; i<nContributingParticles; i++) {
+		MCParticle part = hit.getMCParticle(i);
+		double energy = hit.getContributedEnergy(i);
+		m_mapParticleToEnergy.put(part, new Double(energy));
+	    }
+	}
+
+	public SortMCList(List<SimCalorimeterHit> hits) {
+	    m_mapParticleToEnergy = new HashMap<MCParticle, Double> ();
+	    for (SimCalorimeterHit hit : hits) {
+		int nContributingParticles = hit.getMCParticleCount();
+		for (int i=0; i<nContributingParticles; i++) {
+		    MCParticle part = hit.getMCParticle(i);
+		    double totalEnergy = hit.getContributedEnergy(i);
+		    Double previousTotalEnergy = m_mapParticleToEnergy.get(part);
+		    if (previousTotalEnergy != null) {
+			totalEnergy += previousTotalEnergy.doubleValue();
+		    }
+		    m_mapParticleToEnergy.put(part, new Double(totalEnergy));
+		}
+	    }
+	}
+
+	public List<MCParticle> contributingMCParticles() {
+	    ArrayList<MCParticle> output = new ArrayList<MCParticle>();
+	    output.addAll(m_mapParticleToEnergy.keySet());
+	    return output;
+	}
+
+	public int compare(MCParticle o1, MCParticle o2) {
+	    double energy1 = (m_mapParticleToEnergy.get(o1)).doubleValue();
+	    double energy2 = (m_mapParticleToEnergy.get(o2)).doubleValue();
+	    if (energy1 > energy2) {
+		return +1;
+	    } else if (energy1 < energy2) {
+		return -1;
+	    } else if (energy1 == energy2) {
+		return 0;
+	    } else {
+		// NaN or similar
+		throw new AssertionError("Particles "+o1+","+o2+": an energy is undefined. Energies: "+energy1+","+energy2);
+	    }
+	}
+    }
+
+    protected Map<MCParticle, ArrayList<SimCalorimeterHit> > m_mapMCParticlesToHits;
+
+    protected void makeMapMCParticlesToHits()
+    {
+	// Make a map: MCParticle --> list of hits
+	m_mapMCParticlesToHits = new HashMap<MCParticle, ArrayList<SimCalorimeterHit> >();
+	for (SimCalorimeterHit hit : getCalorimeterHits()) {
+	    int nContributingParticles = hit.getMCParticleCount();
+	    for (int i=0; i<nContributingParticles; i++) {
+		MCParticle contributingPart = hit.getMCParticle(i);
+		ArrayList<SimCalorimeterHit> assocHits = m_mapMCParticlesToHits.get(contributingPart);
+		if (assocHits == null) {
+		    assocHits = new ArrayList<SimCalorimeterHit>();
+		    m_mapMCParticlesToHits.put(contributingPart, assocHits);
+		}
+		assocHits.add(hit);
+	    }
+	}
+    }
+}

lcsim/src/org/lcsim/contrib/uiowa/util
ObjectToClusterWrapper.java added at 1.1
diff -N ObjectToClusterWrapper.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ObjectToClusterWrapper.java	29 Sep 2005 21:05:36 -0000	1.1
@@ -0,0 +1,32 @@
+package util; // package org.lcsim.recon.cluster.util;
+
+import java.util.List;
+import org.lcsim.event.Cluster;
+
+/**
+  * Interface describing a wrapper that takes an arbitrary object and
+  * turns it into a cluster (or takes a list of objects and turns it
+  * into a list of clusters). If it can't handle an object, it throws
+  * an UnwrappableObjectException.
+  */
+
+public interface ObjectToClusterWrapper
+{
+    /**
+      * Wrap one object into a cluster
+      */
+    public Cluster wrapObject(Object obj) throws UnwrappableObjectException;
+
+    /**
+      * Wrap a list of objects into a list of clusters.
+      */
+    public List<Cluster> wrapListOfObjects(List inputList) throws UnwrappableObjectException;
+
+    /**
+      * Wrap a list of objects into a list of clusters, allowing user to 
+      * specify the empty list (outputList) which will hold the clusters.
+      */
+    public List<Cluster> wrapListOfObjects(List inputList, List<Cluster> outputList) throws UnwrappableObjectException;
+
+}
+

lcsim/src/org/lcsim/contrib/uiowa/util
UnwrappableObjectException.java added at 1.1
diff -N UnwrappableObjectException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ UnwrappableObjectException.java	29 Sep 2005 21:05:36 -0000	1.1
@@ -0,0 +1,8 @@
+package util; // package org.lcsim.recon.cluster.util;
+
+import java.lang.String;
+
+public class UnwrappableObjectException extends java.lang.Exception {
+  public UnwrappableObjectException(String m) { super(m); }
+}
+

lcsim/src/org/lcsim/contrib/uiowa/util/decision
DecisionMakerPair.java added at 1.1
diff -N DecisionMakerPair.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ DecisionMakerPair.java	29 Sep 2005 21:05:37 -0000	1.1
@@ -0,0 +1,10 @@
+package util.decision; //package org.lcsim.util.decision;
+
+import java.io.*;
+import java.util.*;
+
+public interface DecisionMakerPair<E,T> {
+
+    public boolean valid(E objectToTest1, T objectToTest2);
+
+}

lcsim/src/org/lcsim/contrib/uiowa/util/decision
DecisionMakerSingle.java added at 1.1
diff -N DecisionMakerSingle.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ DecisionMakerSingle.java	29 Sep 2005 21:05:37 -0000	1.1
@@ -0,0 +1,11 @@
+package util.decision; //package org.lcsim.util.decision;
+
+/**
+  * This interface describes a decision-maker which takes a single
+  * object as input. It is templated...
+  */
+public interface DecisionMakerSingle<E> {
+
+    public boolean valid(E objectToTest);
+
+}

lcsim/src/org/lcsim/contrib/uiowa/util/decision
ListFilter.java added at 1.1
diff -N ListFilter.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ListFilter.java	29 Sep 2005 21:05:37 -0000	1.1
@@ -0,0 +1,26 @@
+package util.decision; //package org.lcsim.util.decision;
+
+import java.util.*;
+
+public class ListFilter<E> 
+{
+    public ListFilter (DecisionMakerSingle<E> dec) {
+      m_dec = dec;
+    }
+
+    public List<E> filterList(List<E> inputList, List<E> outputList) {
+      for (E item : inputList) {
+        if (m_dec.valid(item)) {
+          outputList.add(item);
+        }
+      }
+      return outputList;
+    }
+
+    public List<E> filterList(List<E> inputList) {
+      List<E> emptyList = new ArrayList<E>();
+      return filterList(inputList, emptyList);
+    }
+
+    protected DecisionMakerSingle<E> m_dec = null;
+}
CVSspam 0.2.8