Author: [log in to unmask]
Date: Mon Jun 8 19:17:47 2015
New Revision: 3115
Log:
change default pulse width to 9.6 ns
Modified:
java/trunk/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCEcalReadoutDriver.java
Modified: java/trunk/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCEcalReadoutDriver.java
=============================================================================
--- java/trunk/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCEcalReadoutDriver.java (original)
+++ java/trunk/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCEcalReadoutDriver.java Mon Jun 8 19:17:47 2015
@@ -49,41 +49,26 @@
private Subdetector ecal;
private EcalConditions ecalConditions = null;
//buffer for preamp signals (units of volts, no pedestal)
- private Map<Long, RingBuffer> signalMap = null;
+ private Map<Long, RingBuffer> analogPipelines = null;
//ADC pipeline for readout (units of ADC counts)
- private Map<Long, FADCPipeline> pipelineMap = null;
+ private Map<Long, FADCPipeline> digitalPipelines = null;
//buffer for window sums
- private Map<Long, Integer> sumMap = null;
+ private Map<Long, Integer> triggerPathHitSums = null;
//buffer for timestamps
- private Map<Long, Integer> timeMap = null;
+ private Map<Long, Integer> triggerPathHitTimes = null;
//queue for hits to be output to clusterer
- private PriorityQueue<RawCalorimeterHit> outputQueue = null;
- //length of ring buffer (in readout cycles)
+ private PriorityQueue<RawCalorimeterHit> triggerPathDelayQueue = null;
+ //output buffer for hits
+ private LinkedList<RawCalorimeterHit> triggerPathCoincidenceQueue = new LinkedList<RawCalorimeterHit>();
private int bufferLength = 100;
- //length of readout pipeline (in readout cycles)
private int pipelineLength = 2000;
- //shaper time constant in ns
- private double tp = 6.95;
- //delay (number of readout periods) between start of summing window and output of hit to clusterer
+ private double tp = 9.6;
private int delay0 = 32;
- //start of readout window relative to trigger time (in readout cycles)
- //in FADC documentation, "Programmable Latency" or PL
private int readoutLatency = 100;
- //number of ADC samples to read out
- //in FADC documentation, "Programmable Trigger Window" or PTW
private int readoutWindow = 100;
- //number of ADC samples to read out before each rising threshold crossing
- //in FADC documentation, "number of samples before" or NSB
private int numSamplesBefore = 5;
- //number of ADC samples to read out after each rising threshold crossing
- //in FADC documentation, "number of samples before" or NSA
private int numSamplesAfter = 30;
-// private HPSEcalConverter converter = null;
- //output buffer for hits
- private LinkedList<RawCalorimeterHit> buffer = new LinkedList<RawCalorimeterHit>();
- //number of readout periods for which a given hit stays in the buffer
private int coincidenceWindow = 2;
- //output collection name for hits read out from trigger
private String ecalReadoutCollectionName = "EcalReadoutHits";
private int mode = ECAL_PULSE_INTEGRAL_MODE;
private int readoutThreshold = 10;
@@ -92,17 +77,8 @@
private double fixedGain = -1;
private boolean constantTriggerWindow = true;
private boolean addNoise = false;
-
- // 32.8 p.e./MeV = New detector in 2014
- // 2 p.e./MeV = Test Run detector
- private double pePerMeV = 32.8; //photoelectrons per MeV, used to calculate noise
-
- //switch between test run and 2014 definitions of gain constants
- // true = ONLY simulation studies in 2014
- // false = Test Run data/simulations and 2014+ Detector's real data
+ private double pePerMeV = 32.8;
private boolean use2014Gain = false;
-
- //switch between three pulse shape functions
private PulseShape pulseShape = PulseShape.ThreePole;
public enum PulseShape {
@@ -118,14 +94,34 @@
// converter = new HPSEcalConverter(null);
}
+ /**
+ * Add noise (photoelectron statistics and readout/preamp noise) to hits
+ * before adding them to the analog pipeline.
+ *
+ * @param addNoise True to add noise, default of false.
+ */
public void setAddNoise(boolean addNoise) {
this.addNoise = addNoise;
}
+ /**
+ * Sets the trigger-path hit processing algorithm.
+ *
+ * @param constantTriggerWindow True for 2014+ FADC behavior, false for test
+ * run behavior. True by default.
+ */
public void setConstantTriggerWindow(boolean constantTriggerWindow) {
this.constantTriggerWindow = constantTriggerWindow;
}
+ /**
+ * Override the ECal gains set in the conditions system with a single
+ * uniform value.
+ *
+ * @param fixedGain Units of MeV/(ADC counts in pulse integral). Negative
+ * value causes the conditions system to be used for gains. Default is
+ * negative.
+ */
public void setFixedGain(double fixedGain) {
this.fixedGain = fixedGain;
}
@@ -134,78 +130,176 @@
this.ecalName = ecalName;
}
+ /**
+ * Threshold for readout-path hits. For 2014+ running this should always
+ * equal the trigger threshold.
+ *
+ * @param readoutThreshold Units of ADC counts, default of 10.
+ */
public void setReadoutThreshold(int readoutThreshold) {
this.readoutThreshold = readoutThreshold;
}
+ /**
+ * Scale factor for trigger-path hit amplitudes. Only used for test run.
+ *
+ * @param scaleFactor Default of 1.
+ */
public void setScaleFactor(double scaleFactor) {
this.scaleFactor = scaleFactor;
}
+ /**
+ * Threshold for trigger-path hits. For 2014+ running this should always
+ * equal the readout threshold.
+ *
+ * @param triggerThreshold Units of ADC counts, default of 10.
+ */
public void setTriggerThreshold(int triggerThreshold) {
this.triggerThreshold = triggerThreshold;
}
+ /**
+ * Output collection name for readout-path hits.
+ *
+ * @param ecalReadoutCollectionName
+ */
public void setEcalReadoutCollectionName(String ecalReadoutCollectionName) {
this.ecalReadoutCollectionName = ecalReadoutCollectionName;
}
+ /**
+ * Number of ADC samples to process after each rising threshold crossing. In
+ * FADC documentation, "number of samples after" or NSA.
+ *
+ * @param numSamplesAfter Units of 4 ns FADC clock cycles, default of 30.
+ */
public void setNumSamplesAfter(int numSamplesAfter) {
this.numSamplesAfter = numSamplesAfter;
}
+ /**
+ * Number of ADC samples to process before each rising threshold crossing.
+ * In FADC documentation, "number of samples before" or NSB.
+ *
+ * @param numSamplesBefore Units of 4 ns FADC clock cycles, default of 5.
+ */
public void setNumSamplesBefore(int numSamplesBefore) {
this.numSamplesBefore = numSamplesBefore;
}
+ /**
+ * Start of readout window relative to trigger time (in readout cycles). In
+ * FADC documentation, "Programmable Latency" or PL.
+ *
+ * @param readoutLatency Units of 4 ns FADC clock cycles, default of 100.
+ */
public void setReadoutLatency(int readoutLatency) {
this.readoutLatency = readoutLatency;
}
+ /**
+ * Number of ADC samples to read out. In FADC documentation, "Programmable
+ * Trigger Window" or PTW.
+ *
+ * @param readoutWindow Units of 4 ns FADC clock cycles, default of 100.
+ */
public void setReadoutWindow(int readoutWindow) {
this.readoutWindow = readoutWindow;
}
+ /**
+ * Number of clock cycles for which the same trigger-path hit is sent to the
+ * clusterer. Only used for old clusterer simulations (CTPClusterDriver).
+ * Otherwise this should be set to 1.
+ *
+ * @param coincidenceWindow Units of 4 ns FADC clock cycles, default of 1.
+ */
public void setCoincidenceWindow(int coincidenceWindow) {
this.coincidenceWindow = coincidenceWindow;
}
+ /**
+ * Switch between test run and 2014 definitions of gain constants. True for
+ * MC studies and mock data in 2014. For all real data (test run and 2014+),
+ * test run MC, and 2015+ production MC, this should be false.
+ *
+ *
+ * @param use2014Gain True ONLY for simulation studies in 2014. Default of
+ * false.
+ */
public void setUse2014Gain(boolean use2014Gain) {
this.use2014Gain = use2014Gain;
}
+ /**
+ * Model used for the preamp pulse shape.
+ *
+ * @param pulseShape ThreePole, DoubleGaussian, or CRRC. Default is
+ * ThreePole.
+ */
public void setPulseShape(String pulseShape) {
this.pulseShape = PulseShape.valueOf(pulseShape);
}
+ /**
+ * Shaper time constant. Definition depends on the pulse shape. For the
+ * three-pole function, this is equal to RC, or half the peaking time.
+ *
+ * @param tp Units of ns, default of 9.6.
+ */
public void setTp(double tp) {
this.tp = tp;
}
-// public void setFallTime(double fallTime) {
-// this.fallTime = fallTime;
-// }
+ /**
+ * Photoelectrons per MeV, used to calculate noise due to photoelectron
+ * statistics. Test run detector had a value of 2 photoelectrons/MeV; new
+ * 2014 detector has a value of 32.8 photoelectrons/MeV.
+ *
+ * @param pePerMeV Units of photoelectrons/MeV, default of 32.8.
+ */
public void setPePerMeV(double pePerMeV) {
this.pePerMeV = pePerMeV;
}
-// public void setRiseTime(double riseTime) {
-// this.riseTime = riseTime;
-// }
+ /**
+ * Latency between threshold crossing and output of trigger-path hit to
+ * clusterer.
+ *
+ * @param delay0 Units of 4 ns FADC clock cycles, default of 32.
+ */
public void setDelay0(int delay0) {
this.delay0 = delay0;
}
+ /**
+ * Length of analog pipeline.
+ *
+ * @param bufferLength Units of 4 ns FADC clock cycles, default of 100.
+ */
public void setBufferLength(int bufferLength) {
this.bufferLength = bufferLength;
resetFADCBuffers();
}
+ /**
+ * Length of digital pipeline. The digital pipeline in the FADC is 2000
+ * cells long.
+ *
+ * @param pipelineLength Units of 4 ns FADC clock cycles, default of 2000.
+ */
public void setPipelineLength(int pipelineLength) {
this.pipelineLength = pipelineLength;
resetFADCBuffers();
}
+ /**
+ * Mode for readout-path hits.
+ *
+ * @param mode 1, 2 or 3. Values correspond to the standard FADC mode
+ * numbers (1=raw, 2=pulse, 3=pulse integral).
+ */
public void setMode(int mode) {
this.mode = mode;
if (mode != ECAL_RAW_MODE && mode != ECAL_PULSE_MODE && mode != ECAL_PULSE_INTEGRAL_MODE) {
@@ -219,7 +313,7 @@
* @return
*/
public Map<Long, RingBuffer> getSignalMap() {
- return signalMap;
+ return analogPipelines;
}
/**
@@ -228,16 +322,23 @@
* @return
*/
public Map<Long, FADCPipeline> getPipelineMap() {
- return pipelineMap;
- }
-
+ return digitalPipelines;
+ }
+
+ /**
+ * Digitize values in the analog pipelines and append them to the digital
+ * pipelines. Integrate trigger-path hits and add them to the trigger path
+ * queues. Read out trigger-path hits to the list sent to the clusterer.
+ *
+ * @param hits List to be filled by this method.
+ */
@Override
protected void readHits(List<RawCalorimeterHit> hits) {
- for (Long cellID : signalMap.keySet()) {
- RingBuffer signalBuffer = signalMap.get(cellID);
-
- FADCPipeline pipeline = pipelineMap.get(cellID);
+ for (Long cellID : analogPipelines.keySet()) {
+ RingBuffer signalBuffer = analogPipelines.get(cellID);
+
+ FADCPipeline pipeline = digitalPipelines.get(cellID);
pipeline.step();
// Get the channel data.
@@ -250,9 +351,9 @@
int pedestalSubtractedValue = digitizedValue - pedestal;
//System.out.println(signalBuffer.currentValue() + " " + currentValue + " " + pipeline.currentValue());
- Integer sum = sumMap.get(cellID);
+ Integer sum = triggerPathHitSums.get(cellID);
if (sum == null && pedestalSubtractedValue > triggerThreshold) {
- timeMap.put(cellID, readoutCounter);
+ triggerPathHitTimes.put(cellID, readoutCounter);
if (constantTriggerWindow) {
int sumBefore = 0;
for (int i = 0; i < numSamplesBefore; i++) {
@@ -261,57 +362,57 @@
}
sumBefore += pipeline.getValue(numSamplesBefore - i - 1);
}
- sumMap.put(cellID, sumBefore);
+ triggerPathHitSums.put(cellID, sumBefore);
} else {
- sumMap.put(cellID, pedestalSubtractedValue);
+ triggerPathHitSums.put(cellID, pedestalSubtractedValue);
}
}
if (sum != null) {
if (constantTriggerWindow) {
- if (timeMap.get(cellID) + numSamplesAfter >= readoutCounter) {
+ if (triggerPathHitTimes.get(cellID) + numSamplesAfter >= readoutCounter) {
if (debug) {
- System.out.format("trigger %d, %d: %d\n", cellID, readoutCounter - timeMap.get(cellID) + numSamplesBefore - 1, pipeline.getValue(0));
+ System.out.format("trigger %d, %d: %d\n", cellID, readoutCounter - triggerPathHitTimes.get(cellID) + numSamplesBefore - 1, pipeline.getValue(0));
}
- sumMap.put(cellID, sum + pipeline.getValue(0));
- } else if (timeMap.get(cellID) + delay0 <= readoutCounter) {
+ triggerPathHitSums.put(cellID, sum + pipeline.getValue(0));
+ } else if (triggerPathHitTimes.get(cellID) + delay0 <= readoutCounter) {
// System.out.printf("sum = %f\n", sum);
- outputQueue.add(new BaseRawCalorimeterHit(cellID,
+ triggerPathDelayQueue.add(new BaseRawCalorimeterHit(cellID,
(int) Math.round(sum / scaleFactor),
- 64 * timeMap.get(cellID)));
- sumMap.remove(cellID);
+ 64 * triggerPathHitTimes.get(cellID)));
+ triggerPathHitSums.remove(cellID);
}
} else {
- if (pedestalSubtractedValue < triggerThreshold || timeMap.get(cellID) + delay0 == readoutCounter) {
+ if (pedestalSubtractedValue < triggerThreshold || triggerPathHitTimes.get(cellID) + delay0 == readoutCounter) {
// System.out.printf("sum = %f\n",sum);
- outputQueue.add(new BaseRawCalorimeterHit(cellID,
+ triggerPathDelayQueue.add(new BaseRawCalorimeterHit(cellID,
(int) Math.round((sum + pedestalSubtractedValue) / scaleFactor),
- 64 * timeMap.get(cellID)));
- sumMap.remove(cellID);
+ 64 * triggerPathHitTimes.get(cellID)));
+ triggerPathHitSums.remove(cellID);
} else {
- sumMap.put(cellID, sum + pedestalSubtractedValue);
+ triggerPathHitSums.put(cellID, sum + pedestalSubtractedValue);
}
}
}
signalBuffer.step();
}
- while (outputQueue.peek() != null && outputQueue.peek().getTimeStamp() / 64 <= readoutCounter - delay0) {
- if (outputQueue.peek().getTimeStamp() / 64 < readoutCounter - delay0) {
+ while (triggerPathDelayQueue.peek() != null && triggerPathDelayQueue.peek().getTimeStamp() / 64 <= readoutCounter - delay0) {
+ if (triggerPathDelayQueue.peek().getTimeStamp() / 64 < readoutCounter - delay0) {
System.out.println(this.getName() + ": Stale hit in output queue");
- outputQueue.poll();
+ triggerPathDelayQueue.poll();
} else {
- buffer.add(outputQueue.poll());
- }
- }
- while (!buffer.isEmpty() && buffer.peek().getTimeStamp() / 64 <= readoutCounter - delay0 - coincidenceWindow) {
- buffer.remove();
+ triggerPathCoincidenceQueue.add(triggerPathDelayQueue.poll());
+ }
+ }
+ while (!triggerPathCoincidenceQueue.isEmpty() && triggerPathCoincidenceQueue.peek().getTimeStamp() / 64 <= readoutCounter - delay0 - coincidenceWindow) {
+ triggerPathCoincidenceQueue.remove();
}
if (debug) {
- for (RawCalorimeterHit hit : buffer) {
+ for (RawCalorimeterHit hit : triggerPathCoincidenceQueue) {
System.out.format("new hit: energy %d\n", hit.getAmplitude());
}
}
- hits.addAll(buffer);
+ hits.addAll(triggerPathCoincidenceQueue);
}
@Override
@@ -355,7 +456,7 @@
}
protected short[] getWindow(long cellID) {
- FADCPipeline pipeline = pipelineMap.get(cellID);
+ FADCPipeline pipeline = digitalPipelines.get(cellID);
short[] adcValues = new short[readoutWindow];
for (int i = 0; i < readoutWindow; i++) {
adcValues[i] = (short) pipeline.getValue(readoutLatency - i - 1);
@@ -369,7 +470,7 @@
protected List<RawTrackerHit> readWindow() {
// System.out.println("Reading FADC data");
List<RawTrackerHit> hits = new ArrayList<RawTrackerHit>();
- for (Long cellID : pipelineMap.keySet()) {
+ for (Long cellID : digitalPipelines.keySet()) {
short[] adcValues = getWindow(cellID);
EcalChannelConstants channelData = findChannel(cellID);
boolean isAboveThreshold = false;
@@ -389,7 +490,7 @@
protected List<RawTrackerHit> readPulses() {
// System.out.println("Reading FADC data");
List<RawTrackerHit> hits = new ArrayList<RawTrackerHit>();
- for (Long cellID : pipelineMap.keySet()) {
+ for (Long cellID : digitalPipelines.keySet()) {
short[] window = getWindow(cellID);
short[] adcValues = null;
int pointerOffset = 0;
@@ -423,7 +524,7 @@
protected List<RawCalorimeterHit> readIntegrals() {
// System.out.println("Reading FADC data");
List<RawCalorimeterHit> hits = new ArrayList<RawCalorimeterHit>();
- for (Long cellID : pipelineMap.keySet()) {
+ for (Long cellID : digitalPipelines.keySet()) {
short[] window = getWindow(cellID);
int adcSum = 0;
int pointerOffset = 0;
@@ -456,11 +557,17 @@
return hits;
}
+ /**
+ * Fill the analog pipelines with the preamp pulses generated by hits in the
+ * ECal.
+ *
+ * @param hits ECal hits from SLIC/Geant4.
+ */
@Override
protected void putHits(List<CalorimeterHit> hits) {
//fill the readout buffers
for (CalorimeterHit hit : hits) {
- RingBuffer eDepBuffer = signalMap.get(hit.getCellID());
+ RingBuffer eDepBuffer = analogPipelines.get(hit.getCellID());
double energyAmplitude = hit.getRawEnergy();
// Get the channel data.
EcalChannelConstants channelData = findChannel(hit.getCellID());
@@ -476,6 +583,9 @@
}
energyAmplitude += RandomGaussian.getGaussian(0, noise);
}
+ if ((1) * readoutPeriod + readoutTime() - (ClockSingleton.getTime() + hit.getTime()) >= readoutPeriod) {
+ throw new RuntimeException("trying to add a hit to the analog pipeline, but time seems incorrect");
+ }
for (int i = 0; i < bufferLength; i++) {
eDepBuffer.addToCell(i, energyAmplitude * pulseAmplitude((i + 1) * readoutPeriod + readoutTime() - (ClockSingleton.getTime() + hit.getTime()), hit.getCellID()));
}
@@ -485,9 +595,9 @@
@Override
protected void initReadout() {
//initialize buffers
- sumMap = new HashMap<Long, Integer>();
- timeMap = new HashMap<Long, Integer>();
- outputQueue = new PriorityQueue(20, new TimeComparator());
+ triggerPathHitSums = new HashMap<Long, Integer>();
+ triggerPathHitTimes = new HashMap<Long, Integer>();
+ triggerPathDelayQueue = new PriorityQueue(20, new TimeComparator());
resetFADCBuffers();
}
@@ -506,17 +616,26 @@
if (ecal == null) {
return false;
}
- signalMap = new HashMap<Long, RingBuffer>();
- pipelineMap = new HashMap<Long, FADCPipeline>();
+ analogPipelines = new HashMap<Long, RingBuffer>();
+ digitalPipelines = new HashMap<Long, FADCPipeline>();
Set<Long> cells = ((HPSEcal3) ecal).getNeighborMap().keySet();
for (Long cellID : cells) {
EcalChannelConstants channelData = findChannel(cellID);
- signalMap.put(cellID, new RingBuffer(bufferLength));
- pipelineMap.put(cellID, new FADCPipeline(pipelineLength, (int) Math.round(channelData.getCalibration().getPedestal())));
+ analogPipelines.put(cellID, new RingBuffer(bufferLength));
+ digitalPipelines.put(cellID, new FADCPipeline(pipelineLength, (int) Math.round(channelData.getCalibration().getPedestal())));
}
return true;
}
+ /**
+ * Returns pulse amplitude at the given time (relative to hit time). Gain is
+ * applied.
+ *
+ * @param time Units of ns. Relative to hit time (negative=before the start
+ * of the pulse).
+ * @param cellID Crystal ID as returned by hit.getCellID().
+ * @return Amplitude, units of volts/GeV.
+ */
private double pulseAmplitude(double time, long cellID) {
// Get the channel data.
EcalChannelConstants channelData = findChannel(cellID);
@@ -546,10 +665,11 @@
/**
* Returns pulse amplitude at the given time (relative to hit time).
- * Amplitude is normalized so the pulse integral is 1.
- *
- * @param time
- * @return
+ *
+ * @param time Units of ns. Relative to hit time (negative=before the start
+ * of the pulse).
+ * @return Amplitude, units of inverse ns. Normalized so the pulse integral
+ * is 1.
*/
public static double pulseAmplitude(double time, PulseShape shape, double shapingTime) {
if (time <= 0.0) {
|