CMS 3D CMS Logo

CSCDriftSim.cc
Go to the documentation of this file.
9 #include "Math/GenVector/RotationZ.h"
13 
14 #include "CLHEP/Random/RandFlat.h"
15 #include "CLHEP/Random/RandGaussQ.h"
16 #include "CLHEP/Units/GlobalPhysicalConstants.h"
17 #include "CLHEP/Units/GlobalSystemOfUnits.h"
18 
19 #include <cmath>
20 #include <iostream>
21 
22 static const int N_INTEGRAL_STEPS = 700;
23 
25  : bz(0.), // should make these local variables
26  ycell(0.),
27  zcell(0.),
28  dNdEIntegral(N_INTEGRAL_STEPS, 0.),
29  STEP_SIZE(0.01),
30  ELECTRON_DIFFUSION_COEFF(0.0161),
31  theMagneticField(nullptr) {
32  // just initialize avalanche sim. There has to be a better
33  // way to take the integral of a function!
34  double sum = 0.;
35  int i;
36  for (i = 0; i < N_INTEGRAL_STEPS; ++i) {
37  if (i > 1) {
38  double xx = STEP_SIZE * (double(i) - 0.5);
39  double dNdE = pow(xx, 0.38) * exp(-1.38 * xx);
40 
41  sum += dNdE;
42  }
43  // store this value in the map
44  dNdEIntegral[i] = sum;
45  }
46 
47  // now normalize the whole map
48  for (i = 0; i < N_INTEGRAL_STEPS; ++i) {
49  dNdEIntegral[i] /= sum;
50  }
51 }
52 
54 
56  const CSCLayer *layer,
57  int nearestWire,
58  const PSimHit &simHit,
59  CLHEP::HepRandomEngine *engine) {
60  const CSCChamberSpecs *specs = layer->chamber()->specs();
61  const CSCLayerGeometry *geom = layer->geometry();
62  math::LocalPoint clusterPos(pos.x(), pos.y(), pos.z());
63  LogTrace("CSCDriftSim") << "CSCDriftSim: ionization cluster at: " << pos;
64  // set the coordinate system with the x-axis along the nearest wire,
65  // with the origin in the center of the chamber, on that wire.
66  math::LocalVector yShift(0, -1. * geom->yOfWire(nearestWire), 0.);
67  ROOT::Math::RotationZ rotation(-1. * geom->wireAngle());
68 
69  clusterPos = yShift + clusterPos;
70  clusterPos = rotation * clusterPos;
71  GlobalPoint globalPosition = layer->surface().toGlobal(pos);
72  assert(theMagneticField != nullptr);
73 
74  // bz = theMagneticField->inTesla(globalPosition).z() * 10.;
75 
76  // We need magnetic field in _local_ coordinates
77  // Interface now allows access in kGauss directly.
78  bz = layer->toLocal(theMagneticField->inKGauss(globalPosition)).z();
79 
80  // these subroutines label the coordinates in GEANT coords...
81  ycell = clusterPos.z() / specs->anodeCathodeSpacing();
82  zcell = 2. * clusterPos.y() / specs->wireSpacing();
83 
84  LogTrace("CSCDriftSim") << "CSCDriftSim: bz " << bz << " avgDrift " << avgDrift() << " wireAngle "
85  << geom->wireAngle() << " ycell " << ycell << " zcell " << zcell;
86 
87  double avgPathLength, pathSigma, avgDriftTime, driftTimeSigma;
88  static const float B_FIELD_CUT = 15.f;
89  if (fabs(bz) < B_FIELD_CUT) {
90  avgPathLength = avgPathLengthLowB();
91  pathSigma = pathSigmaLowB();
92  avgDriftTime = avgDriftTimeLowB();
93  driftTimeSigma = driftTimeSigmaLowB();
94  } else {
95  avgPathLength = avgPathLengthHighB();
96  pathSigma = pathSigmaHighB();
97  avgDriftTime = avgDriftTimeHighB();
98  driftTimeSigma = driftTimeSigmaHighB();
99  }
100 
101  // electron drift path length
102  double pathLength = std::max(CLHEP::RandGaussQ::shoot(engine, avgPathLength, pathSigma), 0.);
103 
104  // electron drift distance along the anode wire, including diffusion
105  double diffusionSigma = ELECTRON_DIFFUSION_COEFF * sqrt(pathLength);
106  double x = clusterPos.x() + CLHEP::RandGaussQ::shoot(engine, avgDrift(), driftSigma()) +
107  CLHEP::RandGaussQ::shoot(engine, 0., diffusionSigma);
108 
109  // electron drift time
110  double driftTime = std::max(CLHEP::RandGaussQ::shoot(engine, avgDriftTime, driftTimeSigma), 0.);
111 
112  //@@ Parameters which should be defined outside the code
113  // f_att is the fraction of drift electrons lost due to attachment
114  // static const double f_att = 0.5;
115  static const double f_collected = 0.82;
116 
117  // Avalanche charge, with fluctuation ('avalancheCharge()' is the fluctuation
118  // generator!)
119  // double charge = avalancheCharge() * f_att * f_collected *
120  // gasGain(layer->id()) * e_SI * 1.e15;
121  // doing fattachment by random chance of killing
122  double charge = avalancheCharge(engine) * f_collected * gasGain(layer->id()) * e_SI * 1.e15;
123 
124  float t = simHit.tof() + driftTime;
125  LogTrace("CSCDriftSim") << "CSCDriftSim: tof = " << simHit.tof() << " driftTime = " << driftTime
126  << " MEDH = " << CSCDetectorHit(nearestWire, charge, x, t, &simHit);
127  return CSCDetectorHit(nearestWire, charge, x, t, &simHit);
128 }
129 
130 // Generate avalanche fluctuation
131 #include <algorithm>
132 double CSCDriftSim::avalancheCharge(CLHEP::HepRandomEngine *engine) {
133  double returnVal = 0.;
134  // pick a random value along the dNdE integral
135  double x = CLHEP::RandFlat::shoot(engine);
136  size_t i;
137  size_t isiz = dNdEIntegral.size();
138  /*
139  for(i = 0; i < isiz-1; ++i) {
140  if(dNdEIntegral[i] > x) break;
141  }
142  */
143  // return position of first element with a value >= x
144  std::vector<double>::const_iterator p = lower_bound(dNdEIntegral.begin(), dNdEIntegral.end(), x);
145  if (p == dNdEIntegral.end())
146  i = isiz - 1;
147  else
148  i = p - dNdEIntegral.begin();
149 
150  // now extrapolate between values
151  if (i == isiz - 1) {
152  // edm::LogInfo("CSCDriftSim") << "Funky integral in CSCDriftSim " << x;
153  returnVal = STEP_SIZE * double(i) * dNdEIntegral[i];
154  } else {
155  double x1 = dNdEIntegral[i];
156  double x2 = dNdEIntegral[i + 1];
157  returnVal = STEP_SIZE * (double(i) + (x - x1) / (x2 - x1));
158  }
159  LogTrace("CSCDriftSim") << "CSCDriftSim: avalanche fluc " << returnVal << " " << x;
160 
161  return returnVal;
162 }
163 
164 double CSCDriftSim::gasGain(const CSCDetId &detId) const {
165  double result = 130000.; // 1.30 E05
166  // if ME1/1, add some extra gas gain to compensate
167  // for a smaller gas gap
168  int ring = detId.ring();
169  if (detId.station() == 1 && (ring == 1 || ring == 4)) {
170  result = 213000.; // 2.13 E05 ( to match real world as of Jan-2011)
171  }
172  return result;
173 }
double zcell
Definition: CSCDriftSim.h:67
double pathSigmaHighB()
double driftSigma() const
double avgDrift() const
Definition: CSCDriftParam.cc:8
GlobalVector inKGauss(const GlobalPoint &gp) const
Field value ad specified global point, in KGauss.
Definition: MagneticField.h:33
CSCDetectorHit getWireHit(const Local3DPoint &ionClusterPosition, const CSCLayer *, int wire, const PSimHit &simHit, CLHEP::HepRandomEngine *)
Definition: CSCDriftSim.cc:55
const MagneticField * theMagneticField
Definition: CSCDriftSim.h:74
double avgPathLengthHighB()
const double STEP_SIZE
Definition: CSCDriftSim.h:70
assert(be >=bs)
double driftTimeSigmaLowB()
double driftTimeSigmaHighB()
#define LogTrace(id)
constexpr std::array< uint8_t, layerIndexSize > layer
double avgDriftTimeHighB()
double avalancheCharge(CLHEP::HepRandomEngine *)
Definition: CSCDriftSim.cc:132
#define e_SI
double avgDriftTimeLowB()
const double ELECTRON_DIFFUSION_COEFF
Definition: CSCDriftSim.h:72
double pathSigmaLowB()
T sqrt(T t)
Definition: SSEVec.h:19
double ycell
Definition: CSCDriftSim.h:67
static const int N_INTEGRAL_STEPS
Definition: CSCDriftSim.cc:22
int station() const
Definition: CSCDetId.h:79
double avgPathLengthLowB()
double gasGain(const CSCDetId &id) const
Definition: CSCDriftSim.cc:164
std::vector< double > dNdEIntegral
Definition: CSCDriftSim.h:69
int ring() const
Definition: CSCDetId.h:68
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< float >, ROOT::Math::LocalCoordinateSystemTag > LocalPoint
point in local coordinate system
Definition: Point3D.h:15
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< float >, ROOT::Math::LocalCoordinateSystemTag > LocalVector
vector in local coordinate system
Definition: Vector3D.h:25
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29