Commit in lcsim/src/org/lcsim/recon/cluster/util on MAIN
HitNearBarrelEndcapBoundaryDecision.java+185added 1.1
MJC: A tool to check whether a hit is near the barrel/endcap boundary

lcsim/src/org/lcsim/recon/cluster/util
HitNearBarrelEndcapBoundaryDecision.java added at 1.1
diff -N HitNearBarrelEndcapBoundaryDecision.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ HitNearBarrelEndcapBoundaryDecision.java	13 Jul 2008 23:32:00 -0000	1.1
@@ -0,0 +1,185 @@
+package org.lcsim.recon.cluster.util;
+
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.util.decision.DecisionMakerSingle;
+import org.lcsim.recon.cluster.util.HitInECALDecision;
+
+import org.lcsim.event.*;
+import org.lcsim.util.*;
+import org.lcsim.detector.solids.*;
+import org.lcsim.detector.*;
+import org.lcsim.geometry.subdetector.*;
+
+/**
+ * Determine whether a hit is in the boundary region near the barrel/endcap interface.
+ *
+  * @version $Id: HitNearBarrelEndcapBoundaryDecision.java,v 1.1 2008/07/13 23:32:00 mcharles Exp $
+  * @author Mat Charles
+ */
+
+public class HitNearBarrelEndcapBoundaryDecision extends Driver implements DecisionMakerSingle<CalorimeterHit> 
+{
+    protected double m_cutEcal = 0.0;
+    protected double m_cutHcal = 0.0;
+    protected int m_barrelLayerRange = 0;
+
+    /** 
+     * Constructor takes cut-off distances for ECAL, HCAL as arguments, plus the number of
+     * layers in the barrel to look at.
+     *
+     * cutEcal : tolerance (in mm) for how far to look in the transverse direction from the edge in the ECAL.
+     * cutHcal : tolerance (in mm) for how far to look in the transverse direction from the edge in the HCAL.
+     * barrelLayerRange: how many layers (mininum 1) to check in the barrel.
+     */
+    public HitNearBarrelEndcapBoundaryDecision(double cutEcal, double cutHcal, int barrelLayerRange) {
+	m_cutEcal = cutEcal;
+	m_cutHcal = cutHcal;
+	m_barrelLayerRange = barrelLayerRange;
+    }
+
+    protected double m_ECAL_endcap_zmin;
+    protected double m_ECAL_endcap_zmax;
+    protected double m_HCAL_endcap_zmin;
+    protected double m_HCAL_endcap_zmax;
+    /**
+     * A couple of pieces of geometry information cannot be figured out on the
+     * fly, so we have to know them in advance.
+     */
+    public void initGeometry(EventHeader event) {
+        org.lcsim.geometry.Detector det = event.getDetector();
+        CylindricalCalorimeter endcapECAL = ((CylindricalCalorimeter) det.getSubdetectors().get("EMEndcap"));
+        CylindricalCalorimeter endcapHCAL = ((CylindricalCalorimeter) det.getSubdetectors().get("HADEndcap"));
+	m_ECAL_endcap_zmin = endcapECAL.getZMin();
+	m_ECAL_endcap_zmax = endcapECAL.getZMax();
+	m_HCAL_endcap_zmin = endcapHCAL.getZMin();
+	m_HCAL_endcap_zmax = endcapHCAL.getZMax();
+    }
+    
+    /**
+     * This class needs some geometry information which has to come from event.
+     * You can supply this with initGeometry(), or you can add the class as a
+     * Driver in which case it'll pick it up automatically.
+     */
+    public void process(EventHeader event) {
+	initGeometry(event);
+    }
+
+    /**
+     * Check whether the hit is near the boundary.
+     * 
+     * If hit is in the barrel, check whether its |z|
+     * co-ordinate is within [cut-off] of edge of barrel.
+     * If hit is in the endcap, check whether its r
+     * co-ordinate is within [cut-off] of outer edge of endcap.
+     */
+    public boolean valid(CalorimeterHit hit) {
+        org.lcsim.geometry.Subdetector subdet = hit.getSubdetector();
+	org.lcsim.geometry.IDDecoder id = hit.getIDDecoder();
+
+	// Check whether subdetector is barrel or endcap:
+	if (!subdet.isCalorimeter()) { throw new AssertionError("CalorimeterHit not from calorimeter!"); }
+	boolean isBarrel = subdet.isBarrel();
+	boolean isEndcap = subdet.isEndcap();
+	if (isBarrel && isEndcap) { throw new AssertionError("CalorimeterHit in barrel and endcap!"); }
+	if (!isBarrel && !isEndcap) { throw new AssertionError("CalorimeterHit neither in barrel nor endcap!"); }
+
+	// Figure out whether we're in the ECAL or the HCAL:
+	String subdetName = subdet.getName();
+	boolean isECAL = false;
+	if (isBarrel) {
+	    if (subdetName.compareTo("EMBarrel") == 0) {
+		isECAL = true;
+	    } else if (subdetName.compareTo("HADBarrel") == 0) {
+		isECAL = false;
+	    } else {
+		throw new AssertionError("Barrel calorimeter not recognized: "+subdetName);
+	    }
+	} else {
+	    if (subdetName.compareTo("EMEndcap") == 0) {
+		isECAL = true;
+	    } else if (subdetName.compareTo("HADEndcap") == 0) {
+		isECAL = false;
+	    } else {
+		throw new AssertionError("Endcap calorimeter not recognized: "+subdetName);
+	    }
+	}
+	// Record the cut (max distance allowed from edge to be considered in the border region):
+	double cutOff = m_cutEcal;
+	double endcap_zmin = m_ECAL_endcap_zmin;
+	double endcap_zmax = m_ECAL_endcap_zmax;
+	if (!isECAL) {
+	    cutOff = m_cutHcal;
+	    endcap_zmin = m_HCAL_endcap_zmin;
+	    endcap_zmax = m_HCAL_endcap_zmax;
+	}
+
+	// Now, what are the dimensions of the current subdetector?
+	IDetectorElement subDetectorElement = subdet.getDetectorElement();
+	IGeometryInfo subDetectorGeometry = null;
+	if (isBarrel) {
+	    // Barrel -- just one geometry:
+            subDetectorGeometry = subDetectorElement.getGeometry();
+        } else {
+            // Endcap -- extra level of indirection
+            IDetectorElement oneEndcap = subDetectorElement.getChildren().get(0);
+            subDetectorGeometry = oneEndcap.getGeometry();
+        }
+	ILogicalVolume subDetectorLogicalVolume = subDetectorGeometry.getLogicalVolume();
+	ISolid solidVolume = subDetectorLogicalVolume.getSolid();
+
+	// The way the detector is built is like this:
+	//
+	// ...-----------------------------------+
+	//                                       |
+	//                     Barrel            |
+	//                                       |
+	// ...-----------------------------------+  <-- rMin
+	//                            +----------+  <-- rMax
+	//                            |          |
+	//                            |  Endcap  |
+	//                            |          |
+	//                      zMin--^          ^--zMax
+	//
+	// 
+	// So for the ENDCAP, we are in the border region if r ~ rMax.
+	// 
+	// For the BARREL, we are in the border region if zMin <~ z <~ zMax AND r ~ rMin
+
+	if (solidVolume instanceof org.lcsim.detector.solids.Tube) {
+	    org.lcsim.detector.solids.Tube tubeVolume = (org.lcsim.detector.solids.Tube) solidVolume;
+	    double rMin = tubeVolume.getInnerRadius();
+	    double rMax = tubeVolume.getOuterRadius();
+	    double zHalfLength = tubeVolume.getZHalfLength();
+	    if (zHalfLength <= 0.0) { throw new AssertionError("zHalfLength = "+zHalfLength+" -- illegal value"); }
+	    double hitPos[] = hit.getPosition();
+	    if (isBarrel) {
+		// Barrel: Are we within the border region (in z)?
+		double hitModZ = Math.abs(hitPos[2]);
+		boolean inBorderRegionZ = (hitModZ <= endcap_zmax + cutOff) && (hitModZ >= endcap_zmin - cutOff);
+		// Barrel: Are we within the border region (in r)?
+		// This is a bit different because we're now dealing with a longitudinal
+		// segmentation (rather than transverse). So just check whether we're in the
+		// innermost layer.
+		int layer = getLayer(hit);
+		boolean inBorderRegionR = (layer < m_barrelLayerRange);
+		double hitR = Math.sqrt(hitPos[0]*hitPos[0] + hitPos[1]*hitPos[1]);
+		return (inBorderRegionZ && inBorderRegionR);
+	    } else {
+		// Endcap: Check how far we are from the edge (in r)
+		double hitR = Math.sqrt(hitPos[0]*hitPos[0] + hitPos[1]*hitPos[1]);
+		double distanceFromEdge = rMax - hitR;
+		return (distanceFromEdge <= cutOff);
+	    }
+	} else {
+	    // Don't know how to handle this geometry
+	    throw new AssertionError("Detector is not a tube!");
+	}	    
+    }
+
+    protected int getLayer(CalorimeterHit hit) {
+        org.lcsim.geometry.IDDecoder id = hit.getIDDecoder();
+        id.setID(hit.getCellID());
+        int layer = id.getLayer();
+        return layer;
+    }
+}
CVSspam 0.2.8