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)
#define e_SI
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
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