Commit in hps-java/src/main/java/org/lcsim/hps on MAIN | |||
evio/ECalEvioWriter.java | +2 | -1 | 1.2 -> 1.3 |
/ECalEvioReader.java | +2 | -1 | 1.2 -> 1.3 |
/LCSimTestRunEventBuilder.java | +3 | -3 | 1.8 -> 1.9 |
users/meeg/HPSGenericRawTrackerHitPrintDriver.java | +64 | added 1.1 | |
/HPSEcalAnalogPrintDriver.java | +13 | -10 | 1.1 -> 1.2 |
/HPSEcalDigitalPrintDriver.java | +3 | -3 | 1.3 -> 1.4 |
/HPSEcalRawTrackerHitPrintDriver.java | +3 | -3 | 1.1 -> 1.2 |
util/RingBuffer.java | +4 | -4 | 1.4 -> 1.5 |
recon/tracking/apv25/HPSAPV25.java | +354 | -553 | 1.3 -> 1.4 |
/HPSSiSensorReadout.java | +451 | -520 | 1.6 -> 1.7 |
recon/tracking/HPSDataProcessingModule.java | +349 | -373 | 1.10 -> 1.11 |
/HPSMakeSVTCellID.java | +8 | -8 | 1.3 -> 1.4 |
monitoring/MonitoringApplication.java | +1 | -1 | 1.10 -> 1.11 |
+1257 | -1480 |
cleaning up SVT code in preparation for adding pedestal/noise to conditions system
diff -u -r1.2 -r1.3 --- ECalEvioWriter.java 7 Apr 2012 00:07:24 -0000 1.2 +++ ECalEvioWriter.java 10 Apr 2012 01:00:13 -0000 1.3 @@ -29,7 +29,7 @@
/** * * @author Sho Uemura <[log in to unmask]>
- * @version $Id: ECalEvioWriter.java,v 1.2 2012/04/07 00:07:24 meeg Exp $
+ * @version $Id: ECalEvioWriter.java,v 1.3 2012/04/10 01:00:13 meeg Exp $
*/ public class ECalEvioWriter implements EvioWriter {
@@ -43,6 +43,7 @@
public void setEcalName(String ecalName) { this.ecalName = ecalName;
+ ecalIDConverter = null;
} public void setHitCollectionName(String hitCollectionName) {
diff -u -r1.2 -r1.3 --- ECalEvioReader.java 7 Apr 2012 00:07:24 -0000 1.2 +++ ECalEvioReader.java 10 Apr 2012 01:00:13 -0000 1.3 @@ -21,7 +21,7 @@
/** * * @author Sho Uemura <[log in to unmask]>
- * @version $Id: ECalEvioReader.java,v 1.2 2012/04/07 00:07:24 meeg Exp $
+ * @version $Id: ECalEvioReader.java,v 1.3 2012/04/10 01:00:13 meeg Exp $
*/ public class ECalEvioReader { // Names of subdetectors.
@@ -40,6 +40,7 @@
public void setEcalName(String ecalName) { this.ecalName = ecalName;
+ ecalIDConverter = null;
} public void setRawCalorimeterHitCollectionName(String rawCalorimeterHitCollectionName) {
diff -u -r1.8 -r1.9 --- LCSimTestRunEventBuilder.java 7 Apr 2012 00:07:24 -0000 1.8 +++ LCSimTestRunEventBuilder.java 10 Apr 2012 01:00:13 -0000 1.9 @@ -19,7 +19,7 @@
* Build LCSim events from EVIO data. * @author Sho Uemura <[log in to unmask]> * @author Jeremy McCormick <[log in to unmask]>
- * @version $Id: LCSimTestRunEventBuilder.java,v 1.8 2012/04/07 00:07:24 meeg Exp $
+ * @version $Id: LCSimTestRunEventBuilder.java,v 1.9 2012/04/10 01:00:13 meeg Exp $
*/ public class LCSimTestRunEventBuilder implements LCSimEventBuilder {
@@ -115,9 +115,9 @@
} public EventHeader makeLCSimEvent(EvioEvent evioEvent) {
-// if (debug) {
+ if (debug) {
System.out.println("Read EVIO event number " + evioEvent.getHeader().getNumber());
-// }
+ }
// Create a new LCSimEvent. EventHeader lcsimEvent = new BaseLCSimEvent(0, evioEvent.getHeader().getNumber(), detector.getDetectorName());
diff -N HPSGenericRawTrackerHitPrintDriver.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ HPSGenericRawTrackerHitPrintDriver.java 10 Apr 2012 01:00:13 -0000 1.1 @@ -0,0 +1,64 @@
+/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.lcsim.hps.users.meeg; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.List; +import org.lcsim.event.EventHeader; +import org.lcsim.event.RawTrackerHit; +import org.lcsim.util.Driver; + +/** + * + * @author Sho Uemura <[log in to unmask]> + * @version $Id: HPSGenericRawTrackerHitPrintDriver.java,v 1.1 2012/04/10 01:00:13 meeg Exp $ + */ +public class HPSGenericRawTrackerHitPrintDriver extends Driver { + + String outputFileName; + PrintWriter outputStream = null; + + public HPSGenericRawTrackerHitPrintDriver() { + } + + public void setOutputFileName(String outputFileName) { + this.outputFileName = outputFileName; + } + + public void startOfData() { + if (outputFileName != null) { + try { + outputStream = new PrintWriter(outputFileName); + } catch (IOException ex) { + throw new RuntimeException("Invalid outputFilePath!"); + } + } else { + outputStream = new PrintWriter(System.out, true); + } + } + + public void process(EventHeader event) { + // Get the list of ECal hits. + if (event.hasCollection(RawTrackerHit.class)) { + //outputStream.println("Reading RawTrackerHits from event " + event.getEventNumber()); + List<List<RawTrackerHit>> listOfLists = event.get(RawTrackerHit.class); + for (List<RawTrackerHit> hits : listOfLists) { + + //FIXME: this check is necessary because hasCollection(type, name) doesn't seem to actually check type! + if (!hits.isEmpty() && !RawTrackerHit.class.isInstance(hits.get(0))) { + return; + } + outputStream.printf("List with %d RawTrackerHits:\n", hits.size()); + for (RawTrackerHit hit : hits) { + outputStream.printf("%d\t%d\n", hit.getCellID() , hit.getADCValues().length); + for (int i = 0; i < hit.getADCValues().length; i++) { + outputStream.printf("%d\n", hit.getADCValues()[i]); + } + } + } + } + } +}
diff -u -r1.1 -r1.2 --- HPSEcalAnalogPrintDriver.java 21 Mar 2012 23:26:48 -0000 1.1 +++ HPSEcalAnalogPrintDriver.java 10 Apr 2012 01:00:13 -0000 1.2 @@ -17,7 +17,7 @@
/** * * @author Sho Uemura <[log in to unmask]>
- * @version $Id: HPSEcalAnalogPrintDriver.java,v 1.1 2012/03/21 23:26:48 meeg Exp $
+ * @version $Id: HPSEcalAnalogPrintDriver.java,v 1.2 2012/04/10 01:00:13 meeg Exp $
*/ public class HPSEcalAnalogPrintDriver extends Driver {
@@ -61,6 +61,8 @@
} catch (IOException ex) { throw new RuntimeException("Invalid outputFilePath!"); }
+ } else { + outputStream = new PrintWriter(System.out, true);
} }
@@ -73,16 +75,17 @@
@Override public void process(EventHeader event) { // Get the list of ECal hits.
- List<CalorimeterHit> hits = event.get(CalorimeterHit.class, ecalCollectionName); - if (hits == null) { - throw new RuntimeException("Event is missing ECal hits collection!"); - } - for (CalorimeterHit hit : hits) { - dec.setID(hit.getCellID()); - if (outputStream != null) {
+ if (event.hasCollection(CalorimeterHit.class, ecalCollectionName)) { + //outputStream.println("Reading RawTrackerHits from event " + event.getEventNumber()); + List<CalorimeterHit> hits = event.get(CalorimeterHit.class, ecalCollectionName); + + //FIXME: this check is necessary because hasCollection(type, name) doesn't seem to actually check type! + if (!hits.isEmpty() && !CalorimeterHit.class.isInstance(hits.get(0))) { + return; + } + for (CalorimeterHit hit : hits) { + dec.setID(hit.getCellID());
outputStream.printf("%d\t%d\t%f\t%f\n", dec.getValue("ix"), dec.getValue("iy"), hit.getTime(), hit.getRawEnergy());
- } else { - System.out.printf("%d\t%d\t%f\t%f\n", dec.getValue("ix"), dec.getValue("iy"), hit.getTime(), hit.getRawEnergy());
} } }
diff -u -r1.3 -r1.4 --- HPSEcalDigitalPrintDriver.java 7 Apr 2012 00:07:25 -0000 1.3 +++ HPSEcalDigitalPrintDriver.java 10 Apr 2012 01:00:13 -0000 1.4 @@ -17,7 +17,7 @@
/** * * @author Sho Uemura <[log in to unmask]>
- * @version $Id: HPSEcalDigitalPrintDriver.java,v 1.3 2012/04/07 00:07:25 meeg Exp $
+ * @version $Id: HPSEcalDigitalPrintDriver.java,v 1.4 2012/04/10 01:00:13 meeg Exp $
*/ public class HPSEcalDigitalPrintDriver extends Driver {
@@ -66,7 +66,7 @@
throw new RuntimeException("Invalid outputFilePath!"); } } else {
- outputStream = new PrintWriter(System.out);
+ outputStream = new PrintWriter(System.out, true);
} }
@@ -86,7 +86,7 @@
return; }
- outputStream.println("Reading RawCalorimeterHit from event " + event.getEventNumber());
+ //outputStream.println("Reading RawCalorimeterHit from event " + event.getEventNumber());
for (RawCalorimeterHit hit : hits) { dec.setID(hit.getCellID()); outputStream.printf("%d\t%d\t%d\t%d\n", dec.getValue("ix"), dec.getValue("iy"), hit.getTimeStamp() * timeScale, hit.getAmplitude());
diff -u -r1.1 -r1.2 --- HPSEcalRawTrackerHitPrintDriver.java 7 Apr 2012 00:07:25 -0000 1.1 +++ HPSEcalRawTrackerHitPrintDriver.java 10 Apr 2012 01:00:13 -0000 1.2 @@ -17,7 +17,7 @@
/** * * @author Sho Uemura <[log in to unmask]>
- * @version $Id: HPSEcalRawTrackerHitPrintDriver.java,v 1.1 2012/04/07 00:07:25 meeg Exp $
+ * @version $Id: HPSEcalRawTrackerHitPrintDriver.java,v 1.2 2012/04/10 01:00:13 meeg Exp $
*/ public class HPSEcalRawTrackerHitPrintDriver extends Driver {
@@ -61,7 +61,7 @@
throw new RuntimeException("Invalid outputFilePath!"); } } else {
- outputStream = new PrintWriter(System.out);
+ outputStream = new PrintWriter(System.out, true);
} }
@@ -74,7 +74,7 @@
public void process(EventHeader event) { // Get the list of ECal hits. if (event.hasCollection(RawTrackerHit.class, ecalCollectionName)) {
- outputStream.println("Reading RawTrackerHits from event " + event.getEventNumber());
+ //outputStream.println("Reading RawTrackerHits from event " + event.getEventNumber());
List<RawTrackerHit> hits = event.get(RawTrackerHit.class, ecalCollectionName); //FIXME: this check is necessary because hasCollection(type, name) doesn't seem to actually check type!
diff -u -r1.4 -r1.5 --- RingBuffer.java 1 Apr 2012 21:20:56 -0000 1.4 +++ RingBuffer.java 10 Apr 2012 01:00:13 -0000 1.5 @@ -4,13 +4,13 @@
* Ring buffer for storing ECal (and possibly SVT) samples for trigger and readout * * @author Sho Uemura <[log in to unmask]>
- * @version $Id: RingBuffer.java,v 1.4 2012/04/01 21:20:56 meeg Exp $
+ * @version $Id: RingBuffer.java,v 1.5 2012/04/10 01:00:13 meeg Exp $
*/ public class RingBuffer {
- private double[] array; - private int size; - private int ptr;
+ protected double[] array; + protected int size; + protected int ptr;
public RingBuffer(int size) { this.size = size;
diff -u -r1.3 -r1.4 --- HPSAPV25.java 30 Mar 2012 23:54:47 -0000 1.3 +++ HPSAPV25.java 10 Apr 2012 01:00:13 -0000 1.4 @@ -1,4 +1,3 @@
-
package org.lcsim.hps.recon.tracking.apv25; //--- Java ---//
@@ -13,562 +12,364 @@
//--- hps-java ---// import org.lcsim.hps.util.ClockSingleton;
+import org.lcsim.hps.util.RingBuffer;
/** * * @author Omar Moreno <[log in to unmask]>
- * @version $Id: HPSAPV25.java,v 1.3 2012/03/30 23:54:47 omoreno Exp $
+ * @version $Id: HPSAPV25.java,v 1.4 2012/04/10 01:00:13 meeg Exp $
*/ public class HPSAPV25 {
- - //--- APV25 parameters ---// - //------------------------// - - private static final double APV25_FRONT_END_GAIN = 100.0; // [mV/MIP] - private static final double APV25_MULTIPLEXER_GAIN = 1; // mA/MIP - private static final double APV25_NOISE_INTERCEPT_PEAK = 270; // e- RMS - private static final double APV25_NOISE_INTERCEPT_DECON = 396; //e- RMS - private static final double APV25_NOISE_SLOPE_PEAK = 36; // e- rms/pF - private static final double APV25_NOISE_SLOPE_DECON = 59.4; // e- rms/pF - - // Number of electron-hole pairs created by a min. ionizing particle - // in 300 micrometers of Si - private static final int MIP = 25000; // electron-hole pairs - - // Total number of channels per APV25 chip - private static final int APV25_CHANNELS = 128; - - // APV25 trigger bit - public static boolean triggerBit = false; - - // - private int apv25ShapingTime = 35; // [ns] - private int apv25SamplingTime = 24; // [ns] - private double analogDCLevel = 0; // [mA] (Pedestal) - public int apv25ClockCycle = 0; - private String apv25Mode = "multi-peak"; - - // APV25 Channel - private APV25Channel channel; - - // Histograms - protected AIDA aida = AIDA.defaultInstance(); - - /** - * Constructor - */ - public HPSAPV25( ) - { - // Create a single instance of an APV25 channel - channel = new APV25Channel(); - - } - - - //--- Methods ---// - //---------------// - - /** - * Set the APV25 shaping time - * - * @param shapingTime : APV25 shaping time - */ - public void setShapingTime(int shapingTime) - { - apv25ShapingTime = shapingTime; - } - - /** - * Set the operating mode of the APV25 to either "peak", - * "deconvolution", or "multi-peak". - * - * @param mode : APV25 operating mode - */ - public void setAPV25Mode(String mode) - { - apv25Mode = mode; - } - - /** - * Set the time interval at which the shaper output is sampled - * - * @param sampleTime : time interval - */ - public void setSamplingTime(int sampleTime) - { - apv25SamplingTime = sampleTime; - } - - /** - * - */ - public void setAnalogDCLevel(double dcLevel) - { - analogDCLevel = dcLevel; - } - - /** - * Return an instance of an APV25 channel. Currently, there is only a - * single instance of the channel ( instead of 128 that the actual chip - * has). However, the analog buffers of each channels are distinct and - * are stored in a sorted map for later use. - * - * @return an instance of APV25Channel - */ - public APV25Channel getChannel() - { - return channel; - } - - /** - * Inject charge into a channel and shape the signal. The resulting - * shaper signal is then sampled into the analog pipeline - * - * @param charge : Total charge being injected - * @param pipeline : Analog pipeline associated with a channel - */ - public APV25AnalogPipeline injectCharge( double charge, - double noiseRMS, - APV25AnalogPipeline pipeline) - { - // Shape the injected charge - getChannel().shapeSignal(charge); - - // Sample the resulting shaper signal - return getChannel().sampleShaperSignal(pipeline, noiseRMS); - - } - - /** - * Increment the position of the trigger and writer pointers of all - * channels - * - * @param analogPipelineMap : - */ - public void incrementAllPointerPositions( - Map<Integer, APV25AnalogPipeline> analogPipelineMap ) - { - // Loop through all of the channels and increment the position of - // all the trigger and writer pointers - for(Map.Entry<Integer, APV25AnalogPipeline> entry : analogPipelineMap.entrySet()){ - entry.getValue().stepWritterPointer(); - entry.getValue().stepTriggerPointer(); - } - - } - - /** - * - */ - public int getSamplingTime() - { - return apv25SamplingTime; - } - - - /** - * Increment the APV25 clock cycle by one - */ - public void stepAPV25Clock(){ - apv25ClockCycle += 1; - } - - /** - * - */ - public Map<Integer, double[]> APV25Multiplexer( - Map<Integer, APV25AnalogPipeline> pipelineMap){ - - Map<Integer /* chip */, double[]> apv25Map = new HashMap<Integer, double[]>(); - - // The address of the APV25. There is only a single address for all - // chips - double[] apv25Address = { 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0 }; - double[] output; - - // Create the data streams - for(int chipIndex = 0; - chipIndex < Math.ceil((double) pipelineMap.size()/APV25_CHANNELS); - chipIndex++){ - - apv25Map.put(chipIndex, createOutputArray(apv25Address, -4)); - } - - // Loop over all channels and readout the cells which the - // trigger pointer points to - for(int channelN = 0; channelN < pipelineMap.size(); channelN++ ){ - - output - = apv25Map.get((int) Math.floor(channelN/APV25_CHANNELS)); - - output[channelN%128 + 12] - += (pipelineMap.get(channelN).readOut()/APV25_FRONT_END_GAIN)*APV25_MULTIPLEXER_GAIN + analogDCLevel; - - } - return apv25Map; - } - - /** - * - */ - private double[] createOutputArray( double[] address, double error ){ - - // Create the array which will contain the output format. The array values - // will range from -4 microAmps to 4 microAmps. - double[] output = new double[141]; - for( int index = 0; index < output.length; index++ ){ - output[ index ] = -4.0; // microAmps - } - - // Header - double[] header = { 4.0, 4.0, 4.0 }; - - // Fill the array with the header, address and error bit and tick - System.arraycopy( header, 0, output, 0, 3); - output[header.length] = error; - System.arraycopy( address, 0, output, 4, 8); - output[ output.length - 1 ] = 4.0; - - return output; - } - - //------------------------------------------// - // APV25 Channel // - //-----------------------------------------// - - public class APV25Channel { - - // Analog pipeline length - private static final int ANALOG_PIPELINE_LENGTH = 192; - // Analog pipeline - private APV25AnalogPipeline analogPipeline; - // Shaper signal - private APV25ShaperSignal shaperSignal; - - /** - * Constructor - */ - public APV25Channel(){} - - /** - * Shape the injected charge - * - * @param charge - */ - private void shapeSignal(double charge) - { - shaperSignal = new APV25ShaperSignal(charge); - } - - /** - * Return the noise in electrons for a given strip capacitance - * - * @param capacitance : strip capacitance in pF - * @return noise in electrons - */ - public double computeNoise( double capacitance ) - { - if( apv25Mode.equals("peak") - || apv25Mode.equals("multi-peak") ) - return APV25_NOISE_INTERCEPT_PEAK - + APV25_NOISE_SLOPE_PEAK*capacitance; - else - return APV25_NOISE_INTERCEPT_DECON - + APV25_NOISE_SLOPE_DECON*capacitance; - } - - /** - * Sample the shaper signal and fill the analog pipeline. - * - * @param channel : Channel number - */ - private APV25AnalogPipeline sampleShaperSignal( - APV25AnalogPipeline pipeline, double noiseRMS ){ - - // Set the analog pipeline corresponding to the channel - analogPipeline = pipeline; - - // Obtain the beam time - double beam_time = ClockSingleton.getTime(); - - // Fill the analog pipeline starting with the cell to which - // the writer pointer is pointing to. Signals arriving within - // the same bucket of length apv25SamplingTime will be shifted - // in time depending on when they arrive. - for(int cell = 0; cell < ANALOG_PIPELINE_LENGTH; cell++) { - - // Time at which the shaper signal will be sampled - int sample_time = cell*apv25SamplingTime - - ((int) beam_time)%apv25SamplingTime; - - // Sample the shaper signal - double sample - = shaperSignal.getAmplitudeAtTime(sample_time); - - // Only add the value into the buffer if it is greater than - // the noise threshold. Note that this isn't done within - // the apv25, however, it will clean up the signal a bit - // for simulation purposes - // This should be done by the data processing module - if( sample > 0.0001 /*(1*noiseRMS/MIP)*APV25_FRONT_END_GAIN)*/) { - analogPipeline.addToCell(cell, sample ); - } - } - - // Reset the overflow position - analogPipeline.resetOverflow(); - - return analogPipeline; - } - - //-----------------------------------// - //--- APV25 Shaper Signal ---// - //-----------------------------------// - - - /** - * - */ - private class APV25ShaperSignal { - - // Shaper signal maximum amplitude - private double maxAmp = 0; - - /** - * Constructor - * - * @param charge : input charge into the channel - */ - APV25ShaperSignal( double charge ){ - - maxAmp = (charge/MIP)*APV25_FRONT_END_GAIN; // mV - - //---> - aida.histogram1D("Shaper Signal Max Amplitude", 100, 0, 500).fill(maxAmp); - //---> - } - - /** - * Get the amplitude at a time t - * - * @param time : time at which the shaper signal is to be - * sampled - */ - private double getAmplitudeAtTime( double time ){ - - return maxAmp*(time/apv25ShapingTime)*Math.exp( - 1-(time/apv25ShapingTime)); - } - } - - - //-------------------------------------// - //--- APV25 Analog Pipeline ---// - //-------------------------------------// - // Note that the buffer is modeled after a circular buffer - - public class APV25AnalogPipeline implements Iterable { - - private double[] pipeline; - - public int _trigger_pointer = 0; - public int _writer_pointer = 0; - int _trigger_latency = 220; - - int overflow_pos = 0; - - - /** - * Constructor - */ - public APV25AnalogPipeline( ) { - - // Initialize the pipeline to the APV25 pipeline length - pipeline = new double[ ANALOG_PIPELINE_LENGTH ]; - - // Initialize the position of the writter pointer to a - // random position - _writer_pointer - = (int)( Math.random()*( ANALOG_PIPELINE_LENGTH + 1 )); - - // Set the position of the trigger pointer - _trigger_pointer = _writer_pointer - - (int) Math.floor(_trigger_latency/apv25SamplingTime ); - - if( _trigger_pointer < 0 ) - _trigger_pointer += ANALOG_PIPELINE_LENGTH; - } - - /** - * Set the trigger latency - * - * @param latency : trigger latency in [ns] - */ - public void setTriggerLatency( int latency ){ - _trigger_latency = latency; - } - - /** - * Reset the overflow position to the beginning of the buffer - */ - public void resetOverflow( ){ - overflow_pos = 0; - } - - /** - * Add a given value to the specified buffer cell - * - * @param position : position of the buffer cell - * @param element : value to be added at the given position - */ - private void addToCell( int position, double element ) { - - // Offset the position by the writter pointer position - position += _writer_pointer; - - // If the cell position is at the end begin writing at the - // beginning of the buffer until the trigger pointer - // position is reached - if( position >= ANALOG_PIPELINE_LENGTH - && overflow_pos != _trigger_pointer ) { - position = overflow_pos; - overflow_pos++; - } else if( position >= ANALOG_PIPELINE_LENGTH - && overflow_pos == _trigger_pointer ) return; - - pipeline[ position ] - = pipeline[ position ] + element; - } - - /** - * Clear the specified cell of all its values - */ - private void clearCell( int position ){ - pipeline[ position ] = 0; - } - - /** - * Step the trigger pointer to the next position in the analog - * pipeline - */ - private void stepTriggerPointer( ) { - - // First clear the element to which the trigger used to - // point to of any signal information - pipeline[ _trigger_pointer ] = 0; - - // Increment the position of the trigger pointer to the next - // cell in the buffer - _trigger_pointer++; - - if( _trigger_pointer >= ANALOG_PIPELINE_LENGTH ) - _trigger_pointer = 0; - } - - /** - * Step the writer pointer to the next position in the analog - * pipeline - */ - private void stepWritterPointer( ){ - - _writer_pointer++; - if( _writer_pointer >= ANALOG_PIPELINE_LENGTH ) - _writer_pointer = 0; - } - - /** - * - */ - private double readOut( ){ - - double pipelineValue = pipeline[ _trigger_pointer ]; - pipeline[ _trigger_pointer ] = 0; - return pipelineValue; - } - - /** - * - */ - public void printAnalogPipeline() - { - System.out.print("[ "); - for(int index = 0; index < pipeline.length; index++){ - if(index == _trigger_pointer){ - System.out.print("TP====>"); - } - if(index == _writer_pointer){ - System.out.print("WP====>"); - } - System.out.print(pipeline[index] + ", "); - } - System.out.println("] "); - } - - /** - * - */ - public double getTriggerPointerValue() - { - return pipeline[_trigger_pointer]; - } - - public double getTriggerPointerValuePlusOne() - { - if(_trigger_pointer + 1 == 192) return pipeline[0]; - return pipeline[_trigger_pointer + 1]; - } - - - /** - * - */ - @Override - public Iterator<Double> iterator(){ - return new APV25AnalogPipelineIterator( ); - } - - - //--------------------------------------// - //--- APV25 Analog Pipeline Iterator ---// - //--------------------------------------// - - /** - * - */ - private class APV25AnalogPipelineIterator - implements Iterator<Double> { - - private int index = 0; - - - /** - * Checks to see if the next element in the buffer exist - */ - @Override - public boolean hasNext( ) { - return index < ANALOG_PIPELINE_LENGTH; - } - - - /** - * - */ - @Override - public Double next( ){ - if( !hasNext() ) throw new NoSuchElementException( ); - return pipeline[index++]; - } - - - /** - * - */ - @Override - public void remove( ) { - throw new UnsupportedOperationException( - "Not Supported!"); - } - } - } - }
+ + //--- APV25 parameters ---// + //------------------------// + private static final double APV25_FRONT_END_GAIN = 100.0; // [mV/MIP] + private static final double APV25_MULTIPLEXER_GAIN = 1; // mA/MIP + private static final double APV25_NOISE_INTERCEPT_PEAK = 270; // e- RMS + private static final double APV25_NOISE_INTERCEPT_DECON = 396; //e- RMS + private static final double APV25_NOISE_SLOPE_PEAK = 36; // e- rms/pF + private static final double APV25_NOISE_SLOPE_DECON = 59.4; // e- rms/pF + // Number of electron-hole pairs created by a min. ionizing particle + // in 300 micrometers of Si + private static final int MIP = 25000; // electron-hole pairs + // Total number of channels per APV25 chip + private static final int APV25_CHANNELS = 128; + // APV25 trigger bit + public static boolean triggerBit = false; + // + private int apv25ShapingTime = 35; // [ns] + private int apv25SamplingTime = 24; // [ns] + private double analogDCLevel = 0; // [mA] (Pedestal) + public int apv25ClockCycle = 0; + private String apv25Mode = "multi-peak"; + // APV25 Channel + private APV25Channel channel; + // Histograms + protected AIDA aida = AIDA.defaultInstance(); + + /** + * Constructor + */ + public HPSAPV25() { + // Create a single instance of an APV25 channel + channel = new APV25Channel(); + + } + + //--- Methods ---// + //---------------// + /** + * Set the APV25 shaping time + * + * @param shapingTime : APV25 shaping time + */ + public void setShapingTime(int shapingTime) { + apv25ShapingTime = shapingTime; + } + + /** + * Set the operating mode of the APV25 to either "peak", + * "deconvolution", or "multi-peak". + * + * @param mode : APV25 operating mode + */ + public void setAPV25Mode(String mode) { + apv25Mode = mode; + } + + /** + * Set the time interval at which the shaper output is sampled + * + * @param sampleTime : time interval + */ + public void setSamplingTime(int sampleTime) { + apv25SamplingTime = sampleTime; + } + + /** + * + */ + public void setAnalogDCLevel(double dcLevel) { + analogDCLevel = dcLevel; + } + + /** + * Return an instance of an APV25 channel. Currently, there is only a + * single instance of the channel ( instead of 128 that the actual chip + * has). However, the analog buffers of each channels are distinct and + * are stored in a sorted map for later use. + * + * @return an instance of APV25Channel + */ + public APV25Channel getChannel() { + return channel; + } + + /** + * Inject charge into a channel and shape the signal. The resulting + * shaper signal is then sampled into the analog pipeline + * + * @param charge : Total charge being injected + * @param pipeline : Analog pipeline associated with a channel + */ + public void injectCharge(double charge, + double noiseRMS, + APV25AnalogPipeline pipeline) { + // Shape the injected charge + getChannel().shapeSignal(charge); + + // Sample the resulting shaper signal + getChannel().sampleShaperSignal(pipeline, noiseRMS); + } + + /** + * Increment the position of the trigger and writer pointers of all + * channels + * + * @param analogPipelineMap : + */ + public void incrementAllPointerPositions( + Map<Integer, APV25AnalogPipeline> analogPipelineMap) { + // Loop through all of the channels and increment the position of + // all the trigger and writer pointers + for (Map.Entry<Integer, APV25AnalogPipeline> entry : analogPipelineMap.entrySet()) { + entry.getValue().step(); + } + + } + + /** + * + */ + public int getSamplingTime() { + return apv25SamplingTime; + } + + /** + * Increment the APV25 clock cycle by one + */ + public void stepAPV25Clock() { + apv25ClockCycle += 1; + } + + /** + * + */ + public Map<Integer, double[]> APV25Multiplexer( + Map<Integer, APV25AnalogPipeline> pipelineMap) { + + Map<Integer /* chip */, double[]> apv25Map = new HashMap<Integer, double[]>(); + + // The address of the APV25. There is only a single address for all + // chips + double[] apv25Address = {4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0}; + double[] output; + + // Create the data streams + for (int chipIndex = 0; + chipIndex < Math.ceil((double) pipelineMap.size() / APV25_CHANNELS); + chipIndex++) { + + apv25Map.put(chipIndex, createOutputArray(apv25Address, -4)); + } + + // Loop over all channels and readout the cells which the + // trigger pointer points to + for (int channelN = 0; channelN < pipelineMap.size(); channelN++) { + + output = apv25Map.get((int) Math.floor(channelN / APV25_CHANNELS)); + + output[channelN % 128 + 12] += (pipelineMap.get(channelN).readOut() / APV25_FRONT_END_GAIN) * APV25_MULTIPLEXER_GAIN + analogDCLevel; + + } + return apv25Map; + } + + /** + * + */ + private double[] createOutputArray(double[] address, double error) { + + // Create the array which will contain the output format. The array values + // will range from -4 microAmps to 4 microAmps. + double[] output = new double[141]; + for (int index = 0; index < output.length; index++) { + output[ index] = -4.0; // microAmps + } + + // Header + double[] header = {4.0, 4.0, 4.0}; + + // Fill the array with the header, address and error bit and tick + System.arraycopy(header, 0, output, 0, 3); + output[header.length] = error; + System.arraycopy(address, 0, output, 4, 8); + output[ output.length - 1] = 4.0; + + return output; + } + + //------------------------------------------// + // APV25 Channel // + //-----------------------------------------// + public class APV25Channel { + + // Analog pipeline length + private static final int ANALOG_PIPELINE_LENGTH = 192; + // Shaper signal + private APV25ShaperSignal shaperSignal; + + /** + * Constructor + */ + public APV25Channel() { + } + + /** + * Shape the injected charge + * + * @param charge + */ + private void shapeSignal(double charge) { + shaperSignal = new APV25ShaperSignal(charge); + } + + /** + * Return the noise in electrons for a given strip capacitance + * + * @param capacitance : strip capacitance in pF + * @return noise in electrons + */ + public double computeNoise(double capacitance) { + if (apv25Mode.equals("peak") + || apv25Mode.equals("multi-peak")) { + return APV25_NOISE_INTERCEPT_PEAK + + APV25_NOISE_SLOPE_PEAK * capacitance; + } else { + return APV25_NOISE_INTERCEPT_DECON + + APV25_NOISE_SLOPE_DECON * capacitance; + } + } + + /** + * Sample the shaper signal and fill the analog pipeline. + * + * @param channel : Channel number + */ + private void sampleShaperSignal( + APV25AnalogPipeline pipeline, double noiseRMS) { + + // Obtain the beam time + double beam_time = ClockSingleton.getTime(); + + // Fill the analog pipeline starting with the cell to which + // the writer pointer is pointing to. Signals arriving within + // the same bucket of length apv25SamplingTime will be shifted + // in time depending on when they arrive. + for (int cell = 0; cell < ANALOG_PIPELINE_LENGTH; cell++) { + + // Time at which the shaper signal will be sampled + int sample_time = cell * apv25SamplingTime + - ((int) beam_time) % apv25SamplingTime; + // Sample the shaper signal + double sample = shaperSignal.getAmplitudeAtTime(sample_time); + + // Only add the value into the buffer if it is greater than + // the noise threshold. Note that this isn't done within + // the apv25, however, it will clean up the signal a bit + // for simulation purposes + // This should be done by the data processing module + //if( sample > 0.0001 /*(1*noiseRMS/MIP)*APV25_FRONT_END_GAIN)*/) { + pipeline.addToCell(cell, sample); + //} + } + } + + //-----------------------------------// + //--- APV25 Shaper Signal ---// + //-----------------------------------// + /** + * + */ + private class APV25ShaperSignal { + + // Shaper signal maximum amplitude + private double maxAmp = 0; + + /** + * Constructor + * + * @param charge : input charge into the channel + */ + APV25ShaperSignal(double charge) { + + maxAmp = (charge / MIP) * APV25_FRONT_END_GAIN; // mV + + //---> + aida.histogram1D("Shaper Signal Max Amplitude", 100, 0, 500).fill(maxAmp); + //---> + } + + /** + * Get the amplitude at a time t + * + * @param time : time at which the shaper signal is to be + * sampled + */ + private double getAmplitudeAtTime(double time) { + + return maxAmp * (Math.max(0, time) / apv25ShapingTime) * Math.exp( + 1 - (time / apv25ShapingTime)); + } + } + + //-------------------------------------// + //--- APV25 Analog Pipeline ---// + //-------------------------------------// + // Note that the buffer is modeled after a circular buffer + public class APV25AnalogPipeline extends RingBuffer { + private int _trigger_latency = (int) Math.floor(220 / apv25SamplingTime); + + public APV25AnalogPipeline() { + super(ANALOG_PIPELINE_LENGTH); + } + + /** + * Set the trigger latency + * + * @param latency : trigger latency in [ns] + */ + public void setTriggerLatency(int latency) { + _trigger_latency = (int) Math.floor(latency / apv25SamplingTime); + } + + private double readOut() { + double pipelineValue = currentValue(); + array[0] = 0; + return pipelineValue; + } + + @Override + public void addToCell(int position, double element) { + if (position + _trigger_latency > size) { + return; + } + super.addToCell(position + _trigger_latency, element); + } + + public void printAnalogPipeline() { + System.out.print("[ "); + for (int index = 0; index < size; index++) { + if (index == ptr) { + System.out.print("TP====>"); + } + if (index == ptr + _trigger_latency) { + System.out.print("WP====>"); + } + System.out.print(array[index] + ", "); + } + System.out.println("] "); + } + } + }
}
diff -u -r1.6 -r1.7 --- HPSSiSensorReadout.java 30 Mar 2012 23:55:45 -0000 1.6 +++ HPSSiSensorReadout.java 10 Apr 2012 01:00:13 -0000 1.7 @@ -1,4 +1,3 @@
-
package org.lcsim.hps.recon.tracking.apv25; //--- Java ---//
@@ -27,7 +26,7 @@
import org.lcsim.detector.tracker.silicon.ChargeCarrier; import org.lcsim.detector.tracker.silicon.SiSensor; import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
-import org.lcsim.detector.tracker.silicon.SiTrackerModule;
+import org.lcsim.detector.tracker.silicon.SiTrackerModule;
import org.lcsim.event.EventHeader; import org.lcsim.event.SimTrackerHit; import org.lcsim.geometry.Detector;
@@ -47,529 +46,461 @@
import org.lcsim.hps.recon.tracking.HPSRTM; import org.lcsim.hps.util.ClockSingleton;
-
/** * * @author Omar Moreno <[log in to unmask]>
- * @version $Id: HPSSiSensorReadout.java,v 1.6 2012/03/30 23:55:45 omoreno Exp $
+ * @version $Id: HPSSiSensorReadout.java,v 1.7 2012/04/10 01:00:13 meeg Exp $
*/ public class HPSSiSensorReadout extends Driver {
- - // - boolean debug = true; - - // Array to store the trigger time - public static final List<Double> triggerTimeStamp - = new ArrayList<Double>(); - - // - List<String> processPaths = new ArrayList<String>(); - List<IDetectorElement> processDetectorElements - = new ArrayList<IDetectorElement>(); - List<String> readouts = new ArrayList<String>(); - - // - Set<SiSensor> processSensors = new HashSet<SiSensor>(); - Set<SiTrackerModule> processModules = new HashSet<SiTrackerModule>(); - - // FIFO queue to store trigger times - public Queue<Integer> triggerQueue; - - // # of strips per Si sensor - private static final int STRIPS_PER_SENSOR = 667; - - private HPSAPV25 apv25; - private SiSensorSim siSimulation; - private HPSRTM rtm; - private HPSDataProcessingModule dpm; - - private static Random random = new Random(); - private static BinomialDistribution binomial - = new BinomialDistributionImpl(1,1); - private static NormalDistribution gaussian - = new NormalDistributionImpl(0.0,1.0); - - - private double noiseThreshold = 4; // e- RMS - - // A map used to associate a sensor to the channels and analog pipelines - // of the APV25s being used to readout the sensor - public Map< Long /* sensor number */, - Map<Integer /* channel */, APV25AnalogPipeline>> sensorToPipelineMap; - - // A map used to associate an APV25 channel to its analog pipeline - public Map<Integer /* channel */, - APV25AnalogPipeline> analogPipelineMap; - - // A map used to associate a sensor to the output of the APV25s being - // used to readout the sensor - public Map<Long, Map<Integer /* chip # */, double[]>> sensorToAnalogDataMap; - - // A map used to associate a sensor to the digitzed output of the APV25s - // being used to readout the sensor - public Map<Long, Map<Integer /*chip # */, double[]>> sensorToDigitalDataMap; - - // - public Map<Integer, double[]> analogData; - public Map<Integer, double[]> digitalData; - - public Map<Integer, List<SimTrackerHit> > eventToSimTrackerHitMap; - - // - protected AIDA aida = AIDA.defaultInstance(); - public Profile1D pipe; - - int n_events = 0; - - - /** - * Constructor - */ - public HPSSiSensorReadout() - { - sensorToPipelineMap = new HashMap<Long, Map<Integer, APV25AnalogPipeline>>(); - sensorToAnalogDataMap = new HashMap<Long, Map<Integer, double[]>>(); - sensorToDigitalDataMap = new HashMap<Long, Map<Integer, double[]>>(); - - eventToSimTrackerHitMap = new HashMap<Integer, List<SimTrackerHit> >(); - - //--- Sensor Simulation ---// - //-------------------------// - siSimulation = new CDFSiSensorSim(); - - //--- APV25 Simulation ---// - //------------------------// - apv25 = new HPSAPV25(); - // Set the APV25 Shaping time [ns] - apv25.setShapingTime(35); - // Set the APV25 operating mode - apv25.setAPV25Mode("multi-peak"); - // Set the APV25 analog pipeline sampling time - apv25.setSamplingTime(24); - - - // - rtm = new HPSRTM(14); - - // Instantiate the DPM - dpm = new HPSDataProcessingModule(); - dpm.setNoise(18); - dpm.setNoiseThreshold(3); - dpm.setSamplesAboveThresh(3); - dpm.setPedestal(1638); - dpm.enableThresholdCut(); - - add(dpm); - - // Instantiate trigger time queue - triggerQueue = new LinkedList<Integer>(); - - // Specify the readouts to process - readouts.add("TrackerHits"); - - // Specify the detectors to process - processPaths.add("Tracker"); - - } - - /** - * - */ - @Override - public void detectorChanged(Detector detector) - { - super.detectorChanged(detector); - - // Proces detectors specified by path, otherwise process the entire - // detector - IDetectorElement detectorElement = detector.getDetectorElement(); - for(String detectorElementPath : processPaths ){ - processDetectorElements.add( - detectorElement.findDetectorElement(detectorElementPath)); - } - - if(processDetectorElements.isEmpty()) - processDetectorElements.add(detectorElement); - - for(IDetectorElement dElement : processDetectorElements ){ - processSensors.addAll(dElement.findDescendants(SiSensor.class)); - processModules.addAll( - dElement.findDescendants(SiTrackerModule.class)); - } - - // Initialize the sensor maps - for(SiSensor sensor: processSensors){ - - sensorToPipelineMap.put(sensor.getIdentifier().getValue(), - new HashMap<Integer, APV25AnalogPipeline>()); - for(int channel = 0; channel < STRIPS_PER_SENSOR; channel++){ - sensorToPipelineMap.get(sensor.getIdentifier().getValue()).put(channel,apv25.getChannel().new APV25AnalogPipeline()); - } - - sensorToAnalogDataMap.put(sensor.getIdentifier().getValue(), - new HashMap<Integer, double[]>() ); - - sensorToDigitalDataMap.put(sensor.getIdentifier().getValue(), - new HashMap<Integer, double[]>() ); - - } - } - - /** - * - */ - @Override - public void process(EventHeader event) - { - - - super.process(event); - - if((ClockSingleton.getTime() + ClockSingleton.getDt())%24 == 0){ - for(Map.Entry<Long, Map<Integer, APV25AnalogPipeline>> sensor : sensorToPipelineMap.entrySet()){ - apv25.incrementAllPointerPositions(sensor.getValue()); - } - apv25.stepAPV25Clock(); - } - - // Loop over all sensors - for(SiSensor sensor : processSensors){ - // Readout the sensors - readoutSensor(sensor); - } - - // If a trigger is received readout the APV25 and digitize all hits - if(HPSAPV25.triggerBit){ - - triggerTimeStamp.add(ClockSingleton.getTime()); - - // Only add the trigger if there isn't another trigger being - // processed - if(!triggerQueue.contains(apv25.apv25ClockCycle)){ - // Add the time at which each of the six samples should be - // collected to the trigger queue - for(int sample = 0; sample < 6; sample++){ - triggerQueue.offer(apv25.apv25ClockCycle + sample); - } - } - // Reset the APV25 trigger bit - HPSAPV25.triggerBit = false; - } - - // Process any triggers in the queue - if(triggerQueue.peek() != null){ - - // Remove any samples that might have already been processed - if(triggerQueue.peek() < apv25.apv25ClockCycle){ - for(int sample = 0; sample < 6; sample++){ - triggerQueue.remove(); - } - } - else if(triggerQueue.peek() == apv25.apv25ClockCycle){ - readoutAPV25(); - triggerQueue.remove(); - } - } - } - - /** - * - */ - @Override - public void startOfData() - { - // Set up readouts if they haven't been set - if(!readouts.isEmpty()){ - super.add(new SimTrackerHitReadoutDriver(readouts)); - } - - super.startOfData(); - readouts.clear(); - - } - - /** - * - * @param sensor - */ - public void makeRawHits(SiSensor sensor) - { - readoutSensor(sensor); - } - - /** - * Readout the electrodes of an HPS Si sensor and inject the charge into - * the APV25 readout chip. - * - * @param sensor : HPS Si sensor - */ - public void readoutSensor(SiSensor sensor) - { - // Set the sensor to be used in the charge deposition simulation - siSimulation.setSensor(sensor); - - // Perform the charge deposition simulation - Map<ChargeCarrier, SiElectrodeDataCollection> electrodeDataMap - = siSimulation.computeElectrodeData(); - - // Loop over each charge carrier (electron or hole) - for(ChargeCarrier carrier : ChargeCarrier.values()){ - - // If the sensor is capable of collecting the given charge carrier - // then obtain the electrode data for the sensor - if(sensor.hasElectrodesOnSide(carrier)) - { - SiElectrodeDataCollection electrodeDataCol - = electrodeDataMap.get(carrier); - - // If there is no electrode data available create a new - // instance of electode data - if(electrodeDataCol == null){ - electrodeDataCol = new SiElectrodeDataCollection(); - } - - // Get the readout electrodes - SiSensorElectrodes readoutElectrodes - = sensor.getReadoutElectrodes(carrier); - - // Add noise to the electrodes - addNoise(electrodeDataCol, readoutElectrodes); - - // Get the analog pipeline map associated with this sensor - analogPipelineMap - = sensorToPipelineMap.get(sensor.getIdentifier().getValue()); - - // Loop over all channels - for(Integer channel : electrodeDataCol.keySet()){ - - // Get the electrode data for this channel - SiElectrodeData electrodeData - = electrodeDataCol.get(channel); - - // Get the charge in units of electrons - double charge = electrodeData.getCharge(); - - //====> Charge deposition on electrode - aida.histogram1D("Charge", 100,0 ,200000).fill(charge); - //====> - - // Get the RMS noise for this channel - double noise - = apv25.getChannel().computeNoise( - readoutElectrodes.getCapacitance(channel)); - - //===> - aida.histogram1D(this.getClass().getName() + " - RMS Noise - All Channels", 1000, 3500, 4500).fill(noise); - //===> - - // Check to see if an analog pipeline for this channel - // exist. If it doesn't, create one. - if(!analogPipelineMap.containsKey(channel)){ - - - analogPipelineMap.put(channel, - apv25.getChannel().new APV25AnalogPipeline()); - } - - // Get the analog pipeline associated with this channel - APV25AnalogPipeline pipeline - = analogPipelineMap.get(channel); - - // Inject the charge into the APV25 amplifier chain - pipeline = apv25.injectCharge(charge, noise, pipeline); - // Store the analog pipeline for later use - analogPipelineMap.put(channel, pipeline); - - } - } - } - - // Place the analog pipeline back into the sensor map - sensorToPipelineMap.put(sensor.getIdentifier().getValue(), analogPipelineMap); - - // Clear the sensors of all deposited charge - siSimulation.clearReadout(); - } - - /** - * - */ - public void readoutAPV25() - { - // Readout all apv25s - for(Map.Entry<Long, Map<Integer, APV25AnalogPipeline>> sensor : sensorToPipelineMap.entrySet()){ - sensorToAnalogDataMap.put(sensor.getKey(), apv25.APV25Multiplexer(sensor.getValue())); - } - - // Digitize all signals - for(Map.Entry<Long, Map<Integer, double[]>> sensor : sensorToAnalogDataMap.entrySet()){ - sensorToDigitalDataMap.put(sensor.getKey(), rtm.digitize(sensor.getValue())); - } - - // Buffer the samples for further processing - dpm.addSample(sensorToDigitalDataMap); - - } - - - /** - * - * @param electrodeDataCol - * @param electrodes - */ - public void addNoise(SiElectrodeDataCollection electrodeDataCol, - SiSensorElectrodes electrodes) - { - // First add readout noise to the strips in the - // SiElectrodeDataCollection. - - // Loop over the entries in the SiElectrodeDataCollection - for(Entry electrodeDatum : electrodeDataCol.entrySet()){ - - // Get the channel number and electrode data for this entry - int channel = (Integer) electrodeDatum.getKey(); - SiElectrodeData electrodeData - = (SiElectrodeData) electrodeDatum.getValue(); - - // Get the RMS noise for this channel in units of electrons - double noise - = apv25.getChannel().computeNoise( - electrodes.getCapacitance(channel)); - - // Add readout noise to the deposited charge - int noiseCharge = (int) Math.round( random.nextGaussian()*noise); - electrodeData.addCharge(noiseCharge); - } - - // Find the number of strips that are not currently hit - int nElectrodes = electrodes.getNCells(); - int nElectrodesEmpty = nElectrodes - electrodeDataCol.size(); - - // Get the noise threshold in units of the noise charge - - // Calculate how many channels should get noise hits - double integral = Erf.phic(noiseThreshold); - int nChannelsThrow = drawBinomial(nElectrodesEmpty, integral); - - // Now throw Gaussian randoms above the seed threshold and put signals - // on unoccupied channels - for(int ithrow = 0; ithrow < nChannelsThrow; ithrow++) - { - // Throw to get a channel number - int channel = random.nextInt(nElectrodes); - while(electrodeDataCol.keySet().contains(channel)){ - channel = random.nextInt(nElectrodes); - } - - // Calculate the noise for this channel in units of electrons - double noise - = apv25.getChannel().computeNoise( - electrodes.getCapacitance(channel)); - - // Throw Gaussian above threshold - int charge - = (int) Math.round(drawGaussianAboveThreshold(integral)*noise); - - // Add the noise hit to the electrode data collection - electrodeDataCol.add(channel, new SiElectrodeData(charge)); - } - - // Now throw to lower threshold on channels that neighbor hits until - // we are exhausted - - nChannelsThrow = 1; - while(nChannelsThrow > 0){ - - // Get neighbor channels - Set<Integer> neighbors = new HashSet<Integer>(); - for(int channel : electrodeDataCol.keySet()) - { - neighbors.addAll(electrodes.getNearestNeighborCells(channel)); - } - neighbors.removeAll(electrodeDataCol.keySet()); - - nElectrodesEmpty = neighbors.size(); - - integral = Erf.phic(noiseThreshold); - nChannelsThrow = drawBinomial(nElectrodesEmpty, integral); - - // Now throw Gaussian randoms above a threshold and put signals on - // unoccopied channels - for(int ithrow = 0; ithrow < nChannelsThrow; ithrow++) - { - - // Throw to get a channel number - List<Integer> neighborList = new ArrayList<Integer>(neighbors); - - int channel - = neighborList.get(random.nextInt(nElectrodesEmpty)); - - while(electrodeDataCol.keySet().contains(channel)){ - channel - = neighborList.get(random.nextInt(nElectrodesEmpty)); - - } - - // Calculate the noise for this channel in units of electrons - double noise - = apv25.getChannel().computeNoise( - electrodes.getCapacitance(channel)); - - // Throw Gaussian above threshold - int charge - = (int) - Math.round(drawGaussianAboveThreshold(integral)*noise); - - // Add the noise hit to the electrode data collection - electrodeDataCol.add(channel, new SiElectrodeData(charge)); - } - } - } - - /** - * - */ - public static int drawBinomial(int ntrials, double probability) - { - binomial.setNumberOfTrials(ntrials); - binomial.setProbabilityOfSuccess(probability); - - int nsuccess = 0; - try - { - nsuccess = binomial.inverseCumulativeProbability(random.nextDouble()); - } catch (MathException exception) - { - throw new RuntimeException("APV25 failed to calculate inverse cumulative probability of binomial!"); - } - return nsuccess; - } - - - /** - * Return a random variable following normal distribution, but beyond - * threshold provided during initialization. - */ - public static double drawGaussianAboveThreshold(double prob_above_threshold) - { - double draw, cumulative_probability; - - draw = prob_above_threshold * random.nextDouble(); - cumulative_probability = 1.0 - prob_above_threshold + draw; - - assert cumulative_probability < 1.0 : "cumulProb=" + cumulative_probability + ", draw=" + draw + ", probAboveThreshold=" + prob_above_threshold; - assert cumulative_probability >= 0.0 : "cumulProb=" + cumulative_probability + ", draw=" + draw + ", probAboveThreshold=" + prob_above_threshold; - - double gaussian_random = 0; - try - { - gaussian_random = gaussian.inverseCumulativeProbability(cumulative_probability); - } catch (MathException e) - { - System.out.println("MathException caught: " + e); - }
- return gaussian_random; - }
+ // + boolean debug = true; + // Array to store the trigger time + public static final List<Double> triggerTimeStamp = new ArrayList<Double>(); + // + List<String> processPaths = new ArrayList<String>(); + List<IDetectorElement> processDetectorElements = new ArrayList<IDetectorElement>(); + List<String> readouts = new ArrayList<String>(); + // + Set<SiSensor> processSensors = new HashSet<SiSensor>(); + Set<SiTrackerModule> processModules = new HashSet<SiTrackerModule>(); + // FIFO queue to store trigger times + public Queue<Integer> triggerQueue; + // # of strips per Si sensor + private static final int STRIPS_PER_SENSOR = 667; + private HPSAPV25 apv25; + private SiSensorSim siSimulation; + private HPSRTM rtm; + private HPSDataProcessingModule dpm; + private static Random random = new Random(); + private static BinomialDistribution binomial = new BinomialDistributionImpl(1, 1); + private static NormalDistribution gaussian = new NormalDistributionImpl(0.0, 1.0); + private double noiseThreshold = 4; // e- RMS + // A map used to associate a sensor to the channels and analog pipelines + // of the APV25s being used to readout the sensor + public Map< Long /* sensor number */, Map<Integer /* channel */, APV25AnalogPipeline>> sensorToPipelineMap; + // A map used to associate an APV25 channel to its analog pipeline + public Map<Integer /* channel */, APV25AnalogPipeline> analogPipelineMap; + // A map used to associate a sensor to the output of the APV25s being + // used to readout the sensor + public Map<Long, Map<Integer /* chip # */, double[]>> sensorToAnalogDataMap; + // A map used to associate a sensor to the digitzed output of the APV25s + // being used to readout the sensor + public Map<Long, Map<Integer /*chip # */, double[]>> sensorToDigitalDataMap; + // + public Map<Integer, double[]> analogData; + public Map<Integer, double[]> digitalData; + public Map<Integer, List<SimTrackerHit>> eventToSimTrackerHitMap; + // + protected AIDA aida = AIDA.defaultInstance(); + public Profile1D pipe; + int n_events = 0; + + /** + * Constructor + */ + public HPSSiSensorReadout() { + sensorToPipelineMap = new HashMap<Long, Map<Integer, APV25AnalogPipeline>>(); + sensorToAnalogDataMap = new HashMap<Long, Map<Integer, double[]>>(); + sensorToDigitalDataMap = new HashMap<Long, Map<Integer, double[]>>(); + + eventToSimTrackerHitMap = new HashMap<Integer, List<SimTrackerHit>>(); + + //--- Sensor Simulation ---// + //-------------------------// + siSimulation = new CDFSiSensorSim(); + + //--- APV25 Simulation ---// + //------------------------// + apv25 = new HPSAPV25(); + // Set the APV25 Shaping time [ns] + apv25.setShapingTime(35); + // Set the APV25 operating mode + apv25.setAPV25Mode("multi-peak"); + // Set the APV25 analog pipeline sampling time + apv25.setSamplingTime(24); + + + // + rtm = new HPSRTM(14); + + // Instantiate the DPM + dpm = new HPSDataProcessingModule(); + dpm.setNoise(18); + dpm.setNoiseThreshold(3); + dpm.setSamplesAboveThresh(3); + dpm.setPedestal(1638); + dpm.enableThresholdCut(); + + add(dpm); + + // Instantiate trigger time queue + triggerQueue = new LinkedList<Integer>(); + + // Specify the readouts to process + readouts.add("TrackerHits"); + + // Specify the detectors to process + processPaths.add("Tracker"); + + } + + /** + * + */ + @Override + public void detectorChanged(Detector detector) { + super.detectorChanged(detector); + + // Proces detectors specified by path, otherwise process the entire + // detector + IDetectorElement detectorElement = detector.getDetectorElement(); + for (String detectorElementPath : processPaths) { + processDetectorElements.add( + detectorElement.findDetectorElement(detectorElementPath)); + } + + if (processDetectorElements.isEmpty()) { + processDetectorElements.add(detectorElement); + } + + for (IDetectorElement dElement : processDetectorElements) { + processSensors.addAll(dElement.findDescendants(SiSensor.class)); + processModules.addAll( + dElement.findDescendants(SiTrackerModule.class)); + } + + // Initialize the sensor maps + for (SiSensor sensor : processSensors) { + + sensorToPipelineMap.put(sensor.getIdentifier().getValue(), + new HashMap<Integer, APV25AnalogPipeline>()); + for (int channel = 0; channel < STRIPS_PER_SENSOR; channel++) { + sensorToPipelineMap.get(sensor.getIdentifier().getValue()).put(channel, apv25.getChannel().new APV25AnalogPipeline()); + } + + sensorToAnalogDataMap.put(sensor.getIdentifier().getValue(), + new HashMap<Integer, double[]>()); + + sensorToDigitalDataMap.put(sensor.getIdentifier().getValue(), + new HashMap<Integer, double[]>()); + + } + } + + /** + * + */ + @Override + public void process(EventHeader event) { + + + super.process(event); + + if ((ClockSingleton.getTime() + ClockSingleton.getDt()) % 24 == 0) { + for (Map.Entry<Long, Map<Integer, APV25AnalogPipeline>> sensor : sensorToPipelineMap.entrySet()) { + apv25.incrementAllPointerPositions(sensor.getValue()); + } + apv25.stepAPV25Clock(); + } + + // Loop over all sensors + for (SiSensor sensor : processSensors) { + // Readout the sensors + readoutSensor(sensor); + } + + // If a trigger is received readout the APV25 and digitize all hits + if (HPSAPV25.triggerBit) { + + triggerTimeStamp.add(ClockSingleton.getTime()); + + // Only add the trigger if there isn't another trigger being + // processed + if (!triggerQueue.contains(apv25.apv25ClockCycle)) { + // Add the time at which each of the six samples should be + // collected to the trigger queue + for (int sample = 0; sample < 6; sample++) { + triggerQueue.offer(apv25.apv25ClockCycle + sample); + } + } + // Reset the APV25 trigger bit + HPSAPV25.triggerBit = false; + } + + // Process any triggers in the queue + if (triggerQueue.peek() != null) { + + // Remove any samples that might have already been processed + if (triggerQueue.peek() < apv25.apv25ClockCycle) { + for (int sample = 0; sample < 6; sample++) { + triggerQueue.remove(); + } + } else if (triggerQueue.peek() == apv25.apv25ClockCycle) { + readoutAPV25(); + triggerQueue.remove(); + } + } + } + + /** + * + */ + @Override + public void startOfData() { + // Set up readouts if they haven't been set + if (!readouts.isEmpty()) { + super.add(new SimTrackerHitReadoutDriver(readouts)); + } + + super.startOfData(); + readouts.clear(); + + } + + /** + * + * @param sensor + */ + public void makeRawHits(SiSensor sensor) { + readoutSensor(sensor); + } + + /** + * Readout the electrodes of an HPS Si sensor and inject the charge into + * the APV25 readout chip. + * + * @param sensor : HPS Si sensor + */ + public void readoutSensor(SiSensor sensor) { + // Set the sensor to be used in the charge deposition simulation + siSimulation.setSensor(sensor); + + // Perform the charge deposition simulation + Map<ChargeCarrier, SiElectrodeDataCollection> electrodeDataMap = siSimulation.computeElectrodeData(); + + // Loop over each charge carrier (electron or hole) + for (ChargeCarrier carrier : ChargeCarrier.values()) { + + // If the sensor is capable of collecting the given charge carrier + // then obtain the electrode data for the sensor + if (sensor.hasElectrodesOnSide(carrier)) { + SiElectrodeDataCollection electrodeDataCol = electrodeDataMap.get(carrier); + + // If there is no electrode data available create a new + // instance of electode data + if (electrodeDataCol == null) { + electrodeDataCol = new SiElectrodeDataCollection(); + } + + // Get the readout electrodes + SiSensorElectrodes readoutElectrodes = sensor.getReadoutElectrodes(carrier); + + // Add noise to the electrodes + addNoise(electrodeDataCol, readoutElectrodes); + + // Get the analog pipeline map associated with this sensor + analogPipelineMap = sensorToPipelineMap.get(sensor.getIdentifier().getValue()); + + // Loop over all channels + for (Integer channel : electrodeDataCol.keySet()) { + + // Get the electrode data for this channel + SiElectrodeData electrodeData = electrodeDataCol.get(channel); + + // Get the charge in units of electrons + double charge = electrodeData.getCharge(); + + //====> Charge deposition on electrode + aida.histogram1D("Charge", 100, 0, 200000).fill(charge); + //====> + + // Get the RMS noise for this channel + double noise = apv25.getChannel().computeNoise( + readoutElectrodes.getCapacitance(channel)); + + //===> + aida.histogram1D(this.getClass().getName() + " - RMS Noise - All Channels", 1000, 3500, 4500).fill(noise); + //===> + + // Check to see if an analog pipeline for this channel + // exist. If it doesn't, create one. + if (!analogPipelineMap.containsKey(channel)) { + analogPipelineMap.put(channel, + apv25.getChannel().new APV25AnalogPipeline()); + } + + // Get the analog pipeline associated with this channel + APV25AnalogPipeline pipeline = analogPipelineMap.get(channel); + + // Inject the charge into the APV25 amplifier chain + apv25.injectCharge(charge, noise, pipeline); + } + } + } + + // Place the analog pipeline back into the sensor map + sensorToPipelineMap.put(sensor.getIdentifier().getValue(), analogPipelineMap); + + // Clear the sensors of all deposited charge + siSimulation.clearReadout(); + } + + /** + * + */ + public void readoutAPV25() { + // Readout all apv25s + for (Map.Entry<Long, Map<Integer, APV25AnalogPipeline>> sensor : sensorToPipelineMap.entrySet()) { + sensorToAnalogDataMap.put(sensor.getKey(), apv25.APV25Multiplexer(sensor.getValue())); + } + + // Digitize all signals + for (Map.Entry<Long, Map<Integer, double[]>> sensor : sensorToAnalogDataMap.entrySet()) { + sensorToDigitalDataMap.put(sensor.getKey(), rtm.digitize(sensor.getValue())); + } + + // Buffer the samples for further processing + dpm.addSample(sensorToDigitalDataMap); + + } + + /** + * + * @param electrodeDataCol + * @param electrodes + */ + public void addNoise(SiElectrodeDataCollection electrodeDataCol, + SiSensorElectrodes electrodes) { + // First add readout noise to the strips in the + // SiElectrodeDataCollection. + + // Loop over the entries in the SiElectrodeDataCollection + for (Entry electrodeDatum : electrodeDataCol.entrySet()) { + + // Get the channel number and electrode data for this entry + int channel = (Integer) electrodeDatum.getKey(); + SiElectrodeData electrodeData = (SiElectrodeData) electrodeDatum.getValue(); + + // Get the RMS noise for this channel in units of electrons + double noise = apv25.getChannel().computeNoise( + electrodes.getCapacitance(channel)); + + // Add readout noise to the deposited charge + int noiseCharge = (int) Math.round(random.nextGaussian() * noise); + electrodeData.addCharge(noiseCharge); + } + + // Find the number of strips that are not currently hit + int nElectrodes = electrodes.getNCells(); + int nElectrodesEmpty = nElectrodes - electrodeDataCol.size(); + + // Get the noise threshold in units of the noise charge + + // Calculate how many channels should get noise hits + double integral = Erf.phic(noiseThreshold); + int nChannelsThrow = drawBinomial(nElectrodesEmpty, integral); + + // Now throw Gaussian randoms above the seed threshold and put signals + // on unoccupied channels + for (int ithrow = 0; ithrow < nChannelsThrow; ithrow++) { + // Throw to get a channel number + int channel = random.nextInt(nElectrodes); + while (electrodeDataCol.keySet().contains(channel)) { + channel = random.nextInt(nElectrodes); + } + + // Calculate the noise for this channel in units of electrons + double noise = apv25.getChannel().computeNoise( + electrodes.getCapacitance(channel)); + + // Throw Gaussian above threshold + int charge = (int) Math.round(drawGaussianAboveThreshold(integral) * noise); + + // Add the noise hit to the electrode data collection + electrodeDataCol.add(channel, new SiElectrodeData(charge)); + } + + // Now throw to lower threshold on channels that neighbor hits until + // we are exhausted + + nChannelsThrow = 1; + while (nChannelsThrow > 0) { + + // Get neighbor channels + Set<Integer> neighbors = new HashSet<Integer>(); + for (int channel : electrodeDataCol.keySet()) { + neighbors.addAll(electrodes.getNearestNeighborCells(channel)); + } + neighbors.removeAll(electrodeDataCol.keySet()); + + nElectrodesEmpty = neighbors.size(); + + integral = Erf.phic(noiseThreshold); + nChannelsThrow = drawBinomial(nElectrodesEmpty, integral); + + // Now throw Gaussian randoms above a threshold and put signals on + // unoccopied channels + for (int ithrow = 0; ithrow < nChannelsThrow; ithrow++) { + + // Throw to get a channel number + List<Integer> neighborList = new ArrayList<Integer>(neighbors); + + int channel = neighborList.get(random.nextInt(nElectrodesEmpty)); + + while (electrodeDataCol.keySet().contains(channel)) { + channel = neighborList.get(random.nextInt(nElectrodesEmpty)); + + } + + // Calculate the noise for this channel in units of electrons + double noise = apv25.getChannel().computeNoise( + electrodes.getCapacitance(channel)); + + // Throw Gaussian above threshold + int charge = (int) Math.round(drawGaussianAboveThreshold(integral) * noise); + + // Add the noise hit to the electrode data collection + electrodeDataCol.add(channel, new SiElectrodeData(charge)); + } + } + } + + /** + * + */ + public static int drawBinomial(int ntrials, double probability) { + binomial.setNumberOfTrials(ntrials); + binomial.setProbabilityOfSuccess(probability); + + int nsuccess = 0; + try { + nsuccess = binomial.inverseCumulativeProbability(random.nextDouble()); + } catch (MathException exception) { + throw new RuntimeException("APV25 failed to calculate inverse cumulative probability of binomial!"); + } + return nsuccess; + } + + /** + * Return a random variable following normal distribution, but beyond + * threshold provided during initialization. + */ + public static double drawGaussianAboveThreshold(double prob_above_threshold) { + double cumulative_probability; + + cumulative_probability = 1.0 + prob_above_threshold * (random.nextDouble() - 1.0); + + assert cumulative_probability < 1.0 : "cumulProb=" + cumulative_probability + ", probAboveThreshold=" + prob_above_threshold; + assert cumulative_probability >= 0.0 : "cumulProb=" + cumulative_probability + ", probAboveThreshold=" + prob_above_threshold; + + double gaussian_random = 0; + try { + gaussian_random = gaussian.inverseCumulativeProbability(cumulative_probability); + } catch (MathException e) { + System.out.println("MathException caught: " + e); + }
+ return gaussian_random; + }
}
diff -u -r1.10 -r1.11 --- HPSDataProcessingModule.java 5 Apr 2012 23:57:26 -0000 1.10 +++ HPSDataProcessingModule.java 10 Apr 2012 01:00:13 -0000 1.11 @@ -23,380 +23,356 @@
/** * * @author Omar Moreno <[log in to unmask]>
- * @version $Id: HPSDataProcessingModule.java,v 1.10 2012/04/05 23:57:26 jeremy Exp $
+ * @version $Id: HPSDataProcessingModule.java,v 1.11 2012/04/10 01:00:13 meeg Exp $
*/ public class HPSDataProcessingModule extends Driver {
- - Map<Long, Map<Integer, List<Double>>> sensorToBlocksMap; - - // Relate a channel to its six samples - Map<Integer, List<Double>> channelToBlock; - - // Relate a sensor Identifier to the actual sensor - Map<Long, SiSensor> sensorMap = new HashMap<Long, SiSensor>(); - - // Collection of all sensors - Set<SiSensor> sensorSet = new HashSet<SiSensor>(); - - // Collections of RawTrackerHits - List<RawTrackerHit> rawHits; // No cuts are applied - List<RawTrackerHit> rawHitsNoCuts; // Cuts are applied to samples - - // Collection of all SVT data - List<HPSSVTData> svtData; - List<HPSSVTData> svtFpgaData; - - // 1-5 rms noise [ADC Counts] <--- This is going to change
+ + Map<Long, Map<Integer, List<Double>>> sensorToBlocksMap; + // Relate a channel to its six samples + Map<Integer, List<Double>> channelToBlock; + // Relate a sensor Identifier to the actual sensor + Map<Long, SiSensor> sensorMap = new HashMap<Long, SiSensor>(); + // Collection of all sensors + Set<SiSensor> sensorSet = new HashSet<SiSensor>(); + // Collections of RawTrackerHits + List<RawTrackerHit> rawHits; // Cuts are applied + List<RawTrackerHit> rawHitsNoCuts; // No cuts are applied to samples + // Collection of all SVT data + List<HPSSVTData> svtData; + List<HPSSVTData> svtFpgaData; + // 1-5 rms noise [ADC Counts] <--- This is going to change
// int[] noiseThreshold = {1657, 1675, 1692, 1709, 1728};
- - int numberOfSamples = 0; // Total number of APV25 samples - int nSamplesAboveThresh = 3; // Number of samples above noise threshold - int pedestal = 1638; // [ADC counts] For now, all channels have the same pedestal - int flags = 0; // - int noise = 18; // [ADC Counts] RMS noise - int noiseThreshold = 3; // Units of RMS noise - - boolean thresholdCut = false; // Apply threshold cut? - boolean tailCut = false; // Apply tail cut? - boolean noiseSuppression = false; // Apply noise supression? - - double[] apv25DataStream; - - List<Double> samples; - - String RawTrackerHitsCollectionName = "RawTrackerHits"; - String RawTrackerHitsNoCutsCollectionName = "RawTrackerHitsNoCuts"; - String svtCollectionName = "SVTData"; - - /** - * Default Constructor - */ - public HPSDataProcessingModule() - { - channelToBlock = new HashMap<Integer, List<Double>>(); - sensorToBlocksMap = new HashMap<Long, Map<Integer, List<Double>>>(); - rawHits = new ArrayList<RawTrackerHit>(); - rawHitsNoCuts = new ArrayList<RawTrackerHit>(); - svtData = new ArrayList<HPSSVTData>(); - svtFpgaData = new ArrayList<HPSSVTData>(); - } - - /** - * - */ - @Override - public void detectorChanged(Detector detector){ - - // Get the tracker - IDetectorElement tracker - = detector.getDetectorElement().findDetectorElement("Tracker"); - - // Fill the collection of sensors - sensorSet.addAll(tracker.findDescendants(SiSensor.class)); - - for(SiSensor sensor : sensorSet){ - - // Map a sensor to its identifier - sensorMap.put(sensor.getIdentifier().getValue(), sensor); - - // Map a sensor to its corresponding samples - sensorToBlocksMap.put(sensor.getIdentifier().getValue(), - new HashMap<Integer, List<Double>>()); - } - } - - /** - * Set the SVT collection name - */ - public void setSvtCollectionName(String svtCollectionName) - { - this.svtCollectionName = svtCollectionName; - } - - /** - * Set the number of samples above threshold a signal must have - */ - public void setSamplesAboveThresh(int nSamplesAboveThresh) - { - this.nSamplesAboveThresh = nSamplesAboveThresh; - } - - /** - * Set the noise RMS [ADC Counts] - */ - public void setNoise(int noise) - { - this.noise = noise; - } - - /** - * Set the noise threshold in units of RMS noise - */ - public void setNoiseThreshold(int noiseThreshold) - { - this.noiseThreshold = noiseThreshold; - } - - /** - * Set the pedestal value for all channels - */ - public void setPedestal(int pedestal) - { - this.pedestal = pedestal; - } - - /** - * Enable the threshold cut. The threshold cut requires a certain number - * of samples per hit to be above a noise threshold. - */ - public void enableThresholdCut() - { - this.noiseSuppression = true; - } - - /** - * Enable the tail cut. The tail cut requires sample 1 to be greater than - * sample 0 or sample 2 to be greater than sample 1. This eliminates - * hits that may arise due to shaper signal tails. - */ - public void enableTailCut() - { - this.tailCut = true; - } - - /** - * Enable noise suppression cut. Requires samples 2 or 3 to be above a - * threshold noiseThreshold + noise. - */ - public void enableNoiseSuppressionCut() - { - this.noiseSuppression = true; - } - - /** - * Buffer a sample that has been readout from a sensor. - * - * @param sensorToDigitalMap - * A map relating a sensor to the digital samples readout from the - * sensor - */ - public void addSample(Map<Long, Map<Integer, double[]>> sensorToDigitalMap) - { - - /* - * Long: Sensor Identifier - * Integer: Chip Number - * double[]: APV25 Data Stream - */ - - int channelN = 0; - - // Loop through the list of all sensors - for(Map.Entry<Long, Map<Integer, double[]>> sensor : sensorToDigitalMap.entrySet()){ - - // Loop through all APV25s - for(Map.Entry<Integer, double[]> sample : sensor.getValue().entrySet()){ - - // Copy the sample to avoid concurrent modification - apv25DataStream = sample.getValue(); - - // Strip the APV25 data stream of all header information - // This needs to change so that the real chip address can be - // extracted ... - apv25DataStream - = Arrays.copyOfRange(apv25DataStream, 12, apv25DataStream.length-1); - - // Loop through all channels - for(int channel = 0; channel < apv25DataStream.length; channel++){ - - channelN = channel + sample.getKey()*128; - - // Check if a block has been created for this channel. If - // not create it - if(!sensorToBlocksMap.get(sensor.getKey()).containsKey(channelN)){ - sensorToBlocksMap.get(sensor.getKey()).put(channelN, new ArrayList<Double>(6)); - } - - sensorToBlocksMap.get(sensor.getKey()).get(channelN).add(apv25DataStream[channel]); - - } - } - } - numberOfSamples++; - } - - /** - * Finds hits that satisfied all required cuts and creates both - * RawTrackerHits and SVTData - */ - public void findHits() - { - - short[] adc = new short[6]; - int fpgaAddress = 0; - int hybridNumber = 0; - int apvNumber = 0; - - // Clear the list of raw tracker hits - rawHits.clear(); - rawHitsNoCuts.clear(); - svtData.clear(); - - // Loop through all sensors and the corresponding blocks - for(Map.Entry<Long, Map<Integer, List<Double>>> sensor : sensorToBlocksMap.entrySet()){ - - // Get the FPGA address - fpgaAddress = HPSSVTDAQMaps.sensorToDAQPair.get(sensorMap.get(sensor.getKey())).getSecondElement(); - - for(Map.Entry<Integer, List<Double>> block : sensor.getValue().entrySet()){ - - // Convert ADC value to a short - for(int index = 0; index < adc.length; index++){ - adc[index] = block.getValue().get(index).shortValue(); - } - - // Create RawTrackerHits from all hits before applying cuts - rawHitsNoCuts.add(makeRawTrackerHit(block.getKey(), sensorMap.get(sensor.getKey()), adc)); - - // Check if a block has the appropriate number of blocks above - // threshold - if(!(samplesAboveThreshold(adc) >= nSamplesAboveThresh) && thresholdCut) { - block.getValue().clear(); - continue; - } - - // Apply the tail cut - if(!tailCut(adc) && tailCut){ - block.getValue().clear(); - continue; - } - - // Apply noise suppression cut - if(!noiseSuppresionCut(adc) && noiseSuppression){ - block.getValue().clear(); - continue; - } - - // If all cuts are satisfied, create a RawTrackerHit - rawHits.add(makeRawTrackerHit(block.getKey(), sensorMap.get(sensor.getKey()), adc)); - - - // Get the hybrid number - hybridNumber = HPSSVTDAQMaps.sensorToDAQPair.get(sensorMap.get(sensor.getKey())).getFirstElement(); - - // Find the APV number - apvNumber = (int) Math.floor(block.getKey()/128); - - // Create an svtData packet - svtData.add(new HPSSVTData(hybridNumber, apvNumber, block.getKey()%128, fpgaAddress, adc )); - svtFpgaData.add(new HPSSVTData(hybridNumber, apvNumber, block.getKey()%128, fpgaAddress, adc )); - - block.getValue().clear(); - } - - HPSSVTDataBuffer.addToBuffer(svtFpgaData, fpgaAddress); - - // Clear data buffer. - svtFpgaData.clear(); - } - - System.out.println(this.getClass().getName() + ": Total RawTrackerHits before cuts: " + rawHitsNoCuts.size()); - System.out.println(this.getClass().getName() + ": Total RawTrackerHits: " + rawHits.size()); - System.out.println(this.getClass().getName() + ": Total SVTData: " + svtData.size()); - } - - /** - * Creates a rawTrackerHit - * - * @param channelNumber - * Si Strip from which the hit originates from - * @param sensor - * Sensor from which the hit originates from - * @param adcValues - * Shaper signal samples - * @return RawTrackerHit - */ - private RawTrackerHit makeRawTrackerHit( Integer channelNumber, SiSensor sensor, short[] adcValues) - { - IReadout ro = sensor.getReadout(); - - // No time yet - int time = 0; - long cell_id = sensor.makeStripId(channelNumber, 1).getValue(); - - RawTrackerHit rawHit = new BaseRawTrackerHit(time, cell_id, adcValues, new ArrayList<SimTrackerHit>(), sensor); - - ro.addHit(rawHit); - - return rawHit; - } - - /** - * Finds how many samples are above a given threshold - * - * @param adc - * Shaper signal samples - * @return Number of samples above threshold - */ - private int samplesAboveThreshold(short[] adc) - { - // Number of samples above threshold - int nSamplesAboveThreshold = 0; - - for(int sample = 0; sample < adc.length; sample++){ - if(adc[sample] >= pedestal + noiseThreshold*noise) nSamplesAboveThreshold++; - } - return nSamplesAboveThreshold; - } - - /** - * Applies tail cut - * - * @param adc - * Shaper signal samples - * @return true if the cut is satisfied, false otherwise - */ - private boolean tailCut(short[] adc) - { - if(adc[3] > adc[2] || adc[4] > adc[3]) return true; - return false; - } - - /** - * Applies noise suppression cut - * - * @param adc - * Shaper signal samples - * @return true if the cut is satisfied, false otherwise - */ - private boolean noiseSuppresionCut(short[] adc) - { - if(adc[3] > pedestal + noiseThreshold*noise || adc[4] > pedestal + noiseThreshold*noise) return true; - return false; - } - - /** - * - */ - @Override - public void process(EventHeader event) - { - super.process(event); - - // If six samples have been collected process the data - if(numberOfSamples == 6){ - - // Find hits - findHits(); - - // Add RawTrackerHits to the event - event.put(RawTrackerHitsCollectionName, rawHits, RawTrackerHit.class, flags); - - // Add SVTData to event - event.put(this.svtCollectionName, this.svtData, HPSSVTData.class, 0); - - // - numberOfSamples = 0; - } - }
+ int numberOfSamples = 0; // Total number of APV25 samples + int nSamplesAboveThresh = 3; // Number of samples above noise threshold + int pedestal = 1638; // [ADC counts] For now, all channels have the same pedestal + int flags = 0; // + int noise = 18; // [ADC Counts] RMS noise + int noiseThreshold = 3; // Units of RMS noise + private boolean thresholdCut = false; // Apply threshold cut? + private boolean tailCut = false; // Apply tail cut? + private boolean noiseSuppression = false; // Apply noise supression? + double[] apv25DataStream; + List<Double> samples; + String RawTrackerHitsCollectionName = "RawTrackerHits"; + String RawTrackerHitsNoCutsCollectionName = "RawTrackerHitsNoCuts"; + String svtCollectionName = "SVTData"; + + /** + * Default Constructor + */ + public HPSDataProcessingModule() { + channelToBlock = new HashMap<Integer, List<Double>>(); + sensorToBlocksMap = new HashMap<Long, Map<Integer, List<Double>>>(); + rawHits = new ArrayList<RawTrackerHit>(); + rawHitsNoCuts = new ArrayList<RawTrackerHit>(); + svtData = new ArrayList<HPSSVTData>(); + svtFpgaData = new ArrayList<HPSSVTData>(); + } + + /** + * + */ + @Override + public void detectorChanged(Detector detector) { + + // Get the tracker + IDetectorElement tracker = detector.getDetectorElement().findDetectorElement("Tracker"); + + // Fill the collection of sensors + sensorSet.addAll(tracker.findDescendants(SiSensor.class)); + + for (SiSensor sensor : sensorSet) { + + // Map a sensor to its identifier + sensorMap.put(sensor.getIdentifier().getValue(), sensor); + + // Map a sensor to its corresponding samples + sensorToBlocksMap.put(sensor.getIdentifier().getValue(), + new HashMap<Integer, List<Double>>()); + } + } + + /** + * Set the SVT collection name + */ + public void setSvtCollectionName(String svtCollectionName) { + this.svtCollectionName = svtCollectionName; + } + + /** + * Set the number of samples above threshold a signal must have + */ + public void setSamplesAboveThresh(int nSamplesAboveThresh) { + this.nSamplesAboveThresh = nSamplesAboveThresh; + } + + /** + * Set the noise RMS [ADC Counts] + */ + public void setNoise(int noise) { + this.noise = noise; + } + + /** + * Set the noise threshold in units of RMS noise + */ + public void setNoiseThreshold(int noiseThreshold) { + this.noiseThreshold = noiseThreshold; + } + + /** + * Set the pedestal value for all channels + */ + public void setPedestal(int pedestal) { + this.pedestal = pedestal; + } + + /** + * Enable the threshold cut. The threshold cut requires a certain number + * of samples per hit to be above a noise threshold. + */ + public void enableThresholdCut() { + this.thresholdCut = true; + } + + /** + * Enable the tail cut. The tail cut requires sample 1 to be greater than + * sample 0 or sample 2 to be greater than sample 1. This eliminates + * hits that may arise due to shaper signal tails. + */ + public void enableTailCut() { + this.tailCut = true; + } + + /** + * Enable noise suppression cut. Requires samples 2 or 3 to be above a + * threshold noiseThreshold + noise. + */ + public void enableNoiseSuppressionCut() { + this.noiseSuppression = true; + } + + /** + * Buffer a sample that has been readout from a sensor. + * + * @param sensorToDigitalMap + * A map relating a sensor to the digital samples readout from the + * sensor + */ + public void addSample(Map<Long, Map<Integer, double[]>> sensorToDigitalMap) { + + /* + * Long: Sensor Identifier + * Integer: Chip Number + * double[]: APV25 Data Stream + */ + + int channelN = 0; + + // Loop through the list of all sensors + for (Map.Entry<Long, Map<Integer, double[]>> sensor : sensorToDigitalMap.entrySet()) { + + // Loop through all APV25s + for (Map.Entry<Integer, double[]> sample : sensor.getValue().entrySet()) { + + // Copy the sample to avoid concurrent modification + apv25DataStream = sample.getValue(); + + // Strip the APV25 data stream of all header information + // This needs to change so that the real chip address can be + // extracted ... + apv25DataStream = Arrays.copyOfRange(apv25DataStream, 12, apv25DataStream.length - 1); + + // Loop through all channels + for (int channel = 0; channel < apv25DataStream.length; channel++) { + + channelN = channel + sample.getKey() * 128; + + // Check if a block has been created for this channel. If + // not create it + if (!sensorToBlocksMap.get(sensor.getKey()).containsKey(channelN)) { + sensorToBlocksMap.get(sensor.getKey()).put(channelN, new ArrayList<Double>(6)); + } + + sensorToBlocksMap.get(sensor.getKey()).get(channelN).add(apv25DataStream[channel]); + + } + } + } + numberOfSamples++; + } + + /** + * Finds hits that satisfied all required cuts and creates both + * RawTrackerHits and SVTData + */ + public void findHits() { + + int fpgaAddress = 0; + int hybridNumber = 0; + int apvNumber = 0; + + // Clear the list of raw tracker hits + rawHits.clear(); + rawHitsNoCuts.clear(); + svtData.clear(); + + // Loop through all sensors and the corresponding blocks + for (Map.Entry<Long, Map<Integer, List<Double>>> sensor : sensorToBlocksMap.entrySet()) { + + // Get the FPGA address + fpgaAddress = HPSSVTDAQMaps.sensorToDAQPair.get(sensorMap.get(sensor.getKey())).getSecondElement(); + + for (Map.Entry<Integer, List<Double>> block : sensor.getValue().entrySet()) { + short[] adc = new short[6]; + + // Convert ADC value to a short + for (int index = 0; index < adc.length; index++) { + adc[index] = block.getValue().get(index).shortValue(); + } + + // Create RawTrackerHits from all hits before applying cuts + RawTrackerHit newHit = makeRawTrackerHit(block.getKey(), sensorMap.get(sensor.getKey()), adc); + rawHitsNoCuts.add(newHit); + + // Check if a block has the appropriate number of blocks above + // threshold + if (thresholdCut && !(samplesAboveThreshold(adc) >= nSamplesAboveThresh)) { + block.getValue().clear(); + continue; + } + + // Apply the tail cut + if (tailCut && !tailCut(adc)) { + block.getValue().clear(); + continue; + } + + // Apply noise suppression cut + if (noiseSuppression && !noiseSuppressionCut(adc)) { + block.getValue().clear(); + continue; + } + + // If all cuts are satisfied, add the hit to the list of hits to be saved + rawHits.add(newHit); + + // Get the hybrid number + hybridNumber = HPSSVTDAQMaps.sensorToDAQPair.get(sensorMap.get(sensor.getKey())).getFirstElement(); + + // Find the APV number + apvNumber = (int) Math.floor(block.getKey() / 128); + + // Create an svtData packet + svtData.add(new HPSSVTData(hybridNumber, apvNumber, block.getKey() % 128, fpgaAddress, adc)); + svtFpgaData.add(new HPSSVTData(hybridNumber, apvNumber, block.getKey() % 128, fpgaAddress, adc)); + + block.getValue().clear(); + } + + HPSSVTDataBuffer.addToBuffer(svtFpgaData, fpgaAddress); + + // Clear data buffer. + svtFpgaData.clear(); + } + System.out.println(this.getClass().getName() + ": Total RawTrackerHits before cuts: " + rawHitsNoCuts.size()); + System.out.println(this.getClass().getName() + ": Total RawTrackerHits: " + rawHits.size()); + System.out.println(this.getClass().getName() + ": Total SVTData: " + svtData.size()); + } + + /** + * Creates a rawTrackerHit + * + * @param channelNumber + * Si Strip from which the hit originates from + * @param sensor + * Sensor from which the hit originates from + * @param adcValues + * Shaper signal samples + * @return RawTrackerHit + */ + private RawTrackerHit makeRawTrackerHit(Integer channelNumber, SiSensor sensor, short[] adcValues) { + IReadout ro = sensor.getReadout(); + + // No time yet + int time = 0; + long cell_id = sensor.makeStripId(channelNumber, 1).getValue(); + + RawTrackerHit rawHit = new BaseRawTrackerHit(time, cell_id, adcValues, new ArrayList<SimTrackerHit>(), sensor); + + ro.addHit(rawHit); + + return rawHit; + } + + /** + * Finds how many samples are above a given threshold + * + * @param adc + * Shaper signal samples + * @return Number of samples above threshold + */ + private int samplesAboveThreshold(short[] adc) { + // Number of samples above threshold + int nSamplesAboveThreshold = 0; + + for (int sample = 0; sample < adc.length; sample++) { + if (adc[sample] >= pedestal + noiseThreshold * noise) { + nSamplesAboveThreshold++; + } + } + return nSamplesAboveThreshold; + } + + /** + * Applies tail cut + * + * @param adc + * Shaper signal samples + * @return true if the cut is satisfied, false otherwise + */ + private boolean tailCut(short[] adc) { + if (adc[3] > adc[2] || adc[4] > adc[3]) { + return true; + } + return false; + } + + /** + * Applies noise suppression cut + * + * @param adc + * Shaper signal samples + * @return true if the cut is satisfied, false otherwise + */ + private boolean noiseSuppressionCut(short[] adc) { + if (adc[3] > pedestal + noiseThreshold * noise || adc[4] > pedestal + noiseThreshold * noise) { + return true; + } + return false; + } + + /** + * + */ + @Override + public void process(EventHeader event) { + super.process(event); + + // If six samples have been collected process the data + if (numberOfSamples == 6) { + + // Find hits + findHits(); + + // Add RawTrackerHits to the event + event.put(RawTrackerHitsCollectionName, rawHits, RawTrackerHit.class, flags); + + // Add SVTData to event + event.put(this.svtCollectionName, this.svtData, HPSSVTData.class, 0); + + // + numberOfSamples = 0; + } + }
}
diff -u -r1.3 -r1.4 --- HPSMakeSVTCellID.java 28 Mar 2012 18:59:09 -0000 1.3 +++ HPSMakeSVTCellID.java 10 Apr 2012 01:00:13 -0000 1.4 @@ -15,7 +15,7 @@
*/ public class HPSMakeSVTCellID {
- public long HPSMakeSVTCellID(int hybrid, int fpgaAddress, int apv, int channel) {
+ public static long HPSMakeSVTCellID(int hybrid, int fpgaAddress, int apv, int channel) {
// Information from Jeremy about how the CellID is coded // Here's the ID scheme for the SVT in that detector... // <readout name="TrackerHits">
@@ -32,8 +32,8 @@
IIdentifier sensorIdent = sensor.getIdentifier(); SiTrackerIdentifierHelper sensorHelper = (SiTrackerIdentifierHelper) sensor.getIdentifierHelper();
- int layer = 0; - int module = sensorHelper.getModuleValue(sensorIdent);
+ long layer = 0; + long module = sensorHelper.getModuleValue(sensorIdent);
if (module == 0) { //Layers 1-10 (Top SVT Volume) layer = sensorHelper.getLayerValue(sensorIdent); } //Layers 11-20 (Bottom SVT Volume)
@@ -41,15 +41,15 @@
layer = sensorHelper.getLayerValue(sensorIdent) + 10; }
- int sensornum = sensorHelper.getSensorValue(sensorIdent);
+ long sensornum = sensorHelper.getSensorValue(sensorIdent);
- int system = 0;
+ long system = 0;
- int barrel = 0;
+ long barrel = 0;
- int side = sensor.getSensorID(); // according to Omar
+ long side = sensor.getSensorID(); // according to Omar
- int strip = channel;
+ long strip = channel;
long CellID_ = system + (barrel << 6) + (layer << 9) + (module << 13) + (sensornum << 25) + (side << 32) + (strip << 34);
diff -u -r1.10 -r1.11 --- MonitoringApplication.java 9 Apr 2012 00:04:04 -0000 1.10 +++ MonitoringApplication.java 10 Apr 2012 01:00:13 -0000 1.11 @@ -762,7 +762,7 @@
//final String defaultEventBuilder = MCEventBuilder.class.getCanonicalName(); // These are for Test Run data.
- final String defaultSteering = "/org/lcsim/hps/defaultSteering/TestRunMonitoring.lcsim";
+ final String defaultSteering = "/org/lcsim/hps/steering/TestRunMonitoring.lcsim";
final String defaultEventBuilder = LCSimTestRunEventBuilder.class.getCanonicalName(); // Push default settings to JobPanel.
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