Print

Print


Commit in lcsim/sandbox/RobKutschke/TKNHits on MAIN
ReadTKNRawHitsDriverV1.java+163-1321.5 -> 1.6
Now uses official helper class, organizes hits per sensor as a map and removes hack to work around broken list of simtrackerhits.

lcsim/sandbox/RobKutschke/TKNHits
ReadTKNRawHitsDriverV1.java 1.5 -> 1.6
diff -u -r1.5 -r1.6
--- ReadTKNRawHitsDriverV1.java	6 Nov 2007 00:30:56 -0000	1.5
+++ ReadTKNRawHitsDriverV1.java	16 Nov 2007 16:57:03 -0000	1.6
@@ -1,11 +1,10 @@
 import org.lcsim.util.aida.AIDA;
 
 import java.util.List;
-import java.util.ArrayList;
 import java.util.Set;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.HashMap;
+import java.util.TreeMap;
 import org.lcsim.util.Driver;
 
 import org.lcsim.event.EventHeader;
@@ -15,10 +14,10 @@
 import org.lcsim.event.base.BaseRawTrackerHit;
 
 import org.lcsim.geometry.Detector;
-import org.lcsim.geometry.compact.Subdetector;
 import org.lcsim.detector.IDetectorElement;
 import org.lcsim.detector.IGeometryInfo;
 import org.lcsim.detector.IRotation3D;
+import org.lcsim.geometry.compact.Subdetector;
 import org.lcsim.detector.identifier.IExpandedIdentifier;
 import org.lcsim.detector.solids.ISolid;
 import org.lcsim.detector.solids.Box;
@@ -30,53 +29,60 @@
 import org.lcsim.detector.tracker.silicon.SiSensor;
 import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
 import org.lcsim.detector.tracker.silicon.ChargeCarrier;
+import org.lcsim.detector.tracker.silicon.SiTrackerIdentifierHelper;
 
+import org.lcsim.detector.DetectorIdentifierHelper;
+
+import org.lcsim.contrib.SiStripSim.Kpix;
 
 import org.lcsim.detector.driver.SimTrackerHitIdentifierReadoutDriver;
 import org.lcsim.contrib.RobKutschke.TKNHits.TKNRawHitsDriverV1;
-import org.lcsim.contrib.RobKutschke.TKNHits.TrackerIdentifierIndexCache;
 
 /**
  *
  * Driver to illustrate use of the RawTrackerHits created by Tim's code.
  * In this version, all of the hits are returned as a single unsorted vector
- * per system.
+ * per system, where system means one of Tracker Barrel, Tracker Endcap, 
+ * Vertex Barrel, Vertex Endcap, Forward Tracker.
+ *
+ * This version contains tests to compare measured and generated positions.
  *
- * This version also contains tests to compared measured and generated positions.
+ * It also creates a map which organizes RawTrackerHits by sensor; this is just 
+ * one of many possible organizations.
  *
  *@author $Author: kutschke $
- *@version $Id: ReadTKNRawHitsDriverV1.java,v 1.5 2007/11/06 00:30:56 kutschke Exp $
+ *@version $Id: ReadTKNRawHitsDriverV1.java,v 1.6 2007/11/16 16:57:03 kutschke Exp $
  *
- * Date $Date: 2007/11/06 00:30:56 $
+ * Date $Date: 2007/11/16 16:57:03 $
  * 
  * Notes:
  *
- * 0) This example is known to work with the file:
+ * 1) This example is known to work with the file:
  *    http://www.lcsim.org/test/lcio/mu-_10GeV_SiTrackerBarrelTest00.slcio
  *    It has 100 events of single muons, all with an azimuth in a small cone around 
  *    -90 degrees.  This file uses the detector description: SiTrackerBarrelTest00 .
  *
- * 1) There are a few magic numbers that I need to look up in a dictionary and I only
- *    want to do this when the dictionary changes. 
- * 
- * 2) I am not aware of anything in the event model that informs the user that correct 
+ * 2) I am not aware of anything in the event model that informs the user that the correct 
  *    argument to the getElectrodes() method is HOLES, not ELECTRONS.  This is just something
  *    that you need to know a priori.
  *
  * 3) In some cases one can simplify the dot product.  For example, for axial strips,
- *    VecOp( local, uaxis) simplifies to local.x().
- *
- * 4) The RawTrackerHit.getSimTrackerHit() method is currently broken.  I have 
- *    created a hack work around that only works for events with exactly on MCParticle
- *    ( ie does not work for events with decays in flight ).  The Hack returns null
- *    for events with more than 1 MCParticle.  If there is more than 1 MCParticle per event,
- *    and if two MCParticles hit the same sensor, then I have no way of matching 
- *    SimTrackerHits with RawTrackerHits, so I skip the comparison of reconstructed and 
- *    generated quantities for these events.
+ *    VecOp( local, uaxis) simplifies to local.x().  I believe that taking the dot product
+ *    will be robust for all strip/pixel orientations.
  *
- * 5) I have only tested the code with tracker barrel hits.  I am told that it should work  
+ * 4) I have only tested the code with tracker barrel hits.  I am told that it should work  
  *    with tracker endcap hits if waferized versions of the tracker endcap are are present
- *    in the geometry file.  The code does not yet work with pixel devices.
+ *    in the geometry file.  The hit simulation code does not yet work with pixel devices.
+ *
+ * 5) In some events in the standard input file the muons decay or interact in the detector, 
+ *    which means that the code to compute the mc true value of the measurement may sometimes
+ *    give the wrong answer.  This gives rise to outliers in the (measured-generated) plots.
+ *    To verify that the code is working correctly, I have also made some plots only for events 
+ *    that contain a single muon and nothing else; in these plots the tails and outliers are gone.
+ *
+ * 6) The collection of hits on each sensor are organized as a TreeMap.  Why?
+ *      - Choose a Map so that one can address hits by strip number
+ *      - Choose a TreeMap so that the keyset is sorted in order of ascending strip number.
  *
  */
 
@@ -84,10 +90,7 @@
 {
     private AIDA aida = AIDA.defaultInstance();
 
-    // Cache of index values that are expensive to look up.  See note 1.
-    private TrackerIdentifierIndexCache index = null;
-
-    // Names of collections on which to work.  See note 5.
+    // Names of collections on which to work.  See note 4.
     private String[] sim = {"SiTrackerBarrel_RO"};
     private String[] raw = {"RawBarrelTrackerHits"};
 
@@ -114,9 +117,10 @@
      */
     public void detectorChanged( Detector detector) {
 
-	// Initialize the index cache.
+	// Get the helper.
 	Subdetector tracker = findSubdetector( detector, "SiTrackerBarrel");
-	index = new TrackerIdentifierIndexCache( tracker, true );
+	SiTrackerIdentifierHelper helper1 = 
+	    (SiTrackerIdentifierHelper)tracker.getDetectorElement().getIdentifierHelper();
     }
    
     /**
@@ -132,27 +136,31 @@
 	List<RawTrackerHit> rawhits = header.get(RawTrackerHit.class, raw[0] );
 	aida.cloud1D("Number of RawTrackerHits per event").fill(rawhits.size());
 
+	// List of generated MCParticles.  Used in diagnostics only.
+	List<MCParticle> genmcps = header.get(MCParticle.class,header.MC_PARTICLES);
+
 	// Header for the tabluar printout.
 	if ( ++nprint == 1 ){ 
-	    System.out.printf ( "Event System Layer Module Sensor Side Strip Time   ADC NSim\n");
+	    System.out.printf ( "Event Barrel System Layer Module Sensor Side Strip Time     Charge NSim\n");
 	}
 
+	// Container to organize RawTrackerHits on each sensor.
+	Map<SiSensor,Map<Integer,RawTrackerHit>> sensormap = new HashMap<SiSensor,Map<Integer,RawTrackerHit>>();
+
 	// Loop over the raw hits.
 	for ( RawTrackerHit raw : rawhits ){
 
-	    // For hits of this type, the adc array will always be of length 1, exactly.
-	    short adc = raw.getADCValues()[0];
-
-	    // Position in detector heirarchy.
-	    IExpandedIdentifier id = raw.getExpandedIdentifier();
-
-	    // Hit strip.
-	    int strip = id.getValue(index.getStrip());
-
 	    // Information about the wafer on which this hit lives.
 	    IDetectorElement de = raw.getDetectorElement();
 	    SiSensor sensor     = (SiSensor) de;
 	    IGeometryInfo geom  = de.getGeometry();
+	    SiTrackerIdentifierHelper helper = (SiTrackerIdentifierHelper)de.getIdentifierHelper();
+
+	    // Hit strip.
+	    int strip = helper.getStripValue(raw.getIdentifier());
+
+	    // Get the charge on the strip in units of electrons.
+	    double charge = getChargeFromKPix( raw );
 
 	    // The pattern of strips or pixels is encoded within this class. See note 2.
 	    SiSensorElectrodes electrode = sensor.getReadoutElectrodes(ChargeCarrier.HOLE);
@@ -171,120 +179,119 @@
 	    // Reconstructed measurement.  See note 3.  Assume strips not pixels.
 	    double meas_reco = VecOp.dot( local, uaxis);
 
-	    // Links back to the SimTrackerHits that contributed to this hit.  See note 4.
-	    List<SimTrackerHit> badsims = raw.getSimTrackerHit();   // Broken.
-	    List<SimTrackerHit> sims    = hackGetSimTrackerHits(header,sensor);
-
-	    // Skip events for which the hack on the previous line  does not work.  See note 4.
-	    if ( sims != null ){
-
-		// True crossing of track with local z=0 plane.
-		Hep3Vector local_gen  = getTrueZeroCrossing( sims, sensor);
+	    // Links back to the SimTrackerHits that contributed to this hit.
+	    List<SimTrackerHit> sims = raw.getSimTrackerHit();
 
-		// The measured quantity associated with this point.
-		double meas_gen  = VecOp.dot( local_gen, uaxis);
+	    // True crossing of track with local z=0 plane.
+	    Hep3Vector local_gen  = getTrueZeroCrossing( sims, sensor );
 
-		// Difference between measured and generated quantities.
-		double du = meas_reco-meas_gen;
+	    // The true measured quantity associated with this point.
+	    double meas_gen  = VecOp.dot( local_gen, uaxis);
 
-		// Some plots.
-		aida.histogram1D("Measured-Generated coordinate (mm)",100,-0.1,0.1).fill(du);
-		aida.cloud2D("Measured y vs x positions (mm)",-1).fill(global.x(),global.y());
+	    // Difference between measured and generated quantities.
+	    double du = meas_reco-meas_gen;
+
+	    // A diagnostic plot.
+	    aida.histogram1D("Measured-Generated coordinate (mm)",100,-0.15,0.15).fill(du);
+
+	    // Some additional diagnostic plots for events with only a single generated track.  See note 5.
+	    if ( genmcps.size() ==1 ){
+		aida.histogram1D("Muon Only/Measured-Generated coordinate (mm)",100,-0.15,0.15).fill(du);
+		aida.cloud2D("Muon Only/Measured y vs x positions (mm)",-1).fill(global.x(),global.y());
+		aida.cloud2D("Muon Only/Global y vs (Measured-Generated coordinate) (mm)",-1).fill(du,global.y());
 	    }
 
-	    // Some printout.
+	    // Some printout that exercises the identifier helper.
 	    if ( nprint < 6 ){
-		System.out.printf ( "%5d %6d %5d %6d %6d %4d %5d %4d %5d %4d\n",
+
+		System.out.printf ( "%5d %6d %6d %5d %6d %6d %4d %5d %4d %10.1f %4d \n",
 				    header.getEventNumber(),
-				    id.getValue(index.getSystem()),
-				    id.getValue(index.getLayer()),
-				    id.getValue(index.getModule()),
-				    id.getValue(index.getSensor()),
-				    id.getValue(index.getSide()),
-				    id.getValue(index.getStrip()),
+				    helper.getSystem(raw.getIdentifier()),
+				    helper.getBarrel(raw.getIdentifier()),
+				    helper.getLayer(raw.getIdentifier()),
+				    helper.getModuleValue(raw.getIdentifier()),
+				    helper.getSensorValue(raw.getIdentifier()),
+				    helper.getSideValue(raw.getIdentifier()),
+				    helper.getStripValue(raw.getIdentifier()),
 				    raw.getTime(),
-				    adc,
-				    badsims.size()
+				    charge,
+				    sims.size()
 				    );
-
-		// Uncomment this block to inspect the corrupted list of SimTrackerHits.
-		/*
-		for ( SimTrackerHit badsim : badsims ){
-		    double[] pos = badsim.getPoint();
-		    System.out.printf ( "SimTrackerHit: %9.3f  %9.3f  %9.3f | %20.10f  |  ",
-					pos[0], pos[1], pos[2], badsim.getTime() );
-		    System.out.println (badsim);
-		}
-		*/
-
-
 	    }
-
+	    
 	    // Some more histograms.
-	    aida.cloud1D("Raw ADC spectrum").fill(adc);
+	    aida.cloud1D("Raw charge (electrons)").fill(charge);
+	    aida.histogram1D("Raw charge, detail (electrons)",50,0.,40000.).fill(charge);
 	    aida.cloud1D("Strip number").fill(strip);
 	    aida.cloud1D("Reconstructed local position (mm)").fill(meas_reco);
+	    aida.histogram1D("Number of parent SimTrackerHits",30,0.,30.).fill(sims.size());
 
-	}
-    } // process(EventHeader)
+	    // The time field is not yet filled in; it is always zero.
+	    aida.cloud1D("Time").fill(raw.getTime());
 
-    /**
-     * Hack to replace broken functionality of RawTrackerHit.getSimTrackerHit().
-     *
-     * @return a list of all SimTrackerHits that can make a hit on the specified sensor.  
-     *   If there is more than 1 MCParticle in the event, return a null list.
-     *
-     */
-      
-    private List<SimTrackerHit> hackGetSimTrackerHits( EventHeader header, SiSensor sensor ){
-
-	// This hack only works reliably if there is exactly one particle in the event.
-	List<MCParticle> particles = header.get(MCParticle.class,header.MC_PARTICLES);
-	if ( particles.size() > 1 ) return null;
-
-	// Intialize the output.
-	List<SimTrackerHit> list = new ArrayList<SimTrackerHit>();
+	    // See note 5.
+	    if ( genmcps.size() == 0 ){
+		aida.histogram1D("Muon Only/Number of parent SimTrackerHits",30,0.,30.).fill(sims.size());
+	    }
 
-	// List of all SimTrackerHits in the event.
-	List<SimTrackerHit> eventHits = header.get(SimTrackerHit.class, sim[0]);
+	    // Add this hit to the per sensor map.  See note 6.
+	    Map<Integer,RawTrackerHit> rawmap = sensormap.get(sensor);
+	    if ( rawmap == null ){
+		rawmap =  new TreeMap<Integer,RawTrackerHit>();
+		sensormap.put(sensor,rawmap);
+	    }
+	    if ( rawmap.get(strip) == null ){
+		rawmap.put(strip,raw);
+	    }else{
+		System.out.println ("Duplicate strip: " + strip 
+				    + " on module: "    + helper.getModuleValue(raw.getIdentifier())
+				    + " in event:  "    + header.getEventNumber() 
+				    );
+	    }
 
-	// Geometry information about this sensor.
-	IGeometryInfo geom = sensor.getGeometry();
-	ISolid        solid = geom.getLogicalVolume().getSolid();
-	Box           box   = (Box)solid;
-	double        xhalf = box.getXHalfLength();
-	double        yhalf = box.getYHalfLength();
-	double        zhalf = box.getZHalfLength();
+	} // loop over rawhits
 
-	for ( SimTrackerHit sim : eventHits ){
+	// Inspect the organized collection.
+	for ( SiSensor sensor: sensormap.keySet() ){
 
-	    // The position of this hit in global coordinates.
-	    Hep3Vector pos = new BasicHep3Vector( sim.getPoint() );
+	    // Histogram of the number of hits per sensor.
+	    aida.cloud1D("Hits per sensor").fill(sensormap.get(sensor).size());
 
-	    // Position of this hit in sensor-local coordinates.
-	    Hep3Vector local = geom.transformGlobalToLocal(pos);
+	    if ( nprint < 6 ){
+		
+		// Hits on this sensor.
+		Map<Integer,RawTrackerHit> rawmap = sensormap.get(sensor);
+
+		// This traverses strips in ascending order or strip number.
+		for ( Integer i : rawmap.keySet() ){
+		    RawTrackerHit raw   = rawmap.get(i);
+		    IDetectorElement de = raw.getDetectorElement();
+		    SiTrackerIdentifierHelper helper = (SiTrackerIdentifierHelper)de.getIdentifierHelper();
+		    int module = helper.getModuleValue(raw.getIdentifier());
 
-	    // Check if hit is on this sensor. 
-	    double dx = Math.abs(local.x());
-	    double dy = Math.abs(local.y());
-	    double dz = Math.abs(local.z());
-	    if ( dx<=xhalf & dy<yhalf & dz<zhalf ){
-		list.add(sim);
+		    System.out.println ("Sensor: " + module + " " + i );
+		}
 	    }
+
 	}
 
-	return list;
-    }
+    } // process(EventHeader)
+
 
     /**
      *  
-     * Find true coordinates of a hit.
+     * Naive method for finding the true coordinates of a hit.
+     *
+     * The true value is defined to be the point at which the track passes through 
+     * the local z=0 plane of the sensor.  The algorithm can be confused if more
+     * than one true track contributes energy to one raw trackerhit.  So the result 
+     * should only be trusted 100% for events that contain only a single track.
      *
      * @return the point, in sensor-local coordinates, at which the generated track 
      *   passed through the local z=0 plane of the specified sensor.
      *
      * The first argument is a list of SimTrackerHits that are on the sensor
-     * and are associated with the track of interest.  The list must be non-null.
+     * and are associated with the RawTrackerHit of interest.
      *
      * The second argument is the sensor of interest.
      *
@@ -299,7 +306,7 @@
 	// and compute the local coord of that point.
 	SimTrackerHit closest_sim   = null;
 	Hep3Vector    closest_local = null;
-	double mindz                = 1.e10;
+	double mindz                = Double.MAX_VALUE;
 	for ( SimTrackerHit sim : list ){
 
 	    // The position of this hit in global coordinates.
@@ -308,6 +315,7 @@
 	    // Position of this hit in sensor-local coordinates.
 	    Hep3Vector local = geom.transformGlobalToLocal(pos);
 
+	    // Find hit that is closest to the z=0 plane of the sensor.
 	    double dz = Math.abs(local.z());
 	    if ( dz < mindz ){
 		mindz = dz;
@@ -317,32 +325,31 @@
 
 	}
 
-	// Extrapolate the track, as a straight line, from the closest point to the
-	// point at which it crosses the local z=0 plane.  Typically this is step length
-	// less than 100 microns.
+	// Extrapolate the track, as a straight line, to the point at which it crosses the 
+	// local z=0 plane.  Start at the SimTrackerHit that is closest to the z=0 plane.
+	// Typically this is step length less than 100 microns but it can be much longer for 
+	// a track with a direction that is almost in the plane of the sensor.
 
 	// Unit vector along the track direction (in global coord).
 	Hep3Vector t = VecOp.unit(new BasicHep3Vector( closest_sim.getMomentum() ));
 
 	// Unit vector along track direction (in local coord).
-	Hep3Vector tp = rot.rotated(t);
+	Hep3Vector tlocal = rot.rotated(t);
 
 	// Step length  along the track required to move the track to the zlocal=0 plane.
-	double s = -closest_local.z()/tp.z();
+	double s = -closest_local.z()/tlocal.z();
 
 	// Local coord of intersection between the track and the plane.
-	Hep3Vector intersection = VecOp.add( closest_local, VecOp.mult( s, tp));
-
+	Hep3Vector intersection = VecOp.add( closest_local, VecOp.mult( s, tlocal));
 	return intersection;
 
-    }
+    } // getTrueZeroCrossing();
 
     /**
      * Find a named subdector object within the detector.
      *
      * @return Subdetector object that is specified by the second argument.
      *
-     *
      */
     private Subdetector findSubdetector( Detector detector, String sub ){
 	Map<String, Subdetector> subDetMap = detector.getSubdetectors();
@@ -356,4 +363,28 @@
 	return tracker;
     }
 
+    /**
+     *
+     * Use the Kpix code to compute the charge on a strip, specified as 
+     * a RawTrackerHit.  Tim says that this complexity will eventualy be wrapped
+     * up so that users do not need to see it.
+     *
+     * For Kpix chips, the short[] return of getADCValues() is not actually an array 
+     * of adc values; it contains chip state information that includes the adc value
+     * plus additional information.
+     *
+     * @return Charge on the strip in units of electrons.
+     *
+     */
+    private double getChargeFromKPix( RawTrackerHit raw){
+
+	short adc = raw.getADCValues()[1];
+	Kpix.ControlRegisters control_registers = 
+	    Kpix.ControlRegisters.decoded(raw.getADCValues()[0]);
+	Kpix.KpixChannel.ReadoutRegisters readout_registers = 
+	    Kpix.KpixChannel.ReadoutRegisters.decoded(raw.getADCValues()[1]);
+	double charge = Kpix.computeCharge(readout_registers, control_registers);
+	return charge;
+    }
+
 } 
CVSspam 0.2.8