Print

Print


Commit in lcsim/sandbox/RobKutschke/TKNHits on MAIN
ReadTKNRawHitsDriverV1.java+220-351.1 -> 1.2
Compute strip position and true generated hit position.

lcsim/sandbox/RobKutschke/TKNHits
ReadTKNRawHitsDriverV1.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- ReadTKNRawHitsDriverV1.java	1 Nov 2007 22:55:19 -0000	1.1
+++ ReadTKNRawHitsDriverV1.java	5 Nov 2007 21:33:27 -0000	1.2
@@ -1,6 +1,11 @@
-
 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 org.lcsim.util.Driver;
 
 import org.lcsim.event.EventHeader;
@@ -12,10 +17,19 @@
 import org.lcsim.geometry.Detector;
 import org.lcsim.detector.IDetectorElement;
 import org.lcsim.detector.IGeometryInfo;
+import org.lcsim.detector.IRotation3D;
 import org.lcsim.detector.identifier.IExpandedIdentifier;
+import org.lcsim.detector.solids.ISolid;
+import org.lcsim.detector.solids.Box;
 
 import hep.physics.vec.Hep3Vector;
 import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.VecOp;
+
+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.driver.SimTrackerHitIdentifierReadoutDriver;
 import org.lcsim.contrib.RobKutschke.TKNHits.TKNRawHitsDriverV1;
@@ -27,24 +41,55 @@
  * In this version, all of the hits are returned as a single unsorted vector
  * per system.
  *
+ * This version also contains tests to compared measured and generated positions.
+ *
  *@author $Author: kutschke $
- *@version $Id: ReadTKNRawHitsDriverV1.java,v 1.1 2007/11/01 22:55:19 kutschke Exp $
+ *@version $Id: ReadTKNRawHitsDriverV1.java,v 1.2 2007/11/05 21:33:27 kutschke Exp $
+ *
+ * Date $Date: 2007/11/05 21:33:27 $
+ * 
+ * Notes:
+ *
+ * 0) 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 .
  *
- * Date $Date: 2007/11/01 22:55:19 $
+ * 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.  Ideally all of the code should be
+ *    within detectorChanged() but I don't yet know how to do that.  So the cache is 
+ *    invalidated when the detector changes and recomputed on the first event following
+ *    a detector change.
+ * 
+ * 2) I am not aware of anything in the event model that informs the user that 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.
+ *
+ * 5) 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.
  *
  */
 
-
 public class ReadTKNRawHitsDriverV1 extends Driver
 {
     private AIDA aida = AIDA.defaultInstance();
 
-    // Cache of index values that are expensive to look up.
+    // Cache of index values that are expensive to look up.  See note 1.
     private TrackerIdentifierIndexCache index = null;
 
-    // Names of collections on which to work.  
-    // As of 11/01/07 the example only works with the tracker barrel but, in the future 
-    // it will work with all Tracker, Vertex Detector and forward tracker hits.
+    // Names of collections on which to work.  See note 5.
     private String[] sim = {"SiTrackerBarrel_RO"};
     private String[] raw = {"RawBarrelTrackerHits"};
 
@@ -53,12 +98,12 @@
 
     /**
      * Constructor:
-     * Add the necessary drivers using super.
+     * Add the necessary sub-drivers using super.
      *
      */
     public ReadTKNRawHitsDriverV1(){
 
-	// Attach SimTrackerHits to the detector.
+	// Attach SimTrackerHits to their detector elements.
 	super.add( new SimTrackerHitIdentifierReadoutDriver( sim ) );
 
 	// Create Raw Trackerhits and put them in the event.
@@ -71,24 +116,26 @@
      */
     public void detectorChanged( Detector detector) {
 
-	// Invalidate the cached indices when the detector changes.
+	// Invalidate the cached indices.  See note 1.
 	index = null;
+	System.out.println ("Detector: " + detector.getName() );
+
     }
    
     /**
-     *  This does the main work of the class.
+     *  Loop over the RawTrackerHits; make printout and histograms.
      *
      */
     public void process(EventHeader header)
     {
-	// Create the list of RawTrackerHits in the event.
+	// Create the list of RawTrackerHits and add it to the event.
 	super.process(header);
-	
+
 	// Get the list of RawTrackerHits from the event.
 	List<RawTrackerHit> rawhits = header.get(RawTrackerHit.class, raw[0] );
 	aida.cloud1D("Number of RawTrackerHits per event").fill(rawhits.size());
 
-	// Make sure cached indices are valid.
+	// Make sure cached indices are valid. See note 1.
 	if ( index == null ){
 	    if ( rawhits.size() > 0 ){
 		index = new TrackerIdentifierIndexCache( rawhits.get(0), true );
@@ -99,39 +146,67 @@
 
 	// Header for the tabluar printout.
 	if ( ++nprint == 1 ){ 
-	    System.out.printf ( "Event System Layer Module Sensor Side Strip Time   ADC NSim");
-	    System.out.printf ( "  (        Local Origin         )\n");
+	    System.out.printf ( "Event System Layer Module Sensor Side Strip Time   ADC NSim\n");
 	}
 
 	// Loop over the raw hits.
 	for ( RawTrackerHit raw : rawhits ){
 
-	    // Need concrete type to access some methods.
-	    // At present, this will not survive persistency.
-	    BaseRawTrackerHit base = (BaseRawTrackerHit) raw;
-	    
 	    // 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 = base.getExpandedIdentifier();
+	    IExpandedIdentifier id = raw.getExpandedIdentifier();
+
+	    // Hit strip.
+	    int strip = id.getValue(index.getStrip());
 
 	    // Information about the wafer on which this hit lives.
-	    IDetectorElement de = base.getDetectorElement();
+	    IDetectorElement de = raw.getDetectorElement();
+	    SiSensor sensor     = (SiSensor) de;
 	    IGeometryInfo geom  = de.getGeometry();
 
-	    // Coordinates of wafer center in global system.
-	    Hep3Vector center  = geom.getPosition();
+	    // The pattern of strips or pixels is encoded within this class. See note 2.
+	    SiSensorElectrodes electrode = sensor.getReadoutElectrodes(ChargeCarrier.HOLE);
+
+	    // Convert the strip number to positions in local and global coord.
+	    Hep3Vector local  = electrode.getCellPosition(strip);
+	    Hep3Vector global = geom.transformLocalToGlobal(local);
+
+	    // Unit vector in measurement direction, in local coord.
+	    Hep3Vector uaxis = electrode.getMeasuredCoordinate(0);
+
+	    // For pixels there would be a second measurement direction, in local coord.
+	    Hep3Vector vaxis = ( electrode.getNAxes() == 2 ) ?
+		electrode.getMeasuredCoordinate(1): null;
+
+	    // 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> sims = 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 ){
 
-	    // Links back to the SimTrackerHits that contributed to this hit.
-	    // As of 11/01/07 this returns a corrupt list.
-	    List<SimTrackerHit> sims = raw.getSimTrackerHit();
+		// True crossing of track with local z=0 plane.
+		Hep3Vector local_gen  = getTrueZeroCrossing( sims, sensor);
 
-	    // Coming soon: convert the strip number to a local position.
+		// The measured quantity associated with this point.
+		double meas_gen  = VecOp.dot( local_gen, uaxis);
+
+		// Difference between measured and generated quantities.
+		double du = meas_reco-meas_gen;
+
+		// 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());
+	    }
 
 	    // Some printout.
 	    if ( nprint < 6 ){
-		System.out.printf ( "%5d %6d %5d %6d %6d %4d %5d %4d %5d %4d  (%9.3f %9.3f %9.3f)\n",
+		System.out.printf ( "%5d %6d %5d %6d %6d %4d %5d %4d %5d %4d\n",
 				    header.getEventNumber(),
 				    id.getValue(index.getSystem()),
 				    id.getValue(index.getLayer()),
@@ -141,10 +216,7 @@
 				    id.getValue(index.getStrip()),
 				    raw.getTime(),
 				    adc,
-				    sims.size(),
-				    center.x(),
-				    center.y(),
-				    center.z()
+				    sims.size()
 				    );
 
 		// Uncomment this block to inspect the corrupted list of SimTrackerHits.
@@ -159,9 +231,122 @@
 
 	    }
 
-	    // And some histograms.
+	    // Some more histograms.
 	    aida.cloud1D("Raw ADC spectrum").fill(adc);
+	    aida.cloud1D("Strip number").fill(strip);
+	    aida.cloud1D("Reconstructed local position (mm)").fill(meas_reco);
 
 	}
     } // process(EventHeader)
+
+    /**
+     * 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>();
+
+	// List of all SimTrackerHits in the event.
+	List<SimTrackerHit> eventHits = header.get(SimTrackerHit.class, sim[0]);
+
+	// 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();
+
+	for ( SimTrackerHit sim : eventHits ){
+
+	    // The position of this hit in global coordinates.
+	    Hep3Vector pos = new BasicHep3Vector( sim.getPoint() );
+
+	    // Position of this hit in sensor-local coordinates.
+	    Hep3Vector local = geom.transformGlobalToLocal(pos);
+
+	    // 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);
+	    }
+	}
+
+	return list;
+    }
+
+    /**
+     *  
+     * Find true coordinates of a hit.
+     *
+     * @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.
+     *
+     * The second argument is the sensor of interest.
+     *
+     */
+    private Hep3Vector getTrueZeroCrossing( List<SimTrackerHit> list, SiSensor sensor ){
+	
+	// Geometry information about this sensor.
+	IGeometryInfo geom = sensor.getGeometry();
+	IRotation3D   rot   = geom.getGlobalToLocal().getRotation();
+	
+	// Find the SimTrackerHit that is closest to the local z=0 plane
+	// and compute the local coord of that point.
+	SimTrackerHit closest_sim   = null;
+	Hep3Vector    closest_local = null;
+	double mindz                = 1.e10;
+	for ( SimTrackerHit sim : list ){
+
+	    // The position of this hit in global coordinates.
+	    Hep3Vector pos = new BasicHep3Vector( sim.getPoint() );
+
+	    // Position of this hit in sensor-local coordinates.
+	    Hep3Vector local = geom.transformGlobalToLocal(pos);
+
+	    double dz = Math.abs(local.z());
+	    if ( dz < mindz ){
+		mindz = dz;
+		closest_sim   = sim;
+		closest_local = local;
+	    }
+
+	}
+
+	// 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.
+
+	// 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);
+
+	// Step length  along the track required to move the track to the zlocal=0 plane.
+	double s = -closest_local.z()/tp.z();
+
+	// Local coord of intersection between the track and the plane.
+	Hep3Vector intersection = VecOp.add( closest_local, VecOp.mult( s, tp));
+
+	return intersection;
+
+    }
+
+
 } 
CVSspam 0.2.8