Print

Print


Author: [log in to unmask]
Date: Wed Dec  9 18:08:46 2015
New Revision: 4041

Log:
Merge nathan-dev back into trunk.  Should be exactly 2 files changed.  Svn merging takes longer than actually testing the code.

Modified:
    java/trunk/   (props changed)
    java/trunk/recon/src/main/java/org/hps/recon/particle/ReconParticleDriver.java
    java/trunk/recon/src/main/java/org/hps/recon/utils/TrackClusterMatcher.java

Modified: java/trunk/recon/src/main/java/org/hps/recon/particle/ReconParticleDriver.java
 =============================================================================
--- java/trunk/recon/src/main/java/org/hps/recon/particle/ReconParticleDriver.java	(original)
+++ java/trunk/recon/src/main/java/org/hps/recon/particle/ReconParticleDriver.java	Wed Dec  9 18:08:46 2015
@@ -6,6 +6,8 @@
 import hep.physics.vec.HepLorentzVector;
 import hep.physics.vec.VecOp;
 
+import java.io.FileWriter;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -16,7 +18,6 @@
 import org.hps.recon.tracking.CoordinateTransformations;
 import org.hps.recon.tracking.TrackUtils;
 import org.hps.recon.utils.TrackClusterMatcher;
-import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.ReconstructedParticle;
@@ -25,8 +26,8 @@
 import org.lcsim.event.base.BaseCluster;
 import org.lcsim.event.base.BaseReconstructedParticle;
 import org.lcsim.geometry.Detector;
+import org.lcsim.geometry.subdetector.HPSEcal3;
 import org.lcsim.util.Driver;
-import org.lcsim.geometry.subdetector.HPSEcal3;
 
 
 /**
@@ -50,6 +51,9 @@
     public static final int MOLLER_TOP = 0;
     public static final int MOLLER_BOT = 1;
     
+    // normalized cluster-track distance required for qualifying as a match:
+    private double MAXNSIGMAPOSITIONMATCH=30.0;
+
     HPSEcal3 ecal;
 
     /**
@@ -180,6 +184,15 @@
         this.trackCollectionNames = trackCollectionNames;
     }
 
+    /**
+     * Set the requirement on cluster-track position matching in terms of N-sigma.
+     * 
+     * @param nsigma
+     */
+    public void setNSigmaPositionMatch(double nsigma) {
+    	MAXNSIGMAPOSITIONMATCH=nsigma;
+    }
+    
         
     
     /**
@@ -235,15 +248,16 @@
         
         // Create a mapping of matched clusters to corresponding tracks.
         HashMap<Cluster, Track> clusterToTrack = new HashMap<Cluster,Track>();
-
+        
         // Loop through all of the track collections and try to match every
         // track to a cluster.  Allow a cluster to be matched to multiple 
         // tracks and use a probability (to be coded later) to determine what 
         // the best match is.
         // TODO: At some point, pull this out to it's own method
         for (List<Track> tracks : trackCollections) {
+       
             for (Track track : tracks) {
-
+            	
                 // Create a reconstructed particle to represent the track.
                 ReconstructedParticle particle = new BaseReconstructedParticle();
 
@@ -257,6 +271,9 @@
 
                 // Derive the charge of the particle from the track.
                 ((BaseReconstructedParticle) particle).setCharge(track.getCharge() * flipSign);
+
+                // initialize PID quality to a junk value:
+                ((BaseReconstructedParticle)particle).setGoodnessOfPid(-9999);
 
                 // Extrapolate the particle ID from the track. Positively
                 // charged particles are assumed to be positrons and those
@@ -267,36 +284,48 @@
                     ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(11, 0, 0, 0));
                 }
 
+                // normalized distance of the closest match:
+                double smallestNSigma=Double.MAX_VALUE;
+               
+                // try to find a matching cluster:
                 Cluster matchedCluster = null;
-
-                // Track the best matching cluster for the track.
-                // TODO: This should find the best match not just the first match.
-                clusterLoop:
                 for (Cluster cluster : clusters) {
-                    // Check if the cluster and track are a valid match.
-                    if (matcher.isMatch(cluster, track)) {
-
-                    	// Store the matched cluster to matched track.
-                    	clusterToTrack.put(cluster, track);
-                    	
-                        // Store the matched cluster.
-                        matchedCluster = cluster;
-
-                        // Since a match has been found, the loop can be
-                        // terminated.
-                        break clusterLoop;
+
+                    // normalized distance between this cluster and track:
+                    final double thisNSigma=matcher.getNSigmaPosition(cluster, particle);
+
+                    // ignore if matching quality doesn't make the cut:
+                    if (thisNSigma > MAXNSIGMAPOSITIONMATCH) continue;
+
+                    // ignore if we already found a cluster that's a better match:
+                    if (thisNSigma > smallestNSigma) continue;
+
+                    // we found a new best cluster candidate for this track:
+                    smallestNSigma = thisNSigma;
+                    matchedCluster = cluster;
+
+                    // prefer using GBL tracks to correct (later) the clusters, for some consistency:
+                    if (track.getType() >= 32 || !clusterToTrack.containsKey(matchedCluster)) {
+                    	  clusterToTrack.put(matchedCluster,track);
                     }
                 }
 
                 // If a cluster was found that matches the track...
                 if (matchedCluster != null) {
+
+                    // add cluster to the particle:
                     particle.addCluster(matchedCluster);
 
-                    int pid = particle.getParticleIDUsed().getPDG();
+                    // use pid quality to store track-cluster matching quality:
+                    ((BaseReconstructedParticle)particle).setGoodnessOfPid(smallestNSigma);
+                    
+                    // propogate pid to the cluster:
+                    final int pid = particle.getParticleIDUsed().getPDG();
                     if (Math.abs(pid) == 11) {
                         ((BaseCluster) matchedCluster).setParticleId(pid);
                     }
 
+                    // unmatched clusters will (later) be used to create photon particles:
                     unmatchedClusters.remove(matchedCluster);
                 }
 
@@ -306,42 +335,40 @@
         }
 
         // Iterate over the remaining unmatched clusters.
-        if (!unmatchedClusters.isEmpty()) {
-            for (Cluster unmatchedCluster : unmatchedClusters) {
-
-                // Create a reconstructed particle to represent the unmatched cluster.
-                ReconstructedParticle particle = new BaseReconstructedParticle();
-
-                // The particle is assumed to be a photon, since it did not leave a track.
-                ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(22, 0, 0, 0));
-
-                int pid = particle.getParticleIDUsed().getPDG();
-                if (Math.abs(pid) != 11) {
-                    ((BaseCluster) unmatchedCluster).setParticleId(pid);
-                }
-
-                // Add the cluster to the particle.
-                particle.addCluster(unmatchedCluster);
-
-                // Set the reconstructed particle properties based on the cluster properties.
-                ((BaseReconstructedParticle) particle).setCharge(0);
-
-                // Add the particle to the reconstructed particle list.
-                particles.add(particle);
-            }
+        for (Cluster unmatchedCluster : unmatchedClusters) {
+
+            // Create a reconstructed particle to represent the unmatched cluster.
+            ReconstructedParticle particle = new BaseReconstructedParticle();
+
+            // The particle is assumed to be a photon, since it did not leave a track.
+            ((BaseReconstructedParticle) particle).setParticleIdUsed(new SimpleParticleID(22, 0, 0, 0));
+
+            int pid = particle.getParticleIDUsed().getPDG();
+            if (Math.abs(pid) != 11) {
+                ((BaseCluster) unmatchedCluster).setParticleId(pid);
+            }
+
+            // Add the cluster to the particle.
+            particle.addCluster(unmatchedCluster);
+
+            // Set the reconstructed particle properties based on the cluster properties.
+            ((BaseReconstructedParticle) particle).setCharge(0);
+
+            // Add the particle to the reconstructed particle list.
+            particles.add(particle);
         }
 
         // Apply the corrections to the Ecal clusters using track information, if available
         for (Cluster cluster : clusters) {
             if (cluster.getParticleId() != 0) {
-            	if (clusterToTrack.containsKey(cluster)){
-            		Track matchedT = clusterToTrack.get(cluster);
-            		double ypos = TrackUtils.getTrackStateAtECal(matchedT).getReferencePoint()[2];
-            		ClusterUtilities.applyCorrections(ecal, cluster, ypos);
-            	}
-            	else {
-            		ClusterUtilities.applyCorrections(ecal, cluster);          		
-            	}
+                if (clusterToTrack.containsKey(cluster)){
+                    Track matchedT = clusterToTrack.get(cluster);
+                    double ypos = TrackUtils.getTrackStateAtECal(matchedT).getReferencePoint()[2];
+                    ClusterUtilities.applyCorrections(ecal, cluster, ypos);
+                }
+                else {
+                    ClusterUtilities.applyCorrections(ecal, cluster);          		
+                }
             }
         }
 
@@ -645,7 +672,7 @@
     // Beam size variables.
     // The beamsize array is in the tracking frame
     /* TODO  mg-May 14, 2014:  the the beam size from the conditions db...also beam position!  */
-    protected double[] beamSize = {0.001, 0.130, 0.050}; //rough estimate from harp scans during engineering run production running
+    protected double[] beamSize = {0.001, 0.2, 0.02};
     protected double bField;
 
     //  flipSign is a kludge...

Modified: java/trunk/recon/src/main/java/org/hps/recon/utils/TrackClusterMatcher.java
 =============================================================================
--- java/trunk/recon/src/main/java/org/hps/recon/utils/TrackClusterMatcher.java	(original)
+++ java/trunk/recon/src/main/java/org/hps/recon/utils/TrackClusterMatcher.java	Wed Dec  9 18:08:46 2015
@@ -1,8 +1,4 @@
 package org.hps.recon.utils;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
 
 import hep.aida.IAnalysisFactory;
 import hep.aida.IHistogram1D;
@@ -13,12 +9,17 @@
 import hep.physics.vec.BasicHep3Vector;
 import hep.physics.vec.Hep3Vector;
 
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hps.recon.tracking.CoordinateTransformations;
+import org.hps.recon.tracking.TrackUtils;
 import org.lcsim.event.Cluster;
+import org.lcsim.event.ReconstructedParticle;
 import org.lcsim.event.Track;
 import org.lcsim.event.TrackState;
 import org.lcsim.geometry.FieldMap;
-import org.hps.recon.tracking.CoordinateTransformations;
-import org.hps.recon.tracking.TrackUtils;
 
 /**
  * Utility used to determine if a track and cluster are matched.
@@ -63,6 +64,55 @@
     private double topClusterTrackMatchDeltaYHigh = 28; // mm 
     private double bottomClusterTrackMatchDeltaYLow = -28; // mm 
     private double bottomClusterTrackMatchDeltaYHigh = 24; // mm 
+
+    /**
+     * Rafo's parameterization of cluster-seed x/y position residuals as function of energy.
+     * 
+     * Derived using GBL/seed tracks, non-analytic extrapolation, uncorrected cluster positions,
+     * and EngRun2015-Nominal-v3-4-fieldmap detector.
+     * 
+     *  f = p0+e*(p1+e*(p2+e*(p3+e*(p4+e*p5))))
+     */
+    private static final double dxMeanTopPosiGBL[] = { 6.67414,-9.57296, 5.70647, 27.4523,-28.1103,-9.11424 };
+    private static final double dxSigmTopPosiGBL[] = { 52.6437,-478.805, 1896.73,-3761.48, 3676.77,-1408.31 };
+    private static final double dxMeanBotPosiGBL[] = { 4.13802, 15.8887,-74.2844,-9.78944, 308.541,-287.668 };
+    private static final double dxSigmBotPosiGBL[] = { 37.6513,-294.851, 1002.15,-1639.08, 1228.02,-308.754 };
+    
+    private static final double dxMeanTopElecGBL[] = {-1.6473,  5.58701, 25.3977,-17.1523,-121.025, 145.969 };
+    private static final double dxSigmTopElecGBL[] = { 48.7018,-423.599, 1592.66,-2959.99, 2668.97,-919.876 };
+    private static final double dxMeanBotElecGBL[] = {-6.63558, 83.7763,-460.451, 1275.63,-1702.83, 873.913 };
+    private static final double dxSigmBotElecGBL[] = { 47.0029,-411.784, 1586.52,-3083.37, 2985.58,-1145.53 };
+    
+    private static final double dyMeanTopPosiGBL[] = { 0.71245, 5.57585,-6.50267,-8.21688, 39.8607,-43.9661 };
+    private static final double dySigmTopPosiGBL[] = { 33.0213,-275.174, 1168.77,-2642.34, 3045.52,-1406.21 };
+    private static final double dyMeanBotPosiGBL[] = {-5.532,   74.9738,-383.972, 977.849,-1250.28, 637.75  };
+    private static final double dySigmBotPosiGBL[] = { 19.019, -83.9253, 133.813, 119.883,-546.951, 405.207 };
+    
+    private static final double dyMeanTopElecGBL[] = { 2.88498,-20.4101, 62.9689, 25.6386,-259.957, 207.145 };
+    private static final double dySigmTopElecGBL[] = { 8.65583, 120.676,-1166.43, 3811.72,-5383.19, 2787.42 };
+    private static final double dyMeanBotElecGBL[] = {-9.02276, 112.329,-489.761, 953.037,-829.96,  260.772 };
+    private static final double dySigmBotElecGBL[] = { 23.4856,-108.19,  158.7,   189.261,-682.034, 459.15  };
+
+    private static final double dxMeanTopPosiSeed[] ={ 11.6245,-28.5061, 13.0332, 59.9465,-21.1014,-63.6126 };
+    private static final double dxSigmTopPosiSeed[] ={ 61.5911,-540.596, 2077.22,-3973.22, 3704.45,-1332.07 };
+    private static final double dxMeanBotPosiSeed[] ={ 4.53394, 11.3773,-63.7127,-2.81629, 273.868,-264.709 };
+    private static final double dxSigmBotPosiSeed[] ={ 48.3163,-409.249, 1590.36,-3212.85, 3326.04,-1402.3  };
+    
+    private static final double dxMeanTopElecSeed[] ={ 2.14163,-20.8713, 76.3054,  34.894,-340.272,  295.24 };
+    private static final double dxSigmTopElecSeed[] ={ 48.585, -385.166, 1320.26,-2157.45, 1581.06,-366.012 };
+    private static final double dxMeanBotElecSeed[] ={-3.44302, 12.4687, 4.09878,-30.0057,-13.3151, 40.2707 };
+    private static final double dxSigmBotElecSeed[] ={ 48.4089,-385.494, 1341.37,-2271.52, 1814.02,-526.555 };
+
+    private static final double dyMeanTopPosiSeed[] ={-0.127741,10.4944, -18.242,-12.9155, 81.0116,-73.9773 };
+    private static final double dySigmTopPosiSeed[] ={ 37.3097, -357.55, 1607.03,-3709.55, 4282.36,-1957.91 };
+    private static final double dyMeanBotPosiSeed[] ={ 2.24392,-55.2003,  405.04,-1250.64, 1731.47,-887.262 };
+    private static final double dySigmBotPosiSeed[] ={ 25.5776,-199.731,  754.59,-1408.72, 1240.36,-400.912 };
+
+    private static final double dyMeanTopElecSeed[] ={ 3.25429,-24.0858, 69.0145, 34.1213,-297.752, 239.939 };
+    private static final double dySigmTopElecSeed[] ={ 19.9111,-53.2699,-261.915,  1593.2,-2774.01, 1605.54 };
+    private static final double dyMeanBotElecSeed[] ={-7.72963, 98.1346, -427.91, 840.225,-751.188, 250.792 };
+    private static final double dySigmBotElecSeed[] ={ 21.7909,-85.4757,-56.9423, 977.522,-1902.05, 1137.92 };
+
 
     /**
      * Z position to start extrapolation from
@@ -194,10 +244,101 @@
             tPos = new BasicHep3Vector(trackStateAtEcal.getReferencePoint());
             tPos = CoordinateTransformations.transformVectorToDetector(tPos);
         }
+       
+        return Math.sqrt(Math.pow(cPos.x()-tPos.x(),2)+Math.pow(cPos.y()-tPos.y(),2));
+    }
+    
+    /**
+     * Calculate #sigma between cluster-track x/y position at calorimeter.
+     *
+     * Based on Rafo's parameterizations.  Requires non-analytic extrapolation
+     * and uncorrected cluster positions.
+     * 
+     * @param cluster = position-uncorrected cluster
+     * @param track
+     *
+     * @return #sigma between cluster and track positions
+     */
+    public double getNSigmaPosition(Cluster cluster,ReconstructedParticle particle) {
+
+        if (particle.getTracks().size()<1) return Double.MAX_VALUE;
+    	  Track track=particle.getTracks().get(0);
+    	
+        if (this.useAnalyticExtrapolator)
+            throw new RuntimeException("This is to be used with non-analytic extrapolator only.");
+
+        // Get the cluster position:
+        Hep3Vector cPos = new BasicHep3Vector(cluster.getPosition());
+
+        // whether track is in top half of detector:
+        final boolean isTopTrack = track.getTrackStates().get(0).getTanLambda() > 0;
+
+        // ignore if track and cluster in different halves:
+        if (isTopTrack != cPos.y()>0) return Double.MAX_VALUE;
+
+        // Get the extrapolated track position at the calorimeter:
+        TrackState trackStateAtEcal = TrackUtils.getTrackStateAtECal(track);
+        Hep3Vector tPos = new BasicHep3Vector(trackStateAtEcal.getReferencePoint());
+        tPos = CoordinateTransformations.transformVectorToDetector(tPos);
+
+        // whether it's a GBL track:
+        final boolean isGBL = track.getType() >= 32;
+       
+        // choose which parameterization of mean and sigma to use:
+        double dxMean[],dyMean[],dxSigm[],dySigm[];
+        if (particle.getCharge()>0) {
+            if (isTopTrack) {
+                dxMean = isGBL ? dxMeanTopPosiGBL : dxMeanTopPosiSeed;
+                dxSigm = isGBL ? dxSigmTopPosiGBL : dxSigmTopPosiSeed;
+                dyMean = isGBL ? dyMeanTopPosiGBL : dyMeanTopPosiSeed;
+                dySigm = isGBL ? dySigmTopPosiGBL : dySigmTopPosiSeed;
+            }
+            else {
+                dxMean = isGBL ? dxMeanBotPosiGBL : dxMeanBotPosiSeed;
+                dxSigm = isGBL ? dxSigmBotPosiGBL : dxSigmBotPosiSeed;
+                dyMean = isGBL ? dyMeanBotPosiGBL : dyMeanBotPosiSeed;
+                dySigm = isGBL ? dySigmBotPosiGBL : dySigmBotPosiSeed;
+            }
+        }
+        else if (particle.getCharge()<0) {
+            if (isTopTrack) {
+                dxMean = isGBL ? dxMeanTopElecGBL : dxMeanTopElecSeed;
+                dxSigm = isGBL ? dxSigmTopElecGBL : dxSigmTopElecSeed;
+                dyMean = isGBL ? dyMeanTopElecGBL : dyMeanTopElecSeed;
+                dySigm = isGBL ? dySigmTopElecGBL : dySigmTopElecSeed;
+            }
+            else {
+                dxMean = isGBL ? dxMeanBotElecGBL : dxMeanBotElecSeed;
+                dxSigm = isGBL ? dxSigmBotElecGBL : dxSigmBotElecSeed;
+                dyMean = isGBL ? dyMeanBotElecGBL : dyMeanBotElecSeed;
+                dySigm = isGBL ? dySigmBotElecGBL : dySigmBotElecSeed;
+            }
+        }
+        else return Double.MAX_VALUE;
+
+        // get particle energy:
+        Hep3Vector p3 = new BasicHep3Vector(track.getTrackStates().get(0).getMomentum());
+        p3 = CoordinateTransformations.transformVectorToDetector(p3);
+        double ee = p3.magnitude();
         
-        return Math.sqrt(Math.pow(cPos.x()-tPos.x(),2)+Math.pow(cPos.y()-tPos.y(),2));
-    }
-    
+        // Rafo's parameterization isn't measured above 650 MeV/c but expected to be constant:
+        if (ee > 0.65) ee=0.65;
+
+        // calculate measured mean and sigma of deltaX and deltaY for this energy:
+        double aDxMean=0,aDxSigm=0,aDyMean=0,aDySigm=0;
+        for (int ii=dxMean.length-1; ii>=0; ii--) aDxMean = dxMean[ii] + ee*aDxMean;
+        for (int ii=dxSigm.length-1; ii>=0; ii--) aDxSigm = dxSigm[ii] + ee*aDxSigm;
+        for (int ii=dyMean.length-1; ii>=0; ii--) aDyMean = dyMean[ii] + ee*aDyMean;
+        for (int ii=dySigm.length-1; ii>=0; ii--) aDySigm = dySigm[ii] + ee*aDySigm;
+
+        // calculate nSigma between track and cluster:
+        final double nSigmaX = (cPos.x() - tPos.x() - aDxMean) / aDxSigm;
+        final double nSigmaY = (cPos.y() - tPos.y() - aDyMean) / aDySigm;
+        return Math.sqrt(nSigmaX*nSigmaX + nSigmaY*nSigmaY);
+        //return Math.sqrt( 1 / ( 1/nSigmaX/nSigmaX + 1/nSigmaY/nSigmaY ) );
+    }
+
+
     /**
      * Determine if a track is matched to a cluster. Currently, this is
      * determined by checking that the track and cluster are within the same
@@ -388,4 +529,16 @@
             e.printStackTrace();
         }
     }
+
+    /**
+     * Class to store track-cluster matching qualities.
+     */
+    public class TrackClusterMatch {
+    	private double nSigmaPositionMatch=Double.MAX_VALUE;
+    	public TrackClusterMatch(ReconstructedParticle pp, Cluster cc) {
+    	    nSigmaPositionMatch = getNSigmaPosition(cc,pp);
+    	}
+    	public double getNSigmaPositionMatch() { return nSigmaPositionMatch; }
+    }
+    
 }