Commit in lcsim/src/org/lcsim/contrib/garfield on MAIN
tester/ExampleDriverKsTest.java+54added 1.1
      /ExampleDriverTrackingTest.java+50added 1.1
      /KsTest.java+190added 1.1
      /RatedTrack.java+1-11.3 -> 1.4
      /TrackingTest.java+6-1211.2 -> 1.3
      /TrackingTestBase.java+203-481.2 -> 1.3
      /ExampleDriver.java-501.2 removed
util/BasicTrack.java+11.1 -> 1.2
    /Const.java+21-31.1 -> 1.2
    /MCUtil.java+11.1 -> 1.2
    /NoSuchParameterException.java+11.1 -> 1.2
+528-223
3 added + 1 removed + 7 modified, total 11 files
Refactored the track finder tester package, added Kshort reconstruction efficiency test. 
Added "frequently used particles" enum to Const.

lcsim/src/org/lcsim/contrib/garfield/tester
ExampleDriverKsTest.java added at 1.1
diff -N ExampleDriverKsTest.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ExampleDriverKsTest.java	23 Jan 2007 03:50:12 -0000	1.1
@@ -0,0 +1,54 @@
+package org.lcsim.contrib.garfield.tester;
+
+import java.util.*;
+import org.lcsim.event.*;
+import org.lcsim.recon.cluster.nn.NearestNeighborClusterDriver;
+import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
+import org.lcsim.contrib.garfield.*;
+import org.lcsim.contrib.garfield.kshort.*;
+import org.lcsim.contrib.garfield.util.*;
+import org.lcsim.contrib.garfield.mcTrackFinder.*;
+
+/**
+ * An example driver that runs calorimeter-assisted track finder, then K short finder, 
+ * and uses tester package to analyse their performance.
+ *
+ * @author D. Onoprienko
+ * @version $Id: ExampleDriverKsTest.java,v 1.1 2007/01/23 03:50:12 onoprien Exp $
+ */
+public class ExampleDriverKsTest extends Driver {
+  
+   private AIDA aida = AIDA.defaultInstance();
+   
+   public ExampleDriverKsTest() {
+     
+     add(new Const());
+     
+     GarfieldHitConverter hitDigitizer = new GarfieldHitConverter();
+     hitDigitizer.set("OUTPUT_COLLECTION_NAME", "GarfieldHits");
+     add(hitDigitizer);
+
+     add(new NearestNeighborClusterDriver(2, 2, 1, 2, 0.));
+
+     add(new EmcalMipStubs("GarfieldMipStubs",0));
+     add(new GarfieldTrackFinder(0));
+     
+     K0ShortFinder k0finder = new K0ShortFinder("K0Short", 1);
+     k0finder.setCut("D0",0.);
+     k0finder.setCut("Pt",0.0);
+     add(k0finder);     
+     
+     MCTrackFinder mcTrackFinder = new MCTrackFinder();
+     mcTrackFinder.addTrackerHitList("GarfieldHits");
+     mcTrackFinder.set("Track_Collection_Name", "CheaterTracks");
+     add(mcTrackFinder);
+     
+     KsTest test = new KsTest();
+     test.set("RECONSTRUCTED_TRACK_COLLECTION_NAME", "GarfieldTracks");
+     test.set("MC_TRACK_COLLECTION_NAME", "CheaterTracks");
+     test.set("LOG_FILE", "testKs.log");
+     add(test);
+   }
+
+}
\ No newline at end of file

lcsim/src/org/lcsim/contrib/garfield/tester
ExampleDriverTrackingTest.java added at 1.1
diff -N ExampleDriverTrackingTest.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ExampleDriverTrackingTest.java	23 Jan 2007 03:50:12 -0000	1.1
@@ -0,0 +1,50 @@
+package org.lcsim.contrib.garfield.tester;
+
+import java.util.*;
+import org.lcsim.event.*;
+import org.lcsim.recon.cluster.nn.NearestNeighborClusterDriver;
+import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
+import org.lcsim.contrib.garfield.*;
+import org.lcsim.contrib.garfield.util.*;
+import org.lcsim.contrib.garfield.mcTrackFinder.*;
+
+/**
+ * An example driver that runs calorimeter-assisted track finder, and uses
+ * tester package to analyse its performance.
+ *
+ * @author D. Onoprienko
+ * @version $Id: ExampleDriverTrackingTest.java,v 1.1 2007/01/23 03:50:12 onoprien Exp $
+ */
+public class ExampleDriverTrackingTest extends Driver {
+  
+   private AIDA aida = AIDA.defaultInstance();
+   
+   public ExampleDriverTrackingTest() {
+     
+     add(new Const());
+     
+     GarfieldHitConverter hitDigitizer = new GarfieldHitConverter();
+     hitDigitizer.set("OUTPUT_COLLECTION_NAME", "GarfieldHits");
+     add(hitDigitizer);
+
+     add(new NearestNeighborClusterDriver(2, 2, 1, 2, 0.));
+
+     add(new EmcalMipStubs("GarfieldMipStubs",0));
+     add(new GarfieldTrackFinder(0));
+     
+     MCTrackFinder mcTrackFinder = new MCTrackFinder();
+     mcTrackFinder.addTrackerHitList("GarfieldHits");
+     mcTrackFinder.set("Track_Collection_Name", "CheaterTracks");
+     add(mcTrackFinder);
+     
+     TrackingTest test = new TrackingTest("General Track Finding Test");
+     test.set("RECONSTRUCTED_TRACK_COLLECTION_NAME", "GarfieldTracks");
+     test.set("MC_TRACK_COLLECTION_NAME", "CheaterTracks");
+     test.set("MCTrackCut_Pt", 1.0*Const.GeV);
+     test.set("MCTrackCut_Theta", 45.*Const.degree);
+     test.set("MCTrackCut_nLayers", 3);
+     add(test);
+   }
+
+}
\ No newline at end of file

lcsim/src/org/lcsim/contrib/garfield/tester
KsTest.java added at 1.1
diff -N KsTest.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ KsTest.java	23 Jan 2007 03:50:12 -0000	1.1
@@ -0,0 +1,190 @@
+package org.lcsim.contrib.garfield.tester;
+
+import java.util.*;
+import org.lcsim.event.*;
+import org.lcsim.util.Driver;
+import hep.physics.particle.Particle;
+import org.lcsim.util.aida.AIDA;
+import hep.aida.ITree;
+import org.lcsim.contrib.garfield.util.*;
+import org.lcsim.contrib.garfield.mcTrackFinder.*;
+
+import static org.lcsim.contrib.garfield.util.Const.Particle.*;
+
+/**
+ * An example of track finding performance test that looks at reconstruction of
+ * charged pions produced in K short decays. Also calculates K short reconstrustion efficiency.
+ *
+ * @author D. Onoprienko
+ * @version $Id: KsTest.java,v 1.1 2007/01/23 03:50:12 onoprien Exp $
+ */
+public class KsTest extends TrackingTestBase {
+  
+// -- Indices into the statistics (per event and cumulative) arrays :  ---------
+  
+  protected final int _I_nMCTracks;
+  protected final int _I_eMCTracks;
+  protected final int _I_nMCTracksReconstructed;
+  protected final int _I_eMCTracksReconstructed;
+  
+  protected final int _I_nKs;
+  protected final int _I_nKsRreconstructed;
+  protected final int _I_nKsFake;
+  protected final int _I_nKsTwoPionsReconstructed;
+  
+// -- Constructors :  ----------------------------------------------------------
+  
+  public KsTest() {
+    
+    super("K0S Reconstruction Test");
+    
+    _I_nMCTracks = createIndex("Number of tracks produced by charged pion from KS0");
+    _I_eMCTracks = createIndex("Total Pt of tracks produced by charged pion from KS0", IndexType.NOPRINT);
+    _I_nMCTracksReconstructed = createIndex("Number of reconstructed tracks produced by charged pion from KS0");
+    _I_eMCTracksReconstructed = createIndex("Total Pt of reconstructed tracks produced by charged pion from KS0", IndexType.NOPRINT);
+    
+    _I_nKs = createIndex("Number of KS0");
+    _I_nKsRreconstructed = createIndex("Number of true reconstructed KS0");
+    _I_nKsFake = createIndex("Number of fake reconstructed KS0");
+    _I_nKsTwoPionsReconstructed = createIndex("Number of KS0 with both pions reconstructed");
+  }
+  
+// -- Event processing :  ------------------------------------------------------
+  
+  protected void analyzeEvent(EventHeader event) {
+    
+    // Pion reconstruction efficiency
+
+    for (MCTrack mcTrack : _mcTrackList) {
+      if (mcTrack.getStatus(IN_CLASS) == YES) {
+        _statE[_I_nMCTracks] += 1.;
+        _statE[_I_eMCTracks] += mcTrack.getPt();
+        if (isReconstructed(mcTrack)) {
+          _statE[_I_nMCTracksReconstructed] += 1.;
+          _statE[_I_eMCTracksReconstructed] += mcTrack.getPt();
+        }
+      }
+    }
+    
+    // Compile a list of Kshorts that decayed into pi+pi- pair
+    
+    ArrayList<MCParticle> kShortListMC = new ArrayList<MCParticle>();    
+    List<MCParticle> mcParticleList = event.getMCParticles();
+    for (MCParticle mcPart : mcParticleList) {
+      if (mcPart.getPDGID() == K_SHORT.PDGID) {
+        List<MCParticle> dList = mcPart.getDaughters();
+        if ((dList.size() == 2) && 
+            (dList.get(0).getPDGID() == PI_MINUS.PDGID || dList.get(0).getPDGID() == PI_PLUS.PDGID) &&
+            (dList.get(1).getPDGID() == PI_MINUS.PDGID || dList.get(1).getPDGID() == PI_PLUS.PDGID)) {
+          kShortListMC.add(mcPart);
+        }
+      }
+    }
+    
+    // Get list of reconstructed KS0 from the event:
+    
+    List<ReconstructedParticle> kShortListReco;
+    try {
+      kShortListReco = event.get(ReconstructedParticle.class, "K0Short");
+    } catch (Exception e) {
+      kShortListReco = new ArrayList<ReconstructedParticle>(1);
+      System.out.println("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD");
+    }
+
+//    try {
+//      event.get("K0Short");
+//    } catch (Exception e) {
+//      kShortListReco = new ArrayList<ReconstructedParticle>(1);
+//      System.out.println("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ");
+//    }
+//    kShortListReco = new ArrayList<ReconstructedParticle>(1);
+    
+    // KS0 statistics 
+
+    List<ReconstructedParticle> matchedRecoKsList = new ArrayList<ReconstructedParticle>();
+    for (MCParticle mcKS : kShortListMC) {
+      
+      _statE[_I_nKs] += 1.;
+      
+      for (ReconstructedParticle recoKS : kShortListReco) {
+        if (matchKShort(recoKS, mcKS)) {
+          _statE[_I_nKsRreconstructed] += 1.;
+          matchedRecoKsList.add(recoKS);
+          break;
+        }
+      }
+      
+      List<MCTrack> mcTrackList = getMCTracks(mcKS);
+      if (mcTrackList.size() == 2 && isReconstructed(mcTrackList.get(0)) && isReconstructed(mcTrackList.get(1))) {
+        _statE[_I_nKsTwoPionsReconstructed] += 1.;
+      }
+      
+    }    
+    _statE[_I_nKsFake] = kShortListReco.size() - matchedRecoKsList.size();
+
+  }
+  
+  protected void endOfData() {
+    String[] messages = new String[] {
+      " ",
+      "For charged pions from KS0 decays :",
+      " ",
+      "Reconstruction efficiency: " + _statC[_I_nMCTracksReconstructed]/_statC[_I_nMCTracks],
+      "Pt reconstruction efficiency: " + _statC[_I_eMCTracksReconstructed]/_statC[_I_eMCTracks],
+      " ",
+      "For KS0 :",
+      " ",
+      "Reconstruction efficiency: " + _statC[_I_nKsRreconstructed]/_statC[_I_nKs],
+      "Two-track reconstruction efficiency: " + _statC[_I_nKsTwoPionsReconstructed]/_statC[_I_nKs],
+      "Fake rate: " + _statC[_I_nKsFake]/(_statC[_I_nKsFake] + _statC[_I_nKsRreconstructed]),
+      " "
+    };
+    printCumulativeStatistics(true, messages);
+  }
+
+  
+// -- Overriding selector methods of TrackingTestBase :  -----------------------
+
+  /**
+   * Accepts tracks produced by charged pions coming from KS0 decays.
+   * Superclass {@link TrackinTestBase#mcTrackFilter(MCTrack mcTrack)} is also
+   * called so cuts on Pt, Theta and the number of layers can be used.
+   */
+  protected boolean mcTrackFilter(MCTrack mcTrack) {
+    
+    if (!super.mcTrackFilter(mcTrack)) return false;
+    
+    MCParticle mcPart = mcTrack.getMCParticle();
+    List<MCParticle> parentList = mcPart.getParents();
+    return (((mcPart.getPDGID() == PI_MINUS.PDGID) || (mcPart.getPDGID() == PI_PLUS.PDGID))
+         && (parentList != null) && (parentList.size() == 1)
+         && (parentList.get(0).getPDGID() == K_SHORT.PDGID));
+  }
+  
+// -- Private helper methods :  ------------------------------------------------
+  
+  /** Get list of MCTracks for daughters of an MCParticle. */
+  private List<MCTrack> getMCTracks(MCParticle mcPart) {
+    List<MCTrack> tList = new ArrayList<MCTrack>(2);
+    List<MCParticle> dList = mcPart.getDaughters();
+    for (MCTrack mcTrack : _mcTrackList) {
+      if (dList.contains(mcTrack.getMCParticle())) tList.add(mcTrack);
+    }
+    return tList;
+  }
+  
+  /** Returns true if reconstructed and Monte Carlo particles refer to the same KShort. */
+  private boolean matchKShort(ReconstructedParticle recoKS, MCParticle mcKS) {
+    List<MCTrack> mcList = getMCTracks(mcKS);
+    List<Track> recoList = recoKS.getTracks();
+    return (
+             (mcList.size() == 2) && (recoList.size() == 2) &&
+             (
+               (matchTracks(recoList.get(0), mcList.get(0)) && matchTracks(recoList.get(1), mcList.get(1))) || 
+               (matchTracks(recoList.get(0), mcList.get(1)) && matchTracks(recoList.get(1), mcList.get(0)))
+             )
+           );
+    
+  }
+  
+}

lcsim/src/org/lcsim/contrib/garfield/tester
RatedTrack.java 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- RatedTrack.java	15 Dec 2006 16:54:57 -0000	1.3
+++ RatedTrack.java	23 Jan 2007 03:50:12 -0000	1.4
@@ -12,7 +12,7 @@
  * of integer status flags. 
  *
  * @author D. Onoprienko
- * @version $Id: RatedTrack.java,v 1.3 2006/12/15 16:54:57 onoprien Exp $
+ * @version $Id: RatedTrack.java,v 1.4 2007/01/23 03:50:12 onoprien Exp $
  */
 public class RatedTrack {
 

lcsim/src/org/lcsim/contrib/garfield/tester
TrackingTest.java 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- TrackingTest.java	15 Dec 2006 16:54:57 -0000	1.2
+++ TrackingTest.java	23 Jan 2007 03:50:12 -0000	1.3
@@ -17,7 +17,7 @@
  * A general example of track finding performance test.
  *
  * @author D. Onoprienko
- * @version $Id: TrackingTest.java,v 1.2 2006/12/15 16:54:57 onoprien Exp $
+ * @version $Id: TrackingTest.java,v 1.3 2007/01/23 03:50:12 onoprien Exp $
  */
 public class TrackingTest extends TrackingTestBase {
   
@@ -34,12 +34,15 @@
   
   /** Default constructor. */
   public TrackingTest() {
+    super("TrackingTest");
     _I_nMCTracks = createIndex("Number of reconstructable tracks");
     _I_eMCTracks = createIndex("Total momentum of reconstructable tracks", IndexType.NOPRINT);
     _I_nMCTracksReconstructed = createIndex("Number of reconstructed reconstructable tracks");
     _I_eMCTracksReconstructed = createIndex("Total momentum of reconstructed reconstructable tracks", IndexType.NOPRINT);
     _I_nRecoTracks = createIndex("Number of reconstructed tracks", IndexType.NOPRINT);
     _I_nRecoTracksFake = createIndex("Number of fake tracks", IndexType.PRINTEVENT);
+    
+    _mcTrackCut_nLayers = 3;
   }
   
   /** Constructor taking the name of the test. */
@@ -48,55 +51,6 @@
     set("TEST_NAME", name);
   }
   
-// -- Setters :  ---------------------------------------------------------------
-
-  /** 
-   * Set any integer parameter. 
-   * The following parameters can be set with this method:<br>
-   * <tt>"MCTrackCut_nLayers"</tt> - cut on minimum number of layers with hits 
-   *                   for MCTrack to be considered reconstructable. Default: 3.<br>
-   * @param name   Name of parameter to be set
-   * @param value  Value to be assigned to the parameter.
-   * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
-   *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
-   *         and set their own parameters.
-   */
-  public void set(String name, int value) {
-    if (name == "MCTrackCut_nLayers") {
-      _mcTrackCut_nLayers = value;
-    } else {
-      throw new NoSuchParameterException(name, this.getClass());
-    }
-  }
-
-  /** 
-   * Set any double parameter. 
-   * The following parameters can be set with this method:<br>
-   * <tt>"MCTrackCut_Pt"</tt> - cut on Pt for MCTrack to be considered reconstructable. Default: 0.<br>
-   * <tt>"MCTrackCut_Theta"</tt> - cut on Theta for MCTrack to be considered reconstructable. Default: 0.<br>
-   * <tt>"MCTrackCut_Rapidity"</tt> - cut on pseudo-rapidity for MCTrack to be considered reconstructable. Default: infinity.<br>
-   * @param name   Name of parameter to be set
-   * @param value  Value to be assigned to the parameter.
-   * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
-   *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
-   *         and set their own parameters.
-   */
-  public void set(String name, double value) {
-    if (name == "MCTrackCut_Pt") {
-      _mcTrackCut_Pt = value;
-    } else if (name == "MCTrackCut_Theta") {
-      _mcTrackCut_theta = value;
-    } else if (name == "MCTrackCut_Rapidity") {
-      if (value < 10000.) {
-        _mcTrackCut_theta = 2.*Math.atan(Math.exp(-value));
-      } else {
-        _mcTrackCut_theta = 0.;
-      }
-    } else {
-      throw new NoSuchParameterException(name, this.getClass());
-    }    
-  }
-  
 // -- Processing event :  ------------------------------------------------------
   
   protected void analyzeEvent(EventHeader event) {
@@ -139,84 +93,15 @@
     printStatistics(event);
   }
   
-  /** 
-   * Definition of a successfully reconstracted MCTrack.
-   * Require that there is a reconstructed track that picked up hits from this
-   * MCTrack in at least 3 layers. Given current limitations of {@link Track},
-   * we only check that there is a track with 3 common hits at the moment.
-   */
-  protected boolean isReconstructed(MCTrack mcTrack) {
-    return mcTrack.getTracks().size() > 0;
-  }
-
-  /**
-   * Definition of fake track.
-   * What I'd like to have here is that the track is fake if there is no MCParticle
-   * that contributed to its hits in all but one layer.
-   * Given current limitations of {@link Track}, the actual definition is:
-   * the track is fake if there is no MCTrack that contains all but one of its hits.
-   */
-  protected boolean isFake(RatedTrack track) {
-    List<MCTrack> mcTrackList = track.getMCTracks();
-    if (mcTrackList.size() == 0) return true;
-    List<TrackerHit> recoHitList = track.getTrack().getTrackerHits();
-    for (MCTrack mcTrack : mcTrackList) {
-      int nSomeoneElsesHits = 0;
-      for (TrackerHit hit : recoHitList) {
-        if (!mcTrack.getTrackerHits().contains(hit)) nSomeoneElsesHits++;
-      }
-      if (nSomeoneElsesHits <= 1) return false;
-    }
-    return true;
-  }
-    
-  protected void suspend() {
+  protected void endOfData() {
     if (_statC[_I_nMCTracks] == 0 || _statC[_I_nRecoTracks] == 0) return;
     String[] messages = new String[] {
       "Reconstruction efficiency: " + _statC[_I_nMCTracksReconstructed]/_statC[_I_nMCTracks],
       "Momentum reconstruction efficiency: " + _statC[_I_eMCTracksReconstructed]/_statC[_I_eMCTracks],
       "Purity: " + (1.-_statC[_I_nRecoTracksFake]/_statC[_I_nRecoTracks])
     };
-    printCumulativeStatistics(messages);
-  }
-  
-  protected void endOfData() {suspend();}
-  
-// -- Override selector methods from TrackingTestBase :  -----------------------
-  
-  /** 
-   * Definition of "reconstructable" track. 
-   * Cuts on Pt, Theta, and a minimum number of layers with hits.
-   * Cut values can be set at run time.
-   */
-  protected boolean mcTrackFilter(MCTrack mcTrack) {
-    if (mcTrack.getPt() < _mcTrackCut_Pt) return false;
-    if (mcTrack.getTheta() < _mcTrackCut_theta) return false;
-    if (mcTrack.getNLayers() < _mcTrackCut_nLayers) return false;
-    return true;
-  }
-  
-  /** 
-   * Definition of matching reconstructed and MC tracks.
-   * Tracks match if they have common hits in at least 3 layers.
-   * (Alternative definition to be considered later: Tracks match if MCParticle 
-   * contributed to hits of reconstructed track in at least 3 layers).
-   * Current implementation simply asks for 3 common hits since
-   * {@link TrackerHit} is completely "detector blind" at the moment. 
-   */
-  protected boolean matchTracks(Track track, MCTrack mcTrack) {
-    List<TrackerHit> recoTrackHitList = track.getTrackerHits();
-    List<TrackerHit> mcTrackHitList = mcTrack.getTrackerHits();
-    int nMatch = 0;
-    for (TrackerHit hit : mcTrackHitList) {
-      if (recoTrackHitList.contains(hit)) nMatch++;
-    }
-    return nMatch > 2;
+    printCumulativeStatistics(true, messages);
   }
  
 // -- Private fields :  --------------------------------------------------------
-  
-  double _mcTrackCut_Pt = 0.;
-  double _mcTrackCut_theta = 0.;
-  int _mcTrackCut_nLayers = 3;
 }

lcsim/src/org/lcsim/contrib/garfield/tester
TrackingTestBase.java 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- TrackingTestBase.java	15 Dec 2006 16:54:57 -0000	1.2
+++ TrackingTestBase.java	23 Jan 2007 03:50:12 -0000	1.3
@@ -3,6 +3,7 @@
 import java.util.*;
 import java.lang.reflect.*;
 import javax.swing.*;
+import java.io.*;
 import org.lcsim.event.*;
 import org.lcsim.contrib.garfield.util.*;
 import org.lcsim.contrib.garfield.mcTrackFinder.*;
@@ -15,31 +16,36 @@
 
 
 /**
- * Abstract class that provides infrastructure and utility methods for testing track finders.
+ * Abstract driver class that provides infrastructure and utility methods for testing track finders.
  * See {@link TrackingTest} and {@link TrackingTestKs} for examples of use.
  * <p>
- * Classes implementing particular tests should extend this class, overriding
- * {@link #analyzeEvent(EventHeader)} and, if necessary,
- * {@link #eventFilter(EventHeader)},
- * {@link #matchTracks(Track track, MCTrack mcTrack)},
- * {@link #mcTrackFilter(MCTrack mcTrack)},
- * {@link #suspend()}, and {@link #endOfData()} methods.
+ * Classes implementing particular tests should extend this class, overriding<br>
+ * {@link #analyzeEvent(EventHeader)}<br>
+ * and, if necessary,<br>
+ * {@link #eventFilter(EventHeader event)},<br>
+ * {@link #matchTracks(Track track, MCTrack mcTrack)},<br>
+ * {@link #mcTrackFilter(MCTrack mcTrack)},<br>
+ * {@link #isReconstructed(MCTrack mcTrack)},<br>
+ * {@link #isFake(RatedTrack track)},<br>
+ * {@link #suspend()}, {@link #startOfData()}, and {@link #endOfData()} methods.<br>
+ * Default implementations are provided for these methods.
  * <p>
  * Subclusses extending this driver should be added to the event processing chain
- * after track findind stage. When the driver's {@link #process(EventHeader event)}
- * method is called by the framework, it creates a list of Monte Carlo tracks,
- * associates hits and reconstructed tracks with them, and then calls
- * {@link #analyzeEvent(EventHeader)} method that should be implemented by subclasses.
+ * after track findind stage. Cheater track finder should also be run to create a
+ * list of MCTracks and put it into the event. 
  * <p>
- * Only events for which {@link #eventFilter(EventHeader)} returns <code>true</code>
- * are processed. Reconstructed track is associated with Monte Carlo track if
- * {@link #matchTracks(Track track, MCTrack mcTrack)} returns <code>true</code>.
- * Monte Carlo tracks for which {@link #mcTrackFilter(MCTrack mcTrack)} returns 
- * <code>true</code> are marked as being in the requested class (subsequent calls to
+ * When the driver's {@link #process(EventHeader event)}
+ * method is called by the framework, it fetches a list of Monte Carlo tracks,
+ * marks those for which {@link #mcTrackFilter(MCTrack mcTrack)} returns 
+ * <tt>true</tt> as being in the requested class (subsequent calls to
  * {@link MCTrack#getStatus(int) mcTrack.getStatus(TrackingTestBase.IN_CLASS)}
- * will return <code>TrackingTestBase.YES</code>. Default implementations are provided
- * for these methods, but subclasses will need to overwrite some or all of them to 
- * perform a meaningful test.
+ * will return <tt>TrackingTestBase.YES</tt>),
+ * associates MCTracks and reconstructed tracks for which 
+ * {@link #matchTracks(Track track, MCTrack mcTrack)} returns <tt>true</tt> with 
+ * each other, and then calls
+ * {@link #analyzeEvent(EventHeader)} method that should be implemented by subclasses.
+ * <p>
+ * Only events for which {@link #eventFilter(EventHeader)} returns <tt>true</tt> are processed.
  * <p>
  * Any number of variables for accumulating statistics can be created with
  * {@link #createIndex(String name, IndexType... args)}. Data put into
@@ -48,7 +54,7 @@
  * {@link #printCumulativeStatistics()}.
  *
  * @author D. Onoprienko
- * @version $Id: TrackingTestBase.java,v 1.2 2006/12/15 16:54:57 onoprien Exp $
+ * @version $Id: TrackingTestBase.java,v 1.3 2007/01/23 03:50:12 onoprien Exp $
  */
 abstract public class TrackingTestBase extends Driver {
   
@@ -61,9 +67,11 @@
   public static final int NO = -2;
   
 // -- Constructors :  ----------------------------------------------------------
-  
+
+  /** Default constructor. */
   public TrackingTestBase() {
     _testName = "";
+    _logStream = null;
     _aida = AIDA.defaultInstance();
     _tree = _aida.tree();
     _mcTrackListName = "";
@@ -71,12 +79,22 @@
     _nEvents = 0;
   }
   
+  /** Constructor taking the name of the test. */
+  public TrackingTestBase(String name) {
+    this();
+    set("TEST_NAME", name);
+  }
+  
   // -- Setters :  -------------------------------------------------------------
   
   /** 
    * Set any <tt>String</tt> parameter.
    * The following parameters can be set with this method:<br>
    * <tt>"TEST_NAME"</tt> - name of the test. The name will printed with the test output statistics.<br>
+   * <tt>"LOG_FILE"</tt> - specifies distination where statistics is to be printed. "POPUP" (default) will bring
+   *                       up a pop-up window; "STDOUT" uses System.out.println() (when running inside JAS3, this 
+   *                       means end-of-run statistics will not be printed at all, due to a bug in the framework;
+   *                       everything else is treated as a file name.<br>
    * <tt>"RECONSTRUCTED_TRACK_COLLECTION_NAME"</tt> - name of reconstructed track 
    *                         collection produced by the track finder being tested.<br>
    * <tt>"MC_TRACK_COLLECTION_NAME"</tt> - name of MCTrack collection created by previously run MCTrackFinder.
@@ -89,6 +107,19 @@
   public void set(String name, String value) {
     if (name == "TEST_NAME") {
         _testName = value;
+    } else if (name == "LOG_FILE") {
+        if (_logStream != null) _logStream.close();
+        if (value.equalsIgnoreCase("POPUP")) {
+          _logStream = null;
+        } else if (value.equalsIgnoreCase("STDOUT")) {
+          _logStream = System.out;
+        } else {
+          try {
+            _logStream = new PrintStream(value);
+          } catch (FileNotFoundException e) {
+            System.err.println("Failed to open file: " + value);
+          }
+        }
     } else if (name == "RECONSTRUCTED_TRACK_COLLECTION_NAME") {
         _recoTrackListName = value;
     } else if (name == "MC_TRACK_COLLECTION_NAME") {
@@ -97,6 +128,53 @@
       throw new NoSuchParameterException(name, this.getClass());
     }
   }
+
+  /** 
+   * Set any double parameter. 
+   * The following parameters can be set with this method:<br>
+   * <tt>"MCTrackCut_Pt"</tt> - cut on Pt for MCTrack to be considered reconstructable. Default: 0.<br>
+   * <tt>"MCTrackCut_Theta"</tt> - cut on Theta for MCTrack to be considered reconstructable. Default: 0.<br>
+   * <tt>"MCTrackCut_Rapidity"</tt> - cut on pseudo-rapidity for MCTrack to be considered reconstructable. Default: infinity.<br>
+   * @param name   Name of parameter to be set
+   * @param value  Value to be assigned to the parameter.
+   * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
+   *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
+   *         and set their own parameters.
+   */
+  public void set(String name, double value) {
+    if (name == "MCTrackCut_Pt") {
+      _mcTrackCut_Pt = value;
+    } else if (name == "MCTrackCut_Theta") {
+      _mcTrackCut_theta = value;
+    } else if (name == "MCTrackCut_Rapidity") {
+      if (value < 10000.) {
+        _mcTrackCut_theta = 2.*Math.atan(Math.exp(-value));
+      } else {
+        _mcTrackCut_theta = 0.;
+      }
+    } else {
+      throw new NoSuchParameterException(name, this.getClass());
+    }    
+  }
+
+  /** 
+   * Set any integer parameter. 
+   * The following parameters can be set with this method:<br>
+   * <tt>"MCTrackCut_nLayers"</tt> - cut on minimum number of layers with hits 
+   *                   for MCTrack to be considered reconstructable. Default: 3.<br>
+   * @param name   Name of parameter to be set
+   * @param value  Value to be assigned to the parameter.
+   * @throws NoSuchParameterException Thrown if the supplied parameter name is unknown.
+   *         Subclasses may catch this exception after a call to <tt>super.set()</tt>
+   *         and set their own parameters.
+   */
+  public void set(String name, int value) {
+    if (name == "MCTrackCut_nLayers") {
+      _mcTrackCut_nLayers = value;
+    } else {
+      throw new NoSuchParameterException(name, this.getClass());
+    }
+  }
   
 // -- Processing event :  ------------------------------------------------------
   
@@ -167,23 +245,74 @@
     return true;
   }
   
-  /**
+  /** 
+   * Returns <tt>true</tt> if Monte Carlo track belongs to the class that needs to be included in analysis.
+   * Cuts on Pt, Theta, and a minimum number of layers with hits.
+   * Cut values can be set at run time, leaving them at default values means no cuts.
+   * Subclasses can overwrite this method to provide their own definition of "reconstructable" track.
+   */
+  protected boolean mcTrackFilter(MCTrack mcTrack) {
+    if (mcTrack.getPt() < _mcTrackCut_Pt) return false;
+    if (mcTrack.getTheta() < _mcTrackCut_theta) return false;
+    if (mcTrack.getNLayers() < _mcTrackCut_nLayers) return false;
+    return true;
+  }
+  
+  /** 
    * Returns <code>true</code> if reconstructed track and Monte Carlo track are deemed to describe the same track.
-   * Default implementation returns <code>true</code> if all hits associated with the reconstructed track are
-   * also associated with the MC track. Subclasses should overwrite this method if different algorithm is desired.
+   * Default implementation: tracks match if they have common hits in at least 3 layers.
+   * (Alternative definition to be considered later: Tracks match if MCParticle 
+   * contributed to hits of reconstructed track in at least 3 layers).
+   * <i>Current implementation simply asks for 3 common hits since
+   * {@link TrackerHit} is completely "detector blind" at the moment.</i>
+   * Subclasses can overwrite this method to provide their own definition of matching tracks.
    */
   protected boolean matchTracks(Track track, MCTrack mcTrack) {
     List<TrackerHit> recoTrackHitList = track.getTrackerHits();
     List<TrackerHit> mcTrackHitList = mcTrack.getTrackerHits();
-    return mcTrackHitList.containsAll(recoTrackHitList);
+    int nMatch = 0;
+    for (TrackerHit hit : mcTrackHitList) {
+      if (recoTrackHitList.contains(hit)) nMatch++;
+    }
+    return nMatch > 2;
   }
   
-  /**
-   * Returns <code>true</code> if Monte Carlo track belongs to the class that needs to be included in analysis.
-   * Default implementation in <tt>TrackingTestBase</tt> always returns <tt>true</tt>.
-   * Subclasses should overwrite this method to provide their own definition of "reconstructable" track.
+  /** 
+   * Definition of a successfully reconstracted MCTrack.
+   * This method is not called internally by any <tt>TrackingTestBase</tt> methods,
+   * but can be used (or overridded) by subclasses.
+   * What I would like to do here is to require that there is a reconstructed 
+   * track that picked up hits from this MCTrack in at least 3 layers.
+   * Given current limitations of {@link TrackerHit} that has no layer information,
+   * the default implementation returns <tt>true</tt> if any reconstructed 
+   * tracks have been associated with MCTrack supplied as a parameter. If default
+   * implementation of {@link matchTracks(Track, MCTrack)} is used, that means
+   * requiring a reconstructed track with 3 hits common with the given MCTrack.
    */
-  protected boolean mcTrackFilter(MCTrack mcTrack) {
+  protected boolean isReconstructed(MCTrack mcTrack) {
+    return mcTrack.getTracks().size() > 0;
+  }
+
+  /**
+   * Definition of fake track.
+   * This method is not called internally by any <tt>TrackingTestBase</tt> methods,
+   * but can be used (or overridded) by subclasses.
+   * In the future, I'd like to consider the track fake if there is no MCParticle
+   * that contributed to its hits in all but one layer.
+   * Given current limitations of {@link TrackerHit}, the actual definition is:
+   * the track is fake if there is no MCTrack that contains all but one of its hits.
+   */
+  protected boolean isFake(RatedTrack track) {
+    List<MCTrack> mcTrackList = track.getMCTracks();
+    if (mcTrackList.size() == 0) return true;
+    List<TrackerHit> recoHitList = track.getTrack().getTrackerHits();
+    for (MCTrack mcTrack : mcTrackList) {
+      int nSomeoneElsesHits = 0;
+      for (TrackerHit hit : recoHitList) {
+        if (!mcTrack.getTrackerHits().contains(hit)) nSomeoneElsesHits++;
+      }
+      if (nSomeoneElsesHits <= 1) return false;
+    }
     return true;
   }
   
@@ -194,15 +323,18 @@
   
   /**
    * Called by the framework when the event processing is suspended.
-   * Unless overwritten in the subclass, prints out standard cumulative statistics.
+   * Unless overwritten in the subclass, calls {@link #endOfData()}.
    */
-  protected void suspend() {printCumulativeStatistics();}
+  protected void suspend() {endOfData();}
   
   /**
    * Called when all data processing is finished.
    * Unless overwritten in the subclass, prints out standard cumulative statistics.
    */
-  protected void endOfData() {printCumulativeStatistics();}
+  protected void endOfData() {
+    printCumulativeStatistics();
+//    if (_logStream != null && _logStream != System.out) _logStream.close();
+  }
   
   /**
    * Called before the first event is processed, or after a rewind.
@@ -215,6 +347,26 @@
   
 // -- Protected helper methods:  -----------------------------------------------
   
+  /** 
+   * Print to the log.
+   * The output destination can be set with <tt>set("LOG_FILE", destination)</tt>.
+   * See {@link #set(String, String)} for details.
+   */
+  protected void printLog(String title, String... messages) {
+    if (_logStream != null) {
+      if (title != null) {
+        _logStream.println("");
+        _logStream.println(title);
+        _logStream.println("");
+      }
+      for (String line : messages) {
+        _logStream.println(line);
+      }
+    } else {
+      JOptionPane.showMessageDialog(null, messages, title, JOptionPane.INFORMATION_MESSAGE);
+    }
+  }
+  
   protected enum IndexType {NOSUM, SUM, SUM2, NOPRINT, PRINTEVENT, PRINTSUM, PRINTALL}
   
   /**
@@ -296,7 +448,7 @@
     return size;
   }
   
-  /** Print statistics at the end of an event. */
+  /** Print standard statistics at the end of an event to standard output. */
   protected void printStatistics(EventHeader event) {
     System.out.println("");
     System.out.println("Tracking test: " + _testName + ", statistics for event " + event.getEventNumber());
@@ -309,11 +461,13 @@
   }
   
   /** 
-   * Print cumulative statistics. 
+   * Print cumulative statistics to the log. 
+   * The output destination can be set with <tt>set("LOG_FILE", destination)</tt>.
+   * See {@link #set(String, String)} for details.
    * @param messages  Array of strings that should be printed before standard statistics.
    * @param printStandard   Flag to indicate whether to print standard statistics.
    */
-  protected void printCumulativeStatistics(String[] messages, boolean printStandard) {
+  protected void printCumulativeStatistics(boolean printStandard, String... messages) {
     ArrayList<String> msgList = new ArrayList<String>(20);
     msgList.add("");
     if (messages != null) for (String msg : messages) msgList.add("  " + msg);
@@ -325,34 +479,35 @@
       }
     }
     msgList.add("");
-    Object[] msgArray = msgList.toArray();
-    JOptionPane.showMessageDialog(null, msgArray,
-            "Tracking test: " + _testName + " cumulative statistics  (" + _nEvents + " events)",
-            JOptionPane.INFORMATION_MESSAGE);
+    String[] msgArray = new String[msgList.size()];
+    msgArray = msgList.toArray(msgArray);
+    printLog("Tracking test: " + _testName + " cumulative statistics  (" + _nEvents + " events)", msgArray);
   }
   
   /** 
    * Print standard cumulative statistics. 
+   * The output destination can be set with <tt>set("LOG_FILE", destination)</tt>.
+   * See {@link #set(String, String)} for details.
    */
-  protected void printCumulativeStatistics() {printCumulativeStatistics(null, true);}
-  
-  /** 
-   * Print cumulative statistics. 
-   * @param messages  Array of strings that should be printed before standard statistics.
-   */
-  protected void printCumulativeStatistics(String[] messages) {printCumulativeStatistics(messages, true);}
+  protected void printCumulativeStatistics() {printCumulativeStatistics(true);}
   
 // -- Private fields :  --------------------------------------------------------
   
   protected String _testName = "";
   
+  protected PrintStream _logStream;
+  
   protected List<MCTrack> _mcTrackList;
   protected List<Track> _recoTrackList;
   protected ArrayList<RatedTrack> _ratedTrackList;
   
   protected String _mcTrackListName;
   protected String _recoTrackListName;
-  
+
+  protected double _mcTrackCut_Pt = 0.;
+  protected double _mcTrackCut_theta = 0.;
+  protected int _mcTrackCut_nLayers = 0;
+
   protected int _nEvents;         // Number of events analyzed
   protected double[] _statE;      // Array to hold per event statistics
   protected double[] _statC;      // Array to hold cumulative statistics

lcsim/src/org/lcsim/contrib/garfield/tester
ExampleDriver.java removed after 1.2
diff -N ExampleDriver.java
--- ExampleDriver.java	15 Dec 2006 16:54:57 -0000	1.2
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,50 +0,0 @@
-package org.lcsim.contrib.garfield.tester;
-
-import java.util.*;
-import org.lcsim.event.*;
-import org.lcsim.recon.cluster.nn.NearestNeighborClusterDriver;
-import org.lcsim.util.Driver;
-import org.lcsim.util.aida.AIDA;
-import org.lcsim.contrib.garfield.*;
-import org.lcsim.contrib.garfield.util.*;
-import org.lcsim.contrib.garfield.mcTrackFinder.*;
-
-/**
- * An example driver showing how to use calorimeter-assisted track finder and 
- * the tester package.
- *
- * @author D. Onoprienko
- * @version $Id: ExampleDriver.java,v 1.2 2006/12/15 16:54:57 onoprien Exp $
- */
-public class ExampleDriver extends Driver {
-  
-   private AIDA aida = AIDA.defaultInstance();
-   
-   public ExampleDriver() {
-     
-     add(new Const());
-     
-     GarfieldHitConverter hitDigitizer = new GarfieldHitConverter();
-     hitDigitizer.set("OUTPUT_COLLECTION_NAME", "GarfieldHits");
-     add(hitDigitizer);
-
-     add(new NearestNeighborClusterDriver(2, 2, 1, 2, 0.));
-
-     add(new EmcalMipStubs("GarfieldMipStubs",0));
-     add(new GarfieldTrackFinder(0));
-     
-     MCTrackFinder mcTrackFinder = new MCTrackFinder();
-     mcTrackFinder.addTrackerHitList("GarfieldHits");
-     mcTrackFinder.set("Track_Collection_Name", "CheaterTracks");
-     add(mcTrackFinder);
-     
-     TrackingTest test = new TrackingTest("General Track Finding Test");
-     test.set("RECONSTRUCTED_TRACK_COLLECTION_NAME", "GarfieldTracks");
-     test.set("MC_TRACK_COLLECTION_NAME", "CheaterTracks");
-     test.set("MCTrackCut_Pt", 1.0*Const.GeV);
-     test.set("MCTrackCut_Theta", 45.*Const.degree);
-     test.set("MCTrackCut_nLayers", 3);
-     add(test);
-   }
-
-}
\ No newline at end of file

lcsim/src/org/lcsim/contrib/garfield/util
BasicTrack.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- BasicTrack.java	15 Dec 2006 16:54:58 -0000	1.1
+++ BasicTrack.java	23 Jan 2007 03:50:12 -0000	1.2
@@ -14,6 +14,7 @@
  * Includes method for initializing track parameters from momentum at a given point.
  *
  * @author D. Onoprienko
+ * @version $Id: BasicTrack.java,v 1.2 2007/01/23 03:50:12 onoprien Exp $
  */
 public class BasicTrack implements Track {
 

lcsim/src/org/lcsim/contrib/garfield/util
Const.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- Const.java	15 Dec 2006 16:54:58 -0000	1.1
+++ Const.java	23 Jan 2007 03:50:12 -0000	1.2
@@ -12,10 +12,11 @@
  * Default units (those equal to 1.0) are millimeter, second, Tesla, and GeV.
  *
  * @author D. Onoprienko
+ * @version $Id: Const.java,v 1.2 2007/01/23 03:50:12 onoprien Exp $
  */
 public class Const extends Driver {
   
-  // --- Units :  --------------------------------------------------------------
+// --- Units :  ----------------------------------------------------------------
   
   public static final double mm = 1.;
   public static final double millimeter = mm;
@@ -40,11 +41,28 @@
   
   public static final double degree = Math.PI / 180.;
   
-  // -- Physics constants :  ---------------------------------------------------
+// -- Physics constants :  -----------------------------------------------------
   
   public static final double SPEED_OF_LIGHT = 2.99792458e8 * (meter/second);
   
-  // -- Detector parameters :  -------------------------------------------------
+// -- Frequently used particles :  ---------------------------------------------
+  
+  public enum Particle {
+    
+    PI_PLUS(211),
+    PI_MINUS(-211),
+    PI_0(111),
+    K_SHORT(310),
+    LAMBDA(3122),
+    SIGMA_PLUS(3222),
+    SIGMA_MINUS(3112),
+    SIGMA_0(3212);
+    
+    public final int PDGID;    
+    private Particle(int pdgID) {PDGID = pdgID;}
+  }
+  
+// -- Detector parameters :  ---------------------------------------------------
   
   public enum SubDet {
     

lcsim/src/org/lcsim/contrib/garfield/util
MCUtil.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- MCUtil.java	15 Dec 2006 16:54:58 -0000	1.1
+++ MCUtil.java	23 Jan 2007 03:50:12 -0000	1.2
@@ -14,6 +14,7 @@
 /**
  *
  * @author D. Onoprienko
+ * @version $Id: MCUtil.java,v 1.2 2007/01/23 03:50:12 onoprien Exp $
  */
 public class MCUtil {
     

lcsim/src/org/lcsim/contrib/garfield/util
NoSuchParameterException.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- NoSuchParameterException.java	15 Dec 2006 16:54:58 -0000	1.1
+++ NoSuchParameterException.java	23 Jan 2007 03:50:12 -0000	1.2
@@ -4,6 +4,7 @@
  * Exception to be thrown by <tt>set(name,value)</tt> methods of various classes.
  *
  * @author D. Onoprienko
+ * @version $Id: NoSuchParameterException.java,v 1.2 2007/01/23 03:50:12 onoprien Exp $
  */
 public class NoSuchParameterException extends RuntimeException {
   
CVSspam 0.2.8