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>