CMS 3D CMS Logo

CSCWireElectronicsSim.cc
Go to the documentation of this file.
8 
9 #include "CLHEP/Random/RandGaussQ.h"
10 #include "CLHEP/Units/GlobalPhysicalConstants.h"
11 #include "CLHEP/Units/GlobalSystemOfUnits.h"
12 
13 #include <iostream>
14 
16  : CSCBaseElectronicsSim(p), theFraction(0.5), theWireNoise(0.0), theWireThreshold(0.) {
18 }
19 
24 }
25 
26 int CSCWireElectronicsSim::readoutElement(int element) const { return theLayerGeometry->wireGroup(element); }
27 
28 void CSCWireElectronicsSim::fillDigis(CSCWireDigiCollection &digis, CLHEP::HepRandomEngine *engine) {
29  if (theSignalMap.empty()) {
30  return;
31  }
32 
33  // Loop over analog signals, run the fractional discriminator on each one,
34  // and save the DIGI in the layer.
35  for (CSCSignalMap::iterator mapI = theSignalMap.begin(), lastSignal = theSignalMap.end(); mapI != lastSignal;
36  ++mapI) {
37  int wireGroup = (*mapI).first;
38  const CSCAnalogSignal &signal = (*mapI).second;
39  LogTrace("CSCWireElectronicsSim") << "CSCWireElectronicsSim: dump of wire signal follows... " << signal;
40  int signalSize = signal.getSize();
41 
42  int timeWord = 0; // and this will remain if too early or late (<bx-6 or >bx+9)
43 
44  // the way we handle noise in this chamber is by randomly varying
45  // the threshold
47  if (doNoise_) {
48  threshold += CLHEP::RandGaussQ::shoot(engine) * theWireNoise;
49  }
50  for (int ibin = 0; ibin < signalSize; ++ibin) {
51  if (signal.getBinValue(ibin) > threshold) {
52  // jackpot. Now define this signal as everything up until
53  // the signal goes below zero.
54  int lastbin = signalSize;
55  int i;
56  for (i = ibin; i < signalSize; ++i) {
57  if (signal.getBinValue(i) < 0.) {
58  lastbin = i;
59  break;
60  }
61  }
62 
63  float qMax = 0.0;
64  // in this loop, find the max charge and the 'fifth' electron arrival
65  for (i = ibin; i < lastbin; ++i) {
66  float next_charge = signal.getBinValue(i);
67  if (next_charge > qMax) {
68  qMax = next_charge;
69  }
70  }
71 
72  int bin_firing_FD = 0;
73  for (i = ibin; i < lastbin; ++i) {
74  if (signal.getBinValue(i) >= qMax * theFraction) {
75  bin_firing_FD = i;
76  //@@ Long-standing but unlikely minor bug, I (Tim) think - following
77  //'break' was missing...
78  //@@ ... So if both ibins 0 and 1 could fire FD, we'd flag the
79  // firing bin as 1 not 0
80  //@@ (since the above test was restricted to bin_firing_FD==0 too).
81  break;
82  }
83  }
84 
85  float tofOffset = timeOfFlightCalibration(wireGroup);
86  int chamberType = theSpecs->chamberType();
87 
88  // Note that CSCAnalogSignal::superimpose does not reset theTimeOffset
89  // to the earliest of the two signal's time offsets. If it did then we
90  // could handle signals from any time range e.g. form pileup events many
91  // bx's from the signal bx (bx=0). But then we would be wastefully
92  // storing signals over times which we can never see in the real
93  // detector, because only hits within a few bx's of bx=0 are read out.
94  // Instead, the working time range for wire hits is always started from
95  // theSignalStartTime, set as a parameter in the config file.
96  // On the other hand, if any of the overlapped CSCAnalogSignals happens
97  // to have a timeOffset earlier than theSignalStartTime (which is
98  // currently set to -100 ns) then we're in trouble. For pileup events
99  // this would mean events from collisions earlier than 4 bx before the
100  // signal bx.
101 
102  float fdTime = theSignalStartTime + theSamplingTime * bin_firing_FD;
103  if (doNoise_) {
104  fdTime += theTimingCalibrationError[chamberType] * CLHEP::RandGaussQ::shoot(engine);
105  }
106 
107  float bxFloat = (fdTime - tofOffset - theBunchTimingOffsets[chamberType]) / theBunchSpacing + theOffsetOfBxZero;
108  int bxInt = static_cast<int>(bxFloat);
109  if (bxFloat >= 0 && bxFloat < 16) {
110  timeWord |= (1 << bxInt);
111  // discriminator stays high for 35 ns
112  if (bxFloat - bxInt > 0.6) {
113  timeWord |= (1 << (bxInt + 1));
114  }
115  }
116 
117  // Wire digi as of Oct-2006 adapted to real data: time word has 16 bits
118  // with set bit flagging appropriate bunch crossing, and bx 0
119  // corresponding to the 7th bit, 'bit 6':
120 
121  // 1st bit set (bit 0) <-> bx -6
122  // 2nd 1 <-> bx -5
123  // ... ... ....
124  // 7th 6 <-> bx 0
125  // 8th 7 <-> bx +1
126  // ... ... ....
127  // 16th 15 <-> bx +9
128 
129  // skip over all the time bins used for this digi
130  ibin = lastbin;
131  } // if over threshold
132  } // loop over time bins in signal
133 
134  // Only create a wire digi if there is a wire hit within [-6 bx, +9 bx]
135  if (timeWord != 0) {
136  CSCWireDigi newDigi(wireGroup, timeWord);
137  LogTrace("CSCWireElectronicsSim") << "CSCWireElectronicsSim: " << newDigi;
138  digis.insertDigi(layerId(), newDigi);
139  addLinks(channelIndex(wireGroup));
140  }
141  } // loop over wire signals
142 }
143 
145  static const float fC_by_ns = 1000000;
146  static const float resistor = 20000;
147  static const float amplifier_pole = 1 / 7.5;
148  static const float fastest_chamber_exp_risetime = 10.;
149  static const float p0 = amplifier_pole;
150  static const float p1 = 1 / fastest_chamber_exp_risetime;
151 
152  static const float dp = p0 - p1;
153 
154  // ENABLE DISC:
155 
156  static const float norm = -12 * resistor * p1 * pow(p0 / dp, 4) / fC_by_ns;
157 
158  float enable_disc_volts =
159  norm * (exp(-p0 * t) * (1 + t * dp + pow(t * dp, 2) / 2 + pow(t * dp, 3) / 6) - exp(-p1 * t));
160  static const float collectionFraction = 0.12;
161  static const float igain = 1. / 0.005; // volts per fC
162  return enable_disc_volts * igain * collectionFraction;
163 }
164 
166  // calibration is done for groups of 8 wire groups, facetiously
167  // called wireGroupGroups
168  int middleWireGroup = wireGroup - wireGroup % 8 + 4;
169  int numberOfWireGroups = theLayerGeometry->numberOfWireGroups();
170  if (middleWireGroup > numberOfWireGroups)
171  middleWireGroup = numberOfWireGroups;
172 
173  GlobalPoint centerOfGroupGroup = theLayer->centerOfWireGroup(middleWireGroup);
174  float averageDist = centerOfGroupGroup.mag();
175  float averageTOF = averageDist * cm / c_light; // Units of c_light: mm/ns
176 
177  LogTrace("CSCWireElectronicsSim") << "CSCWireElectronicsSim: TofCalib wg = " << wireGroup
178  << " mid wg = " << middleWireGroup << " av dist = " << averageDist
179  << " av tof = " << averageTOF;
180 
181  return averageTOF;
182 }
std::vector< double > theBunchTimingOffsets
int chamberType() const
const CSCChamberSpecs * theSpecs
const CSCLayerGeometry * theLayerGeometry
CSCDetId layerId() const
the CSCDetId corresponding to the current layer
float wireNoise(float timeInterval) const
CSCWireElectronicsSim(const edm::ParameterSet &p)
configurable parameters
int getSize() const
#define LogTrace(id)
void fillDigis(CSCWireDigiCollection &digis, CLHEP::HepRandomEngine *)
int numberOfWireGroups() const
T mag() const
Definition: PV3DBase.h:64
void initParameters() override
initialization for each layer
int wireGroup(int wire) const
float calculateAmpResponse(float t) const override
virtual void addLinks(int channelIndex)
float getBinValue(int i) const
virtual float timeOfFlightCalibration(int wireGroup) const
#define e_SI
int readoutElement(int element) const override
int channelIndex(int channel) const override
we code strip indices from 1-80, and wire indices start at 100
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
GlobalPoint centerOfWireGroup(int wireGroup) const
Definition: CSCLayer.cc:10
std::vector< double > theTimingCalibrationError