lcsim/src/org/lcsim/recon/cluster/util
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;
+ }
+}