CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch9/src/SimMuon/CSCDigitizer/src/CSCWireElectronicsSim.cc

Go to the documentation of this file.
00001 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00002 #include "SimMuon/CSCDigitizer/src/CSCWireElectronicsSim.h"
00003 #include "SimMuon/CSCDigitizer/src/CSCAnalogSignal.h"
00004 #include "DataFormats/CSCDigi/interface/CSCWireDigi.h"
00005 #include "Geometry/CSCGeometry/interface/CSCLayer.h"
00006 #include "Geometry/CSCGeometry/interface/CSCLayerGeometry.h"
00007 #include "Geometry/CSCGeometry/interface/CSCChamberSpecs.h"
00008 #include "CLHEP/Units/GlobalPhysicalConstants.h"
00009 #include "CLHEP/Units/GlobalSystemOfUnits.h"  
00010 #include <iostream>
00011 
00012 
00013 CSCWireElectronicsSim::CSCWireElectronicsSim(const edm::ParameterSet & p) 
00014  : CSCBaseElectronicsSim(p),
00015    theFraction(0.5),
00016    theWireNoise(0.0),
00017    theWireThreshold(0.)
00018 {
00019   fillAmpResponse();
00020 }
00021 
00022 
00023 void CSCWireElectronicsSim::initParameters() {
00024   nElements = theLayerGeometry->numberOfWireGroups();
00025   theWireNoise = theSpecs->wireNoise(theShapingTime)
00026                 * e_SI * pow(10.0,15);
00027   theWireThreshold = theWireNoise * 8;
00028 }
00029 
00030 
00031 int CSCWireElectronicsSim::readoutElement(int element) const {
00032   return theLayerGeometry->wireGroup(element);
00033 }
00034 
00035 void CSCWireElectronicsSim::fillDigis(CSCWireDigiCollection & digis) {
00036 
00037   if(theSignalMap.empty()) {
00038     return;
00039   }
00040 
00041   // Loop over analog signals, run the fractional discriminator on each one,
00042   // and save the DIGI in the layer.
00043   for(CSCSignalMap::iterator mapI = theSignalMap.begin(),
00044       lastSignal = theSignalMap.end();
00045       mapI != lastSignal; ++mapI) 
00046   {
00047     int wireGroup = (*mapI).first;
00048     const CSCAnalogSignal & signal = (*mapI).second;
00049     LogTrace("CSCWireElectronicsSim") << "CSCWireElectronicsSim: dump of wire signal follows... " 
00050        <<  signal;
00051     int signalSize = signal.getSize();
00052 
00053     int timeWord = 0; // and this will remain if too early or late (<bx-6 or >bx+9)
00054 
00055     // the way we handle noise in this chamber is by randomly varying
00056     // the threshold
00057     float threshold = theWireThreshold;
00058     if (doNoise_) {
00059        threshold += theRandGaussQ->fire() * theWireNoise;
00060     }
00061     for(int ibin = 0; ibin < signalSize; ++ibin)
00062     {
00063       if(signal.getBinValue(ibin) > threshold) 
00064       {
00065         // jackpot.  Now define this signal as everything up until
00066         // the signal goes below zero.
00067         int lastbin = signalSize;
00068         int i;
00069         for(i = ibin; i < signalSize; ++i) {
00070           if(signal.getBinValue(i) < 0.) {
00071             lastbin = i;
00072             break;
00073           }
00074         }
00075 
00076         float qMax = 0.0;
00077         // in this loop, find the max charge and the 'fifth' electron arrival
00078         for ( i = ibin; i < lastbin; ++i)
00079         {
00080           float next_charge = signal.getBinValue(i);
00081           if(next_charge > qMax) {
00082             qMax = next_charge;
00083           }
00084         }
00085      
00086         int bin_firing_FD = 0;
00087         for ( i = ibin; i < lastbin; ++i)
00088         {
00089           if( signal.getBinValue(i) >= qMax * theFraction )
00090           {
00091              bin_firing_FD = i;
00092              //@@ Long-standing but unlikely minor bug, I (Tim) think - following 'break' was missing...
00093              //@@ ... So if both ibins 0 and 1 could fire FD, we'd flag the firing bin as 1 not 0
00094              //@@ (since the above test was restricted to bin_firing_FD==0 too).
00095              break;
00096           }
00097         } 
00098 
00099         float tofOffset = timeOfFlightCalibration(wireGroup);
00100         int chamberType = theSpecs->chamberType();
00101 
00102         // Note that CSCAnalogSignal::superimpose does not reset theTimeOffset to the earliest
00103         // of the two signal's time offsets. If it did then we could handle signals from any
00104         // time range e.g. form pileup events many bx's from the signal bx (bx=0).
00105         // But then we would be wastefully storing signals over times which we can never
00106         // see in the real detector, because only hits within a few bx's of bx=0 are read out.
00107         // Instead, the working time range for wire hits is always started from
00108         // theSignalStartTime, set as a parameter in the config file.
00109         // On the other hand, if any of the overlapped CSCAnalogSignals happens to have
00110         // a timeOffset earlier than theSignalStartTime (which is currently set to -100 ns)
00111         // then we're in trouble. For pileup events this would mean events from collisions
00112         // earlier than 4 bx before the signal bx.
00113 
00114         float fdTime = theSignalStartTime + theSamplingTime*bin_firing_FD;
00115         if(doNoise_) {
00116           fdTime += theTimingCalibrationError[chamberType] * theRandGaussQ->fire();
00117         }
00118 
00119         float bxFloat = (fdTime - tofOffset- theBunchTimingOffsets[chamberType]) / theBunchSpacing
00120                            + theOffsetOfBxZero;
00121         int bxInt = static_cast<int>(bxFloat);
00122         if(bxFloat >= 0 && bxFloat < 16)
00123         {
00124            timeWord |= (1 << bxInt );
00125            // discriminator stays high for 35 ns
00126            if(bxFloat-bxInt > 0.6) 
00127            {
00128              timeWord |= (1 << (bxInt+1) );
00129            }
00130         }
00131 
00132         // Wire digi as of Oct-2006 adapted to real data: time word has 16 bits with set bit
00133         // flagging appropriate bunch crossing, and bx 0 corresponding to the 7th bit, 'bit 6':
00134   
00135         //      1st bit set (bit 0) <-> bx -6
00136         //      2nd              1  <-> bx -5
00137         //      ...           ...       ....
00138         //      7th              6  <-> bx  0
00139         //      8th              7  <-> bx +1
00140         //      ...           ...       ....
00141         //     16th             15  <-> bx +9
00142 
00143         // skip over all the time bins used for this digi
00144         ibin = lastbin;
00145       } // if over threshold
00146     } // loop over time bins in signal
00147 
00148     // Only create a wire digi if there is a wire hit within [-6 bx, +9 bx]
00149     if(timeWord != 0)
00150     {
00151       CSCWireDigi newDigi(wireGroup, timeWord);
00152       LogTrace("CSCWireElectronicsSim") << newDigi;
00153       digis.insertDigi(layerId(), newDigi);
00154       addLinks(channelIndex(wireGroup));
00155     }
00156   } // loop over wire signals   
00157 }
00158 
00159 
00160 float CSCWireElectronicsSim::calculateAmpResponse(float t) const {
00161   static const float fC_by_ns = 1000000;
00162   static const float resistor = 20000;
00163   static const float amplifier_pole               = 1/7.5;
00164   static const float fastest_chamber_exp_risetime = 10.;
00165   static const float p0=amplifier_pole;
00166   static const float p1=1/fastest_chamber_exp_risetime;
00167 
00168   static const float dp = p0 - p1;
00169 
00170   // ENABLE DISC:
00171 
00172   static const float norm = -12 * resistor * p1 * pow(p0/dp, 4) / fC_by_ns;
00173 
00174   float enable_disc_volts = norm*(  exp(-p0*t) *(1          +
00175                                                  t*dp       +
00176                                                  pow(t*dp,2)/2 +
00177                                                  pow(t*dp,3)/6  )
00178                                     - exp(-p1*t) );
00179   static const float collectionFraction = 0.12;
00180   static const float igain = 1./0.005; // volts per fC
00181   return enable_disc_volts * igain * collectionFraction;
00182 }                                                                               
00183 
00184 
00185 float CSCWireElectronicsSim::timeOfFlightCalibration(int wireGroup) const {
00186   // calibration is done for groups of 8 wire groups, facetiously
00187   // called wireGroupGroups
00188   int middleWireGroup = wireGroup - wireGroup%8 + 4;
00189   int numberOfWireGroups = theLayerGeometry->numberOfWireGroups();
00190   if(middleWireGroup > numberOfWireGroups) 
00191      middleWireGroup = numberOfWireGroups;
00192 
00193   GlobalPoint centerOfGroupGroup = theLayer->centerOfWireGroup(middleWireGroup);
00194   float averageDist = centerOfGroupGroup.mag();
00195   float averageTOF  = averageDist * cm / c_light; // Units of c_light: mm/ns
00196 
00197   LogTrace("CSCWireElectronicsSim") << "CSCWireElectronicsSim: TofCalib  wg = " << wireGroup << 
00198        " mid wg = " << middleWireGroup << 
00199        " av dist = " << averageDist << 
00200       " av tof = " << averageTOF;
00201   
00202   return averageTOF;
00203 }
00204