File indexing completed on 2024-04-06 12:30:46
0001 #include "CLHEP/Units/defs.h"
0002 #include "CLHEP/Units/SystemOfUnits.h"
0003 #include "CLHEP/Units/GlobalPhysicalConstants.h"
0004 #include "SimMuon/GEMDigitizer/interface/ME0SimpleModel.h"
0005 #include "Geometry/GEMGeometry/interface/ME0EtaPartitionSpecs.h"
0006 #include "Geometry/CommonTopologies/interface/TrapezoidalStripTopology.h"
0007 #include "Geometry/GEMGeometry/interface/ME0Geometry.h"
0008 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0009 #include "FWCore/Utilities/interface/Exception.h"
0010 #include "CLHEP/Random/RandFlat.h"
0011 #include "CLHEP/Random/RandPoissonQ.h"
0012 #include "CLHEP/Random/RandGaussQ.h"
0013 #include <cmath>
0014 #include <utility>
0015 #include <map>
0016
0017 ME0SimpleModel::ME0SimpleModel(const edm::ParameterSet& config)
0018 : ME0DigiModel(config),
0019 averageEfficiency_(config.getParameter<double>("averageEfficiency")),
0020 averageShapingTime_(config.getParameter<double>("averageShapingTime")),
0021 timeResolution_(config.getParameter<double>("timeResolution")),
0022 timeJitter_(config.getParameter<double>("timeJitter")),
0023 averageNoiseRate_(config.getParameter<double>("averageNoiseRate")),
0024 signalPropagationSpeed_(config.getParameter<double>("signalPropagationSpeed")),
0025 bxwidth_(config.getParameter<int>("bxwidth")),
0026 minBunch_(config.getParameter<int>("minBunch")),
0027 maxBunch_(config.getParameter<int>("maxBunch")),
0028 digitizeOnlyMuons_(config.getParameter<bool>("digitizeOnlyMuons")),
0029 doBkgNoise_(config.getParameter<bool>("doBkgNoise")),
0030 doNoiseCLS_(config.getParameter<bool>("doNoiseCLS")),
0031 fixedRollRadius_(config.getParameter<bool>("fixedRollRadius")),
0032 simulateElectronBkg_(config.getParameter<bool>("simulateElectronBkg")),
0033 instLumi_(config.getParameter<double>("instLumi")),
0034 rateFact_(config.getParameter<double>("rateFact")),
0035 referenceInstLumi_(config.getParameter<double>("referenceInstLumi")),
0036 ME0ElecBkgParam0_(config.getParameter<double>("ME0ElecBkgParam0")),
0037 ME0ElecBkgParam1_(config.getParameter<double>("ME0ElecBkgParam1")),
0038 ME0ElecBkgParam2_(config.getParameter<double>("ME0ElecBkgParam2")),
0039 ME0ElecBkgParam3_(config.getParameter<double>("ME0ElecBkgParam3")),
0040 ME0NeuBkgParam0_(config.getParameter<double>("ME0NeuBkgParam0")),
0041 ME0NeuBkgParam1_(config.getParameter<double>("ME0NeuBkgParam1")),
0042 ME0NeuBkgParam2_(config.getParameter<double>("ME0NeuBkgParam2")),
0043 ME0NeuBkgParam3_(config.getParameter<double>("ME0NeuBkgParam3")) {}
0044
0045 ME0SimpleModel::~ME0SimpleModel() {}
0046
0047 void ME0SimpleModel::setup() { return; }
0048
0049 void ME0SimpleModel::simulateSignal(const ME0EtaPartition* roll,
0050 const edm::PSimHitContainer& simHits,
0051 CLHEP::HepRandomEngine* engine) {
0052 stripDigiSimLinks_.clear();
0053 detectorHitMap_.clear();
0054 stripDigiSimLinks_ = StripDigiSimLinks(roll->id().rawId());
0055
0056 theME0DigiSimLinks_.clear();
0057 theME0DigiSimLinks_ = ME0DigiSimLinks(roll->id().rawId());
0058 bool digiMuon = false;
0059 bool digiElec = false;
0060 for (const auto& hit : simHits) {
0061 if (std::abs(hit.particleType()) != 13 && digitizeOnlyMuons_)
0062 continue;
0063 double elecEff = 0.;
0064 double partMom = hit.pabs();
0065 double checkMuonEff = CLHEP::RandFlat::shoot(engine, 0., 1.);
0066 double checkElecEff = CLHEP::RandFlat::shoot(engine, 0., 1.);
0067 if (std::abs(hit.particleType()) == 13 && checkMuonEff < averageEfficiency_)
0068 digiMuon = true;
0069 if (std::abs(hit.particleType()) != 13)
0070 {
0071 if (partMom <= 1.95e-03)
0072 elecEff = 1.7e-05 * std::exp(2.1 * partMom * 1000.);
0073 if (partMom > 1.95e-03 && partMom < 10.e-03)
0074 elecEff =
0075 1.34 * log(7.96e-01 * partMom * 1000. - 5.75e-01) / (1.34 + log(7.96e-01 * partMom * 1000. - 5.75e-01));
0076 if (partMom > 10.e-03)
0077 elecEff = 1.;
0078 if (checkElecEff < elecEff)
0079 digiElec = true;
0080 }
0081 if (!(digiMuon || digiElec))
0082 continue;
0083 const int bx(getSimHitBx(&hit, engine));
0084 const std::vector<std::pair<int, int> >& cluster(simulateClustering(roll, &hit, bx, engine));
0085 for (const auto& digi : cluster) {
0086 detectorHitMap_.emplace(digi, &hit);
0087 strips_.emplace(digi);
0088 }
0089 }
0090 }
0091
0092 int ME0SimpleModel::getSimHitBx(const PSimHit* simhit, CLHEP::HepRandomEngine* engine) {
0093 int bx = -999;
0094 const LocalPoint& simHitPos(simhit->localPosition());
0095 const float tof(simhit->timeOfFlight());
0096
0097 float randomJitterTime = CLHEP::RandGaussQ::shoot(engine, 0., timeJitter_);
0098 const ME0DetId& id(simhit->detUnitId());
0099 const ME0EtaPartition* roll(geometry_->etaPartition(id));
0100 if (!roll) {
0101 throw cms::Exception("Geometry") << "ME0SimpleModel::getSimHitBx() - ME0 simhit id does not match any ME0 roll id: "
0102 << id << "\n";
0103 return 999;
0104 }
0105 if (roll->id().region() == 0) {
0106 throw cms::Exception("Geometry")
0107 << "ME0SimpleModel::getSimHitBx() - this ME0 id is from barrel, which cannot happen: " << roll->id() << "\n";
0108 }
0109 const int nstrips = roll->nstrips();
0110 float middleStrip = nstrips / 2.;
0111 const LocalPoint& middleOfRoll = roll->centreOfStrip(middleStrip);
0112 const GlobalPoint& globMiddleRol = roll->toGlobal(middleOfRoll);
0113 double muRadius = sqrt(globMiddleRol.x() * globMiddleRol.x() + globMiddleRol.y() * globMiddleRol.y() +
0114 globMiddleRol.z() * globMiddleRol.z());
0115 double timeCalibrationOffset_ = (muRadius * CLHEP::ns * CLHEP::cm) / (CLHEP::c_light);
0116 const TrapezoidalStripTopology* top(dynamic_cast<const TrapezoidalStripTopology*>(&(roll->topology())));
0117 const float halfStripLength(0.5 * top->stripLength());
0118 const float distanceFromEdge(halfStripLength - simHitPos.y());
0119
0120
0121 double signalPropagationSpeedTrue = signalPropagationSpeed_ * CLHEP::c_light / (CLHEP::ns * CLHEP::cm);
0122
0123 const float averagePropagationTime(distanceFromEdge / signalPropagationSpeedTrue);
0124
0125 float randomResolutionTime = CLHEP::RandGaussQ::shoot(engine, 0., timeResolution_);
0126 const float simhitTime(tof + averageShapingTime_ + randomResolutionTime + averagePropagationTime + randomJitterTime);
0127 float referenceTime = 0.;
0128 referenceTime = timeCalibrationOffset_ + halfStripLength / signalPropagationSpeedTrue + averageShapingTime_;
0129 const float timeDifference(simhitTime - referenceTime);
0130
0131 bx = static_cast<int>(std::round((timeDifference) / bxwidth_));
0132
0133
0134 const bool debug(false);
0135 if (debug) {
0136 LogDebug("ME0SimpleModel") << "checktime "
0137 << "bx = " << bx << "\tdeltaT = " << timeDifference << "\tsimT = " << simhitTime
0138 << "\trefT = " << referenceTime << "\ttof = " << tof
0139 << "\tavePropT = " << averagePropagationTime
0140 << "\taveRefPropT = " << halfStripLength / signalPropagationSpeedTrue << std::endl;
0141 }
0142 return bx;
0143 }
0144
0145 void ME0SimpleModel::simulateNoise(const ME0EtaPartition* roll, CLHEP::HepRandomEngine* engine) {
0146 if (!doBkgNoise_)
0147 return;
0148 const ME0DetId me0Id(roll->id());
0149 const int nstrips(roll->nstrips());
0150 double trArea(0.0);
0151 double trStripArea(0.0);
0152
0153 if (me0Id.region() == 0) {
0154 throw cms::Exception("Geometry")
0155 << "ME0Synchronizer::simulateNoise() - this ME0 id is from barrel, which cannot happen.";
0156 }
0157 const TrapezoidalStripTopology* top_(dynamic_cast<const TrapezoidalStripTopology*>(&(roll->topology())));
0158 const float striplength(top_->stripLength());
0159 trStripArea = (roll->pitch()) * striplength;
0160 trArea = trStripArea * nstrips;
0161 const int nBxing(maxBunch_ - minBunch_ + 1);
0162 const float rollRadius(
0163 fixedRollRadius_
0164 ? top_->radius()
0165 : top_->radius() + CLHEP::RandFlat::shoot(engine, -1. * top_->stripLength() / 2., top_->stripLength() / 2.));
0166
0167 const float rSqrtR = rollRadius * sqrt(rollRadius);
0168
0169
0170 double averageNeutralNoiseRatePerRoll = 0.;
0171 double averageNoiseElectronRatePerRoll = 0.;
0172 double averageNoiseRatePerRoll = 0.;
0173 if (me0Id.station() != 1) {
0174 throw cms::Exception("Geometry")
0175 << "ME0SimpleModel::simulateNoise() - this ME0 id is from station 1, which cannot happen: " << roll->id()
0176 << "\n";
0177 } else {
0178 averageNeutralNoiseRatePerRoll = ME0NeuBkgParam0_ * rollRadius * std::exp(ME0NeuBkgParam1_ / rSqrtR) +
0179 ME0NeuBkgParam2_ / rSqrtR + ME0NeuBkgParam3_ / (sqrt(rollRadius));
0180
0181 if (simulateElectronBkg_)
0182 averageNoiseElectronRatePerRoll = ME0ElecBkgParam0_ * rSqrtR * std::exp(ME0ElecBkgParam1_ / rSqrtR) +
0183 ME0ElecBkgParam2_ / rSqrtR + ME0ElecBkgParam3_ / (sqrt(rollRadius));
0184 averageNoiseRatePerRoll = averageNeutralNoiseRatePerRoll + averageNoiseElectronRatePerRoll;
0185 averageNoiseRatePerRoll *= instLumi_ * rateFact_ * 1.0 / referenceInstLumi_;
0186 }
0187
0188
0189 if (simulateIntrinsicNoise_) {
0190 const double aveIntrinsicNoisePerStrip(averageNoiseRate_ * nBxing * bxwidth_ * trStripArea * 1.0e-9);
0191 for (int j = 0; j < nstrips; ++j) {
0192 int randPoissonQ = CLHEP::RandPoissonQ::shoot(engine, aveIntrinsicNoisePerStrip);
0193
0194 for (int k = 0; k < randPoissonQ; k++) {
0195 const int time_hit(static_cast<int>(CLHEP::RandFlat::shoot(engine, nBxing)) + minBunch_);
0196 strips_.emplace(k + 1, time_hit);
0197 }
0198 }
0199 }
0200
0201
0202 const double averageNoise(averageNoiseRatePerRoll * nBxing * bxwidth_ * trArea * 1.0e-9);
0203 int randPoissonQ = CLHEP::RandPoissonQ::shoot(engine, averageNoise);
0204
0205 for (int i = 0; i < randPoissonQ; ++i) {
0206 const int centralStrip(static_cast<int>(CLHEP::RandFlat::shoot(engine, 1, nstrips)));
0207 const int time_hit(static_cast<int>(CLHEP::RandFlat::shoot(engine, nBxing)) + minBunch_);
0208 if (doNoiseCLS_) {
0209 std::vector<std::pair<int, int> > cluster;
0210 cluster.emplace_back(centralStrip, time_hit);
0211 int clusterSize((CLHEP::RandFlat::shoot(engine)) <= 0.53 ? 1 : 2);
0212 if (clusterSize == 2) {
0213 if (CLHEP::RandFlat::shoot(engine) < 0.5) {
0214 if (CLHEP::RandFlat::shoot(engine) < averageEfficiency_ && (centralStrip - 1 > 0))
0215 cluster.emplace_back(centralStrip - 1, time_hit);
0216 } else {
0217 if (CLHEP::RandFlat::shoot(engine) < averageEfficiency_ && (centralStrip + 1 <= nstrips))
0218 cluster.emplace_back(centralStrip + 1, time_hit);
0219 }
0220 }
0221 for (const auto& digi : cluster) {
0222 strips_.emplace(digi);
0223 }
0224 }
0225 else {
0226 strips_.emplace(centralStrip, time_hit);
0227 }
0228 }
0229 return;
0230 }
0231
0232 std::vector<std::pair<int, int> > ME0SimpleModel::simulateClustering(const ME0EtaPartition* roll,
0233 const PSimHit* simHit,
0234 const int bx,
0235 CLHEP::HepRandomEngine* engine) {
0236 const StripTopology& topology = roll->specificTopology();
0237 const LocalPoint& hit_position(simHit->localPosition());
0238 const int nstrips(roll->nstrips());
0239 int centralStrip = 0;
0240 if (!(topology.channel(hit_position) + 1 > nstrips))
0241 centralStrip = topology.channel(hit_position) + 1;
0242 else
0243 centralStrip = topology.channel(hit_position);
0244 const GlobalPoint& pointSimHit = roll->toGlobal(hit_position);
0245 const GlobalPoint& pointDigiHit = roll->toGlobal(roll->centreOfStrip(centralStrip));
0246 double deltaX = pointSimHit.x() - pointDigiHit.x();
0247
0248
0249 std::vector<std::pair<int, int> > cluster;
0250 cluster.clear();
0251 cluster.emplace_back(centralStrip, bx);
0252
0253
0254 int clusterSize((CLHEP::RandFlat::shoot(engine)) <= 0.53 ? 1 : 2);
0255 if (clusterSize == 2) {
0256 if (deltaX <= 0) {
0257 if (CLHEP::RandFlat::shoot(engine) < averageEfficiency_ && (centralStrip - 1 > 0))
0258 cluster.emplace_back(centralStrip - 1, bx);
0259 } else {
0260 if (CLHEP::RandFlat::shoot(engine) < averageEfficiency_ && (centralStrip + 1 <= nstrips))
0261 cluster.emplace_back(centralStrip + 1, bx);
0262 }
0263 }
0264 return cluster;
0265 }