6 added files
lcsim/src/org/lcsim/contrib/uiowa/mst
diff -N ClusterNotEmptyDecisionMaker.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ClusterNotEmptyDecisionMaker.java 29 Sep 2005 21:03:47 -0000 1.1
@@ -0,0 +1,33 @@
+package mst; //package org.lcsim.recon.cluster.mst;
+
+import util.decision.*; //import org.lcsim.util.decision.*;
+
+import java.util.List;
+import org.lcsim.event.Cluster;
+
+/**
+ * A simple decision maker which always returns valid
+ * for clusters that have at least one hit.
+ */
+public class ClusterNotEmptyDecisionMaker implements DecisionMakerSingle<Cluster>, DecisionMakerPair<Cluster,Cluster> {
+
+ /**
+ * Simple constructor
+ */
+ public ClusterNotEmptyDecisionMaker() {}
+
+ /**
+ * Returns true provided the cluster has at least one hit
+ */
+ public boolean valid (Cluster clus){
+ return (clus.getCalorimeterHits().size() > 0);
+ }
+
+ /**
+ * Returns true provided each cluster has at least one hit
+ */
+ public boolean valid (Cluster clus1, Cluster clus2) {
+ return valid(clus1) && valid(clus2);
+ }
+
+}
lcsim/src/org/lcsim/contrib/uiowa/mst
diff -N GeometricalDistance.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ GeometricalDistance.java 29 Sep 2005 21:03:47 -0000 1.1
@@ -0,0 +1,36 @@
+package mst; //package org.lcsim.recon.cluster.mst;
+
+import java.io.*;
+import java.util.*;
+
+import org.lcsim.event.Cluster;
+
+/**
+ * A distance metric that computes the 3D distance
+ * between two clusters.
+ */
+public class GeometricalDistance implements Metrics {
+
+ /**
+ * Simple constructor
+ */
+ public GeometricalDistance(){}
+
+ /**
+ * Compute the 3D distance between two clusters. Each cluster's
+ * position is taken as Cluster.getPosition(), which is usually
+ * the center of energy. The method then returns the distance
+ * between the two position points.
+ */
+ public double getDistance (Cluster cluster1, Cluster cluster2){
+ double[] coOne = cluster1.getPosition();
+ double[] coTwo = cluster2.getPosition();
+
+ double distance = Math.sqrt((coOne[0]-coTwo[0])*(coOne[0]-coTwo[0])
+ + (coOne[1]-coTwo[1])*(coOne[1]-coTwo[1])
+ + (coOne[2]-coTwo[2])*(coOne[2]-coTwo[2]));
+
+ return distance;
+ }
+
+}
lcsim/src/org/lcsim/contrib/uiowa/mst
diff -N MSTClusterBuilder.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ MSTClusterBuilder.java 29 Sep 2005 21:03:47 -0000 1.1
@@ -0,0 +1,139 @@
+package mst; //package org.lcsim.recon.cluster.mst;
+
+import util.decision.*; //import org.lcsim.util.decision.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.Cluster;
+import org.lcsim.recon.cluster.util.BasicCluster;
+
+/**
+ * A class to build clusters using the Minimum Spanning Tree (MST)
+ * algorithm.
+ *
+ * NB! Why are a bunch of things private instead of protected?
+ * If I want to extend this class, shouldn't I be allowed to know
+ * what the threshold is?
+ */
+public class MSTClusterBuilder {
+
+ /**
+ * Constructor.
+ * @param list The objects that will be clustered. If these are hits, they must be pre-wrapped into Cluster format.
+ */
+ public MSTClusterBuilder (List<Cluster> list, EventHeader event){
+ inputList = list;
+ thisEvent = event;
+ }
+
+ /**
+ * Main clustering routine. Any two objects where metric(object1,object2)<threshold
+ * will be placed in the same output cluster (though the converse is not necessarily true).
+ * In addition, three decision makers are checked for validity (seedDecision, pairDecision, outputDecision).
+ */
+ public List<Cluster> doClustering(){
+ List<Cluster> outputList = new ArrayList<Cluster>();
+ usedList.clear();
+
+ if (inputList == null ) throw new AssertionError ("empty inputList");
+
+ if (theMetrics == null ) throw new AssertionError ("no metrics");
+
+ if ( !thresholdSet ) throw new AssertionError ("no threshold");
+
+ Iterator iter = inputList.iterator();
+ while (iter.hasNext()){
+ Cluster inOne = (Cluster) iter.next();
+ if (!usedList.contains(inOne) && seedDecision.valid(inOne)){
+ BasicCluster out = new BasicCluster();
+ recursiveClusterer(inOne, out);
+ if (outputDecision.valid(out)) {
+ outputList.add(out);
+ }
+ }
+ }
+ return outputList;
+ }
+
+ /**
+ * An internal routine for clustering
+ */
+ private void recursiveClusterer(Cluster inOne, BasicCluster out){
+ out.addCluster(inOne);
+ usedList.add(inOne);
+ Iterator iter = inputList.iterator();
+ while (iter.hasNext()){
+ Cluster inTwo = (Cluster) iter.next();
+ if (!usedList.contains(inTwo)){
+ if (pairDecision.valid(inOne, inTwo)){
+ double d = theMetrics.getDistance(inOne, inTwo);
+ if (d < threshold){
+ recursiveClusterer(inTwo, out);
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ private List<Cluster> inputList; // was protected
+ private Collection<Cluster> usedList = new HashSet<Cluster>(); // was protected
+
+ private Metrics theMetrics = null;
+ private double threshold;
+ private boolean thresholdSet = false;
+ private DecisionMakerSingle<Cluster> seedDecision = new ClusterNotEmptyDecisionMaker();
+ private DecisionMakerPair<Cluster,Cluster> pairDecision = new ClusterNotEmptyDecisionMaker();
+ private DecisionMakerSingle<Cluster> outputDecision = new ClusterNotEmptyDecisionMaker();
+
+ protected EventHeader thisEvent = null;
+
+ /**
+ * Specify the metric to be used. This must be done
+ * before doClustering() can be called.
+ */
+ public void registerMetrics(Metrics m){
+ theMetrics = m;
+ }
+
+ /**
+ * Specify the threshold to be used. This must be done
+ * before doClustering() can be called.
+ */
+ public void setThreshold(double t){
+ threshold = t;
+ thresholdSet = true;
+ }
+
+ /**
+ * Specify the seed decision. For an object to be the first
+ * (or only) object in a cluster, it must pass the seed decision.
+ * Objects do not pass the seed decision will either be picked up
+ * in a cluster as it spreads, or will not appear in any cluster.
+ */
+ public void setSeedDecision(DecisionMakerSingle<Cluster> d){
+ seedDecision = d;
+ }
+
+ /**
+ * Specify the pair decision. To link two objects, the pair decision
+ * must be valid AND metric(object1,object2)<threshold. If either
+ * condition fails there will not be a direct link, though it is still
+ * possible for both to end up in the same cluster (e.g. if both are
+ * successfully linked to a third object).
+ */
+ public void setPairDecision(DecisionMakerPair<Cluster,Cluster> d){
+ pairDecision = d;
+ }
+
+ /**
+ * Specify the output decision. For a cluster to be written out to the
+ * output list, this decision must be valid.
+ */
+ public void setOutputDecision(DecisionMakerSingle<Cluster> d){
+ outputDecision = d;
+ }
+
+}
lcsim/src/org/lcsim/contrib/uiowa/mst
diff -N MSTClusterDriver.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ MSTClusterDriver.java 29 Sep 2005 21:03:47 -0000 1.1
@@ -0,0 +1,102 @@
+package mst; //package org.lcsim.recon.cluster.mst;
+
+import util.*; //import org.lcsim.recon.cluster.util.*;
+import util.decision.*; //import org.lcsim.util.decision.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.lcsim.util.Driver;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.CalorimeterHit;
+
+public class MSTClusterDriver extends Driver {
+
+ private double threshold = 3.0;
+ private String calType = "EMCal";
+ private String userTag;
+ private String clusterName = "MSTCluster "+calType;
+ private Metrics metrics = new GeometricalDistance();
+ private boolean useEndcap = false;
+ private DecisionMakerSingle inputDecision = new ClusterNotEmptyDecisionMaker();
+ private DecisionMakerSingle seedDecision = new ClusterNotEmptyDecisionMaker();
+ private DecisionMakerPair pairDecision = new ClusterNotEmptyDecisionMaker();
+ private DecisionMakerSingle outputDecision = new ClusterNotEmptyDecisionMaker();
+ private List<String> listToGet;
+
+ public MSTClusterDriver(String inString){
+ calType = inString;
+ listToGet = new ArrayList();
+ if ( calType == "EMCal" || calType == "all") {
+ listToGet.add("EcalBarrHits");
+ if (useEndcap) listToGet.add("EcalEndcapHits");
+ } else if ( calType == "HCal" || calType == "all") {
+ listToGet.add("HcalBarrHits");
+ if (useEndcap) listToGet .add("HcalEndcapHits");
+ } else if ( calType == "User" ) {
+ } else {
+ throw new AssertionError("Calorimeter type '"+calType+"' not recognized.");
+ }
+ }
+
+ public void process(EventHeader event){
+ List<Cluster> inputList = new ArrayList<Cluster> ();
+
+ for (String s : listToGet) {
+ ObjectToClusterWrapper wrap = new BasicObjectToClusterWrapper();
+ List l = event.get(Object.class, s);
+ try {
+ List<Cluster> wrappedList = wrap.wrapListOfObjects(l);
+ inputList.addAll(wrappedList);
+ } catch (UnwrappableObjectException x) {
+ // We fed it an object it didn't understand (not a Cluster or CalorimeterHit)
+ throw new AssertionError(x);
+ }
+ }
+ ListFilter<Cluster> filter = new ListFilter<Cluster> (inputDecision);
+ List<Cluster> list = filter.filterList(inputList);
+
+ MSTClusterBuilder clusterBuilder = new MSTClusterBuilder( list, event );
+ clusterBuilder.registerMetrics(metrics);
+ clusterBuilder.setThreshold(threshold);
+ clusterBuilder.setSeedDecision(seedDecision);
+ clusterBuilder.setPairDecision(pairDecision);
+ clusterBuilder.setOutputDecision(outputDecision);
+ List<Cluster> outputList = clusterBuilder.doClustering();
+ event.put(clusterName, outputList );
+ }
+
+ public void setThreshold(double value){
+ threshold = value;
+ System.out.println("Threshold: "+threshold);
+ }
+
+ public void setClusterName(String string){
+ clusterName = string;
+ System.out.println("ClusterName: "+clusterName);
+ }
+
+ public void registerMetrics(Metrics inMetrics){
+ metrics = inMetrics;
+ }
+
+ public void setInputDecision(DecisionMakerSingle decision){
+ inputDecision = decision;}
+
+ public void setSeedDecision(DecisionMakerSingle decision){
+ seedDecision = decision;}
+
+ public void setPairDecision(DecisionMakerPair decision){
+ pairDecision = decision;}
+
+ public void setOutputDecision(DecisionMakerSingle decision){
+ outputDecision = decision;}
+
+ public void addUserInputList(String tag){
+ listToGet.add(tag);
+ }
+ public void resetUserInputList(){listToGet.clear();}
+
+ public void useEndcap(boolean use){useEndcap = use;}
+}
lcsim/src/org/lcsim/contrib/uiowa/mst
diff -N Metrics.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Metrics.java 29 Sep 2005 21:03:48 -0000 1.1
@@ -0,0 +1,12 @@
+package mst; //package org.lcsim.recon.cluster.mst;
+
+import java.io.*;
+import java.util.*;
+
+import org.lcsim.event.Cluster;
+
+public interface Metrics {
+
+ public double getDistance(Cluster c1, Cluster c2);
+
+}
lcsim/src/org/lcsim/contrib/uiowa/mst
diff -N MinimumHitToHitDistance.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ MinimumHitToHitDistance.java 29 Sep 2005 21:03:48 -0000 1.1
@@ -0,0 +1,35 @@
+package mst; //package org.lcsim.recon.cluster.mst;
+
+import java.util.List;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.Cluster;
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.VecOp;
+
+import org.lcsim.event.Cluster;
+
+public class MinimumHitToHitDistance implements Metrics {
+
+ public MinimumHitToHitDistance(){}
+
+ public double getDistance (Cluster cluster1, Cluster cluster2){
+ // get min hit-hit distance
+ double minDist = Double.NaN;
+ boolean firstCheck = true;
+ for (CalorimeterHit hit1 : cluster1.getCalorimeterHits()) {
+ for (CalorimeterHit hit2 : cluster2.getCalorimeterHits()) {
+ Hep3Vector vect1 = new BasicHep3Vector(hit1.getPosition());
+ Hep3Vector vect2 = new BasicHep3Vector(hit2.getPosition());
+ Hep3Vector displacement = VecOp.sub(vect1, vect2);
+ double dist = displacement.magnitude();
+ if (firstCheck || dist<minDist) {
+ minDist = dist;
+ firstCheck = false;
+ }
+ }
+ }
+ return minDist;
+ }
+
+}
CVSspam 0.2.8