Print

Print


Author: [log in to unmask]
Date: Thu Oct  8 18:09:02 2015
New Revision: 3817

Log:
Added Calorimeter-only cuts so we can study tracking

Modified:
    java/trunk/recon/src/main/java/org/hps/recon/filtering/MollerCandidateFilter.java
    java/trunk/steering-files/src/main/resources/org/hps/steering/production/MollerCandidateFilter.lcsim

Modified: java/trunk/recon/src/main/java/org/hps/recon/filtering/MollerCandidateFilter.java
 =============================================================================
--- java/trunk/recon/src/main/java/org/hps/recon/filtering/MollerCandidateFilter.java	(original)
+++ java/trunk/recon/src/main/java/org/hps/recon/filtering/MollerCandidateFilter.java	Thu Oct  8 18:09:02 2015
@@ -1,18 +1,30 @@
 package org.hps.recon.filtering;
 
 import static java.lang.Math.abs;
+import java.util.ArrayList;
 import java.util.List;
+import org.hps.conditions.database.DatabaseConditionsManager;
 import org.hps.record.epics.EpicsData;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.ReconstructedParticle;
+import org.lcsim.geometry.Detector;
+import org.lcsim.geometry.subdetector.HPSEcal3;
+import org.lcsim.geometry.subdetector.HPSEcal3.NeighborMap;
 
 /**
- * Class to strip off Moller candidates. Currently defined as: e- e- events with
- * tracks matched to clusters. Neither electron can be a full-energy candidate
- * (momentum less than _fullEnergyCut [0.85GeV]) but the momentum sum must be
- * consistent with the beam energy (greater than _mollerMomentumSumMin and less
- * than _mollerMomentumSumMax). The Ecal cluster times must be within _timingCut
+ * Class to strip off Moller candidates.
+ *
+ * Currently the tight selection is defined as: e- e- events with tracks matched
+ * to each cluster. Neither electron can be a full-energy candidate (momentum
+ * less than _fullEnergyCut [0.85GeV]) but the momentum sum must be consistent
+ * with the beam energy (greater than _mollerMomentumSumMin and less than
+ * _mollerMomentumSumMax). The Ecal cluster times must be within _timingCut
  * [2.5ns] of each other.
+ * 
+ * One can also set calorimeter-only cuts if one is interested in understanding
+ * tracking issues.
  *
  * @author Norman A Graf
  *
@@ -21,14 +33,41 @@
 public class MollerCandidateFilter extends EventReconFilter
 {
 
+    private boolean _keepEpicsDataEvents = false;
+
+    // the following are for the tight cuts
+    private boolean _tight = false;
     private String _mollerCandidateCollectionName = "TargetConstrainedMollerCandidates";
     private double _mollerMomentumSumMin = 0.85;
     private double _mollerMomentumSumMax = 1.3;
     private double _fullEnergyCut = 0.85;
-    private double _clusterTimingCut = 2.5;
-
-    private boolean _tight = false;
-    private boolean _keepEpicsDataEvents = false;
+    //the following are for the calorimeter cluster cuts
+    private String _mollerCandidateClusterCollectionName = "EcalClustersCorr";
+    //first, single cluster cuts
+    private double _clusterTimeLo = 40;
+    private double _clusterTimeHi = 48;
+    private double _clusterMaxX = 0.;
+    // pair cuts
+    private double _clusterXSumLo = -175.;
+    private double _clusterXSumHi = -145.;
+    private double _clusterXDiffLo = -80.;
+    private double _clusterXDiffHi = 80.;
+    private double _clusterESumLo = 0.85;
+    private double _clusterESumHi = 1.1;
+    private double _clusterEDiffLo = -0.3;
+    private double _clusterEDiffHi = 0.3;
+
+    private HPSEcal3 ecal;
+    private NeighborMap neighborMap;
+
+    private double _clusterDeltaTimeCut = 2.5;
+
+    @Override
+    protected void detectorChanged(Detector detector)
+    {
+        ecal = (HPSEcal3) DatabaseConditionsManager.getInstance().getDetectorObject().getSubdetector("Ecal");
+        neighborMap = ecal.getNeighborMap();
+    }
 
     @Override
     protected void process(EventHeader event)
@@ -42,64 +81,129 @@
                 return;
             }
         }
-        if (!event.hasCollection(ReconstructedParticle.class, _mollerCandidateCollectionName)) {
-            skipEvent();
-        }
-        List<ReconstructedParticle> mollerCandidates = event.get(ReconstructedParticle.class, _mollerCandidateCollectionName);
-        if (mollerCandidates.size() == 0) {
-            skipEvent();
-        }
-
-        // tight requires ONLY ONE real vertex fit 
+        // tight requires two electron final state particles with a vertex fit 
         if (_tight) {
-            if (mollerCandidates.size() != 2) {
+            if (!event.hasCollection(ReconstructedParticle.class, _mollerCandidateCollectionName)) {
                 skipEvent();
             }
-        }
-
-        for (ReconstructedParticle rp : mollerCandidates) {
-
-            ReconstructedParticle e1 = null;
-            ReconstructedParticle e2 = null;
-
-            List<ReconstructedParticle> electrons = rp.getParticles();
-            if (electrons.size() != 2) {
+            List<ReconstructedParticle> mollerCandidates = event.get(ReconstructedParticle.class, _mollerCandidateCollectionName);
+            if (mollerCandidates.size() == 0) {
                 skipEvent();
             }
-            // require both electrons to be associated with an ECal cluster
-            e1 = electrons.get(0);
-            if (e1.getClusters().size() == 0) {
+            for (ReconstructedParticle rp : mollerCandidates) {
+                ReconstructedParticle e1 = null;
+                ReconstructedParticle e2 = null;
+                List<ReconstructedParticle> electrons = rp.getParticles();
+                if (electrons.size() != 2) {
+                    skipEvent();
+                }
+                // require both electrons to be associated with an ECal cluster
+                e1 = electrons.get(0);
+                if (e1.getClusters().size() == 0) {
+                    skipEvent();
+                }
+                e2 = electrons.get(1);
+                if (e2.getClusters().size() == 0) {
+                    skipEvent();
+                }
+                // remove full energy electrons
+                double p1 = e1.getMomentum().magnitude();
+                if (p1 > _fullEnergyCut) {
+                    skipEvent();
+                }
+                double p2 = e2.getMomentum().magnitude();
+                if (p2 > _fullEnergyCut) {
+                    skipEvent();
+                }
+                // require momentum sum to be approximately the beam energy
+                double pSum = p1 + p2;
+                if (pSum < _mollerMomentumSumMin || pSum > _mollerMomentumSumMax) {
+                    skipEvent();
+                }
+                // calorimeter cluster timing cut
+                // first CalorimeterHit in the list is the seed crystal
+                double t1 = e1.getClusters().get(0).getCalorimeterHits().get(0).getTime();
+                double t2 = e2.getClusters().get(0).getCalorimeterHits().get(0).getTime();
+                if (abs(t1 - t2) > _clusterDeltaTimeCut) {
+                    skipEvent();
+                }
+            }
+        } // end of tight selection cuts
+        else // apply only calorimeter-based cuts
+        {
+            if (!event.hasCollection(Cluster.class, _mollerCandidateClusterCollectionName)) {
                 skipEvent();
             }
-            e2 = electrons.get(1);
-            if (e2.getClusters().size() == 0) {
+            List<Cluster> clusters = event.get(Cluster.class, _mollerCandidateClusterCollectionName);
+            List<Cluster> goodClusters = new ArrayList<Cluster>();
+            for (Cluster c : clusters) {
+                // check that cluster is on electron side
+                if (c.getPosition()[0] > _clusterMaxX) {
+                    continue;
+                }
+                // check that cluster is in time window
+                CalorimeterHit seedHit = c.getCalorimeterHits().get(0);
+                double t = seedHit.getTime();
+                if (t < _clusterTimeLo || t > _clusterTimeHi) {
+                    continue;
+                }
+                // remove edge clusters
+                int nNeighbors = neighborMap.get(seedHit.getCellID()).size();
+                if (nNeighbors < 8) {
+                    continue;
+                }
+            } // end of loop looking for good clusters
+            if (goodClusters.size() < 2) {
                 skipEvent();
             }
-            // remove full energy electrons
-            double p1 = e1.getMomentum().magnitude();
-            if (p1 > _fullEnergyCut) {
+            // should now have at least two good clusters, start looking at pairs
+            boolean goodPair = false;
+            out:
+            for (int i = 0; i < goodClusters.size() - 1; ++i) {
+                for (int j = i + 1; j < goodClusters.size(); ++j) {
+                    Cluster c1 = goodClusters.get(i);
+                    Cluster c2 = goodClusters.get(j);
+                    double[] pos1 = c1.getPosition();
+                    double[] pos2 = c2.getPosition();
+                    // require clusters to be on opposite sides of y=0 (top/bottom)
+                    if (pos1[1] * pos2[1] > 0) {
+                        continue;
+                    }
+                    // cut on x position sum
+                    if (pos1[0] + pos2[0] < _clusterXSumLo || pos1[0] + pos2[0] > _clusterXSumHi) {
+                        continue;
+                    }
+                    // cut on x position diff
+                    // TODO resolve this source of bias (should be abs)
+                    if (pos1[0] - pos2[0] < _clusterXDiffLo || pos1[0] - pos2[0] > _clusterXDiffHi) {
+                        continue;
+                    }
+                    // require energy sum to be close to beam energy
+                    double e1 = c1.getEnergy();
+                    double e2 = c2.getEnergy();
+                    if (e1 + e2 < _clusterESumLo || e1 + e2 > _clusterESumHi) {
+                        continue;
+                    }
+                    // require energy difference to be small
+                    // TODO resolve this source of bias (should be abs)
+                    if (e1 - e2 < _clusterEDiffLo || e1 - e2 > _clusterEDiffHi) {
+                        continue;
+                    }
+                    // require both cluster times to be the same
+                    double t1 = c1.getCalorimeterHits().get(0).getTime();
+                    double t2 = c2.getCalorimeterHits().get(0).getTime();
+                    if (abs(t1 - t2) > _clusterDeltaTimeCut) {
+                        continue;
+                    }
+                    // if we got here we have a good pair
+                    goodPair = true;
+                    break out;
+                } // end of j loop
+            } // end of i loop
+            if (!goodPair) {
                 skipEvent();
             }
-            double p2 = e2.getMomentum().magnitude();
-            if (p2 > _fullEnergyCut) {
-                skipEvent();
-            }
-
-            // require momentum sum to be approximately the beam energy
-            double pSum = p1 + p2;
-            if (pSum < _mollerMomentumSumMin || pSum > _mollerMomentumSumMax) {
-                skipEvent();
-            }
-
-            // calorimeter cluster timing cut
-            // first CalorimeterHit in the list is the seed crystal
-            double t1 = e1.getClusters().get(0).getCalorimeterHits().get(0).getTime();
-            double t2 = e2.getClusters().get(0).getCalorimeterHits().get(0).getTime();
-
-            if (abs(t1 - t2) > _clusterTimingCut) {
-                skipEvent();
-            }
-        }
+        }// end of calorimeter-only selection block
         incrementEventPassed();
     }
 
@@ -108,9 +212,9 @@
      *
      * @param d
      */
-    public void setClusterTimingCut(double d)
-    {
-        _clusterTimingCut = d;
+    public void setClusterDeltaTimeCut(double d)
+    {
+        _clusterDeltaTimeCut = d;
     }
 
     /**
@@ -164,7 +268,7 @@
     {
         _tight = b;
     }
-    
+
     /**
      * Setting this true keeps ALL events containing EPICS data
      *
@@ -174,4 +278,131 @@
     {
         _keepEpicsDataEvents = b;
     }
+
+    // Calorimeter-only selection cuts
+    /**
+     * Name of Moller Candidate Calorimeter Cluster Collection Name
+     *
+     * @param s
+     */
+    public void setMollerCandidateClusterCollectionName(String s)
+    {
+        _mollerCandidateClusterCollectionName = s;
+    }
+
+    // Individual Cluster selection cuts
+    /**
+     * Minimum value for the Cluster time [ns]
+     *
+     * @param d
+     */
+    public void setClusterTimeLo(double d)
+    {
+        _clusterTimeLo = d;
+    }
+
+    /**
+     * Maximum value for the Cluster time [ns]
+     *
+     * @param d
+     */
+    public void setClusterTimeHi(double d)
+    {
+        _clusterTimeHi = d;
+    }
+
+    // position
+    /**
+     * Maximum value for the Cluster x position [mm]
+     *
+     * @param d
+     */
+    public void setClusterMaxX(double d)
+    {
+        _clusterMaxX = d;
+    }
+
+    // Cluster Pair selection cuts
+    //position
+    /**
+     * Minimum value for the Cluster x position sum [mm]
+     *
+     * @param d
+     */
+    public void setClusterXSumLo(double d)
+    {
+        _clusterXSumLo = d;
+    }
+
+    /**
+     * Maximum value for the Cluster x position sum [mm]
+     *
+     * @param d
+     */
+    public void setClusterXSumHi(double d)
+    {
+        _clusterXSumHi = d;
+    }
+
+    /**
+     * Minimum value for the Cluster x position difference [mm]
+     *
+     * @param d
+     */
+    public void setClusterXDiffLo(double d)
+    {
+        _clusterXDiffLo = d;
+    }
+
+    /**
+     * Maximum value for the Cluster x position difference [mm]
+     *
+     * @param d
+     */
+    public void setClusterXDiffHi(double d)
+    {
+        _clusterXDiffHi = d;
+    }
+
+    // energy
+    /**
+     * Minimum value for the Cluster Energy sum [mm]
+     *
+     * @param d
+     */
+    public void setClusterESumLo(double d)
+    {
+        _clusterESumLo = d;
+    }
+
+    /**
+     * Maximum value for the Cluster Energy sum [mm]
+     *
+     * @param d
+     */
+    public void setClusterESumHi(double d)
+    {
+        _clusterESumHi = d;
+    }
+
+    /**
+     * Minimum value for the Cluster Energy difference [mm]
+     *
+     * @param d
+     */
+    public void setClusterEDiffLo(double d)
+    {
+        _clusterEDiffLo = d;
+    }
+
+    /**
+     * Maximum value for the Cluster Energy difference [mm]
+     *
+     * @param d
+     */
+    public void setClusterEDiffHi(double d)
+    {
+        _clusterEDiffHi = d;
+    }
+
 }

Modified: java/trunk/steering-files/src/main/resources/org/hps/steering/production/MollerCandidateFilter.lcsim
 =============================================================================
--- java/trunk/steering-files/src/main/resources/org/hps/steering/production/MollerCandidateFilter.lcsim	(original)
+++ java/trunk/steering-files/src/main/resources/org/hps/steering/production/MollerCandidateFilter.lcsim	Thu Oct  8 18:09:02 2015
@@ -24,6 +24,8 @@
         <!-- Driver to strip events -->
        <driver name="StripEvent"
                 type="org.hps.recon.filtering.MollerCandidateFilter">
+              <!-- Setting the tight constraint requires two electrons (track+cluster) -->
+              <tightConstraint>true</tightConstraint>
               <!-- Name of the Moller Candidate Collection of ReconstriuctedParticles -->
               <mollerCandidateCollectionName>TargetConstrainedMollerCandidates</mollerCandidateCollectionName>
               <!-- Maximum momentum of each electron, used to remove full energy electrons -->
@@ -32,8 +34,35 @@
               <mollerMomentumSumMin>0.85</mollerMomentumSumMin>
               <!-- Sum of the two electron momenta should equal the beam energy, this is the high cut -->
               <mollerMomentumSumMax>1.3</mollerMomentumSumMax>
+              <!-- Following is for the calorimeter-only cuts -->
+              <!-- Name of Moller Candidate Calorimeter Cluster Collection Name-->
+              <mollerCandidateClusterCollectionName > "EcalClustersCorr" </mollerCandidateClusterCollectionName>
+              <!-- Minimum value for the Cluster time [ns]-->
+              <clusterTimeLo >40. </clusterTimeLo>
+              <!-- Maximum value for the Cluster time [ns]-->
+              <clusterTimeHi > 48. </clusterTimeHi>
+              <!-- Maximum value for the Cluster x position [mm]-->
+              <clusterMaxX > 0. </clusterMaxX>
+              <!-- Cluster Pair cuts -->
+              <!-- Minimum value for the Cluster x position sum [mm]-->
+              <clusterXSumLo > -175. </clusterXSumLo>
+              <!-- Maximum value for the Cluster x position sum [mm]-->
+              <clusterXSumHi > -145. </clusterXSumHi>
+              <!-- Minimum value for the Cluster x position difference [mm]-->
+              <clusterXDiffLo > -80. </clusterXDiffLo>
+              <!-- Maximum value for the Cluster x position difference [mm]-->
+              <clusterXDiffHi > 80. </clusterXDiffHi>
+              <!-- Minimum value for the Cluster Energy sum [mm]-->
+              <clusterESumLo > 0.85 </clusterESumLo>
+              <!-- Maximum value for the Cluster Energy sum [mm]-->
+              <clusterESumHi > 1.1 </clusterESumHi>
+              <!-- Minimum value for the Cluster Energy difference [mm]-->
+              <clusterEDiffLo > -0.3 </clusterEDiffLo>
+              <!-- Maximum value for the Cluster Energy difference [mm]-->
+              <clusterEDiffHi > 0.3 </clusterEDiffHi>
+
               <!-- Maximum difference in the ECal cluster times -->
-              <clusterTimingCut>2.5</clusterTimingCut>
+              <clusterDeltaTimeCut>2.5</clusterDeltaTimeCut>
               <!-- Setting this true keeps ALL events containing EPICS data -->
               <keepEpicsDataEvents>true</keepEpicsDataEvents>
         </driver>