CMS 3D CMS Logo

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/PhysicalConstants.h"
00009 #include <iostream>
00010 
00011 
00012 CSCWireElectronicsSim::CSCWireElectronicsSim(const edm::ParameterSet & p) 
00013  : CSCBaseElectronicsSim(p),
00014    theFraction(0.5),
00015    theWireNoise(0.0),
00016    theWireThreshold(0.),
00017    theTimingCalibrationError(p.getParameter<double>("wireTimingError"))
00018 {
00019   fillAmpResponse();
00020 }
00021 
00022 
00023 void CSCWireElectronicsSim::initParameters() {
00024   theLayerGeometry = theLayer->geometry();
00025   nElements = theLayerGeometry->numberOfWireGroups();
00026   theWireNoise = theSpecs->wireNoise(theShapingTime)
00027                 * e_SI * pow(10.0,15);
00028   theWireThreshold = theWireNoise * 8;
00029 }
00030 
00031 
00032 int CSCWireElectronicsSim::readoutElement(int element) const {
00033   return theLayerGeometry->wireGroup(element);
00034 }
00035 
00036 void CSCWireElectronicsSim::fillDigis(CSCWireDigiCollection & digis) {
00037 
00038   if(theSignalMap.empty()) {
00039     return;
00040   }
00041 
00042   // Loop over analog signals, run the fractional discriminator on each one,
00043   // and save the DIGI in the layer.
00044   for(CSCSignalMap::iterator mapI = theSignalMap.begin(),
00045       lastSignal = theSignalMap.end();
00046       mapI != lastSignal; ++mapI) 
00047   {
00048     int wireGroup = (*mapI).first;
00049     const CSCAnalogSignal & signal = (*mapI).second;
00050     LogTrace("CSCWireElectronicsSim") << "CSCWireElectronicsSim: dump of wire signal follows... " 
00051        <<  signal;
00052     int signalSize = signal.getSize();
00053 
00054     int timeWord = 0; // and this will remain if too early or late (<bx-6 or >bx+9)
00055 
00056     // the way we handle noise in this chamber is by randomly varying
00057     // the threshold
00058     float threshold = theWireThreshold;
00059     if (doNoise_) {
00060        threshold += theRandGaussQ->fire() * theWireNoise;
00061     }
00062     for(int ibin = 0; ibin < signalSize; ++ibin)
00063     {
00064       if(signal.getBinValue(ibin) > threshold) 
00065       {
00066         // jackpot.  Now define this signal as everything up until
00067         // the signal goes below zero.
00068         int lastbin = signalSize;
00069         int i;
00070         for(i = ibin; i < signalSize; ++i) {
00071           if(signal.getBinValue(i) < 0.) {
00072             lastbin = i;
00073             break;
00074           }
00075         }
00076 
00077         float qMax = 0.0;
00078         // in this loop, find the max charge and the 'fifth' electron arrival
00079         for ( i = ibin; i < lastbin; ++i)
00080         {
00081           float next_charge = signal.getBinValue(i);
00082           if(next_charge > qMax) {
00083             qMax = next_charge;
00084           }
00085         }
00086      
00087         int bin_firing_FD = 0;
00088         for ( i = ibin; i < lastbin; ++i)
00089         {
00090           if( bin_firing_FD == 0 && signal.getBinValue(i) >= qMax * theFraction )
00091           {
00092              bin_firing_FD = i;
00093           }
00094         } 
00095         float tofOffset = timeOfFlightCalibration(wireGroup);
00096         int chamberType = theSpecs->chamberType();
00097 
00098         // Note that CSCAnalogSignal::superimpose does not reset theTimeOffset to the earliest
00099         // of the two signal's time offsets. If it did then we could handle signals from any
00100         // time range e.g. form pileup events many bx's from the signal bx (bx=0).
00101         // But then we would be wastefully storing signals over times which we can never
00102         // see in the real detector, because only hits within a few bx's of bx=0 are read out.
00103         // Instead, the working time range for wire hits is always started from
00104         // theSignalStartTime, set as a parameter in the config file.
00105         // On the other hand, if any of the overlapped CSCAnalogSignals happens to have
00106         // a timeOffset earlier than theSignalStartTime (which is currently set to -100 ns)
00107         // then we're in trouble. For pileup events this would mean events from collisions
00108         // earlier than 4 bx before the signal bx.
00109 
00110         float fdTime = theSignalStartTime + theSamplingTime*bin_firing_FD;
00111         if(doNoise_) {
00112           fdTime += theTimingCalibrationError * theRandGaussQ->fire();
00113         }
00114 
00115         float bxFloat = (fdTime - tofOffset- theBunchTimingOffsets[chamberType]) / theBunchSpacing
00116                            + theOffsetOfBxZero;
00117         if(bxFloat >= 0 && bxFloat < 16)
00118         {
00119            timeWord |= (1 << static_cast<int>(bxFloat) );
00120         }
00121 
00122         // Wire digi as of Oct-2006 adapted to real data: time word has 16 bits with set bit
00123         // flagging appropriate bunch crossing, and bx 0 corresponding to the 7th bit, 'bit 6':
00124   
00125         //      1st bit set (bit 0) <-> bx -6
00126         //      2nd              1  <-> bx -5
00127         //      ...           ...       ....
00128         //      7th              6  <-> bx  0
00129         //      8th              7  <-> bx +1
00130         //      ...           ...       ....
00131         //     16th             15  <-> bx +9
00132 
00133         // skip over all the time bins used for this digi
00134         ibin = lastbin;
00135       } // if over threshold
00136     } // loop over time bins in signal
00137 
00138     // Only create a wire digi if there is a wire hit within [-6 bx, +9 bx]
00139     if(timeWord != 0)
00140     {
00141       CSCWireDigi newDigi(wireGroup, timeWord);
00142       LogTrace("CSCWireElectronicsSim") << newDigi;
00143       digis.insertDigi(layerId(), newDigi);
00144       addLinks(channelIndex(wireGroup));
00145     }
00146   } // loop over wire signals   
00147 }
00148 
00149 
00150 float CSCWireElectronicsSim::calculateAmpResponse(float t) const {
00151   static const float fC_by_ns = 1000000;
00152   static const float resistor = 20000;
00153   static const float amplifier_pole               = 1/7.5;
00154   static const float fastest_chamber_exp_risetime = 10.;
00155   static const float p0=amplifier_pole;
00156   static const float p1=1/fastest_chamber_exp_risetime;
00157 
00158   static const float dp = p0 - p1;
00159 
00160   // ENABLE DISC:
00161 
00162   static const float norm = -12 * resistor * p1 * pow(p0/dp, 4) / fC_by_ns;
00163 
00164   float enable_disc_volts = norm*(  exp(-p0*t) *(1          +
00165                                                  t*dp       +
00166                                                  pow(t*dp,2)/2 +
00167                                                  pow(t*dp,3)/6  )
00168                                     - exp(-p1*t) );
00169   static const float collectionFraction = 0.12;
00170   static const float igain = 1./0.005; // volts per fC
00171   return enable_disc_volts * igain * collectionFraction;
00172 }                                                                               
00173 
00174 
00175 float CSCWireElectronicsSim::signalDelay(int element, float pos) const {
00176   // readout is on right edge of chamber, signal speed is c
00177   // zero calibrated to chamber center
00178   // pos is assumed to be in wire coordinates, not local
00179   float distance = -1. * pos; // in cm
00180   float speed = c_light / cm;
00181   float delay = distance / speed;
00182   return delay;
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  

Generated on Tue Jun 9 17:47:31 2009 for CMSSW by  doxygen 1.5.4