4 added files
lcsim/src/org/lcsim/recon/cluster/structural
diff -N CheatFragmentMerger.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ CheatFragmentMerger.java 4 Jul 2006 23:59:53 -0000 1.1
@@ -0,0 +1,228 @@
+package org.lcsim.recon.cluster.structural;
+
+import java.util.List;
+import java.util.Vector;
+import java.util.Map;
+import java.util.HashMap;
+import org.lcsim.util.Driver;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.recon.cluster.util.BasicCluster;
+import org.lcsim.recon.cluster.analysis.*;
+
+/**
+ * Merge fragments into other clusters (cheating).
+ * The rules are that we cannot do primary fragment ID.
+ * So here is how the algorithm looks:
+ *
+ * For each fragment:
+ * 1) Find the dominant MC particle
+ * 2) Find the dominant cluster of that MC particle
+ * 3) If that cluster is in the "nonFragments" list, merge into it
+ * 4) If not, put the fragment to one side
+ *
+ * Then for fragments left over:
+ * 5) If the dominant cluster was a fragment that got merged into a
+ * nonFragment, also merge this fragment into the same nonFragment
+ * 6) If the dominant cluster was a fragment that did not get merged,
+ * promote it to nonFragment and merge into it.
+ */
+
+public class CheatFragmentMerger extends Driver implements FragmentMerger
+{
+ public CheatFragmentMerger() {
+ super();
+ }
+ public void process(EventHeader event) {
+ super.process(event);
+ m_event = event;
+ }
+
+ // Support for association:
+ transient protected EventHeader m_event = null;
+ protected CreateClusterAnalysisLists m_clusterAssociator = null;
+ protected String m_clusterAssociatorOutputListMCParticleToCluster;
+ protected String m_clusterAssociatorOutputListClusterToMCParticle;
+ protected String[] m_clusterAssociatorHitListNames;
+ protected String[] m_clusterAssociatorClusterListNames;
+ protected String m_clusterAssociatorMCListName;
+ public void initializeAssociator(String hitListNameToCreate, String clusterListNameToCreate, String mcListName, String outputListMCParticleToCluster, String outputListClusterToMCParticle) {
+ m_clusterAssociatorHitListNames = new String[1];
+ m_clusterAssociatorClusterListNames = new String[1];
+ m_clusterAssociatorHitListNames[0] = hitListNameToCreate;
+ m_clusterAssociatorClusterListNames[0] = clusterListNameToCreate;
+ m_clusterAssociatorMCListName = mcListName;
+ m_clusterAssociatorOutputListMCParticleToCluster = outputListMCParticleToCluster;
+ m_clusterAssociatorOutputListClusterToMCParticle = outputListClusterToMCParticle;
+ m_clusterAssociator = new CreateClusterAnalysisLists(m_clusterAssociatorHitListNames, m_clusterAssociatorClusterListNames, m_clusterAssociatorMCListName, m_clusterAssociatorOutputListMCParticleToCluster, m_clusterAssociatorOutputListClusterToMCParticle);
+ }
+
+ /**
+ * Merge or otherwise handle the lists of fragments and non-fragments.
+ *
+ * @param fragments Input list of fragment Clusters
+ * @param nonFragments Input list of primary Clusters
+ * @return List of merged/manipulated Clusters
+ */
+ public List<Cluster> mergeFragments(List<Cluster> fragments, List<Cluster> nonFragments)
+ {
+ // Association:
+ doAssoc(fragments, nonFragments);
+
+ // Our output will be a new set of clusters that contain the old ones.
+ // So we'll need wrapped output, starting with the nonFragments.
+ List<Cluster> outputClusters = new Vector<Cluster>();
+ Map<Cluster,BasicCluster> mapToWrappedClusters = new HashMap<Cluster,BasicCluster> ();
+ for (Cluster nonfrag : nonFragments) {
+ BasicCluster newCluster = new BasicCluster();
+ newCluster.addCluster(nonfrag);
+ mapToWrappedClusters.put(nonfrag,newCluster);
+ outputClusters.add(newCluster);
+ }
+
+ // OK. For each fragment, find the immediate parent.
+ Map<Cluster,Cluster> mapFragmentsToParentNonFragments = new HashMap<Cluster,Cluster> ();
+ Map<Cluster,Cluster> mapFragmentsToParentFragments = new HashMap<Cluster,Cluster> ();
+ for (Cluster fragment : fragments) {
+ Cluster target = findBestMerge(fragment, nonFragments, fragments);
+ if (nonFragments.contains(target)) {
+ mapFragmentsToParentNonFragments.put(fragment, target);
+ } else {
+ assert(fragments.contains(target)); // sanity check
+ mapFragmentsToParentFragments.put(fragment, target);
+ }
+ }
+
+ // Handle the fragment merging carefully.
+ // We use a map from fragments to any associated daughters.
+ // Initially, each fragment goes in as a parent with no daughters.
+ Map<Cluster,List<Cluster>> mapFragmentsToDaughters = new HashMap<Cluster,List<Cluster>>();
+ for (Cluster fragment : mapFragmentsToParentNonFragments.keySet()) {
+ mapFragmentsToDaughters.put(fragment, new Vector<Cluster>());
+ }
+
+ // We will loop around until the keySet of the map holds only fragments
+ // which do not have fragment parents. This can happen because:
+ // a) Their parent is a nonFragment
+ // b) They have no parent
+ // c) They have a fragment parent, but it is ultimately one of their
+ // own daughters (i.e. a loop exists)
+ boolean noChangeThisPass = false;
+ while (!noChangeThisPass) {
+ noChangeThisPass = true;
+ for (Cluster fragment : mapFragmentsToDaughters.keySet()) {
+ List<Cluster> fragmentDaughters = mapFragmentsToDaughters.get(fragment);
+ Cluster fragmentParent = mapFragmentsToParentFragments.get(fragment);
+ if (fragmentParent != null) {
+ // Find it
+ for (Cluster testFragment : mapFragmentsToDaughters.keySet()) {
+ if (fragment == testFragment) { break; }
+ List<Cluster> testDaughters = mapFragmentsToDaughters.get(testFragment);
+ if (testFragment == fragmentParent || testDaughters.contains(fragmentParent)) {
+ // Match
+ testDaughters.add(fragment);
+ testDaughters.addAll(fragmentDaughters);
+ mapFragmentsToDaughters.remove(fragment);
+ noChangeThisPass = false;
+ break;
+ }
+ }
+ }
+ if (!noChangeThisPass) { break; }
+ }
+ }
+
+ // Finished looping
+ for (Cluster fragment : mapFragmentsToDaughters.keySet()) {
+ List<Cluster> fragmentDaughters = mapFragmentsToDaughters.get(fragment);
+ Cluster nonFragmentParent = mapFragmentsToParentNonFragments.get(fragment);
+ if (nonFragmentParent != null) {
+ BasicCluster wrappedParent = mapToWrappedClusters.get(nonFragmentParent);
+ wrappedParent.addCluster(fragment);
+ for (Cluster daughter : fragmentDaughters) {
+ wrappedParent.addCluster(daughter);
+ }
+ } else {
+ // Promote
+ BasicCluster wrappedFragment = new BasicCluster();
+ wrappedFragment.addCluster(fragment);
+ for (Cluster daughter : fragmentDaughters) {
+ wrappedFragment.addCluster(daughter);
+ }
+ // Add to output
+ outputClusters.add(wrappedFragment);
+ }
+ }
+
+ {
+ int nFragmentClusters = fragments.size();
+ int nNonFragmentClusters = nonFragments.size();
+ int nFragmentHits = 0;
+ int nNonFragmentHits = 0;
+ for (Cluster clus : fragments) { nFragmentHits += clus.getCalorimeterHits().size(); }
+ for (Cluster clus : nonFragments) { nNonFragmentHits += clus.getCalorimeterHits().size(); }
+ System.out.println(this.getClass()+": Input was "+nFragmentClusters+" fragments with "+nFragmentHits+" hits plus "+nNonFragmentClusters
+ +" non-fragments with "+nNonFragmentHits+" hits ("+(nFragmentHits+nNonFragmentHits)+" total)");
+ int nOutputClusters = outputClusters.size();
+ int nOutputHits = 0;
+ for (Cluster clus : outputClusters) { nOutputHits += clus.getCalorimeterHits().size(); }
+ System.out.println(this.getClass()+": Output was "+nOutputClusters+" clusters with "+nOutputHits+" hits");
+ }
+
+ // Return output, which is the wrapped clusters with fragments merged in.
+ return outputClusters;
+ }
+
+ protected Cluster findBestMerge(Cluster fragment, List<Cluster> nonFragments, List<Cluster> fragments)
+ {
+ // Here we need to cheat.
+
+ // Look for the list of cluster info objects
+ List<ClusterMCPInfo> clusterInfoList = m_event.get(ClusterMCPInfo.class, m_clusterAssociatorOutputListClusterToMCParticle);
+
+ // Find the info:
+ ClusterMCPInfo info = null;
+ for (ClusterMCPInfo currentInfo : clusterInfoList) {
+ Cluster currentCluster = currentInfo.getCluster();
+ if (currentCluster == fragment) {
+ info = currentInfo;
+ }
+ }
+
+ if (info == null) {
+ throw new java.lang.NullPointerException("ERROR: Info not found");
+ } else {
+ // Found it OK.
+ // We look up which the dominant contributing MCParticle is.
+ // Then we look at that MCParticle and see which cluster it
+ // puts the most energy in (the dominant cluster of that particle).
+
+ MCPClusterInfo maxParticleInfo = info.getMaxMCPC();
+ Cluster maxClusterOfMaxParticle = maxParticleInfo.getMaxCluster();
+ if (maxClusterOfMaxParticle == fragment) {
+ // It happens to be a primary already somehow.
+ return null;
+ } else {
+ // Found a parent. Check it's in one of the lists:
+ assert(nonFragments.contains(maxClusterOfMaxParticle) || fragments.contains(maxClusterOfMaxParticle));
+ return maxClusterOfMaxParticle;
+ }
+ }
+ }
+
+ private void doAssoc(List<Cluster> fragments, List<Cluster> nonFragments) {
+ List<CalorimeterHit> hitList = new Vector<CalorimeterHit>();
+ List<Cluster> clusterList = new Vector<Cluster>();
+ clusterList.addAll(fragments);
+ clusterList.addAll(nonFragments);
+ for (Cluster clus : clusterList) {
+ hitList.addAll(clus.getCalorimeterHits());
+ }
+ m_event.put(m_clusterAssociatorHitListNames[0], hitList);
+ m_event.put(m_clusterAssociatorClusterListNames[0], clusterList);
+ // Go!
+ m_clusterAssociator.CreateLists(m_event);
+ }
+
+}
lcsim/src/org/lcsim/recon/cluster/structural
diff -N FragmentHandler.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ FragmentHandler.java 4 Jul 2006 23:59:53 -0000 1.1
@@ -0,0 +1,114 @@
+package org.lcsim.recon.cluster.structural;
+
+import java.util.*;
+import org.lcsim.util.*;
+import org.lcsim.event.*;
+import org.lcsim.recon.cluster.util.BasicCluster;
+import org.lcsim.util.hitmap.HitMap;
+
+/**
+ * A Driver to handle fragments. Each event, clusters and individual
+ * hits are read in. A <code>FragmentIdentifier</code> is applied to
+ * the clusters to determine which are fragments. The individual hits
+ * are also treated as fragments. The lists of fragments and
+ * non-fragments are then passed to a <code>FragmentMerger</code>
+ * for further processing. Afterwards, the output cluster list is
+ * written to the event, as is a HitMap with any unused hits.
+ *
+ * The input lists and clusters are left unchanged.
+ *
+ * @see FragmentIdentifier
+ * @see FragmentMerger
+ * @version $Id: FragmentHandler.java,v 1.1 2006/07/04 23:59:53 mcharles Exp $
+ */
+
+public class FragmentHandler extends Driver
+{
+ /**
+ * Constructor.
+ */
+ public FragmentHandler() {}
+
+ /**
+ * Process one event.
+ */
+ public void process(EventHeader event)
+ {
+ // Input Clusters
+ List<Cluster> inputClusters = new Vector<Cluster>();
+ for (String name : m_inputClusterListNames) {
+ List<Cluster> clist = event.get(Cluster.class, name);
+ inputClusters.addAll(clist);
+ }
+
+ // Initially, fill the output hitmap with all hits
+ HitMap leftoverHits = new HitMap();
+ for (Cluster clus : inputClusters) {
+ for (CalorimeterHit hit : clus.getCalorimeterHits()) {
+ Long id = new Long(hit.getCellID());
+ leftoverHits.put(id,hit);
+ }
+ }
+
+ // Sort the input clusters into fragments and non-fragments
+ List<Cluster> fragments = new Vector<Cluster>();
+ List<Cluster> nonFragments = new Vector<Cluster>();
+ for (Cluster clus : inputClusters) {
+ boolean isFragment = m_fragmentID.isFragment(clus, event);
+ if (isFragment) {
+ fragments.add(clus);
+ } else {
+ nonFragments.add(clus);
+ }
+ }
+
+ // Add in any loose hits (treat as one-hit clusters)
+ for (String name : m_inputHitMapNames) {
+ Map<Long,CalorimeterHit> map = (Map<Long,CalorimeterHit>)(event.get(name));
+ leftoverHits.putAll(map);
+ for (CalorimeterHit hit : map.values()) {
+ BasicCluster cl = new BasicCluster();
+ cl.addHit(hit);
+ fragments.add(cl);
+ }
+ }
+
+ // Merge:
+ List<Cluster> mergedClusters = m_fragmentMerger.mergeFragments(fragments, nonFragments);
+
+ // Take used hits out of the "leftoverHits" hitmap. Whatever is
+ // left is the set of unused hits.
+ for (Cluster clus : mergedClusters) {
+ for (CalorimeterHit hit : clus.getCalorimeterHits()) {
+ Long id = new Long(hit.getCellID());
+ leftoverHits.remove(id);
+ }
+ }
+
+ // Output
+ event.put(m_outputClusterListName, mergedClusters);
+ event.put(m_outputHitMapName, leftoverHits);
+ }
+
+ /** Add another named list of clusters. */
+ public void addInputClusterList(String name) {m_inputClusterListNames.add(name);}
+ /** Add another named HitMap. */
+ public void addInputHitMap(String name) {m_inputHitMapNames.add(name);}
+ /** Set the name to write the modified clusters to. */
+ public void setOutputClusterList(String name) {m_outputClusterListName=name;}
+ /** Set the name to write the HitMap of unused hits to. */
+ public void setOutputHitMap(String name) {m_outputHitMapName=name;}
+ /** Specify the FragmentIdentifier to use. */
+ public void setFragmentIdentifier(FragmentIdentifier id) {m_fragmentID=id;}
+ /** Specify the FragmentMerger to use. */
+ public void setFragmentMerger(FragmentMerger merger) {m_fragmentMerger=merger;}
+
+ List<String> m_inputClusterListNames = new Vector<String>();
+ List<String> m_inputHitMapNames = new Vector<String>();
+
+ String m_outputClusterListName;
+ String m_outputHitMapName;
+ FragmentIdentifier m_fragmentID;
+ FragmentMerger m_fragmentMerger;
+
+}
lcsim/src/org/lcsim/recon/cluster/structural
diff -N FragmentMerger.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ FragmentMerger.java 4 Jul 2006 23:59:53 -0000 1.1
@@ -0,0 +1,39 @@
+package org.lcsim.recon.cluster.structural;
+
+import java.util.List;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.EventHeader;
+
+/**
+ * Interface for a class that takes in lists of fragments
+ * and non-fragments, then manipulates them. The conventional
+ * behaviour is to try to merge the fragments in with their
+ * parent non-fragments, but other forms of manipulation
+ * are possible (e.g. purging all fragments).
+ *
+ * Implementing classes should leave the input clusters unchanged.
+ * Do <B>not</B> merge like this:
+ * <BLOCKQUOTE>
+ * nonFragment.addCluster(fragment);
+ * <BLOCKQUOTE>
+ * Instead, create a new cluster and add to it like this:
+ * <BLOCKQUOTE>
+ * BasicCluster newCluster = new BasicCluster();
+ * <BR> newCluster.addCluster(nonFragment);
+ * <BR> newCluster.addCluster(fragment); // repeated for each fragment to be merged into this cluster
+ * </BLOCKQUOTE>
+ *
+ * @version $Id: FragmentMerger.java,v 1.1 2006/07/04 23:59:53 mcharles Exp $
+ */
+
+public interface FragmentMerger
+{
+ /**
+ * Merge or otherwise handle the lists of fragments and non-fragments.
+ *
+ * @param fragments Input list of fragment Clusters
+ * @param nonFragments Input list of primary Clusters
+ * @return List of merged/manipulated Clusters
+ */
+ public List<Cluster> mergeFragments(List<Cluster> fragments, List<Cluster> nonFragments);
+}
lcsim/src/org/lcsim/recon/cluster/structural
diff -N SimpleFragmentMerger.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ SimpleFragmentMerger.java 4 Jul 2006 23:59:53 -0000 1.1
@@ -0,0 +1,140 @@
+package org.lcsim.recon.cluster.structural;
+
+import java.util.*;
+import hep.physics.vec.*;
+import org.lcsim.event.*;
+import org.lcsim.recon.cluster.util.BasicCluster;
+
+/**
+ * A simple implementation of <code>FragmentMerger</code>.
+ * For each fragment, find the best-match non-fragment and
+ * merge it. The best-match is determined using the
+ * protected method <code>findBestMerge</code>. The default
+ * is the nearest (hit-hit distance) non-fragment, but this
+ * can be changed by extending this class and over-riding
+ * that method.
+ *
+ * @version $Id: SimpleFragmentMerger.java,v 1.1 2006/07/04 23:59:53 mcharles Exp $
+ */
+
+public class SimpleFragmentMerger implements FragmentMerger
+{
+ /**
+ * Constructor.
+ */
+ public SimpleFragmentMerger() {}
+
+ /**
+ * Merge the fragments in with the nonFragments. The input lists
+ * are left unaltered.
+ *
+ * @return The list of merged Clusters
+ */
+ public List<Cluster> mergeFragments(List<Cluster> fragments, List<Cluster> nonFragments)
+ {
+ // Our output will be a new set of clusters that contain the old ones.
+ // So we'll need wrapped output:
+ Map<Cluster,BasicCluster> mapToWrappedClusters = new HashMap<Cluster,BasicCluster> ();
+ for (Cluster nonfrag : nonFragments) {
+ BasicCluster newCluster = new BasicCluster();
+ newCluster.addCluster(nonfrag);
+ mapToWrappedClusters.put(nonfrag,newCluster);
+ }
+
+ // First pass: loop over fragments and find the best merge...
+ Map<Cluster,Cluster> mapFragmentsToParents = new HashMap<Cluster,Cluster> ();
+ List<Cluster> unmappedFragments = new Vector<Cluster>();
+ for (Cluster fragment : fragments) {
+ Cluster target = findBestMerge(fragment, nonFragments, fragments);
+ if (target != null) {
+ mapFragmentsToParents.put(fragment, target);
+ } else {
+ unmappedFragments.add(fragment);
+ }
+ }
+
+ // Second pass: Do the merges.
+ // If this implementation can merge fragments into other fragments,
+ // there is a danger that we will wind up with fragments that are
+ // never merged into a non-fragment and hence never written out.
+ for (Cluster fragment : mapFragmentsToParents.keySet()) {
+ Cluster target = mapFragmentsToParents.get(fragment);
+ BasicCluster wrappedTarget = mapToWrappedClusters.get(target);
+ wrappedTarget.addCluster(fragment);
+ }
+
+ // Return output, which is the wrapped non-fragments with fragments merged in.
+ List<Cluster> output = new Vector<Cluster>();
+ output.addAll(mapToWrappedClusters.values());
+ return output;
+ }
+
+ protected Cluster findBestMerge(Cluster fragment, List<Cluster> nonFragments, List<Cluster> fragments)
+ {
+ // This is kind of dumb.
+ // What's the nearest non-fragment using hit-hit distance?
+ Cluster nearest = null;
+ double minDistance = 0;
+ for (Cluster nonFragment : nonFragments) {
+ double dist = distance(fragment, nonFragment);
+ if (dist<minDistance || nearest==null) {
+ nearest = nonFragment;
+ minDistance = dist;
+ }
+ }
+ if (nearest == null) {
+ if (nonFragments.size() != 0) {
+ throw new AssertionError("BUG: There are non-fragments, but none is the nearest");
+ } else {
+ return null;
+ }
+ } else {
+ return nearest;
+ }
+ }
+
+
+ // This belongs outside this class.
+ private double distance(Cluster clus1, Cluster clus2)
+ {
+ // Loop over hits...
+ boolean firstCheck = true;
+ double minDistance = Double.NaN; // Will stay NaN if a cluster is empty
+ List<CalorimeterHit> hits = clus1.getCalorimeterHits();
+ for (CalorimeterHit hit : hits) {
+ double dist = distance(clus2, hit);
+ if (firstCheck || dist<minDistance) {
+ minDistance = dist;
+ firstCheck = false;
+ }
+ }
+
+ return minDistance;
+ }
+ // This belongs outside this class.
+ private double distance(Cluster clus, CalorimeterHit hit)
+ {
+ // Loop over hits...
+ boolean firstCheck = true;
+ double minDistance = Double.NaN; // Will stay NaN if clus is empty
+ List<CalorimeterHit> hits = clus.getCalorimeterHits();
+ for (CalorimeterHit hitInCluster : hits) {
+ double dist = distance(hit, hitInCluster);
+ if (firstCheck || dist<minDistance) {
+ minDistance = dist;
+ firstCheck = false;
+ }
+ }
+
+ return minDistance;
+ }
+ // This belongs outside this class.
+ private double distance(CalorimeterHit hit1, CalorimeterHit hit2)
+ {
+ Hep3Vector vect1 = new BasicHep3Vector(hit1.getPosition());
+ Hep3Vector vect2 = new BasicHep3Vector(hit2.getPosition());
+ Hep3Vector displacement = VecOp.sub(vect1, vect2);
+ return displacement.magnitude();
+ }
+
+}
CVSspam 0.2.8