hps-java/src/main/java/org/lcsim/hps/users/meeg
diff -N SimpleTrackerDigiDriver.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ SimpleTrackerDigiDriver.java 29 Aug 2012 21:01:36 -0000 1.1
@@ -0,0 +1,317 @@
+package org.lcsim.hps.users.meeg;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.detector.identifier.IIdentifier;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiTrackerIdentifierHelper;
+import org.lcsim.detector.tracker.silicon.SiTrackerModule;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.geometry.Detector;
+import org.lcsim.hps.recon.tracking.SvtUtils;
+import org.lcsim.recon.tracking.digitization.sisim.CDFSiSensorSim;
+import org.lcsim.recon.tracking.digitization.sisim.NearestNeighborRMS;
+import org.lcsim.recon.tracking.digitization.sisim.RawTrackerHitMaker;
+import org.lcsim.recon.tracking.digitization.sisim.SiDigitizer;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHit;
+import org.lcsim.recon.tracking.digitization.sisim.SiTrackerHitStrip1D;
+import org.lcsim.recon.tracking.digitization.sisim.StripHitMaker;
+import org.lcsim.recon.tracking.digitization.sisim.config.SimTrackerHitReadoutDriver;
+import org.lcsim.util.Driver;
+import org.lcsim.util.lcio.LCIOUtil;
+
+/**
+ * This Driver runs the tracker digitization to create raw hits and strip hits
+ * from simulated data. The output can be used by a track reconstruction
+ * algorithm like Seed Tracker.
+ *
+ * @author jeremym
+ * @version $Id: SimpleTrackerDigiDriver.java,v 1.1 2012/08/29 21:01:36 meeg Exp $
+ */
+public class SimpleTrackerDigiDriver extends Driver {
+ // Debug switch for development.
+
+ private boolean debug = false;
+ // Collection name.
+ private String readoutCollectionName = "TrackerHits";
+ // Subdetector name.
+ private String subdetectorName = "Tracker";
+ // Name of RawTrackerHit output collection.
+ private String rawTrackerHitOutputCollectionName = "RawTrackerHitMaker_RawTrackerHits";
+ // Name of StripHit1D output collection.
+ private String stripHitOutputCollectionName = "StripClusterer_SiTrackerHitStrip1D";
+ // Readout parameters.
+ private boolean dropBadChannels = true;
+ private double readoutNoiseIntercept = 270.0;
+ private double readoutNoiseSlope = 36.0;
+ private int readoutNBits = 10;
+ private int readoutDynamicRange = 40;
+ // Clustering parameters.
+ private double clusterSeedThreshold = 4.0;
+ private double clusterNeighborThreshold = 3.0;
+ private double clusterThreshold = 4.0;
+ private int clusterMaxSize = 10;
+ private int clusterCentralStripAveragingThreshold = 4;
+ // Clustering errors by number of TrackerHits.
+ private static final double clusterErrorMultiplier = 1.0;
+ private double oneClusterErr = clusterErrorMultiplier / Math.sqrt(12.);
+ private double twoClusterErr = clusterErrorMultiplier / 5.0;
+ private double threeClusterErr = clusterErrorMultiplier / 3.0;
+ private double fourClusterErr = clusterErrorMultiplier / 2.0;
+ private double fiveClusterErr = clusterErrorMultiplier / 1.0;
+ // Various data lists required by digitization.
+ private List<String> readouts = new ArrayList<String>();
+ private List<String> processPaths = new ArrayList<String>();
+ private List<IDetectorElement> processDEs = new ArrayList<IDetectorElement>();
+ private Set<SiSensor> processSensors = new HashSet<SiSensor>();
+ private Set<SiTrackerModule> processModules = new HashSet<SiTrackerModule>();
+ // Digi class objects.
+ private SiDigitizer stripDigitizer;
+ private StripHitMaker stripClusterer;
+ int[][] counts = new int[2][10];
+
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ public void setReadoutCollectionName(String readoutCollectionName) {
+ this.readoutCollectionName = readoutCollectionName;
+ }
+
+ public void setSubdetectorName(String subdetectorName) {
+ this.subdetectorName = subdetectorName;
+ }
+
+ public void setRawTrackerHitOutputCollectionName(String rawTrackerHitOutputCollectionName) {
+ this.rawTrackerHitOutputCollectionName = rawTrackerHitOutputCollectionName;
+ }
+
+ public void setStripHitOutputCollectionName(String stripHitOutputCollectionName) {
+ this.stripHitOutputCollectionName = stripHitOutputCollectionName;
+ }
+
+ public void setDropBadChannels(boolean dropBadChannels) {
+ this.dropBadChannels = dropBadChannels;
+ }
+
+ public void setReadoutNoiseIntercept(double readoutNoiseIntercept) {
+ this.readoutNoiseIntercept = readoutNoiseIntercept;
+ }
+
+ public void setReadoutNoiseSlope(double readoutNoiseSlope) {
+ this.readoutNoiseSlope = readoutNoiseSlope;
+ }
+
+ public void setReadoutNBits(int readoutNBits) {
+ this.readoutNBits = readoutNBits;
+ }
+
+ public void setReadoutDynamicRange(int readoutDynamicRange) {
+ this.readoutDynamicRange = readoutDynamicRange;
+ }
+
+ public void setClusterSeedThreshold(double clusterSeedThreshold) {
+ this.clusterSeedThreshold = clusterSeedThreshold;
+ }
+
+ public void setClusterNeighborThreshold(double clusterNeighborThreshold) {
+ this.clusterNeighborThreshold = clusterNeighborThreshold;
+ }
+
+ public void setClusterThreshold(double clusterThreshold) {
+ this.clusterThreshold = clusterThreshold;
+ }
+
+ public void setClusterMaxSize(int clusterMaxSize) {
+ this.clusterMaxSize = clusterMaxSize;
+ }
+
+ public void setClusterCentralStripAveragingThreshold(int clusterCentralStripAveragingThreshold) {
+ this.clusterCentralStripAveragingThreshold = clusterCentralStripAveragingThreshold;
+ }
+
+ public void setOneClusterErr(double oneClusterErr) {
+ this.oneClusterErr = oneClusterErr;
+ }
+
+ public void setTwoClusterErr(double twoClusterErr) {
+ this.twoClusterErr = twoClusterErr;
+ }
+
+ public void setThreeClusterErr(double threeClusterErr) {
+ this.threeClusterErr = threeClusterErr;
+ }
+
+ public void setFourClusterErr(double fourClusterErr) {
+ this.fourClusterErr = fourClusterErr;
+ }
+
+ public void setFiveClusterErr(double fiveClusterErr) {
+ this.fiveClusterErr = fiveClusterErr;
+ }
+
+ /**
+ * Creates a new instance of TrackerHitDriver.
+ */
+ public SimpleTrackerDigiDriver() {
+ }
+
+ /**
+ * Initializes this Driver's objects with the job parameters.
+ */
+ private void initialize() {
+
+ // Create the sensor simulation.
+ CDFSiSensorSim stripSim = new CDFSiSensorSim();
+
+ // Create the readout chips and set the noise parameters.
+ NoiselessReadoutChip stripReadout = new NoiselessReadoutChip();
+ stripReadout.setDropBadChannels(dropBadChannels);
+ stripReadout.setNoiseIntercept(readoutNoiseIntercept);
+ stripReadout.setNoiseSlope(readoutNoiseSlope);
+ stripReadout.setNbits(readoutNBits);
+ stripReadout.setDynamicRange(readoutDynamicRange);
+
+ // Create the digitizer that produces the raw hits
+ stripDigitizer = new RawTrackerHitMaker(stripSim, stripReadout);
+
+ // Create Strip clustering algorithm.
+ NearestNeighborRMS stripClusteringAlgo = new NearestNeighborRMS();
+ stripClusteringAlgo.setSeedThreshold(clusterSeedThreshold);
+ stripClusteringAlgo.setNeighborThreshold(clusterNeighborThreshold);
+ stripClusteringAlgo.setClusterThreshold(clusterThreshold);
+
+ // Create the clusterers and set hit-making parameters.
+ stripClusterer = new StripHitMaker(stripSim, stripReadout, stripClusteringAlgo);
+ stripClusterer.setMaxClusterSize(clusterMaxSize);
+ stripClusterer.setCentralStripAveragingThreshold(clusterCentralStripAveragingThreshold);
+
+ // Set the cluster errors.
+ stripClusterer.SetOneClusterErr(oneClusterErr);
+ stripClusterer.SetTwoClusterErr(twoClusterErr);
+ stripClusterer.SetThreeClusterErr(threeClusterErr);
+ stripClusterer.SetFourClusterErr(fourClusterErr);
+ stripClusterer.SetFiveClusterErr(fiveClusterErr);
+
+ // Set the readout to process.
+ readouts.add(readoutCollectionName);
+
+ // Set the detector to process.
+ processPaths.add(subdetectorName);
+ }
+
+ /**
+ * This is executed before detectorChanged and initialization of
+ * digitization objects is done here.
+ */
+ @Override
+ public void startOfData() {
+
+ // At start of job, setup digitization objects needed by this Driver.
+ initialize();
+
+ // If readouts not already set, set them up.
+ if (!readouts.isEmpty()) {
+ System.out.println("Adding SimTrackerHitIdentifierReadoutDriver with readouts: " + readouts);
+ super.add(new SimTrackerHitReadoutDriver(readouts));
+ }
+ super.startOfData();
+ readouts.clear(); // FIXME Is this needed?
+ }
+
+ /**
+ * Do initialization once we get a Detector.
+ */
+ @Override
+ public void detectorChanged(Detector detector) {
+
+ // Call sub-Driver's detectorChanged methods.
+ super.detectorChanged(detector);
+
+ // Process detectors specified by path, otherwise process entire
+ // detector
+ IDetectorElement deDetector = detector.getDetectorElement();
+
+ for (String path : processPaths) {
+ processDEs.add(deDetector.findDetectorElement(path));
+ }
+
+ if (processDEs.isEmpty()) {
+ processDEs.add(deDetector);
+ }
+
+ for (IDetectorElement detectorElement : processDEs) {
+ processSensors.addAll(detectorElement.findDescendants(SiSensor.class));
+ //if (debug)
+ // System.out.println("added " + processSensors.size() + " sensors");
+ processModules.addAll(detectorElement.findDescendants(SiTrackerModule.class));
+ //if (debug)
+ // System.out.println("added " + processModules.size() + " modules");
+ }
+ }
+
+ /**
+ * Perform the digitization.
+ */
+ @Override
+ public void process(EventHeader event) {
+ // Call sub-Driver processing.
+ super.process(event);
+
+ // Make new lists for output.
+ List<RawTrackerHit> rawHits = new ArrayList<RawTrackerHit>();
+ List<SiTrackerHit> stripHits1D = new ArrayList<SiTrackerHit>();
+
+ if (event.hasCollection(SimTrackerHit.class, this.readoutCollectionName)) {
+ // Make raw hits.
+ for (SiSensor sensor : processSensors) {
+ rawHits.addAll(stripDigitizer.makeHits(sensor));
+ }
+
+ // Make strip hits.
+ for (SiSensor sensor : processSensors) {
+ stripHits1D.addAll(stripClusterer.makeHits(sensor));
+ }
+
+ // Debug prints.
+ if (debug) {
+ if (event.hasCollection(SimTrackerHit.class, this.readoutCollectionName)) {
+ List<SimTrackerHit> simHits = event.get(SimTrackerHit.class, this.readoutCollectionName);
+ System.out.println("SimTrackerHit collection " + this.readoutCollectionName + " has " + simHits.size() + " hits.");
+ System.out.println("RawTrackerHit collection " + this.rawTrackerHitOutputCollectionName + " has " + rawHits.size() + " hits.");
+ System.out.println("TrackerHit collection " + this.stripHitOutputCollectionName + " has " + stripHits1D.size() + " hits.");
+ } else {
+ System.out.println("SimTrackerHit collection " + this.readoutCollectionName + " not found.");
+ }
+ }
+ }
+
+ if (debug) {
+ for (int mod = 0; mod < 2; mod++) {
+ for (int layer = 0; layer < 10; layer++) {
+ counts[mod][layer] += SvtUtils.getInstance().getSensor(mod, layer).getReadout().getHits(RawTrackerHit.class).size();
+ }
+ }
+ }
+ // Put output hits into collection.
+ int flag = LCIOUtil.bitSet(0, 31, true); // Turn on 64-bit cell ID.
+ event.put(this.rawTrackerHitOutputCollectionName, rawHits, RawTrackerHit.class, flag, toString());
+ event.put(this.stripHitOutputCollectionName, stripHits1D, SiTrackerHitStrip1D.class, 0, toString());
+ }
+
+ public void endOfData() {
+ if (debug) {
+ for (int mod = 0; mod < 2; mod++) {
+ for (int layer = 0; layer < 10; layer++) {
+ System.out.format("mod %d, layer %d, count %d, ID %d\n", mod, layer, counts[mod][layer], SvtUtils.getInstance().getSensor(mod, layer).getIdentifier().getValue());
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
hps-java/src/main/java/org/lcsim/hps/users/meeg
diff -N NoiselessReadoutChip.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ NoiselessReadoutChip.java 29 Aug 2012 21:01:36 -0000 1.1
@@ -0,0 +1,314 @@
+/*
+ * Class BasicReadoutChip
+ */
+package org.lcsim.hps.users.meeg;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import org.lcsim.detector.tracker.silicon.SiSensor;
+import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
+import org.lcsim.event.RawTrackerHit;
+import org.lcsim.hps.recon.tracking.HPSSVTCalibrationConstants;
+import org.lcsim.recon.tracking.digitization.sisim.ReadoutChip;
+import org.lcsim.recon.tracking.digitization.sisim.ReadoutChip.ReadoutChannel;
+import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeData;
+import org.lcsim.recon.tracking.digitization.sisim.SiElectrodeDataCollection;
+
+/**
+ * Basic readout chip class. This class supports the minimal functions expected of
+ * a readout chip. The charge on a strip/pixel is digitized as an integer number
+ * with a simple ADC with programmable resolution and dynamic range. A chip with
+ * 1-bit ADC resolution (binary readout) is treated as a special case.
+ *
+ * Noise is added to strips with charge and random noise hits are generated as well.
+ * Methods are provided to decode the charge and time (although the current
+ * implementation always returns a time of 0).
+ *
+ * This implementation has thresholds that are settable in units of RMS noise of
+ * each channel to enable simluation of highly optimized readout chains. If
+ * absolute thresholds are desired, GenericReadoutChip should be used instead.
+ *
+ * @author Tim Nelson
+ */
+public class NoiselessReadoutChip implements ReadoutChip {
+
+ private BasicChannel _channel = new BasicChannel();
+ private ADC _adc = new ADC();
+ private boolean dropBadChannels = false;
+
+ /** Creates a new instance of BasicReadoutChip */
+ public NoiselessReadoutChip() {
+ }
+
+ public void setDropBadChannels(boolean dropBadChannels) {
+ this.dropBadChannels = dropBadChannels;
+ }
+
+ /**
+ * Set the noise intercept (i.e., the noise for 0 strip/pixel capacitance).
+ * Units are electrons of noise.
+ *
+ * @param noise_intercept noise for 0 capacitance
+ */
+ public void setNoiseIntercept(double noise_intercept) {
+ _channel.setNoiseIntercept(noise_intercept);
+ }
+
+ /**
+ * Set the noise slope (i.e., the proportionality between noise and capacitance).
+ * Units are electrons of noise per fF of capacitance.
+ *
+ * @param noise_slope noise slope per unit capacitance
+ */
+ public void setNoiseSlope(double noise_slope) {
+ _channel.setNoiseSlope(noise_slope);
+ }
+
+ /**
+ * Set the number of bits of ADC resolution
+ *
+ * @param nbits
+ */
+ public void setNbits(int nbits) {
+ getADC().setNbits(nbits);
+ }
+
+ /**
+ * Set the dynamic range of the ADC
+ *
+ * @param dynamic_range in fC
+ */
+ public void setDynamicRange(double dynamic_range) {
+ getADC().setDynamicRange(dynamic_range);
+ }
+
+ /**
+ * Return the BasicChannel associated with a given channel number.
+ * For the basic readout, there is a single instance of BasicChannel
+ * and thus the channel number is ignored.
+ *
+ * @param channel_number channel number
+ * @return associated BasicReadoutChannel
+ */
+ public BasicChannel getChannel(int channel_number) {
+ return _channel;
+ }
+
+ private ADC getADC() {
+ return _adc;
+ }
+
+ /**
+ * Given a collection of electrode data (i.e., charge on strips/pixels),
+ * return a map associating the channel and it's list of raw data.
+ *
+ * @param data electrode data from the charge distribution
+ * @param electrodes strip or pixel electrodes
+ * @return map containing the ADC counts for this sensor
+ */
+ public SortedMap<Integer, List<Integer>> readout(SiElectrodeDataCollection data, SiSensorElectrodes electrodes) {
+
+ // If there is no electrode data for this readout chip, create an empty
+ // electrode data collection
+ if (data == null) {
+ data = new SiElectrodeDataCollection();
+ }
+
+ // Add noise hits to the electrode data collection
+// addNoise(data, electrodes);
+
+ // return the digitized charge data as a map that associates a hit
+ // channel with a list of raw data for the channel
+ return digitize(data, electrodes);
+ }
+
+ /**
+ * Decode the hit charge stored in the RawTrackerHit
+ *
+ * @param hit raw hit
+ * @return hit charge in units of electrons
+ */
+ public double decodeCharge(RawTrackerHit hit) {
+ return getADC().decodeCharge(hit.getADCValues()[0]);
+ }
+
+ /**
+ * Decode the hit time. Currently, the basic readout chip ignores the
+ * hit time and returns 0.
+ *
+ * @param hit raw hit data
+ * @return hit time
+ */
+ public int decodeTime(RawTrackerHit hit) {
+ return 0;
+ }
+
+ /**
+ * Digitizes the hit channels in a SiElectrodeDataCollection.
+ *
+ * The SiElectrodeDataCollection is a map that associates a given channel with
+ * it's SiElectrodeData. The SiElectrodeData encapsulates the deposited charge
+ * on an strip/pixel and any associated SimTrackerHits.
+ *
+ * The output of this class is a map that associates a channel number with
+ * a list of raw data
+ *
+ * @param data electrode data collection
+ * @return map associating channels with a list of raw data
+ */
+ private SortedMap<Integer, List<Integer>> digitize(SiElectrodeDataCollection data,
+ SiSensorElectrodes electrodes) {
+ // Create the map that associates a given sensor channel with it's list of raw data
+ SortedMap<Integer, List<Integer>> chip_data = new TreeMap<Integer, List<Integer>>();
+
+ // Loop over the channels contained in the SiElectrodeDataCollection
+ for (Integer channel : data.keySet()) {
+ if (dropBadChannels && HPSSVTCalibrationConstants.isBadChannel((SiSensor) electrodes.getDetectorElement(), channel)) {
+// System.out.format("%d bad\n", channel);
+ continue;
+ }
+// System.out.format("%d OK\n", channel);
+ // Fetch the electrode data for this channel
+ SiElectrodeData eldata = data.get(channel);
+
+ // Get the charge in units of electrons
+ double charge = eldata.getCharge();
+
+ // Calculate the ADC value for this channel and make sure it is positive
+ int adc = getADC().convert(charge);
+ if (adc <= 0) {
+ continue;
+ }
+
+ // Create a list containing the adc value - for the basic readout
+ // there is only 1 word of raw data
+ List<Integer> channel_data = new ArrayList<Integer>();
+ channel_data.add(adc);
+
+ // Save the list of raw data in the chip_data map
+ chip_data.put(channel, channel_data);
+ }
+
+ return chip_data;
+ }
+
+ /**
+ * BasicChannel class representing a single channel's behavior
+ *
+ * Note that binary readout is a special case. Anything positive value
+ * passed to a binary ADC for digitization is assumed to have crossed t
+ * hreshold and is assigned a value of 1. Decoding binary readout results
+ * in either 0 or dynamic_range.
+ */
+ private class BasicChannel implements ReadoutChannel {
+
+ private double _noise_intercept = 0.;
+ private double _noise_slope = 0.;
+
+ /**
+ * Set the noise (in electrons) for 0 capacitance
+ *
+ * @param noise_intercept noise intercept
+ */
+ private void setNoiseIntercept(double noise_intercept) {
+ _noise_intercept = noise_intercept;
+ }
+
+ /**
+ * Set the capacitative noise slope (in electrons / pF)
+ *
+ * @param noise_slope noise slope
+ */
+ private void setNoiseSlope(double noise_slope) {
+ _noise_slope = noise_slope;
+ }
+
+ /**
+ * Return the noise in electrons for a given strip/pixel capacitance
+ *
+ * @param capacitance capacitance in pF
+ * @return noise in electrons
+ */
+ public double computeNoise(double capacitance) {
+ return _noise_intercept + _noise_slope * capacitance;
+ }
+ }
+
+ /**
+ * ADC class representing analog to digital converter.
+ */
+ private class ADC {
+
+ private int _nbits = 8;
+ private double _dynamic_range = 20.;
+
+ /**
+ * Set the ADC resolution in number of bits.
+ *
+ * @param nbits number of bits
+ */
+ private void setNbits(int nbits) {
+ _nbits = nbits;
+ }
+
+ /**
+ * Set the dynamic range in fC
+ *
+ * @param dynamic range
+ */
+ private void setDynamicRange(double dynamic_range) {
+ _dynamic_range = dynamic_range;
+ }
+
+ /**
+ * Compute the maximum ADC value
+ *
+ * @return largest possible ADC value according to # of bits
+ */
+ private int maxADCValue() {
+ return (int) Math.pow(2, _nbits) - 1;
+ }
+
+ /**
+ * Compute the conversion constant in ADC/fC
+ *
+ * @return conversion constant for ADC
+ */
+ private double conversionConstant() {
+ return maxADCValue() / _dynamic_range;
+ }
+
+ /**
+ * Perform analog to digital conversion
+ *
+ * @return digital ADC output between 0 and maxADCValue
+ */
+ public int convert(double charge) {
+ if (_nbits != 1) {
+ return Math.max(0, Math.min(maxADCValue(), (int) Math.floor(charge * 1.602e-4 * conversionConstant())));
+ } else {
+ if (charge <= 0.0) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ }
+
+ /**
+ * Decode charge from ADC value
+ *
+ * @return charge specified by a given ADC value
+ */
+ public double decodeCharge(int adc_value) {
+ if (_nbits != 1) {
+ return (adc_value + 0.5) / (1.602e-4 * conversionConstant());
+ } else {
+ return adc_value * _dynamic_range;
+ }
+
+ }
+ }
+}