Go to the documentation of this file.00001 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00002 #include "SimMuon/CSCDigitizer/src/CSCDriftSim.h"
00003 #include "SimMuon/CSCDigitizer/src/CSCDetectorHit.h"
00004 #include "Geometry/CSCGeometry/interface/CSCChamberSpecs.h"
00005 #include "Geometry/CSCGeometry/interface/CSCLayer.h"
00006 #include "Geometry/CSCGeometry/interface/CSCLayerGeometry.h"
00007 #include "DataFormats/GeometryVector/interface/LocalVector.h"
00008 #include "SimDataFormats/TrackingHit/interface/PSimHit.h"
00009 #include "MagneticField/Engine/interface/MagneticField.h"
00010 #include "DataFormats/Math/interface/Point3D.h"
00011 #include "DataFormats/Math/interface/Vector3D.h"
00012 #include "Math/GenVector/RotationZ.h"
00013 #include "CLHEP/Units/GlobalPhysicalConstants.h"
00014 #include "CLHEP/Units/GlobalSystemOfUnits.h"
00015 #include <cmath>
00016 #include <iostream>
00017
00018 static const int N_INTEGRAL_STEPS = 700;
00019
00020 CSCDriftSim::CSCDriftSim()
00021 : bz(0.),
00022 ycell(0.),
00023 zcell(0.),
00024 dNdEIntegral(N_INTEGRAL_STEPS, 0.),
00025 STEP_SIZE(0.01),
00026 ELECTRON_DIFFUSION_COEFF(0.0161),
00027 theMagneticField(0),
00028 theRandGaussQ(0),
00029 theRandFlat(0)
00030 {
00031
00032
00033 double sum = 0.;
00034 int i;
00035 for(i = 0; i < N_INTEGRAL_STEPS; ++i) {
00036 if(i > 1) {
00037 double xx = STEP_SIZE * (double(i) - 0.5 );
00038 double dNdE = pow( xx, 0.38) * exp(-1.38*xx);
00039
00040 sum += dNdE;
00041 }
00042
00043 dNdEIntegral[i] = sum;
00044 }
00045
00046
00047 for(i = 0; i < N_INTEGRAL_STEPS; ++i) {
00048 dNdEIntegral[i] /= sum;
00049 }
00050 }
00051
00052
00053 CSCDriftSim::~CSCDriftSim()
00054 {
00055 delete theRandGaussQ;
00056 delete theRandFlat;
00057 }
00058
00059
00060 void CSCDriftSim::setRandomEngine(CLHEP::HepRandomEngine& engine)
00061 {
00062 theRandGaussQ = new CLHEP::RandGaussQ(engine);
00063 theRandFlat = new CLHEP::RandFlat(engine);
00064 }
00065
00066
00067 CSCDetectorHit
00068 CSCDriftSim::getWireHit(const Local3DPoint & pos, const CSCLayer * layer,
00069 int nearestWire, const PSimHit & simHit) {
00070
00071 const CSCChamberSpecs * specs = layer->chamber()->specs();
00072 const CSCLayerGeometry * geom = layer->geometry();
00073 math::LocalPoint clusterPos(pos.x(), pos.y(), pos.z());
00074 LogTrace("CSCDriftSim") << "CSCDriftSim: ionization cluster at: " << pos;
00075
00076
00077 math::LocalVector yShift(0, -1.*geom->yOfWire(nearestWire), 0.);
00078 ROOT::Math::RotationZ rotation(-1.*geom->wireAngle());
00079
00080 clusterPos = yShift + clusterPos;
00081 clusterPos = rotation * clusterPos;
00082 GlobalPoint globalPosition = layer->surface().toGlobal(pos);
00083 assert(theMagneticField != 0);
00084
00085
00086
00087
00088
00089 bz = layer->toLocal( theMagneticField->inKGauss( globalPosition ) ).z();
00090
00091
00092 ycell = clusterPos.z() / specs->anodeCathodeSpacing();
00093 zcell = 2.*clusterPos.y() / specs->wireSpacing();
00094
00095 LogTrace("CSCDriftSim") << "CSCDriftSim: bz " << bz <<" avgDrift " << avgDrift()
00096 << " wireAngle " << geom->wireAngle()
00097 << " ycell " << ycell << " zcell " << zcell;
00098
00099 double avgPathLength, pathSigma, avgDriftTime, driftTimeSigma;
00100 static const float B_FIELD_CUT = 15.f;
00101 if(fabs(bz) < B_FIELD_CUT) {
00102 avgPathLength = avgPathLengthLowB();
00103 pathSigma = pathSigmaLowB();
00104 avgDriftTime = avgDriftTimeLowB();
00105 driftTimeSigma = driftTimeSigmaLowB();
00106 }
00107 else {
00108 avgPathLength = avgPathLengthHighB();
00109 pathSigma = pathSigmaHighB();
00110 avgDriftTime = avgDriftTimeHighB();
00111 driftTimeSigma = driftTimeSigmaHighB();
00112 }
00113
00114
00115 double pathLength = std::max(theRandGaussQ->fire(avgPathLength, pathSigma), 0.);
00116
00117
00118 double diffusionSigma = ELECTRON_DIFFUSION_COEFF * sqrt(pathLength);
00119 double x = clusterPos.x() + theRandGaussQ->fire(avgDrift(), driftSigma())
00120 + theRandGaussQ->fire(0., diffusionSigma);
00121
00122
00123 double driftTime = std::max(theRandGaussQ->fire(avgDriftTime, driftTimeSigma), 0.);
00124
00125
00126
00127
00128 static const double f_collected = 0.82;
00129
00130
00131
00132
00133 double charge = avalancheCharge() * f_collected * gasGain(layer->id()) * e_SI * 1.e15;
00134
00135 float t = simHit.tof() + driftTime;
00136 LogTrace("CSCDriftSim") << "CSCDriftSim: tof = " << simHit.tof() <<
00137 " driftTime = " << driftTime <<
00138 " MEDH = " << CSCDetectorHit(nearestWire, charge, x, t, &simHit);
00139 return CSCDetectorHit(nearestWire, charge, x, t, &simHit);
00140 }
00141
00142
00143 #include <algorithm>
00144 double CSCDriftSim::avalancheCharge() {
00145 double returnVal = 0.;
00146
00147 double x = theRandFlat->fire();
00148 size_t i;
00149 size_t isiz = dNdEIntegral.size();
00150
00151
00152
00153
00154
00155
00156 std::vector<double>::const_iterator p=lower_bound(dNdEIntegral.begin(),dNdEIntegral.end(),x);
00157 if (p==dNdEIntegral.end()) i=isiz-1;
00158 else i = p-dNdEIntegral.begin();
00159
00160
00161
00162 if( i == isiz-1 ) {
00163
00164 returnVal = STEP_SIZE * double(i) * dNdEIntegral[i];
00165 }
00166 else {
00167 double x1 = dNdEIntegral[i];
00168 double x2 = dNdEIntegral[i+1];
00169 returnVal = STEP_SIZE * (double(i) + (x-x1)/(x2-x1));
00170 }
00171 LogTrace("CSCDriftSim") << "CSCDriftSim: avalanche fluc " << returnVal << " " << x ;
00172
00173 return returnVal;
00174 }
00175
00176
00177 double CSCDriftSim::gasGain(const CSCDetId & detId) const
00178 {
00179 double result = 130000.;
00180
00181
00182 int ring = detId.ring();
00183 if(detId.station() == 1 && (ring == 1 || ring == 4))
00184 {
00185 result = 213000.;
00186 }
00187 return result;
00188 }