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