Print

Print


Commit in lcsim/src/org/lcsim/recon/cluster/mipfinder on MAIN
AbstractHitType.java+34added 1.1
DoubleHit.java+83added 1.1
Flash.java+186added 1.1
HitCollection.java+43added 1.1
MIPCluster.java+93added 1.1
MIPClusterBuilder.java+304added 1.1
MIPClusterDriver.java+245added 1.1
SingleHit.java+61added 1.1
+1049
8 added files
MIP-finder

lcsim/src/org/lcsim/recon/cluster/mipfinder
AbstractHitType.java added at 1.1
diff -N AbstractHitType.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ AbstractHitType.java	2 Jan 2006 21:45:19 -0000	1.1
@@ -0,0 +1,34 @@
+package org.lcsim.recon.cluster.mipfinder;
+
+import java.lang.String;
+import org.lcsim.event.CalorimeterHit;
+
+/**
+   Abstract Hit. Designed for use with
+   LCDG4 Geant files 
+   
+   
+   @author Wolfgang F. Mader ([log in to unmask])
+   @version $Id: AbstractHitType.java,v 1.1 2006/01/02 21:45:19 mcharles Exp $
+   
+   Modification Log:
+   -- 07/22/2004 Version 1.0
+   -- 09/26/2005 Ported to org.lcsim by Mat
+*/
+public abstract class AbstractHitType {
+
+    public abstract boolean isValid(CalorimeterHit h, 
+                                    HitCollection hc); 
+    public Object getIdentifier(){ return ((Object) identifier); }
+    public boolean useInSeeds(){
+        return lUseInSeeds; 
+    }
+    public void useInSeeds(boolean b) {
+        if ( lWelcome ) System.out.println(identifier+" used in MIPSeeds: "+b); 
+        lUseInSeeds = b; 
+    }
+    protected boolean lUseInSeeds = true; 
+
+    protected String identifier; 
+    protected static boolean lWelcome = true; 
+}

lcsim/src/org/lcsim/recon/cluster/mipfinder
DoubleHit.java added at 1.1
diff -N DoubleHit.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ DoubleHit.java	2 Jan 2006 21:45:19 -0000	1.1
@@ -0,0 +1,83 @@
+package org.lcsim.recon.cluster.mipfinder;
+
+import org.lcsim.event.CalorimeterHit;
+import java.util.Vector;
+import org.lcsim.geometry.IDDecoder;
+import org.lcsim.geometry.CalorimeterIDDecoder;
+
+/**
+   Double Hit. Designed for use with
+   LCDG4 Geant files 
+   
+   
+   @author Wolfgang F. Mader ([log in to unmask])
+   @version $Id: DoubleHit.java,v 1.1 2006/01/02 21:45:19 mcharles Exp $
+   
+   Modification Log:
+   -- 07/22/2004 Version 1.0
+   -- 09/26/2005 Converted to org.lcsim by Mat
+*/
+
+public class DoubleHit extends AbstractHitType{
+
+    public DoubleHit(){
+	identifier = "doubleHit"; 
+	if ( lWelcome ){
+	    System.out.println(identifier+" used in MIP reconstruction"); 
+	    lWelcome = false; 
+	}
+    }
+
+  /**
+    * Check whether the hit matches the DoubleHit criteria. A DoubleHit is
+    * allowed two MIP hits in the same layer but only one MIP hit in the
+    * layers above and below. The implementation is a little complicated
+    * because some (but not all) of the MIP hits have been removed from
+    * the hit collection, so what we do is require that there is exactly
+    * one unremoved hit in the same layer and exactly one unremoved hit
+    * in the adjacent layers (i.e. one hit total in adjacent layers,
+    * not one per adjacent layer).
+    */
+    public boolean isValid(CalorimeterHit h, 
+			   HitCollection hc  )
+    {
+        // Find all neighbouring cells:
+        int dLayer = 1;
+        int dU = 1;
+        int dV = 1;
+        CalorimeterIDDecoder id = (CalorimeterIDDecoder) h.getIDDecoder();
+        id.setID(h.getCellID());
+        long[] neighbours = id.getNeighbourIDs(dLayer, dU, dV);
+ 
+        // What layer is the main hit in?
+	id.setID(h.getCellID()); 
+	int mainLayer = id.getLayer(); 
+
+        // For each nearby hit, whether it is in the same layer as
+        // the main hit or one layer away.
+        int nNeighbourHitsInSameLayer = 0;
+        int nNeighbourHitsInOtherLayer = 0;
+	for ( int i=0; i<neighbours.length; i++ ){
+	    CalorimeterHit hit = hc.find(neighbours[i]); 	    
+	    if ( hit != null ){
+                // Check the layer indices:
+		id.setID(hit.getCellID()); 
+		int layer = id.getLayer(); 
+                if (layer == mainLayer) {
+                  nNeighbourHitsInSameLayer++;
+                } else if ( (layer==mainLayer-1) || (layer==mainLayer+1) ) {
+		  nNeighbourHitsInOtherLayer++;
+                } else {
+		  throw new AssertionError("Invalid layer "+layer+"; allowed layers: "+(mainLayer-1)+", "+mainLayer+", "+(mainLayer+1));
+		}
+	    }
+	}
+
+        if (nNeighbourHitsInSameLayer==1 && nNeighbourHitsInOtherLayer==1) {
+	  // Meets criteria (see comment at top of method)
+          return true;
+	} else {
+	  return false;
+	}	
+    }
+}

lcsim/src/org/lcsim/recon/cluster/mipfinder
Flash.java added at 1.1
diff -N Flash.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Flash.java	2 Jan 2006 21:45:19 -0000	1.1
@@ -0,0 +1,186 @@
+package org.lcsim.recon.cluster.mipfinder;
+
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Collection;
+
+import org.lcsim.event.CalorimeterHit;
+
+/**
+   Implementation of Hit Collection Flash. Designed for use with
+   LCDG4 Geant files 
+   
+   
+   @author Wolfgang F. Mader ([log in to unmask])
+   @version $Id: Flash.java,v 1.1 2006/01/02 21:45:19 mcharles Exp $
+   
+   Modification Log:
+   -- 07/22/2004 Version 1.0
+   -- 09/26/2005 Converted to org.lcsim by Mat
+*/
+
+// Hits are stored in:
+//
+//  * Hashtable<Long, CalorimeterHit> flashVector
+//  * Object[] array
+//
+// The array is indexed by hashcode of the hit CellID.
+// Each entry in the array is initially null. If filled
+// once, it is set to the hit. If filled again, it is
+// changed into a vector that holds all hits with which
+// it has been filled.
+
+public class Flash extends HitCollection {
+    public Flash(int size) {
+	flashVector = new Hashtable<Long, CalorimeterHit>(); 
+	array = new Object[137*size/50];
+    }
+
+    /**
+     * Internal routine to store a CalorimeterHit in the array
+     */
+    void put(CalorimeterHit h) {
+	flashVector.put(new Long(h.getCellID()), h);
+	
+	int i = hash(h.getCellID());
+	if (array[i] == null) {
+	    // Not yet filled => set to hit
+	    array[i] = h;
+	} else if (array[i] instanceof CalorimeterHit) {
+	    // Already filled exactly once.
+	    // Switch from hit to vector storage and fill:
+	    Vector<CalorimeterHit> v = new Vector<CalorimeterHit>();
+            CalorimeterHit existingHit = (CalorimeterHit) (array[i]);
+	    v.addElement(existingHit);
+	    v.addElement(h);
+	    array[i] = v;
+	} else {
+	    // If not null or CalorimeterHit, should be a Vector.
+	    // Already filled multiple times => fill again
+	    Vector<CalorimeterHit> v = (Vector<CalorimeterHit>) array[i];
+            v.add(h);
+	}
+	return;
+    }
+
+    /**
+     * Internal routine to search for a CalorimeterHit (by CellID) in the Flash
+     */
+    CalorimeterHit find(CalorimeterHit thisHit) {
+	long id  = thisHit.getCellID(); 
+	CalorimeterHit h = find(id); 
+	return h; 
+    }
+
+    /**
+     * Internal routine to look up a CalorimeterHit given its CellID
+     */
+    CalorimeterHit find(long id) {
+	// Convert CellID into a hash code (for use as array index):
+	int i = hash(id);
+	// Now, what's at that point in the array?
+	if (array[i] == null) {
+	    // Nothing
+	    return null;
+	} else if (array[i] instanceof CalorimeterHit) {
+	    // A single CalorimeterHit. Need to verify that full CellID
+	    // matches as well as hashcode
+	    CalorimeterHit h = (CalorimeterHit) array[i];
+	    if (h.getCellID() == id) {
+		return h;
+	    } else {
+		return null;
+	    }
+	} else {
+	    // If not null or CalorimeterHit, should be a Vector.
+	    // Check for a fully matched hit. If there is more than
+	    // one, just return the first.
+	    Vector<CalorimeterHit> v = (Vector<CalorimeterHit>) array[i];
+	    for (CalorimeterHit hit : v) {
+		if (hit.getCellID() == id) {
+		    return hit;
+		}
+	    }
+	    // No matching hit
+	    return null;
+	}
+    }
+
+    /**
+     * Internal routine to remove a CalorimeterHit from the array.
+     */
+    void remove(CalorimeterHit h) {
+	// Remove from the Hashtable:
+	long targetCellID = h.getCellID();
+	flashVector.remove(new Long(targetCellID));
+	
+	// Remove from the array. Start by computing the index (hashcode):
+	int i = hash(h.getCellID());
+	if (array[i] == null) {
+	    // Nothing to remove
+	} else if (array[i] instanceof CalorimeterHit) {
+	    // There's a hit -- check if it matches
+	    CalorimeterHit hitInArray = (CalorimeterHit) (array[i]);
+	    if (hitInArray.getCellID() == targetCellID) {
+		// Match => remove
+		array[i] = null;
+	    }
+	} else {
+	    // If not null or CalorimeterHit, should be a Vector.
+	    // Several hits with that hash. Check them all:
+	    Vector<CalorimeterHit> v = (Vector<CalorimeterHit>) array[i];
+	    Vector<CalorimeterHit> vHitsToRemove = new Vector<CalorimeterHit>();
+	    for (CalorimeterHit currentHit : v) {
+		if (currentHit.getCellID() == targetCellID) {
+		    vHitsToRemove.add(currentHit);
+		}
+	    }
+	    // Remove any matching hits
+	    for (CalorimeterHit currentHit : vHitsToRemove) {
+		boolean removedOK = v.remove(currentHit);
+		if (!removedOK) { throw new AssertionError("Hit "+h+" not removed from HitCollection"); }
+	    }
+	}
+    }
+
+    /**
+     * Internal routine to check the number of hits in the Flash
+     */
+    int getNumberOfHits(){
+	return flashVector.size(); 
+    }
+    
+    /**
+     * Internal routine to get all hits in the Flash
+     */
+    Enumeration<CalorimeterHit> getHits(){
+	return flashVector.elements(); 
+    }
+
+    /**
+     * Internal routine to get all hits in the Flash, in the form of a
+     * Vector. This is a copy, i.e. add/remove actions on the returned
+     * Vector will not affect the Flash.
+     */
+    Vector<CalorimeterHit> getVector(){
+	Vector<CalorimeterHit> v = new Vector<CalorimeterHit>(); 
+	Collection<CalorimeterHit> hits = flashVector.values();
+	v.addAll(hits);
+	return v; 
+    }
+
+    /**
+     * Internal routine to compute the hash of a CellID.
+     */
+    private int hash(long i){
+        long masked = (0x7fffffff & i);
+        long output = masked % array.length;
+        return (int) output;
+    }
+    
+    
+    private Object[] array;
+    private Hashtable<Long, CalorimeterHit> flashVector;
+    private int numberOfHits;
+}

lcsim/src/org/lcsim/recon/cluster/mipfinder
HitCollection.java added at 1.1
diff -N HitCollection.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ HitCollection.java	2 Jan 2006 21:45:19 -0000	1.1
@@ -0,0 +1,43 @@
+package org.lcsim.recon.cluster.mipfinder;
+
+import java.util.List;
+import java.util.Vector; 
+import java.util.Enumeration; 
+
+import org.lcsim.event.CalorimeterHit;
+
+/**
+   Driver for Track Reconstruction in Event. Designed for use with
+   LCDG4 Geant files 
+   
+   
+   @author Wolfgang F. Mader ([log in to unmask])
+   @version $Id: HitCollection.java,v 1.1 2006/01/02 21:45:19 mcharles Exp $
+   
+   Modification Log:
+   -- 07/22/2004 Version 1.0
+   -- 09/26/2005 Ported to org.lcsim by Mat
+*/
+
+public abstract class HitCollection {
+//
+// Constructor Summary
+//
+    public HitCollection(){
+    }
+//
+// Method Summary
+//
+    abstract void put(CalorimeterHit thisHit); 
+    abstract CalorimeterHit find(CalorimeterHit thisHit); 
+    abstract CalorimeterHit find(long id); 
+    abstract void remove(CalorimeterHit thisHit);
+    abstract int getNumberOfHits(); 
+    abstract Enumeration getHits(); 
+    abstract Vector getVector(); 
+    public void fill(List<CalorimeterHit> hits){
+	for (CalorimeterHit hit : hits) {
+	    this.put(hit); 
+	}
+    }
+}

lcsim/src/org/lcsim/recon/cluster/mipfinder
MIPCluster.java added at 1.1
diff -N MIPCluster.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ MIPCluster.java	2 Jan 2006 21:45:19 -0000	1.1
@@ -0,0 +1,93 @@
+package org.lcsim.recon.cluster.mipfinder;
+
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.Cluster;
+import org.lcsim.recon.cluster.util.BasicCluster;
+import org.lcsim.geometry.IDDecoder;
+
+
+/**
+   Class for Cluster Candidates
+
+   @version $Id: MIPCluster.java,v 1.1 2006/01/02 21:45:19 mcharles Exp $
+   @author [log in to unmask]
+*/
+
+public class MIPCluster extends BasicCluster {
+
+    public MIPCluster(int nSeeds, int dir){
+	super();
+	nSeedLayers = nSeeds; 
+	direction = dir; 
+    }
+
+    public double[] getShowerCoordinates(){
+	/**
+	   returns the 3D Coordinates of the last MIP-Hit	   
+	 */
+	if (hits.size() > 0) {
+	    int lastIndex = hits.size() - 1;
+	    CalorimeterHit lastHit =  hits.get(lastIndex);
+	    IDDecoder id = lastHit.getIDDecoder();
+	    id.setID(lastHit.getCellID());
+	    return id.getPosition();
+	} else {
+	    // Not enough hits
+	    return null;
+	}
+    }
+    
+    public boolean isGoodMIP(){
+	boolean lIsGoodMIP = true; 
+	lIsGoodMIP = lIsGoodMIP && hits.size() >= 3; 
+	lIsGoodMIP = lIsGoodMIP && numberOfHitsInSeedLayers(); 
+	return lIsGoodMIP; 
+    }
+
+    public boolean doesFork(){
+	/**
+	   Returns <tt>true</tt> or <tt>false</tt> depending on
+	whether the MIP track forks or not  
+	 */
+	return lFork; 
+    }
+    public void doesFork(boolean b){
+	/**
+	   Sets the <tt>Fork</tt> Flag
+	*/
+	lFork = b; 
+    }
+
+    private boolean numberOfHitsInSeedLayers(){
+	int[] nHits = new int[nSeedLayers]; 
+	
+	int j=0; 
+	for (CalorimeterHit hit : hits) {
+	    IDDecoder id = hit.getIDDecoder();
+	    id.setID(hit.getCellID());
+	    int layer = id.getLayer(); 
+
+	    if ( j < nSeedLayers ) {
+		nHits[j]++; 
+	    }
+	    j++; 
+	}
+
+	int nHSum = 0; 
+	boolean lNOH = true; 
+	for ( int i=0; i<nSeedLayers; i++ ){
+	    lNOH = lNOH && nHits[i] <= 1; 
+	    nHSum += nHits[i];
+	}
+	
+	lNOH = lNOH && nHSum <= nSeedLayers && nHSum >= nSeedLayers-1; 
+	return lNOH; 
+    }
+
+    private int firstLayer = 0; 
+    private int nSeedLayers = 4; 
+    private int direction = +1; 
+
+    private boolean lFork = false; 
+}
+

lcsim/src/org/lcsim/recon/cluster/mipfinder
MIPClusterBuilder.java added at 1.1
diff -N MIPClusterBuilder.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ MIPClusterBuilder.java	2 Jan 2006 21:45:19 -0000	1.1
@@ -0,0 +1,304 @@
+package org.lcsim.recon.cluster.mipfinder;
+
+import java.util.List;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.geometry.IDDecoder;
+import org.lcsim.event.Cluster;
+import org.lcsim.geometry.CalorimeterIDDecoder;
+
+
+/**
+   MIPClusterBuilder
+       -- Recursive Clustering Algorimthm
+
+   Package: MIP
+   
+   Version 1.0
+
+   Modification Log: 
+      -- 23 March 2005: First Version
+      -- 23 Sept 2005: Converted to org.lcsim by Mat
+
+   (c) [log in to unmask]
+*/
+
+public class MIPClusterBuilder{
+
+    public MIPClusterBuilder( List<CalorimeterHit> hits,
+			      List<AbstractHitType> hitTypeList)
+    {
+	thisHits = hits; 
+	hitTypes = hitTypeList;
+    }
+
+    public void initialize(){
+//
+// Initialize Flash
+//
+	flash = new Flash(thisHits.size());
+	for (CalorimeterHit hit : thisHits) {
+	    flash.put(hit); 
+	    // Find layer:
+	    IDDecoder id = hit.getIDDecoder();
+	    id.setID(hit.getCellID());
+	    Integer layer = new Integer(id.getLayer());
+	    // Store the hit in the right per-layer list:
+	    if ( hitTable.containsKey(layer) ) {
+		Vector<CalorimeterHit> v = hitTable.get(layer);
+		v.add(hit); 
+	    } else {
+		Vector<CalorimeterHit> v = new Vector<CalorimeterHit>(); 
+		v.add(hit); 
+		hitTable.put(layer, v); 
+	    }
+	}
+
+
+	if ( !lUserNucleii ){
+	    int j = firstLayer; 
+	    for ( int i=0; i<nSeedLayers; i++ ){
+		if ( hitTable.containsKey(new Integer(j)) ) {
+		    Vector<CalorimeterHit> v = hitTable.get(new Integer(j)); 
+//
+// Require minimum energy for nucleii hits
+//
+		    for (CalorimeterHit hit : v) {
+			if ( hit.getRawEnergy() > eMin && hit.getRawEnergy() < eMax    ) {
+			    nucleii.add(hit); 
+			}
+		    }
+		}
+		j += direction; 
+	    }
+	}
+//
+// Debug output
+//
+	if ( lDebug ){
+	    Set<Integer> layers = hitTable.keySet();
+	    for (Integer i : layers) {
+		Vector<CalorimeterHit> v = hitTable.get(i);
+		System.out.println(this.getClass().getName()+" init: layer "+i+": "+v.size()+" hits"); 
+		for (CalorimeterHit hit : v) {
+		    IDDecoder id = hit.getIDDecoder();
+		    id.setID(hit.getCellID());
+		    System.out.println(this.getClass().getName()+" init:    E="+hit.getRawEnergy()+", hit="+hit+", theta="+id.getTheta()+", phi="+id.getPhi());
+		}
+	    }
+	}
+    }
+	
+//
+// do the Clustering
+//
+    public List<Cluster> getMIPClusterList(){
+	List<Cluster> vCluster = new Vector<Cluster>(); 
+
+	for (CalorimeterHit hit : nucleii) {
+
+	    if ( flash.find(hit) == null ) {
+		// Someone fed us a nucleus that's not in the hit list
+		// It can also be that the hit was used in a previous cluster.
+		continue; 
+	    }
+	    
+	    MIPCluster cluster = new MIPCluster(nSeedLayers, direction);
+	    iSingleHitsInLayer = new HashMap<Integer,Integer> ();
+
+	    if ( validate(hit) ){
+		cluster.addHit(hit); 
+		flash.remove(hit); 
+		
+		extend(cluster,hit,flash); 
+		if ( cluster.isGoodMIP() ) {
+//
+// See if MIP forks. Criterion is two SingeHits in the same Layer
+//
+		    boolean lFork = false; 
+		    Set<Integer> layers = iSingleHitsInLayer.keySet();
+		    for (Integer currentTestLayer : layers) {
+			Integer hitsInLayer = iSingleHitsInLayer.get(currentTestLayer);
+			if (hitsInLayer.intValue() >= 2) {
+			    lFork = true; 
+			}
+		    }
+
+		    cluster.doesFork(lFork); 
+		    vCluster.add(cluster); 
+		}
+	    }
+	}
+//
+// Debug output
+//
+	if ( lDebug ){
+	    for (Cluster cluster : vCluster) {
+		System.out.println(this.getClass().getName()+" found cluster: "+cluster);
+		
+		int i=0; 
+		for (CalorimeterHit hit : cluster.getCalorimeterHits()) {
+		    IDDecoder id = hit.getIDDecoder();
+		    id.setID(hit.getCellID());
+		    System.out.println(this.getClass().getName()+" found cluster:    hit #"+i+":"+hit+", layer="+id.getLayer()+", theta="+id.getTheta()+", phi="+id.getPhi());
+		    i++;
+		}
+	    }
+	}
+
+	return vCluster; 
+    }
+
+    private void extend(MIPCluster c, 
+			CalorimeterHit h, 
+			HitCollection hc ) 
+    {
+	int dLayer = 1;
+	int dU = 1;
+	int dV = 1;
+        CalorimeterIDDecoder id = (CalorimeterIDDecoder) h.getIDDecoder();
+	id.setID(h.getCellID());
+	long[] neighbours = id.getNeighbourIDs(dLayer, dU, dV);
+
+	Vector<CalorimeterHit> vHits = new Vector<CalorimeterHit>(); 
+
+	int iNeighboursInNextLayer = 0; 
+	for ( int i=0; i<neighbours.length; i++ ){
+	    CalorimeterHit hit = hc.find(neighbours[i]); 
+
+	    if ( hit != null ) {
+		id.setID(h.getCellID());
+		int iLayer = id.getLayer() * direction; 
+		id.setID(hit.getCellID());
+		int jLayer = id.getLayer() * direction; 
+
+		if ( jLayer == iLayer+1 ) {
+		    
+		    iNeighboursInNextLayer++; 
+		    if ( validate(hit) ) {
+
+			c.addHit(hit); 
+			hc.remove(hit); 
+			extend(c,hit,hc); 
+		    }
+		}
+	    }
+	}
+	
+    }
+
+    private boolean validate(CalorimeterHit h){
+	boolean lValidate = false; 
+
+	for (AbstractHitType aType : hitTypes) {
+	    if ( isInSeedLayer(h) && !aType.useInSeeds() ) {
+		continue; 
+	    }
+	    if ( aType.isValid(h, flash) ){
+		lValidate = true; 
+	    }
+	    
+	    if ( lValidate && (aType instanceof SingleHit) ){
+		IDDecoder id = h.getIDDecoder();
+		id.setID(h.getCellID());
+		Integer layer = new Integer(id.getLayer());
+		Integer countHitsInLayer = iSingleHitsInLayer.get(layer);
+		if (countHitsInLayer != null) {
+		    // Increment
+		    countHitsInLayer = new Integer(countHitsInLayer.intValue()+1);
+		} else {
+		    // Haven't found a hit in that layer yet, so this is the first
+		    countHitsInLayer = new Integer(1);
+		}
+		iSingleHitsInLayer.put(layer, countHitsInLayer);
+	    }
+	}
+	return lValidate; 
+    }
+
+    private boolean isInSeedLayer(CalorimeterHit hit){
+	IDDecoder id = hit.getIDDecoder();
+	id.setID(hit.getCellID());
+	int layer = id.getLayer(); 
+	return ( direction*layer >= direction*firstLayer &&
+		 direction*layer < direction*(firstLayer+direction*nSeedLayers) ); 
+    }
+
+    private List<CalorimeterHit> thisHits; 
+    private Hashtable<Integer, Vector<CalorimeterHit> > hitTable = new Hashtable<Integer, Vector<CalorimeterHit> > ();
+    private List<AbstractHitType> hitTypes;
+
+    private Flash flash; 
+    private List<CalorimeterHit> nucleii = new Vector<CalorimeterHit>(); 
+    private boolean lUserNucleii = false; 
+
+    public void provideNucleii(List<CalorimeterHit> v){
+	nucleii = v; 
+	lUserNucleii = true; 
+    }
+
+    private double eMin = 0.; 
+    private double eMax = 1000.; 
+
+    public void setMinimumHitEnergy(double v){
+	eMin = v; 
+    }
+    public double getMinimumHitEnergy(){
+	return eMin; 
+    }
+    public void setMaximumHitEnergy(double v){
+	eMax = v; 
+    }
+    public double getMaximumHitEnergy(){
+	return eMax; 
+    }
+
+    public void setNumberOfSeedLayers(int i){
+	nSeedLayers = i; 
+    }
+
+    public int getNumberOfSeedLayers(int i){
+	return ((int) nSeedLayers); 
+    }
+
+    public void setFirstLayer(int i){
+	firstLayer = i; 
+    }
+    public int getFirstLayer(int i){
+	return ((int) firstLayer); 
+    }
+
+    public void setDirectionAndFirstLayer(int newDir, int newFL){
+        setDirection(newDir);
+        setFirstLayer(newFL);
+    }
+
+    public void setDirection(int i){
+	if ( Math.abs(i) != 1 ) 
+	    throw new AssertionError("Direction has to be +/-1"); 
+	direction = i; 
+    }
+
+    public int getDirection(int i){
+	return ((int) direction ); 
+    }
+
+    private int nSeedLayers = 4; 
+    private int firstLayer = 0; 
+    private int direction = 1; 
+    private Map<Integer, Integer> iSingleHitsInLayer; 
+
+    private Vector<Cluster> vMIP = new Vector<Cluster>();  
+    private int depth = 0; 
+
+    private boolean lDebug = false; 
+
+    public void setDebugMode(boolean b){
+	lDebug = b; 
+    }
+}

lcsim/src/org/lcsim/recon/cluster/mipfinder
MIPClusterDriver.java added at 1.1
diff -N MIPClusterDriver.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ MIPClusterDriver.java	2 Jan 2006 21:45:19 -0000	1.1
@@ -0,0 +1,245 @@
+package org.lcsim.recon.cluster.mipfinder;
+
+import java.util.List;
+import java.util.Vector; 
+import java.io.IOException; 
+
+import org.lcsim.util.Driver;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.CalorimeterHit;
+
+
+/**
+ Main Processor for MIP Clustering.
+ <p>
+ Example of Use:
+ <p><blockquote><pre>
+    MIPClusterDriver MIPprocessor = new MIPClusterDriver("EMCal");
+    MIPprocessor.setClusterName("MIPCluster EMCal");
+    //
+    // Now define the HIT Types
+    //
+    List<AbstractHitType> hitTypes = new Vector<AbstractHitType>(); 
+
+    SingleHit sH = new SingleHit();
+    DoubleHit dH = new DoubleHit();
+    //
+    // Say which HIT types to use for MIP seeds
+    //
+    sH.useInSeeds(true); 
+    dH.useInSeeds(false); 
+
+    hitTypes.add(sH);
+    hitTypes.add(dH);
+    MIPprocessor.registerHitTypes(hitTypes);
+    //
+    // Set the Number of Layers considered for MIP Seeds (Default 4)
+    // A minimum and a maximum allowed energy for seed-hits energy can be set
+    //   (default: eMin = 0. and eMax = 1000.)
+    MIPprocessor.setNumberOfSeedLayers(int);
+    MIPprocessor.setMinmumEnergy(double); 
+    MIPprocessor.setMaximumEnergy(double)
+    //
+    // Set Direction
+    //     +1: Algorithm starts from the innermost Layer
+    //     -1: Algorithm starts from the outermost layer
+    //
+    MIPprocessor.setDirectionAndFirstLayer(int newDir,int newFL); 
+    //
+    // The User has the possibility to provide possible MIP starting points
+    //
+    MIPprocessor.provideNucleii(Vector<CalorimeterHit>); 
+    //
+    // Print out some Debug messages
+    //
+    MIPprocessor.setDebugMode(boolean); 
+    //
+    // Tell processor to either append (true) or replace (false,
+    // default) any possible existing list with the same name 
+    //
+    MIPprocessor.setAppend(boolean); 
+    //
+    // Add the MIPprocessor to the list of processors
+    //
+    add(MIPprocessor);
+ </pre></blockquote><p>
+ It generates a ClusterList of MIPClusters in the LCDEvent. Valid
+    argument for the constructor are <tt> EMCal</tt> and <tt> HCal </tt>
+    in order to read the standard EMCal and HCal CalorimeterHits
+    Objects. In addition, a tag  <tt> User</tt> is provided that
+    allows the user to read in his own CalorimeterHits objects.
+    In the latter case, the <tt> setUserTag(string)</tt> has to be set
+    by the user in order to read the corresponding CalorimeterHits
+    Object from <tt> event</tt>.  
+
+ @author [log in to unmask]
+ @version $Id: MIPClusterDriver.java,v 1.1 2006/01/02 21:45:19 mcharles Exp $
+
+   Modification Log:
+   -- 01/08/2005 Version 1.0 available in CVS
+   -- 08/08/2005 Bugfix -- Appending new and existing MIPClusterList
+                 now works as expected.  
+   -- 23/09/2005 Converted to org.lcsim by Mat
+*/
+
+public class MIPClusterDriver extends Driver{
+
+    /**
+       Constructor for MIPCluster processing -- valid Arguments are
+       "EMCal" and "HCal"
+    */
+    public MIPClusterDriver(String inString){ 
+
+	calType = inString; 
+	if ( calType != "EMCal" && calType != "HCal" && calType != "User" ) {
+	    throw new AssertionError("Wrong Calorimter Type Specified"); 
+	}
+
+	printInitialization(); 
+    }
+
+    private String calType = null; //"EMCal"; 
+    private String userTag = null; 
+    private String clusterName = null;// = "MIPCluster "+calType; 
+
+    private Vector<CalorimeterHit> nucleii = new Vector<CalorimeterHit>(); 
+    private boolean lUserNucleii = false; 
+    public void provideNucleii(Vector<CalorimeterHit> v){
+	nucleii = v; 
+	lUserNucleii = true; 
+    }
+
+    public void process(EventHeader event)
+    {
+	// First, we have to get the list of calorimeter hits from
+	// the event header
+	
+	List<CalorimeterHit> hits = null;
+
+	if ( calType == "EMCal" ) {
+	    List<CalorimeterHit>  barrelHits = event.get(CalorimeterHit.class, "EcalBarrHits");
+	    List<CalorimeterHit>  endcapHits = event.get(CalorimeterHit.class, "EcalEndcapHits");
+	    hits = new Vector<CalorimeterHit>();
+	    hits.addAll(barrelHits);
+	    hits.addAll(endcapHits);
+	} else if ( calType == "HCal" ) {
+	    List<CalorimeterHit>  barrelHits = event.get(CalorimeterHit.class, "HcalBarrHits");
+	    List<CalorimeterHit>  endcapHits = event.get(CalorimeterHit.class, "HcalEndcapHits");
+	    hits = new Vector<CalorimeterHit>();
+	    hits.addAll(barrelHits);
+	    hits.addAll(endcapHits);
+	} else if ( calType == "User" ) {
+	    if ( userTag == null ) {
+		throw new AssertionError("No userTag Defined"); 
+	    } else {
+		hits = event.get(CalorimeterHit.class, userTag);
+	    }
+	}
+
+	// Now we need to make the cluster builder which we'll use for
+	// this event only:
+
+	MIPClusterBuilder clusterBuilder = new MIPClusterBuilder(hits, hitTypes); 
+	clusterBuilder.setMinimumHitEnergy(eMin); 
+	clusterBuilder.setMaximumHitEnergy(eMax); 
+	clusterBuilder.setNumberOfSeedLayers(nSeedLayers); 
+	clusterBuilder.setDirectionAndFirstLayer(direction,firstLayer); 
+	if ( lUserNucleii ) { 
+	    clusterBuilder.provideNucleii(nucleii); 
+	}
+	clusterBuilder.setDebugMode(lDebug);
+	clusterBuilder.initialize(); 
+
+	// Find the MIPs:
+
+	List<Cluster> clusters = clusterBuilder.getMIPClusterList(); 
+
+	// Write them out. We might want to append them, so check for that:
+	
+	List<Cluster> outputList = null;
+	if (!lAppend) {
+	    outputList = clusters;
+	} else {
+	    outputList = event.get(Cluster.class, clusterName);
+	    if (outputList == null) {
+		// Can't append because no list => make new one, then append
+		outputList = new Vector<Cluster>();
+	    }
+	    // Append
+	    outputList.addAll(clusters);
+	}
+
+	int flags = 0; // What the hell are these magic flags for?
+	event.put(clusterName, outputList, Cluster.class, flags);
+    }
+    
+    /**
+       Set name for ClusterList 
+     */
+    public void setClusterName(String string){
+	clusterName = string; 
+	System.out.println("ClusterName: "+clusterName); 
+    }
+
+    /**
+       Set Tag for CalorimeterHits provided by user
+    */
+    public void setUserTag(String tag){
+	userTag = tag; 
+    }
+
+    private void printInitialization(){
+	System.out.println(""); 
+	System.out.println("MIPClusterBuilder v1.0 "+calType); 
+	System.out.println("----------------------"); 
+    }
+
+    private double eMin = 0.; 
+    private double eMax = 1000.; 
+    private int direction = 1; 
+    private int firstLayer = 0; 
+    private boolean lDebug = false; 
+    private boolean lAppend = false; 
+    private int nSeedLayers = 4; 
+
+    public void setNumberOfSeedLayers(int n){
+	nSeedLayers = n; 
+    }
+
+    public void setMinimumHitEnergy(double v){
+	eMin = v; 
+    }
+    public void setMaximumHitEnergy(double v){
+	eMax = v; 
+    }
+    public double getMinimumHitEnergy(){
+	return eMin; 
+    }
+    public double getMaximumHitEnergy(){
+	return eMax; 
+    }
+    public void setDirectionAndFirstLayer(int newDir, int newFL){
+	setDirection(newDir); 
+	setFirstLayer(newFL); 
+    }
+
+    private void setDirection(int i){
+	direction = i; 
+    }
+    private void setFirstLayer(int i){
+	firstLayer = i; 
+    }
+
+    public void setDebugMode(boolean b){
+	lDebug = b; 
+    }
+    public void setAppend(boolean b){
+	lAppend = b; 
+    }
+
+    private List<AbstractHitType> hitTypes; 
+    public void registerHitTypes(List<AbstractHitType> hT){
+	hitTypes = hT; 
+    }
+}

lcsim/src/org/lcsim/recon/cluster/mipfinder
SingleHit.java added at 1.1
diff -N SingleHit.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SingleHit.java	2 Jan 2006 21:45:19 -0000	1.1
@@ -0,0 +1,61 @@
+package org.lcsim.recon.cluster.mipfinder;
+
+import org.lcsim.event.CalorimeterHit;
+import java.util.Vector; 
+import org.lcsim.geometry.IDDecoder;
+import org.lcsim.geometry.CalorimeterIDDecoder;
+
+/**
+   Single Hit. Designed for use with
+   LCDG4 Geant files 
+   
+   
+   @author Wolfgang F. Mader ([log in to unmask])
+   @version $Id: SingleHit.java,v 1.1 2006/01/02 21:45:19 mcharles Exp $
+ 
+   Modification Log:
+   -- 07/22/2004 Version 1.0
+   -- 09/26/2005 Converted to org.lcsim by Mat
+*/
+
+public class SingleHit extends AbstractHitType{
+//
+// Constructor Summary
+//
+    public SingleHit(){
+	identifier = "singleHit"; 
+
+	if ( lWelcome ){
+	    System.out.println(identifier+" used in MIP reconstruction"); 
+	    lWelcome = false; 
+	}
+    }
+
+
+/**
+  * Check whether this hit is valid. For a SingleHit this means
+  * that there must be no neighbour hit (within 1 cell) in the same layer.
+  */
+    public boolean isValid(CalorimeterHit h, 
+			   HitCollection hc  ){
+	boolean lSingle = true; 
+
+        // Find all neighbouring cells:
+        int dLayer = 0;
+        int dU = 1;
+        int dV = 1;
+        CalorimeterIDDecoder id = (CalorimeterIDDecoder) h.getIDDecoder();
+        id.setID(h.getCellID());
+        long[] neighbours = id.getNeighbourIDs(dLayer, dU, dV);
+
+        for (int i=0; i<neighbours.length; i++ ) {
+	  CalorimeterHit hit = hc.find(neighbours[i]); 
+	  if ( hit != null ){
+            // There is a bad neighbour => not a valid single hit.
+            lSingle = false; 
+          }
+        }
+
+	return lSingle; 
+    }
+}
CVSspam 0.2.8