Print

Print


Commit in lcsim/src/org/lcsim/recon/tracking/seedtracker on MAIN
SortLayers.java+51added 1.1
ConfirmerExtender.java+209-721.15 -> 1.16
+260-72
1 added + 1 modified, total 2 files
Modified confirm/extend algorithm to speed up tracking for high occupancy events.

lcsim/src/org/lcsim/recon/tracking/seedtracker
SortLayers.java added at 1.1
diff -N SortLayers.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SortLayers.java	28 Feb 2011 19:07:57 -0000	1.1
@@ -0,0 +1,51 @@
+/*
+ * SortLayers.java
+ *
+ * Created on February 23, 2011, 17:05 PM
+ *
+ */
+
+package org.lcsim.recon.tracking.seedtracker;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.lcsim.fit.helicaltrack.HelicalTrackHit;
+
+/**
+ * Comparator used to sort layers by numbers of hits in the layer in
+ * ascending order (i.e., layer with fewest hits is first).
+ *
+ * @author Richard Partridge
+ * @version 1.0
+ */
+public class SortLayers implements Comparator<SeedLayer> {
+
+    private Map<SeedLayer, List<HelicalTrackHit>> _lyrmap;
+
+    /**
+     * SortLayers constructor.
+     *
+     * @param lyrmap map that stores list of hits keyed by layer
+     */
+    public SortLayers(Map<SeedLayer, List<HelicalTrackHit>> lyrmap) {
+
+        _lyrmap = lyrmap;
+    }
+
+    /**
+     * Comparison method that returns 1 if layer b has fewer hits than layer a.
+     *
+     * @param a
+     * @param b
+     * @return
+     */
+    public int compare(SeedLayer a, SeedLayer b) {
+        int na = _lyrmap.get(a).size();
+        int nb = _lyrmap.get(b).size();
+        if (na > nb) return 1;
+        if (na < nb) return -1;
+        return 0;
+    }
+}
\ No newline at end of file

lcsim/src/org/lcsim/recon/tracking/seedtracker
ConfirmerExtender.java 1.15 -> 1.16
diff -u -r1.15 -r1.16
--- ConfirmerExtender.java	19 Jan 2011 20:44:04 -0000	1.15
+++ ConfirmerExtender.java	28 Feb 2011 19:07:57 -0000	1.16
@@ -1,22 +1,30 @@
 /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
+ * ConfirmerExtender.java
  */
 package org.lcsim.recon.tracking.seedtracker;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 
-import org.lcsim.event.MCParticle;
+import org.lcsim.fit.helicaltrack.HelicalTrackFit;
 import org.lcsim.fit.helicaltrack.HelicalTrackFitter.FitStatus;
 import org.lcsim.fit.helicaltrack.HelicalTrackHit;
 import org.lcsim.recon.tracking.seedtracker.diagnostic.ISeedTrackerDiagnostics;
 
 /**
+ * The ConfirmerExtender class attempts to add hits to an input seed.  While the
+ * algorithms used for the confirm and extend phases are identical, there are
+ * small differences in procedures when there are no more tracker layers to check.
+ * The confirm phase simply outputs a list of SeedCandidates that have at least
+ * the minimum number of confirm hits added to the track.  The extend phases
+ * completes track finding and imposes the merge criteria to eliminate inferior
+ * track candidates when a pair of candidates shares more than one hit.
  *
- * @author cozzy
+ * @author cozzy, Richard Partridge
  */
 public class ConfirmerExtender {
 
@@ -25,6 +33,8 @@
         CONFIRM,
         EXTEND;
     }
+    private int _nfit;
+    private int _maxfit = 1000000000;  // initialize maximum number of fits to 10^9
     private HitManager _hmanager;
     private HelixFitter _fitter;
     private MergeSeedLists _merger;
@@ -32,13 +42,10 @@
     private ISeedTrackerDiagnostics _diag = null;
 
     /**
-     * Constructs the Confirmer/Extender class..
-     * @param workinglist The list to work on, either confirmed (extending) or seed (confirming)
-     * @param task the task to do (either Task.CONFIRM or Task.EXTEND)
-     * @param optimize enables the sort / cutoff optimization
-     * @param helixfitter pass the fitter
-     * @param hitmanager pass the hit manager
-     * @param strategy pass the strategy
+     * Constructor for the ConfirmerExtender class.
+     *
+     * @param hitmanager hit manager that provides access to hits sorted by layer / sector
+     * @param helixfitter helix fitter
      */
     public ConfirmerExtender(HitManager hitmanager, HelixFitter helixfitter) {
 
@@ -49,18 +56,53 @@
 
     /**
      * Retrieves the result of the confirmation or extension.
+     *
      * @return result The list of confirmed/extended seeds..
      */
     public List<SeedCandidate> getResult() {
 
         return _result;
     }
+    /**
+     * Set the maximum number of fit trials for a given seed to be confirmed/extended.
+     *
+     * @param maxfit maximum number of trials
+     */
+    public void setMaxFit(int maxfit) {
+        _maxfit = maxfit;
+    }
+
+    /**
+     * Get the number of fit trials for the last confirm/extend.
+     *
+     * @return number of helix fits
+     */
+    public int getNFit() {
+        return _nfit;
+    }
 
+    /**
+     * Set the diagnostic class to be used (null for no diagnostics).
+     *
+     * @param d diagnostic class
+     */
     public void setDiagnostics(ISeedTrackerDiagnostics d) {
         _diag = d;
         _merger.setDiagnostic(_diag);
     }
 
+    /**
+     * Try to confirm a seed using a specified strategy.  The strategy specifies
+     * the layers to use in trying to confirm the seed as well as the minimum number
+     * of confirm layers that were added to the seed.  Typically, there will be a
+     * single confirm layer that is required for a seed to be confirmed.  Confirmed
+     * seeds must also pass the chisq cut and other constraints specified in the strategy.
+     *
+     * @param seed seed to be confirmed
+     * @param strategy strategy to use for confirming this seed
+     * @param bfield magnetic field
+     * @return true if seed was confirmed
+     */
     public boolean Confirm(SeedCandidate seed, SeedStrategy strategy, double bfield) {
 
         //  Create a list to hold the confirmed / extended seeds
@@ -76,6 +118,19 @@
         return _result.size() > 0;
     }
 
+    /**
+     * Try to extend a seed using a specified strategy.  The strategy specifies
+     * the layers to use in extending the seed as well as the minimum number of
+     * layers required for a seed to be a track candidate.  Any track candidates
+     * found as a result of the extend operation are merged with the list of
+     * track candidates found so far to eliminate inferior fits when a pair of
+     * track candidates shares more than one hit.
+     *
+     * @param seed seed to be extended
+     * @param strategy strategy to use
+     * @param bfield magnetic field
+     * @param foundseeds list of track candidates found so far
+     */
     public void Extend(SeedCandidate seed, SeedStrategy strategy, double bfield,
             List<SeedCandidate> foundseeds) {
 
@@ -90,24 +145,102 @@
         return;
     }
 
+    /**
+     * Perform the confirm or extend step.
+     *
+     * @param inputseed seed to be confirmed/extended
+     * @param task confirm or extend (enum)
+     * @param strategy strategy to use
+     * @param bfield magnetic field
+     */
     private void doTask(SeedCandidate inputseed, Task task, SeedStrategy strategy, double bfield) {
 
+        //  Initialize the counter for the number of fits performed on this seed
+        _nfit = 0;
+
         //  Instantiate the fast hit checker
         FastCheck checker = new FastCheck(strategy, bfield, _diag);
 
-        //  Calculate the minimum number of hits to succeed
+        //  Calculate the minimum number of hits to succeed, retrieve the chisq cuts
         int minhits = strategy.getMinHits();
         if (task == Task.CONFIRM) minhits = strategy.getMinConfirm() + 3;
+        double badhitchisq = strategy.getBadHitChisq();
+        double maxchisq = strategy.getMaxChisq();
 
-        //  Create a LIFO queue of seeds to be searched for a confirmation/extension hit
+        //  Create a LIFO queue of seeds to be searched for a confirmation/extension
+        // hit (note that a LIFO queue is used to minimize memory usage)
         LinkedList<SeedCandidate> seedlist = new LinkedList<SeedCandidate>();
 
+        //  The bestseed is a SeedCandidate the meets the requirements for becoming
+        //  a track, shares at least one hit with the inputseed, and has been deemed
+        //  the best such seed by the track merging criteria
+        //
+        //  Initialize the best seed to null
+        SeedCandidate bestseed = null;
+        
+        //  If we have already found track candidates, check for duplicates
+        //  that share hits with the seed, finding the best such duplicate candidate.
+        for (SeedCandidate trkcand : _result) {
+            if (_merger.isDuplicate(inputseed, trkcand))
+                bestseed = findBestCandidate(trkcand, bestseed, strategy);
+        }
+
+        //  Create a map between the SeedLayers to be checked and a list of hits on the layer to check
+        Map<SeedLayer, List<HelicalTrackHit>> hitmap = new HashMap<SeedLayer, List<HelicalTrackHit>>();
+
+        //  Loop over the layers to be checked
+        for (SeedLayer lyr : inputseed.getUncheckedLayers()) {
+
+            //  Create a list of hits to check on this layer
+            List<HelicalTrackHit> hitlist = new ArrayList<HelicalTrackHit>();
+
+            //  Loop over the sectors on this layer to collect hits to check
+            for (Sector sector : _hmanager.getSectors(lyr)) {
+
+                //  If there are no hits, skip this sector
+                if (sector.Hits().isEmpty()) continue;
+
+                //  See if this sector is consistent with this seed
+                if (!checker.CheckSector(inputseed, sector)) continue;
+
+                //  Add the hits for this sector
+                hitlist.addAll(sector.Hits());
+             }
+
+            //  Save the list of hits in the hitmap
+            if (!hitlist.isEmpty()) hitmap.put(lyr, hitlist);
+        }
+
+        //  Create a list of layers that have hits to check
+        List<SeedLayer> lyrlist = new ArrayList<SeedLayer>();
+        lyrlist.addAll(hitmap.keySet());
+
+        //  Sort the layers in order of increasing number of hits
+        SortLayers lyrsort = new SortLayers(hitmap);
+        Collections.sort(lyrlist, lyrsort);
+
+        //  Store the layers to check in the seed
+        inputseed.setUncheckedLayers(lyrlist);
+
         //  Start with the input seed
         seedlist.add(inputseed);
 
         //  Keep looping until we have fully processed all seed candidates
         while (seedlist.size() > 0) {
 
+            //  If we have exceeded the maximum number of fits, print warning and stop processing seed candidates
+            if (_nfit > _maxfit) {
+                System.out.println("Maximum number of fits exceeded in "+task.toString()+" step");
+                if (bestseed == null) {
+                    System.out.println("No track candidates are associated with the seed hits");
+                } else {
+                    System.out.println("Track candidate with "+bestseed.getHits().size()+
+                            " hits and chisq of "+bestseed.getHelix().chisqtot()+
+                            " associated with the seed hits");
+                }
+                break;
+            }
+
             //  Pull the last seed off the queue (use a LIFO queue to minimize queue length)
             SeedCandidate seed = seedlist.poll();
 
@@ -116,6 +249,22 @@
             int possiblehits = lyrsleft + seed.getHits().size();
             if (possiblehits < minhits) continue;
 
+            //  If there is a best fit candidate, see if there is still a chance of beating it
+            if (bestseed != null) {
+
+                //  If the maximimum hits we can achieve is >1 fewer than the best fit, skip this candidate
+                int besthits = bestseed.getHits().size();
+                if (possiblehits < besthits - 1) continue;
+
+                //  If the maximum hits we can achieve equals the best fit, skip if we have a worse chi2
+                double chisq = seed.getHelix().chisqtot();
+                double bestchisq = seed.getHelix().chisqtot();
+                if ((possiblehits == besthits) && chisq > bestchisq) continue;
+
+                //  If the maximum hits we can achieve is 1 fewer than the best fit, skip if the bad hit criteria can't be met
+                if ((possiblehits == besthits - 1) && (chisq > bestchisq - badhitchisq)) continue;
+            }
+
             //  See if there are any layers left for confirm/extend
             if (lyrsleft == 0) {
 
@@ -128,54 +277,31 @@
                 } else if (task == Task.EXTEND) {
 
                     //  Merge the seed into the list of extended seeds
-                    _merger.Merge(_result, seed, strategy);
+                    boolean merged = _merger.Merge(_result, seed, strategy);
+
+                    //  If the seed survived the merge, make it our new best candidate
+                    if (merged) bestseed = findBestCandidate(seed, bestseed, strategy);
                 }
+
+                //  Done with this seed
                 continue;
             }
 
-           //  Pull the next layer off the queue
+            //  Pull the next layer off the queue
             SeedLayer lyr = seed.getNextLayer();
-
-            //  Get the list of sectors associated with this layer
-            List<Sector> sectorlist = _hmanager.getSectors(lyr);
+            HelicalTrackFit helix = seed.getHelix();
 
             //  Retrieve the chisq for the last fit and initialize the best fit chisq for this layer
-            double oldchisq = seed.getHelix().chisqtot();
-            double oldcirclechisq = seed.getHelix().chisq()[0];
+            double oldchisq = helix.chisqtot();
+            double oldcirclechisq = helix.chisq()[0];
             double chisqbest = 1.e99;
 
-            //  Create a list of hits to check for this layer / seed
-            List<HelicalTrackHit> hitlist = new ArrayList<HelicalTrackHit>();
-
-            //  Loop over the sectors with hits
-            for (Sector sector : sectorlist) {
-
-                //  Check that this candidate is compatible with the sector
-                if (!checker.CheckSector(seed, sector)&&_hmanager.getDoSectoring()){
-//                    if (seed.isTrueSeed()) {
-//                        for (HelicalTrackHit hit : sector.Hits()) {
-//                            for (MCParticle mcp : hit.getMCParticles()) {
-//                                if (seed.getMCParticles().contains(mcp)) {
-//                                    System.out.println("Found a true hit in an incompatible sector!!");
-//                                    System.out.println("Sector phi lo: "+sector.philo()+" hi: "+sector.phihi());
-//                                    System.out.println("Sector z lo: "+sector.zlo()+" hi: "+sector.zhi());
-//                                    System.out.println("Hit: "+hit.toString());
-//                                }
-//                            }
-//                        }
-//                    }
-                    continue;
-                }
-
-                //  Add the hits for this confirmation/extension sector to the hitlist
-                hitlist.addAll(sector.Hits());
-            }
-
-            SortHits comp = new SortHits(seed.getHelix());
+            //  Get the list of hits to check for this layer and sort them by x-y distance from current helix
+            List<HelicalTrackHit> hitlist = hitmap.get(lyr);
+            SortHits comp = new SortHits(helix);
             Collections.sort(hitlist, comp);
 
             //  Loop over the sorted hits in this layer
-            boolean foundtrueseed = false;
             for (HelicalTrackHit hit : hitlist) {
 
                 //  Make a test seed including the new hit
@@ -188,48 +314,59 @@
                     continue;
                 }
 
-                if (test.isTrueSeed()) foundtrueseed = true;
-
-                //  See if we have a successful fit
+                //  Fit the test seed
                 boolean success = _fitter.FitCandidate(test, strategy);
+                _nfit++;
 
+
+                //  Check if the fit was successful
                 if (success) {
 
-                     //  Attach the fit to the test seed
-                    test.setHelix(_fitter.getHelix());
+                    //  Success - attach the fit to the test seed
+                    HelicalTrackFit newhelix = _fitter.getHelix();
+                    test.setHelix(newhelix);
 
-                    //  Add the seed to the LIFO queue of seed candidates
+                    //  Add the seed to the LIFO queue of seed candidates and update the best chisq
                     seedlist.addFirst(test);
-                    chisqbest = Math.min(chisqbest, _fitter.getHelix().chisqtot());
+                    chisqbest = Math.min(chisqbest, newhelix.chisqtot());
 
                 } else {
 
                     //  Stop checking hits in this layer if circle chisq increase is too big
                     if (_fitter.getFitStatus() != FitStatus.CircleFitFailed) {
                         double circlechisq = _fitter.getCircleFit().chisq();
-                        if (circlechisq > oldcirclechisq + strategy.getMaxChisq()) {
-                            if (_diag != null && seed.isTrueSeed() && !foundtrueseed) {
-                                for (HelicalTrackHit hitchk : hitlist) {
-                                    for (MCParticle mcp : hitchk.getMCParticles()) {
-                                        if (seed.getMCParticles().contains(mcp)) {
-                                            System.out.println("Stopped checking hits when a true hit was available");
-                                            System.out.println("p: "+mcp.getMomentum().toString());
-                                        }
-                                    }
-                                }
-                            }
-                            break;
-                        }
+                        if (circlechisq > oldcirclechisq + maxchisq) break;
                     }
                 }
             }
 
-            //  Finished checking hits in the current layer
-            //  If all fit tries for this layer are potentially bad hits, include the starting seed in the list
+            //  Finished checking hits in the current layer.  If all the fit trials for
+            //  this layer are potentially bad hits, include the starting seed (less the
+            //  current layer, which was popped off the layer queue) in the seed list.
             if (chisqbest - oldchisq > strategy.getBadHitChisq()) seedlist.addFirst(seed);
         }
 
-        //  Finished looping over the seeds in the LIFO candidate queue
+        //  Finished looping over the seeds in the LIFO candidate queue - we are done!
         return;
     }
+
+    /**
+     * Check two track candidates and return the best one subject to the merging criteria.
+     *
+     * @param trial new candidate to try
+     * @param oldbest previous best candidate (or null if no best candidate has been found)
+     * @param strategy strategy in use
+     * @return best track candidate
+     */
+    private SeedCandidate findBestCandidate(SeedCandidate trial, SeedCandidate oldbest, SeedStrategy strategy) {
+
+        //  If the old best candidate is null, return the trial candidate
+        if (oldbest == null) return trial;
+        
+        //  If the trial candidate is better, return it
+        if (_merger.isBetter(trial, oldbest, strategy)) return trial;
+
+        //  If no improvement, return the old candidate
+        return oldbest;
+    }
 }
\ No newline at end of file
CVSspam 0.2.8