/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
FastSimulation/MuonSimHitProducer/plugins/MuonSimHitProducer.cc
628 строк
29 KB
Christopher Jones
Added edm::stream::WatchRuns to FastSimulation modules
24 мар 2026, 23:26
24 мар 2026, 23:26
63d3b3e
Код
Авторство
О чём код?
// // Package: MuonSimHitProducer // Class: MuonSimHitProducer // /**\class MuonSimHitProducer FastSimulation/MuonSimHitProducer/src/MuonSimHitProducer.cc Description: Fast simulation producer of Muon Sim Hits (to be used for realistic Muon reconstruction) Implementation: <Notes on implementation> */ // // Original Author: Martijn Mulders/Matthew Jones // Created: Wed Jul 30 11:37:24 CET 2007 // Working: Fri Nov 9 09:39:33 CST 2007 // // $Id: MuonSimHitProducer.cc,v 1.36 2011/10/07 08:25:42 aperrott Exp $ // // #include "DataFormats/GeometrySurface/interface/PlaneBuilder.h" #include "DataFormats/GeometrySurface/interface/TangentPlane.h" #include "DataFormats/MuonDetId/interface/DTWireId.h" #include "FastSimulation/MaterialEffects/interface/EnergyLossSimulator.h" #include "FastSimulation/MaterialEffects/interface/MaterialEffects.h" #include "FastSimulation/MaterialEffects/interface/MultipleScatteringSimulator.h" #include "FastSimulation/MaterialEffects/interface/MuonBremsstrahlungSimulator.h" #include "FastSimulation/ParticlePropagator/interface/ParticlePropagator.h" #include "FastSimulation/Utilities/interface/RandomEngineAndDistribution.h" #include "FWCore/Framework/interface/ConsumesCollector.h" #include "FWCore/Framework/interface/stream/EDProducer.h" #include "Geometry/CSCGeometry/interface/CSCGeometry.h" #include "Geometry/DTGeometry/interface/DTGeometry.h" #include "Geometry/RPCGeometry/interface/RPCGeometry.h" #include "Geometry/Records/interface/MuonGeometryRecord.h" #include "MagneticField/Records/interface/IdealMagneticFieldRecord.h" #include "RecoMuon/MeasurementDet/interface/MuonDetLayerMeasurements.h" #include "RecoMuon/Navigation/interface/DirectMuonNavigation.h" #include "RecoMuon/TrackingTools/interface/MuonServiceProxy.h" #include "RecoMuon/TrackingTools/interface/MuonPatternRecoDumper.h" #include "SimDataFormats/Track/interface/SimTrack.h" #include "SimDataFormats/TrackingHit/interface/PSimHitContainer.h" #include "SimDataFormats/Vertex/interface/SimVertex.h" #include "SimGeneral/HepPDTRecord/interface/ParticleDataTable.h" #include "TrackPropagation/SteppingHelixPropagator/interface/SteppingHelixPropagator.h" #include "TrackingTools/GeomPropagators/interface/HelixArbitraryPlaneCrossing.h" #include "TrackingTools/KalmanUpdators/interface/Chi2MeasurementEstimator.h" class MuonSimHitProducer : public edm::stream::EDProducer<edm::stream::WatchRuns> { public: explicit MuonSimHitProducer(const edm::ParameterSet&); private: MuonServiceProxy* theService; Chi2MeasurementEstimator theEstimator; const MagneticField* magfield; const DTGeometry* dtGeom; const CSCGeometry* cscGeom; const RPCGeometry* rpcGeom; const Propagator* propagatorWithMaterial; std::unique_ptr<Propagator> propagatorWithoutMaterial; std::unique_ptr<MaterialEffects> theMaterialEffects; void beginRun(edm::Run const& run, const edm::EventSetup& es) override; void produce(edm::Event&, const edm::EventSetup&) override; void readParameters(const edm::ParameterSet&, const edm::ParameterSet&, const edm::ParameterSet&); // Parameters to emulate the muonSimHit association inefficiency due to delta's double kDT; double fDT; double kCSC; double fCSC; /// Simulate material effects in iron (dE/dx, multiple scattering) void applyMaterialEffects(TrajectoryStateOnSurface& tsosWithdEdx, TrajectoryStateOnSurface& tsos, double radPath, RandomEngineAndDistribution const*, HepPDT::ParticleDataTable const&); // ----------- parameters ---------------------------- bool fullPattern_; bool doL1_, doL3_, doGL_; // tags edm::InputTag simMuonLabel; edm::InputTag simVertexLabel; // tokens edm::EDGetTokenT<std::vector<SimTrack> > simMuonToken; edm::EDGetTokenT<std::vector<SimVertex> > simVertexToken; const edm::ESGetToken<MagneticField, IdealMagneticFieldRecord> magneticFieldESToken_; const edm::ESGetToken<DTGeometry, MuonGeometryRecord> dtGeometryESToken_; const edm::ESGetToken<CSCGeometry, MuonGeometryRecord> cscGeometryESToken_; const edm::ESGetToken<RPCGeometry, MuonGeometryRecord> rpcGeometryESToken_; const edm::ESGetToken<HepPDT::ParticleDataTable, edm::DefaultRecord> particleDataTableESToken_; }; //for debug only //#define FAMOS_DEBUG // // constructors and destructor // MuonSimHitProducer::MuonSimHitProducer(const edm::ParameterSet& iConfig) : theEstimator(iConfig.getParameter<double>("Chi2EstimatorCut")), propagatorWithoutMaterial(nullptr), magneticFieldESToken_(esConsumes<edm::Transition::BeginRun>()), dtGeometryESToken_(esConsumes<edm::Transition::BeginRun>(edm::ESInputTag("", "MisAligned"))), cscGeometryESToken_(esConsumes<edm::Transition::BeginRun>(edm::ESInputTag("", "MisAligned"))), rpcGeometryESToken_(esConsumes<edm::Transition::BeginRun>()), particleDataTableESToken_(esConsumes()) { // Read relevant parameters readParameters(iConfig.getParameter<edm::ParameterSet>("MUONS"), iConfig.getParameter<edm::ParameterSet>("TRACKS"), iConfig.getParameter<edm::ParameterSet>("MaterialEffectsForMuons")); // // register your products ... need to declare at least one possible product... // produces<edm::PSimHitContainer>("MuonCSCHits"); produces<edm::PSimHitContainer>("MuonDTHits"); produces<edm::PSimHitContainer>("MuonRPCHits"); edm::ParameterSet serviceParameters = iConfig.getParameter<edm::ParameterSet>("ServiceParameters"); theService = new MuonServiceProxy(serviceParameters, consumesCollector(), MuonServiceProxy::UseEventSetupIn::Run); // consumes simMuonToken = consumes<std::vector<SimTrack> >(simMuonLabel); simVertexToken = consumes<std::vector<SimVertex> >(simVertexLabel); } // ---- method called once each job just before starting event loop ---- void MuonSimHitProducer::beginRun(edm::Run const& run, const edm::EventSetup& es) { //services magfield = &es.getData(magneticFieldESToken_); dtGeom = &es.getData(dtGeometryESToken_); cscGeom = &es.getData(cscGeometryESToken_); rpcGeom = &es.getData(rpcGeometryESToken_); bool duringEvent = false; theService->update(es, duringEvent); // A few propagators propagatorWithMaterial = &(*(theService->propagator("SteppingHelixPropagatorAny"))); propagatorWithoutMaterial.reset(propagatorWithMaterial->clone()); SteppingHelixPropagator* SHpropagator = dynamic_cast<SteppingHelixPropagator*>(propagatorWithoutMaterial.get()); // Beuark! SHpropagator->setMaterialMode(true); // switches OFF material effects; } // // member functions // // ------------ method called to produce the data ------------ void MuonSimHitProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { auto pdg = iSetup.getHandle(particleDataTableESToken_); RandomEngineAndDistribution random(iEvent.streamID()); MuonPatternRecoDumper dumper; edm::Handle<std::vector<SimTrack> > simMuons; edm::Handle<std::vector<SimVertex> > simVertices; std::vector<PSimHit> theCSCHits; std::vector<PSimHit> theDTHits; std::vector<PSimHit> theRPCHits; DirectMuonNavigation navigation(theService->detLayerGeometry()); iEvent.getByToken(simMuonToken, simMuons); iEvent.getByToken(simVertexToken, simVertices); for (unsigned int itrk = 0; itrk < simMuons->size(); itrk++) { const SimTrack& mySimTrack = (*simMuons)[itrk]; math::XYZTLorentzVector mySimP4( mySimTrack.momentum().x(), mySimTrack.momentum().y(), mySimTrack.momentum().z(), mySimTrack.momentum().t()); // Decaying hadrons are now in the list, and so are their muon daughter // Ignore the hadrons here. int pid = mySimTrack.type(); if (abs(pid) != 13 && abs(pid) != 1000024) continue; double t0 = 0; GlobalPoint initialPosition; int ivert = mySimTrack.vertIndex(); if (ivert >= 0) { t0 = (*simVertices)[ivert].position().t(); GlobalPoint xyzzy((*simVertices)[ivert].position().x(), (*simVertices)[ivert].position().y(), (*simVertices)[ivert].position().z()); initialPosition = xyzzy; } // // Presumably t0 has dimensions of cm if not mm? // Convert to ns for internal calculations. // I wonder where we should get c from? // double tof = t0 / 29.98; #ifdef FAMOS_DEBUG std::cout << " ===> MuonSimHitProducer::reconstruct() found SIMTRACK - pid = " << pid; std::cout << " : pT = " << mySimP4.Pt() << ", eta = " << mySimP4.Eta() << ", phi = " << mySimP4.Phi() << std::endl; #endif // // Produce muons sim hits starting from undecayed simulated muons // GlobalPoint startingPosition(mySimTrack.trackerSurfacePosition().x(), mySimTrack.trackerSurfacePosition().y(), mySimTrack.trackerSurfacePosition().z()); GlobalVector startingMomentum(mySimTrack.trackerSurfaceMomentum().x(), mySimTrack.trackerSurfaceMomentum().y(), mySimTrack.trackerSurfaceMomentum().z()); // // Crap... there's no time-of-flight to the trackerSurfacePosition()... // So, this will be wrong when the curvature can't be neglected, but that // will be rather seldom... May as well ignore the mass too. // GlobalVector dtracker = startingPosition - initialPosition; tof += dtracker.mag() / 29.98; #ifdef FAMOS_DEBUG std::cout << " the Muon START position " << startingPosition << std::endl; std::cout << " the Muon START momentum " << startingMomentum << std::endl; #endif // // Some magic to define a TrajectoryStateOnSurface // PlaneBuilder pb; GlobalVector zAxis = startingMomentum.unit(); GlobalVector yAxis(zAxis.y(), -zAxis.x(), 0); GlobalVector xAxis = yAxis.cross(zAxis); Surface::RotationType rot = Surface::RotationType(xAxis, yAxis, zAxis); PlaneBuilder::ReturnType startingPlane = pb.plane(startingPosition, rot); GlobalTrajectoryParameters gtp(startingPosition, startingMomentum, (int)mySimTrack.charge(), magfield); TrajectoryStateOnSurface startingState(gtp, *startingPlane); std::vector<const DetLayer*> navLayers; if (fabs(startingState.globalMomentum().eta()) > 4.5) { navLayers = navigation.compatibleEndcapLayers(*(startingState.freeState()), alongMomentum); } else { navLayers = navigation.compatibleLayers(*(startingState.freeState()), alongMomentum); } /* edm::ESHandle<Propagator> propagator = theService->propagator("SteppingHelixPropagatorAny"); */ if (navLayers.empty()) continue; #ifdef FAMOS_DEBUG std::cout << "Found " << navLayers.size() << " compatible DetLayers..." << std::endl; #endif TrajectoryStateOnSurface propagatedState = startingState; for (unsigned int ilayer = 0; ilayer < navLayers.size(); ilayer++) { #ifdef FAMOS_DEBUG std::cout << "Propagating to layer " << ilayer << " " << dumper.dumpLayer(navLayers[ilayer]) << std::endl; #endif std::vector<DetWithState> comps = navLayers[ilayer]->compatibleDets(propagatedState, *propagatorWithMaterial, theEstimator); if (comps.empty()) continue; #ifdef FAMOS_DEBUG std::cout << "Propagating " << propagatedState << std::endl; #endif // Starting momentum double pi = propagatedState.globalMomentum().mag(); // Propagate with material effects (dE/dx average only) SteppingHelixStateInfo shsStart(*(propagatedState.freeTrajectoryState())); SteppingHelixStateInfo shsDest; ((const SteppingHelixPropagator*)propagatorWithMaterial) ->propagate(shsStart, navLayers[ilayer]->surface(), shsDest); std::pair<TrajectoryStateOnSurface, double> next(shsDest.getStateOnSurface(navLayers[ilayer]->surface()), shsDest.path()); // No need to continue if there is no valid propagation available. // This happens rarely (~0.1% of ttbar events) if (!next.first.isValid()) continue; // This is the estimate of the number of radiation lengths traversed, // together with the total path length double radPath = shsDest.radPath(); double pathLength = next.second; // Now propagate without dE/dx (average) // [To add the dE/dx fluctuations to the actual dE/dx] std::pair<TrajectoryStateOnSurface, double> nextNoMaterial = propagatorWithoutMaterial->propagateWithPath(propagatedState, navLayers[ilayer]->surface()); // Update the propagated state propagatedState = next.first; double pf = propagatedState.globalMomentum().mag(); // Insert dE/dx fluctuations and multiple scattering // Skip this step if nextNoMaterial.first is not valid // This happens rarely (~0.02% of ttbar events) if (theMaterialEffects && nextNoMaterial.first.isValid()) applyMaterialEffects(propagatedState, nextNoMaterial.first, radPath, &random, *pdg); // Check that the 'shaken' propagatedState is still valid, otherwise continue if (!propagatedState.isValid()) continue; // (No evidence that this ever happens) // // Consider this... 1 GeV muon has a velocity that is only 0.5% slower than c... // We probably can safely ignore the mass for anything that makes it out to the // muon chambers. // double pavg = 0.5 * (pi + pf); double m = mySimP4.M(); double rbeta = sqrt(1 + m * m / (pavg * pavg)) / 29.98; double dtof = pathLength * rbeta; #ifdef FAMOS_DEBUG std::cout << "Propagated to next surface... path length = " << pathLength << " cm, dTOF = " << dtof << " ns" << std::endl; #endif tof += dtof; for (unsigned int icomp = 0; icomp < comps.size(); icomp++) { const GeomDet* gd = comps[icomp].first; if (gd->subDetector() == GeomDetEnumerators::DT) { DTChamberId id(gd->geographicalId()); const DTChamber* chamber = dtGeom->chamber(id); std::vector<const DTSuperLayer*> superlayer = chamber->superLayers(); for (unsigned int isl = 0; isl < superlayer.size(); isl++) { std::vector<const DTLayer*> layer = superlayer[isl]->layers(); for (unsigned int ilayer = 0; ilayer < layer.size(); ilayer++) { DTLayerId lid = layer[ilayer]->id(); #ifdef FAMOS_DEBUG std::cout << " Extrapolated to DT (" << lid.wheel() << "," << lid.station() << "," << lid.sector() << "," << lid.superlayer() << "," << lid.layer() << ")" << std::endl; #endif const GeomDetUnit* det = dtGeom->idToDetUnit(lid); HelixArbitraryPlaneCrossing crossing(propagatedState.globalPosition().basicVector(), propagatedState.globalMomentum().basicVector(), propagatedState.transverseCurvature(), anyDirection); std::pair<bool, double> path = crossing.pathLength(det->surface()); if (!path.first) continue; LocalPoint lpos = det->toLocal(GlobalPoint(crossing.position(path.second))); if (!det->surface().bounds().inside(lpos)) continue; const DTTopology& dtTopo = layer[ilayer]->specificTopology(); int wire = dtTopo.channel(lpos); if (wire - dtTopo.firstChannel() < 0 || wire - dtTopo.lastChannel() > 0) continue; // no drift cell here (on the chamber edge or just outside) // this hit would otherwise be discarded downstream in the digitizer DTWireId wid(lid, wire); double thickness = det->surface().bounds().thickness(); LocalVector lmom = det->toLocal(GlobalVector(crossing.direction(path.second))); lmom = lmom.unit() * propagatedState.localMomentum().mag(); // Factor that takes into account the (rec)hits lost because of delta's, etc.: // (Not fully satisfactory patch, but it seems to work...) double pmu = lmom.mag(); double theDTHitIneff = pmu > 0 ? exp(kDT * log(pmu) + fDT) : 0.; if (random.flatShoot() < theDTHitIneff) continue; double eloss = 0; double pz = fabs(lmom.z()); LocalPoint entry = lpos - 0.5 * thickness * lmom / pz; LocalPoint exit = lpos + 0.5 * thickness * lmom / pz; double dtof = path.second * rbeta; int trkid = mySimTrack.trackId(); unsigned int id = wid.rawId(); short unsigned int processType = 2; PSimHit hit( entry, exit, lmom.mag(), tof + dtof, eloss, pid, id, trkid, lmom.theta(), lmom.phi(), processType); theDTHits.push_back(hit); } } } else if (gd->subDetector() == GeomDetEnumerators::CSC) { CSCDetId id(gd->geographicalId()); const CSCChamber* chamber = cscGeom->chamber(id); std::vector<const CSCLayer*> layers = chamber->layers(); for (unsigned int ilayer = 0; ilayer < layers.size(); ilayer++) { CSCDetId lid = layers[ilayer]->id(); #ifdef FAMOS_DEBUG std::cout << " Extrapolated to CSC (" << lid.endcap() << "," << lid.ring() << "," << lid.station() << "," << lid.layer() << ")" << std::endl; #endif const GeomDetUnit* det = cscGeom->idToDetUnit(lid); HelixArbitraryPlaneCrossing crossing(propagatedState.globalPosition().basicVector(), propagatedState.globalMomentum().basicVector(), propagatedState.transverseCurvature(), anyDirection); std::pair<bool, double> path = crossing.pathLength(det->surface()); if (!path.first) continue; LocalPoint lpos = det->toLocal(GlobalPoint(crossing.position(path.second))); // For CSCs the Bounds are for chamber frames not gas regions // if ( ! det->surface().bounds().inside(lpos) ) continue; // New function knows where the 'active' volume is: const CSCLayerGeometry* laygeom = layers[ilayer]->geometry(); if (!laygeom->inside(lpos)) continue; //double thickness = laygeom->thickness(); gives number which is about 20 times too big double thickness = det->surface().bounds().thickness(); // this one works much better... LocalVector lmom = det->toLocal(GlobalVector(crossing.direction(path.second))); lmom = lmom.unit() * propagatedState.localMomentum().mag(); // Factor that takes into account the (rec)hits lost because of delta's, etc.: // (Not fully satisfactory patch, but it seems to work...) double pmu = lmom.mag(); double theCSCHitIneff = pmu > 0 ? exp(kCSC * log(pmu) + fCSC) : 0.; // Take into account the different geometry in ME11: if (id.station() == 1 && id.ring() == 1) theCSCHitIneff = theCSCHitIneff * 0.442; if (random.flatShoot() < theCSCHitIneff) continue; double eloss = 0; double pz = fabs(lmom.z()); LocalPoint entry = lpos - 0.5 * thickness * lmom / pz; LocalPoint exit = lpos + 0.5 * thickness * lmom / pz; double dtof = path.second * rbeta; int trkid = mySimTrack.trackId(); unsigned int id = lid.rawId(); short unsigned int processType = 2; PSimHit hit( entry, exit, lmom.mag(), tof + dtof, eloss, pid, id, trkid, lmom.theta(), lmom.phi(), processType); theCSCHits.push_back(hit); } } else if (gd->subDetector() == GeomDetEnumerators::RPCBarrel || gd->subDetector() == GeomDetEnumerators::RPCEndcap) { RPCDetId id(gd->geographicalId()); const RPCChamber* chamber = rpcGeom->chamber(id); std::vector<const RPCRoll*> roll = chamber->rolls(); for (unsigned int iroll = 0; iroll < roll.size(); iroll++) { RPCDetId rid = roll[iroll]->id(); #ifdef FAMOS_DEBUG std::cout << " Extrapolated to RPC (" << rid.ring() << "," << rid.station() << "," << rid.sector() << "," << rid.subsector() << "," << rid.layer() << "," << rid.roll() << ")" << std::endl; #endif const GeomDetUnit* det = rpcGeom->idToDetUnit(rid); HelixArbitraryPlaneCrossing crossing(propagatedState.globalPosition().basicVector(), propagatedState.globalMomentum().basicVector(), propagatedState.transverseCurvature(), anyDirection); std::pair<bool, double> path = crossing.pathLength(det->surface()); if (!path.first) continue; LocalPoint lpos = det->toLocal(GlobalPoint(crossing.position(path.second))); if (!det->surface().bounds().inside(lpos)) continue; double thickness = det->surface().bounds().thickness(); LocalVector lmom = det->toLocal(GlobalVector(crossing.direction(path.second))); lmom = lmom.unit() * propagatedState.localMomentum().mag(); double eloss = 0; double pz = fabs(lmom.z()); LocalPoint entry = lpos - 0.5 * thickness * lmom / pz; LocalPoint exit = lpos + 0.5 * thickness * lmom / pz; double dtof = path.second * rbeta; int trkid = mySimTrack.trackId(); unsigned int id = rid.rawId(); short unsigned int processType = 2; PSimHit hit( entry, exit, lmom.mag(), tof + dtof, eloss, pid, id, trkid, lmom.theta(), lmom.phi(), processType); theRPCHits.push_back(hit); } } else { std::cout << "Extrapolated to unknown subdetector '" << gd->subDetector() << "'..." << std::endl; } } } } std::unique_ptr<edm::PSimHitContainer> pcsc(new edm::PSimHitContainer); for (std::vector<PSimHit>::const_iterator i = theCSCHits.begin(); i != theCSCHits.end(); i++) { pcsc->push_back(*i); } iEvent.put(std::move(pcsc), "MuonCSCHits"); std::unique_ptr<edm::PSimHitContainer> pdt(new edm::PSimHitContainer); for (std::vector<PSimHit>::const_iterator i = theDTHits.begin(); i != theDTHits.end(); i++) { pdt->push_back(*i); } iEvent.put(std::move(pdt), "MuonDTHits"); std::unique_ptr<edm::PSimHitContainer> prpc(new edm::PSimHitContainer); for (std::vector<PSimHit>::const_iterator i = theRPCHits.begin(); i != theRPCHits.end(); i++) { prpc->push_back(*i); } iEvent.put(std::move(prpc), "MuonRPCHits"); } void MuonSimHitProducer::readParameters(const edm::ParameterSet& fastMuons, const edm::ParameterSet& fastTracks, const edm::ParameterSet& matEff) { // Muons std::string _simModuleLabel = fastMuons.getParameter<std::string>("simModuleLabel"); std::string _simModuleProcess = fastMuons.getParameter<std::string>("simModuleProcess"); simMuonLabel = edm::InputTag(_simModuleLabel, _simModuleProcess); simVertexLabel = edm::InputTag(_simModuleLabel); std::vector<double> simHitIneffDT = fastMuons.getParameter<std::vector<double> >("simHitDTIneffParameters"); std::vector<double> simHitIneffCSC = fastMuons.getParameter<std::vector<double> >("simHitCSCIneffParameters"); kDT = simHitIneffDT[0]; fDT = simHitIneffDT[1]; kCSC = simHitIneffCSC[0]; fCSC = simHitIneffCSC[1]; // Tracks fullPattern_ = fastTracks.getUntrackedParameter<bool>("FullPatternRecognition"); // The following should be on LogInfo // std::cout << " MUON SIM HITS: FastSimulation parameters " << std::endl; // std::cout << " ============================================== " << std::endl; // if ( fullPattern_ ) // std::cout << " The FULL pattern recognition option is turned ON" << std::endl; // else // std::cout << " The FAST tracking option is turned ON" << std::endl; // Material Effects theMaterialEffects = nullptr; if (matEff.getParameter<bool>("PairProduction") || matEff.getParameter<bool>("Bremsstrahlung") || matEff.getParameter<bool>("MuonBremsstrahlung") || matEff.getParameter<bool>("EnergyLoss") || matEff.getParameter<bool>("MultipleScattering")) theMaterialEffects = std::make_unique<MaterialEffects>(matEff); } void MuonSimHitProducer::applyMaterialEffects(TrajectoryStateOnSurface& tsosWithdEdx, TrajectoryStateOnSurface& tsos, double radPath, RandomEngineAndDistribution const* random, HepPDT::ParticleDataTable const& table) { // The energy loss simulator EnergyLossSimulator* energyLoss = theMaterialEffects->energyLossSimulator(); // The multiple scattering simulator MultipleScatteringSimulator* multipleScattering = theMaterialEffects->multipleScatteringSimulator(); // The Muon Bremsstrahlung simulator MuonBremsstrahlungSimulator* bremsstrahlung = theMaterialEffects->muonBremsstrahlungSimulator(); // Initialize the Particle position, momentum and energy const Surface& nextSurface = tsos.surface(); GlobalPoint gPos = energyLoss ? tsos.globalPosition() : tsosWithdEdx.globalPosition(); GlobalVector gMom = energyLoss ? tsos.globalMomentum() : tsosWithdEdx.globalMomentum(); double mu = 0.1056583692; double en = std::sqrt(gMom.mag2() + mu * mu); // And now create the Particle XYZTLorentzVector position(gPos.x(), gPos.y(), gPos.z(), 0.); XYZTLorentzVector momentum(gMom.x(), gMom.y(), gMom.z(), en); float charge = (float)(tsos.charge()); ParticlePropagator theMuon(rawparticle::makeMuon(charge < 1., momentum, position), nullptr, nullptr, &table); // Recompute the energy loss to get the fluctuations if (energyLoss) { // Difference between with and without dE/dx (average only) // (for corrections once fluctuations are applied) GlobalPoint gPosWithdEdx = tsosWithdEdx.globalPosition(); GlobalVector gMomWithdEdx = tsosWithdEdx.globalMomentum(); double enWithdEdx = std::sqrt(gMomWithdEdx.mag2() + mu * mu); XYZTLorentzVector deltaPos( gPosWithdEdx.x() - gPos.x(), gPosWithdEdx.y() - gPos.y(), gPosWithdEdx.z() - gPos.z(), 0.); XYZTLorentzVector deltaMom( gMomWithdEdx.x() - gMom.x(), gMomWithdEdx.y() - gMom.y(), gMomWithdEdx.z() - gMom.z(), enWithdEdx - en); // Energy loss in iron (+ fluctuations) energyLoss->updateState(theMuon, radPath, random); // Correcting factors to account for slight differences in material descriptions // (Material description is more accurate in the stepping helix propagator) radPath *= -deltaMom.E() / energyLoss->mostLikelyLoss(); double fac = energyLoss->deltaMom().E() / energyLoss->mostLikelyLoss(); // Particle momentum & position after energy loss + fluctuation XYZTLorentzVector theNewMomentum = theMuon.particle().momentum() + energyLoss->deltaMom() + fac * deltaMom; XYZTLorentzVector theNewPosition = theMuon.particle().vertex() + fac * deltaPos; fac = (theNewMomentum.E() * theNewMomentum.E() - mu * mu) / theNewMomentum.Vect().Mag2(); fac = fac > 0. ? std::sqrt(fac) : 1E-9; theMuon.particle().setMomentum( theNewMomentum.Px() * fac, theNewMomentum.Py() * fac, theNewMomentum.Pz() * fac, theNewMomentum.E()); theMuon.particle().setVertex(theNewPosition); } // Does the actual mutliple scattering if (multipleScattering) { // Pass the vector normal to the "next" surface GlobalVector normal = nextSurface.tangentPlane(tsos.globalPosition())->normalVector(); multipleScattering->setNormalVector(normal); // Compute the amount of multiple scattering after a given path length multipleScattering->updateState(theMuon, radPath, random); } // Muon Bremsstrahlung if (bremsstrahlung) { // Compute the amount of Muon Bremsstrahlung after given path length bremsstrahlung->updateState(theMuon, radPath, random); } // Fill the propagated state GlobalPoint propagatedPosition(theMuon.particle().X(), theMuon.particle().Y(), theMuon.particle().Z()); GlobalVector propagatedMomentum(theMuon.particle().Px(), theMuon.particle().Py(), theMuon.particle().Pz()); GlobalTrajectoryParameters propagatedGtp(propagatedPosition, propagatedMomentum, (int)charge, magfield); tsosWithdEdx = TrajectoryStateOnSurface(propagatedGtp, nextSurface); } //define this as a plug-in #include "FWCore/Framework/interface/MakerMacros.h" DEFINE_FWK_MODULE(MuonSimHitProducer);