Print

Print


Commit in lcsim/src/org/lcsim/recon/tracking/digitization/sisim/config on MAIN
CaloDigiSetupDriver.java+328added 1.1
Digi Driver to create SimTrackerHits, RawTrackerHits and TrackerHits from SimCalorimeterHits. These can be fed into the HelicalTrackHitDriver and then used in SeedTracking

lcsim/src/org/lcsim/recon/tracking/digitization/sisim/config
CaloDigiSetupDriver.java added at 1.1
diff -N CaloDigiSetupDriver.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ CaloDigiSetupDriver.java	21 Aug 2012 12:04:12 -0000	1.1
@@ -0,0 +1,328 @@
+package org.lcsim.recon.tracking.digitization.sisim.config;
+
+import hep.physics.matrix.SymmetricMatrix;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.lcsim.conditions.ConditionsManager;
+import org.lcsim.conditions.ConditionsSet;
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.SimCalorimeterHit;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.event.TrackerHit;
+import org.lcsim.event.EventHeader.LCMetaData;
+import org.lcsim.event.base.BaseRawTrackerHit;
+import org.lcsim.event.base.BaseSimTrackerHit;
+import org.lcsim.event.base.BaseTrackerHit;
+import org.lcsim.geometry.Calorimeter;
+import org.lcsim.geometry.Detector;
+import org.lcsim.geometry.IDDecoder;
+import org.lcsim.geometry.compact.Segmentation;
+import org.lcsim.geometry.compact.converter.pandora.CalorimeterConditions;
+import org.lcsim.geometry.segmentation.CartesianGridXY;
+import org.lcsim.geometry.segmentation.GlobalGridXY;
+import org.lcsim.recon.cluster.nn.NearestNeighborClusterer;
+import org.lcsim.spacegeom.CartesianPoint;
+import org.lcsim.spacegeom.SpacePoint;
+import org.lcsim.util.Driver;
+
+public class CaloDigiSetupDriver extends Driver {
+
+	protected String inputCollection;
+	protected String simCollection;
+	protected String rawCollection;
+	protected String digiCollection;
+	protected double mipCut = 0.0;
+	protected double timeCut = 0.0;
+	protected List<Integer> layers;
+	protected int clusteringRange = 1;
+	
+	protected double oneCLusterError = 1./Math.sqrt(12);
+	protected double twoCLusterError = 1./5.;
+	protected double threeCLusterError = 1./3.;
+	protected double fourCLusterError = 1./2.;
+	protected double fiveCLusterError = 1.;
+	
+	/**
+	 * Driver to digitize SimCalorimeterHits as TrackerHits. Intended to be used for the first ECal layers which
+	 * have no absorber plates in front of them and thus are in fact tracking layers.
+	 * 
+	 * First applies threshold cuts from the calorimeter calibration and then performs a nearest neighbor clustering
+	 * on the SimCalorimeterHits. The clusters are converted into RawTrackerHits, maintaining a list of SimTrackerHits
+	 * that correspond to all energy deposits in the calorimeter cluster. There is no time or ADC values set for the
+	 * RawTrackerHits as there is no specific readout foreseen here. At the moment these raw hits only maintain the 
+	 * link to the MCParticles. Finally, TrackerHits are created from the RawTrackerHits. The energy is taken directly
+	 * from the cluster energy. Hit covariances are calculated from the cluster size.
+	 * 
+	 * TODO: Allow to use digitized calorimeter hits as input.
+	 * 
+	 * @author <a href="mailto:[log in to unmask]">Christian Grefe</a>
+	 */
+	public CaloDigiSetupDriver() {
+		// Intended to only use hits from the first layer
+		layers = new ArrayList<Integer>();
+		layers.add(0);
+	}
+	
+	/**
+	 * Sets the name of the collection of SimCalorimeterHits that are used as the input.
+	 * The output names are set automatically, e.g. setting the input collection to EcalBarrelHits
+	 * would produce collections: EcalBarrelTrackerHits, Raw_EcalBarrelTrackerHits and
+	 * Digi_EcalBarrelHits. 
+	 * @param inputCollection
+	 */
+	public void setInputCollection(String inputCollection) {
+		this.inputCollection = inputCollection;
+		// FIXME: maybe not hard code these names?!
+		this.simCollection = inputCollection.replace("Hits", "TrackerHits");
+		this.rawCollection = "Raw_" + inputCollection.replace("Hits", "TrackerHits");
+		this.digiCollection = "Digi_" + inputCollection.replace("Hits", "TrackerHits");
+	}
+	
+	public void setSimHitsCollectionName(String collectionName) {
+		this.simCollection = collectionName;
+	}
+	
+	public void setRawHitsCollectionName(String collectionName) {
+		this.rawCollection = collectionName;
+	}
+	
+	public void setTrackerHitsCollectionName(String collectionName) {
+		this.digiCollection = collectionName;
+	}
+	
+	public void setOneClusterErr(double error) {
+		this.oneCLusterError = error;
+	}
+	
+	public void setTwoClusterErr(double error) {
+		this.oneCLusterError = error;
+	}
+	
+	public void setThreeClusterErr(double error) {
+		this.oneCLusterError = error;
+	}
+	
+	public void setFourClusterErr(double error) {
+		this.oneCLusterError = error;
+	}
+	
+	public void setFiveClusterErr(double error) {
+		this.oneCLusterError = error;
+	}
+	
+	/**
+	 * Sets the calorimeter layers from which hits are converted into TrackerHits.
+	 * This is only intended for the first ECal layer, i.e. layer 0.
+	 * @param layers
+	 */
+	public void setLayers(int[] layers) {
+		this.layers = new ArrayList<Integer>();
+		for (int layer : layers) {
+			this.layers.add(layer);
+		}
+	}
+	
+	/**
+	 * Sets the search range for the nearest neighbor clustering in units of cells
+	 * @param maxClusterExtend
+	 */
+	public void setClusteringRange(int clusteringRange) {
+		this.clusteringRange = clusteringRange;
+	}
+	
+	@Override
+	protected void detectorChanged(Detector detector) {
+		Calorimeter calorimeter = (Calorimeter) detector.getReadout(inputCollection).getIDDecoder().getSubdetector();
+		ConditionsSet caloCalibration = ConditionsManager.defaultInstance().getConditions("CalorimeterCalibration");
+		CalorimeterConditions caloConditions = new CalorimeterConditions(calorimeter, caloCalibration);
+		mipCut = caloConditions.getMipCut();
+		timeCut = caloConditions.getTimeCut();
+	}
+	
+	@Override
+	protected void startOfData() {
+		if (inputCollection == null) {
+			throw new RuntimeException(getName() + ": missing inputCollectionName!");
+		}
+		if (simCollection == null) {
+			throw new RuntimeException(getName() + ": missing simCollectionName!");
+		}
+		if (rawCollection == null) {
+			throw new RuntimeException(getName() + ": missing rawCollectionName!");
+		}
+		if (digiCollection == null) {
+			throw new RuntimeException(getName() + ": missing digiCollectionName!");
+		}
+	}
+	
+	@Override
+	protected void process(EventHeader event) {
+		
+		// Find all calorimeter hits in the relevant layers
+		// Also apply mip threshold and timing cut
+		List<SimCalorimeterHit> inputCaloHits = event.get(SimCalorimeterHit.class, inputCollection); 
+		List<CalorimeterHit> caloHits = new ArrayList<CalorimeterHit>();
+		for (SimCalorimeterHit caloHit : inputCaloHits) {
+			if (layers.contains(caloHit.getLayerNumber()) && caloHit.getRawEnergy() > mipCut && (timeCut == 0 || caloHit.getTime() < timeCut)) {
+				caloHits.add(caloHit);
+			}
+		}
+		
+		// Get the ID decoder and cell sizes. Needed to determine hit resolution
+		LCMetaData meta = event.getMetaData(inputCaloHits);
+		String readoutName = inputCollection;
+		IDDecoder idDecoder = meta.getIDDecoder();
+		Segmentation segmentation = (Segmentation) idDecoder;
+		double cellSizeU = segmentation.getCellSizeU();
+		double cellSizeV = segmentation.getCellSizeV();
+		
+		// Clustering in a single calorimeter layer
+		NearestNeighborClusterer clusterer = new NearestNeighborClusterer( clusteringRange, clusteringRange, 0, 0, 0.);
+		List<Cluster> clusters = clusterer.createClusters(caloHits);
+		
+		// Lists to hold the hits for the output collections
+		List<SimTrackerHit> simHits = new ArrayList<SimTrackerHit>();
+		List<RawTrackerHit> rawHits = new ArrayList<RawTrackerHit>();
+		List<TrackerHit> digiHits = new ArrayList<TrackerHit>();
+		
+		for (Cluster cluster : clusters) {
+			IDetectorElement detectorElement = null;
+			double energy = 0.;
+			double energyTimeSum = 0.;
+			double xTimeSum = 0.;
+			double yTimeSum = 0.;
+			double zTimeSum = 0.;
+			
+			int minU = Integer.MAX_VALUE;
+			int maxU = -Integer.MAX_VALUE;
+			int minV = Integer.MAX_VALUE;
+			int maxV = -Integer.MAX_VALUE;
+			
+			List<RawTrackerHit> clusterRawHits = new ArrayList<RawTrackerHit>();
+			for (CalorimeterHit caloHit : cluster.getCalorimeterHits()) {
+				// Determine the detector element. Note that this is the layer and we expect only hits from a single layer in the cluster
+				if (detectorElement == null) detectorElement = caloHit.getDetectorElement();
+				long cellID = caloHit.getCellID();
+				
+				// FIXME: this should be some encoding based on the readout chip, for now we don't use the raw hits
+				int iTime = 0;
+				short[] adcValues = new short[] {0};
+				
+				List<SimTrackerHit> simTrackerHits = convertCalorimeterHit((SimCalorimeterHit)caloHit, meta);
+	        	
+				double hitTime = caloHit.getTime();
+	        	double hitEnergy = caloHit.getRawEnergy();
+	        	
+	        	// Calculations for energy weighted time and position
+	        	energy += hitEnergy;
+	        	energyTimeSum += hitTime*hitEnergy;
+	        	SpacePoint p = new SpacePoint(caloHit.getPositionVec());
+	        	xTimeSum += p.x()*hitEnergy;
+	        	yTimeSum += p.y()*hitEnergy;
+	        	zTimeSum += p.z()*hitEnergy;
+	        	
+	        	// Determine the cluster extent in local coordinate
+	        	int u = 0;
+	        	int v = 0;
+	        	if (segmentation instanceof CartesianGridXY) {
+	        		CartesianGridXY grid = (CartesianGridXY) segmentation;
+	        		u = grid.getXBin(p.x());
+	        		v = grid.getYBin(p.y());
+	        	} else if (segmentation instanceof GlobalGridXY) {
+	        		GlobalGridXY grid = (GlobalGridXY) segmentation;
+	        		u = grid.getXBin(p.x());
+	        		v = grid.getYBin(p.y());
+	        	} else {
+	        		throw new RuntimeException("Unknown IDDecoder - expected CartesianGridXY or GlobalGridXY");
+	        	}
+	        	if (u < minU) minU = u;
+	        	if (u > maxU) maxU = u;
+	        	if (v < minV) minV = v;
+	        	if (v > maxV) maxV = v;
+	        	
+	        	// Create the raw hit and fill keep the sim hits
+				clusterRawHits.add(new BaseRawTrackerHit(iTime, cellID, adcValues, simTrackerHits, detectorElement));
+				simHits.addAll(simTrackerHits);
+			}
+			// Calculate energy weighted hit time and position
+			double time = energyTimeSum / energy;
+			SpacePoint p = new CartesianPoint(xTimeSum / energy, yTimeSum / energy, zTimeSum / energy );
+			
+			// Calculate cluster dimensions in units of cells
+			int dU = maxU - minU + 1;
+			int dV = maxV - minV + 1;
+			
+			// Set the covariance matrix in local coordinates using the cluster size
+			SymmetricMatrix localCovariance = new SymmetricMatrix(3);
+			localCovariance.setElement(0, 0, Math.pow(cellSizeU*getPositionErrorFactor(dU), 2));
+			localCovariance.setElement(1, 1, Math.pow(cellSizeV*getPositionErrorFactor(dV), 2));
+			localCovariance.setElement(2, 2, 0.0); // layer thickness is negligible
+			
+	        // Transform into global coordinates for track fit
+			SymmetricMatrix globalCovariance = detectorElement.getGeometry().getLocalToGlobal().transformed(localCovariance);
+			
+			// Create the final tracker hit and fill all relevant lists
+			BaseTrackerHit digiHit = new BaseTrackerHit(p.v(), globalCovariance.asPackedArray(true), time, energy, 0);
+			digiHit.addRawTrackerHits(clusterRawHits);
+			rawHits.addAll(clusterRawHits);
+			digiHits.add(digiHit);
+		}
+		
+		// Save the collections in the event
+		event.put(simCollection, simHits, SimTrackerHit.class, 0, readoutName);
+		event.put(rawCollection, rawHits, RawTrackerHit.class, 0, readoutName);
+		event.put(digiCollection, digiHits, TrackerHit.class, 0, readoutName);
+	}
+	
+	
+	// Convenience method to set the appropriate cluster error
+	protected double getPositionErrorFactor(int size) {
+		double errorFactor = 0.0;
+		if (size == 1) {
+			errorFactor = oneCLusterError;
+		} else if (size == 2) {
+			errorFactor = twoCLusterError;
+		} else if (size == 3) {
+			errorFactor = threeCLusterError;
+		} else if (size == 4) {
+			errorFactor = fourCLusterError;
+		} else {
+			errorFactor = fiveCLusterError;
+		}
+		return errorFactor;
+	}
+	
+	
+	// Generic method to convert all contributions of a SimCalorimeterHit into SimTrackerHits
+	static public List<SimTrackerHit> convertCalorimeterHit(SimCalorimeterHit caloHit, LCMetaData meta) {
+		List<SimTrackerHit> trackerHits = new ArrayList<SimTrackerHit>();
+		SpacePoint position = new SpacePoint(caloHit.getPositionVec());
+		IDetectorElement de = caloHit.getDetectorElement();
+		int cellID = (int) caloHit.getCellID();
+		for (int iMCP = 0; iMCP < caloHit.getMCParticleCount(); iMCP++) {
+			MCParticle mcp = caloHit.getMCParticle(iMCP);
+			double energy = caloHit.getContributedEnergy(iMCP);
+			double time = caloHit.getContributedTime(iMCP);
+			SpacePoint momentum = new SpacePoint(mcp.getMomentum()); // this should be a SpacePointVector!
+			// FIXME: use the step position in new LCIO version
+			//float[] stepPosition = caloHit.getStepPosition(iMCP);
+			//SpacePoint mcpPosition = new CartesianPoint(stepPosition[0], stepPosition[1], stepPosition[2]);
+			double pathLength = 0;
+			BaseSimTrackerHit trackerHit = new BaseSimTrackerHit(position.v(), energy, momentum.v(), pathLength, time, cellID, mcp, meta, de);
+			// FIXME: manually set the long id, should be done by the constructor above
+			trackerHit.setCellID64(caloHit.getCellID());
+			
+			trackerHits.add(trackerHit);
+		}
+		return trackerHits;	
+	}
+	
+}
CVSspam 0.2.12


Use REPLY-ALL to reply to list

To unsubscribe from the LCD-CVS list, click the following link:
https://listserv.slac.stanford.edu/cgi-bin/wa?SUBED1=LCD-CVS&A=1