CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch12/src/FastSimulation/MuonSimHitProducer/src/MuonSimHitProducer.cc

Go to the documentation of this file.
00001 //
00002 // Package:    MuonSimHitProducer
00003 // Class:      MuonSimHitProducer
00004 // 
00013 //
00014 // Original Author:  Martijn Mulders/Matthew Jones
00015 //         Created:  Wed Jul 30 11:37:24 CET 2007
00016 //         Working:  Fri Nov  9 09:39:33 CST 2007
00017 //
00018 // $Id: MuonSimHitProducer.cc,v 1.34 2010/07/26 14:07:00 aperrott Exp $
00019 //
00020 //
00021 
00022 // CMSSW headers 
00023 #include "FWCore/ServiceRegistry/interface/Service.h"
00024 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
00025 #include "FWCore/Framework/interface/MakerMacros.h"
00026 
00027 // Fast Simulation headers
00028 #include "FastSimulation/Utilities/interface/RandomEngine.h"
00029 #include "FastSimulation/MuonSimHitProducer/interface/MuonSimHitProducer.h"
00030 #include "FastSimulation/MaterialEffects/interface/MaterialEffects.h"
00031 #include "FastSimulation/MaterialEffects/interface/MultipleScatteringSimulator.h"
00032 #include "FastSimulation/MaterialEffects/interface/EnergyLossSimulator.h"
00033 #include "FastSimulation/ParticlePropagator/interface/ParticlePropagator.h"
00034 
00035 // SimTrack
00036 #include "SimDataFormats/Track/interface/SimTrack.h"
00037 #include "SimDataFormats/Vertex/interface/SimVertex.h"
00038 #include "SimDataFormats/TrackingHit/interface/PSimHitContainer.h"
00039 
00040 // STL headers 
00041 #include <vector>
00042 #include <iostream>
00043 
00044 // RecoMuon headers
00045 #include "RecoMuon/TrackingTools/interface/MuonServiceProxy.h"
00046 #include "RecoMuon/Navigation/interface/DirectMuonNavigation.h"
00047 #include "RecoMuon/MeasurementDet/interface/MuonDetLayerMeasurements.h"
00048 #include "RecoMuon/TrackingTools/interface/MuonPatternRecoDumper.h"
00049 
00050 // Tracking Tools
00051 #include "TrackingTools/GeomPropagators/interface/HelixArbitraryPlaneCrossing.h"
00052 #include "TrackPropagation/SteppingHelixPropagator/interface/SteppingHelixPropagator.h"
00053 
00054 // Data Formats
00055 #include "DataFormats/MuonDetId/interface/DTWireId.h"
00056 #include "DataFormats/GeometrySurface/interface/PlaneBuilder.h"
00057 #include "DataFormats/GeometrySurface/interface/TangentPlane.h"
00058 
00059 
00061 // Geometry, Magnetic Field
00062 #include "Geometry/DTGeometry/interface/DTGeometry.h"
00063 #include "Geometry/CSCGeometry/interface/CSCGeometry.h"
00064 #include "Geometry/RPCGeometry/interface/RPCGeometry.h"
00065 #include "Geometry/Records/interface/MuonGeometryRecord.h"
00066 #include "MagneticField/Records/interface/IdealMagneticFieldRecord.h"
00067 
00069 
00070 // #include "TrackingTools/TrackAssociator/interface/TrackDetectorAssociator.h"
00071 
00072 //for debug only 
00073 //#define FAMOS_DEBUG
00074 
00075 //
00076 // constructors and destructor
00077 //
00078 MuonSimHitProducer::MuonSimHitProducer(const edm::ParameterSet& iConfig):
00079   theEstimator(iConfig.getParameter<double>("Chi2EstimatorCut")),
00080   propagatorWithoutMaterial(0)
00081  {
00082 
00083   //
00084   //  Initialize the random number generator service
00085   //
00086   edm::Service<edm::RandomNumberGenerator> rng;
00087   if ( ! rng.isAvailable() ) {
00088     throw cms::Exception("Configuration") <<
00089       "MuonSimHitProducer requires the RandomGeneratorService \n"
00090       "which is not present in the configuration file. \n"
00091       "You must add the service in the configuration file\n"
00092       "or remove the module that requires it.";
00093   }
00094 
00095   random = new RandomEngine(&(*rng));
00096 
00097   // Read relevant parameters
00098   readParameters(iConfig.getParameter<edm::ParameterSet>("MUONS"),
00099                  iConfig.getParameter<edm::ParameterSet>("TRACKS"),
00100                  iConfig.getParameter<edm::ParameterSet>("MaterialEffectsForMuons"));
00101 
00102   //
00103   //  register your products ... need to declare at least one possible product...
00104   //
00105   produces<edm::PSimHitContainer>("MuonCSCHits");
00106   produces<edm::PSimHitContainer>("MuonDTHits");
00107   produces<edm::PSimHitContainer>("MuonRPCHits");
00108 
00109   edm::ParameterSet serviceParameters =
00110      iConfig.getParameter<edm::ParameterSet>("ServiceParameters");
00111   theService = new MuonServiceProxy(serviceParameters);
00112 }
00113 
00114 // ---- method called once each job just before starting event loop ----
00115 void 
00116 MuonSimHitProducer::beginRun(edm::Run & run, const edm::EventSetup & es) {
00117 
00118   //services
00119   edm::ESHandle<MagneticField>          magField;
00120   edm::ESHandle<DTGeometry>             dtGeometry;
00121   edm::ESHandle<CSCGeometry>            cscGeometry;
00122   edm::ESHandle<RPCGeometry>            rpcGeometry;
00123   edm::ESHandle<Propagator>             propagator;
00124 
00125   es.get<IdealMagneticFieldRecord>().get(magField);
00126   es.get<MuonGeometryRecord>().get("MisAligned",dtGeometry);
00127   es.get<MuonGeometryRecord>().get("MisAligned",cscGeometry);
00128   es.get<MuonGeometryRecord>().get(rpcGeometry);
00129 
00130   magfield = &(*magField);
00131   dtGeom = &(*dtGeometry);
00132   cscGeom = &(*cscGeometry);
00133   rpcGeom = &(*rpcGeometry);
00134 
00135   theService->update(es);
00136 
00137   // A few propagators
00138   propagatorWithMaterial = &(*(theService->propagator("SteppingHelixPropagatorAny")));
00139   propagatorWithoutMaterial = propagatorWithMaterial->clone();
00140   SteppingHelixPropagator* SHpropagator = dynamic_cast<SteppingHelixPropagator*> (propagatorWithoutMaterial); // Beuark!
00141   SHpropagator->setMaterialMode(true); // switches OFF material effects;
00142 
00143 }
00144   
00145 MuonSimHitProducer::~MuonSimHitProducer()
00146 {
00147   // do anything here that needs to be done at destruction time
00148   // (e.g. close files, deallocate resources etc.)
00149   
00150   if ( random ) { 
00151     delete random;
00152   }
00153 
00154   if ( theMaterialEffects ) delete theMaterialEffects;
00155   if ( propagatorWithoutMaterial) delete propagatorWithoutMaterial;
00156 }
00157 
00158 
00159 //
00160 // member functions
00161 //
00162 
00163 // ------------ method called to produce the data  ------------
00164 
00165 void 
00166 MuonSimHitProducer::produce(edm::Event& iEvent,const edm::EventSetup& iSetup) {
00167   // using namespace edm;
00168   // using namespace std;
00169 
00170   MuonPatternRecoDumper dumper;
00171 
00172   edm::Handle<std::vector<SimTrack> > simMuons;
00173   edm::Handle<std::vector<SimVertex> > simVertices;
00174   std::vector<PSimHit> theCSCHits;
00175   std::vector<PSimHit> theDTHits;
00176   std::vector<PSimHit> theRPCHits;
00177 
00178   DirectMuonNavigation navigation(theService->detLayerGeometry());
00179   iEvent.getByLabel(theSimModuleLabel_,theSimModuleProcess_,simMuons);
00180   iEvent.getByLabel(theSimModuleLabel_,simVertices);
00181 
00182   for ( unsigned int itrk=0; itrk<simMuons->size(); itrk++ ) {
00183     const SimTrack &mySimTrack = (*simMuons)[itrk];
00184     math::XYZTLorentzVector mySimP4(mySimTrack.momentum().x(),
00185                                     mySimTrack.momentum().y(),
00186                                     mySimTrack.momentum().z(),
00187                                     mySimTrack.momentum().t());
00188 
00189     // Decaying hadrons are now in the list, and so are their muon daughter
00190     // Ignore the hadrons here.
00191     int pid = mySimTrack.type(); 
00192     if ( abs(pid) != 13 ) continue;
00193 
00194     double t0 = 0;
00195     GlobalPoint initialPosition;
00196     int ivert = mySimTrack.vertIndex();
00197     if ( ivert >= 0 ) {
00198       t0 = (*simVertices)[ivert].position().t();
00199       GlobalPoint xyzzy((*simVertices)[ivert].position().x(),
00200                         (*simVertices)[ivert].position().y(),
00201                         (*simVertices)[ivert].position().z());
00202       initialPosition = xyzzy;
00203     }
00204 //
00205 //  Presumably t0 has dimensions of cm if not mm?
00206 //  Convert to ns for internal calculations.
00207 //  I wonder where we should get c from?
00208 //
00209     double tof = t0/29.98;
00210 
00211 #ifdef FAMOS_DEBUG
00212     std::cout << " ===> MuonSimHitProducer::reconstruct() found SIMTRACK - pid = "
00213               << pid ;
00214     std::cout << " : pT = " << mySimP4.Pt()
00215               << ", eta = " << mySimP4.Eta()
00216               << ", phi = " << mySimP4.Phi() << std::endl;
00217 #endif
00218 
00219 //
00220 //  Produce muons sim hits starting from undecayed simulated muons
00221 //
00222 
00223     GlobalPoint startingPosition(mySimTrack.trackerSurfacePosition().x(),
00224                                  mySimTrack.trackerSurfacePosition().y(),
00225                                  mySimTrack.trackerSurfacePosition().z());
00226     GlobalVector startingMomentum(mySimTrack.trackerSurfaceMomentum().x(),
00227                                   mySimTrack.trackerSurfaceMomentum().y(),
00228                                   mySimTrack.trackerSurfaceMomentum().z());
00229 //
00230 //  Crap... there's no time-of-flight to the trackerSurfacePosition()...
00231 //  So, this will be wrong when the curvature can't be neglected, but that
00232 //  will be rather seldom...  May as well ignore the mass too.
00233 //
00234     GlobalVector dtracker = startingPosition-initialPosition;
00235     tof += dtracker.mag()/29.98;
00236 
00237 #ifdef FAMOS_DEBUG
00238     std::cout << " the Muon START position " << startingPosition << std::endl;
00239     std::cout << " the Muon START momentum " << startingMomentum << std::endl;
00240 #endif
00241 
00242 // 
00243 //  Some magic to define a TrajectoryStateOnSurface
00244 //
00245     PlaneBuilder pb;
00246     GlobalVector zAxis = startingMomentum.unit();
00247     GlobalVector yAxis(zAxis.y(),-zAxis.x(),0); 
00248     GlobalVector xAxis = yAxis.cross(zAxis);
00249     Surface::RotationType rot = Surface::RotationType(xAxis,yAxis,zAxis);
00250     PlaneBuilder::ReturnType startingPlane = pb.plane(startingPosition,rot);
00251     GlobalTrajectoryParameters gtp(startingPosition,
00252                                    startingMomentum,
00253                                    (int)mySimTrack.charge(),
00254                                    magfield);
00255     TrajectoryStateOnSurface startingState(gtp,*startingPlane);
00256 
00257     std::vector<const DetLayer *> navLayers;
00258     if ( fabs(startingState.globalMomentum().eta()) > 4.5 ) {
00259       navLayers = navigation.compatibleEndcapLayers(*(startingState.freeState()),
00260                                                     alongMomentum);
00261     }
00262     else {
00263       navLayers = navigation.compatibleLayers(*(startingState.freeState()),
00264                                                alongMomentum);
00265     }
00266     /*
00267     edm::ESHandle<Propagator> propagator =
00268       theService->propagator("SteppingHelixPropagatorAny");
00269     */
00270 
00271     if ( navLayers.empty() ) continue;
00272 
00273 #ifdef FAMOS_DEBUG
00274       std::cout << "Found " << navLayers.size()
00275                 << " compatible DetLayers..." << std::endl;
00276 #endif
00277 
00278     TrajectoryStateOnSurface propagatedState = startingState;
00279     for ( unsigned int ilayer=0; ilayer<navLayers.size(); ilayer++ ) {
00280 
00281 #ifdef FAMOS_DEBUG
00282       std::cout << "Propagating to layer " << ilayer << " " 
00283                 << dumper.dumpLayer(navLayers[ilayer]) 
00284                 << std::endl;
00285 #endif
00286       
00287       std::vector<DetWithState> comps = 
00288         navLayers[ilayer]->compatibleDets(propagatedState,*propagatorWithMaterial,theEstimator);
00289       if ( comps.empty() ) continue;
00290 
00291 #ifdef FAMOS_DEBUG
00292       std::cout << "Propagating " << propagatedState << std::endl;
00293 #endif
00294 
00295       // Starting momentum
00296       double pi = propagatedState.globalMomentum().mag(); 
00297 
00298       // Propagate with material effects (dE/dx average only)
00299       SteppingHelixStateInfo shsStart(*(propagatedState.freeTrajectoryState()));
00300       const SteppingHelixStateInfo& shsDest = 
00301         ((const SteppingHelixPropagator*)propagatorWithMaterial)->propagate(shsStart,navLayers[ilayer]->surface());
00302       std::pair<TrajectoryStateOnSurface,double> next(shsDest.getStateOnSurface(navLayers[ilayer]->surface()),
00303                                                       shsDest.path());
00304       // No need to continue if there is no valid propagation available.
00305       // This happens rarely (~0.1% of ttbar events)
00306       if ( !next.first.isValid() ) continue; 
00307       // This is the estimate of the number of radiation lengths traversed, 
00308       // together with the total path length 
00309       double radPath = shsDest.radPath();
00310       double pathLength = next.second;
00311 
00312       // Now propagate without dE/dx (average) 
00313       // [To add the dE/dx fluctuations to the actual dE/dx]
00314       std::pair<TrajectoryStateOnSurface,double> nextNoMaterial = 
00315         propagatorWithoutMaterial->propagateWithPath(propagatedState,navLayers[ilayer]->surface());
00316 
00317       // Update the propagated state
00318       propagatedState = next.first;
00319       double pf = propagatedState.globalMomentum().mag();
00320 
00321       // Insert dE/dx fluctuations and multiple scattering
00322       // Skip this step if nextNoMaterial.first is not valid 
00323       // This happens rarely (~0.02% of ttbar events)
00324       if ( theMaterialEffects && nextNoMaterial.first.isValid() ) applyMaterialEffects(propagatedState,nextNoMaterial.first,radPath);
00325       // Check that the 'shaken' propagatedState is still valid, otherwise continue
00326       if ( !propagatedState.isValid() ) continue; 
00327       // (No evidence that this ever happens)
00328 //
00329 //  Consider this... 1 GeV muon has a velocity that is only 0.5% slower than c...
00330 //  We probably can safely ignore the mass for anything that makes it out to the
00331 //  muon chambers.
00332 //
00333       double pavg = 0.5*(pi+pf);
00334       double m = mySimP4.M();
00335       double rbeta = sqrt(1+m*m/(pavg*pavg))/29.98;
00336       double dtof = pathLength*rbeta;
00337 
00338 #ifdef FAMOS_DEBUG
00339       std::cout << "Propagated to next surface... path length = " << pathLength 
00340                 << " cm, dTOF = " << dtof << " ns" << std::endl;
00341 #endif
00342 
00343       tof += dtof;
00344 
00345       for ( unsigned int icomp=0; icomp<comps.size(); icomp++ )
00346         {
00347       const GeomDet *gd = comps[icomp].first;
00348       if ( gd->subDetector() == GeomDetEnumerators::DT ) {
00349         DTChamberId id(gd->geographicalId());
00350         const DTChamber *chamber = dtGeom->chamber(id);
00351         std::vector<const DTSuperLayer *> superlayer = chamber->superLayers();
00352         for ( unsigned int isl=0; isl<superlayer.size(); isl++ ) {
00353           std::vector<const DTLayer *> layer = superlayer[isl]->layers();
00354           for ( unsigned int ilayer=0; ilayer<layer.size(); ilayer++ ) {
00355             DTLayerId lid = layer[ilayer]->id();
00356 #ifdef FAMOS_DEBUG
00357             std::cout << "    Extrapolated to DT (" 
00358                       << lid.wheel() << "," 
00359                       << lid.station() << "," 
00360                       << lid.sector() << "," 
00361                       << lid.superlayer() << "," 
00362                       << lid.layer() << ")" << std::endl;
00363 #endif
00364 
00365             const GeomDetUnit *det = dtGeom->idToDetUnit(lid);
00366 
00367             HelixArbitraryPlaneCrossing crossing(propagatedState.globalPosition().basicVector(),
00368                                                  propagatedState.globalMomentum().basicVector(),
00369                                                  propagatedState.transverseCurvature(),
00370                                                  anyDirection);
00371             std::pair<bool,double> path = crossing.pathLength(det->surface());
00372             if ( ! path.first ) continue;
00373             LocalPoint lpos = det->toLocal(GlobalPoint(crossing.position(path.second)));
00374             if ( ! det->surface().bounds().inside(lpos) ) continue;
00375             const DTTopology& dtTopo = layer[ilayer]->specificTopology();
00376             int wire = dtTopo.channel(lpos);
00377             if (wire < dtTopo.firstChannel() || wire > dtTopo.lastChannel()) continue;
00378             // no drift cell here (on the chamber edge or just outside)
00379             // this hit would otherwise be discarded downstream in the digitizer
00380 
00381             DTWireId wid(lid,wire);
00382             double thickness = det->surface().bounds().thickness();
00383             LocalVector lmom = det->toLocal(GlobalVector(crossing.direction(path.second)));
00384             lmom = lmom.unit()*propagatedState.localMomentum().mag();
00385 
00386             // Factor that takes into account the (rec)hits lost because of delta's, etc.:
00387             // (Not fully satisfactory patch, but it seems to work...)
00388             double pmu = lmom.mag();
00389             double theDTHitIneff = pmu>0? exp(kDT*log(pmu)+fDT):0.;
00390             if (random->flatShoot()<theDTHitIneff) continue;
00391 
00392             double eloss = 0;
00393             double pz = fabs(lmom.z());
00394             LocalPoint entry = lpos - 0.5*thickness*lmom/pz;
00395             LocalPoint exit = lpos + 0.5*thickness*lmom/pz;
00396             double dtof = path.second*rbeta;
00397             int trkid = mySimTrack.trackId();
00398             unsigned int id = wid.rawId();
00399             short unsigned int processType = 2;
00400             PSimHit hit(entry,exit,lmom.mag(),
00401                         tof+dtof,eloss,pid,id,trkid,lmom.theta(),lmom.phi(),processType);
00402             theDTHits.push_back(hit);
00403 
00404           }
00405         }
00406       }
00407       else if ( gd->subDetector() == GeomDetEnumerators::CSC ) {
00408         CSCDetId id(gd->geographicalId());
00409         const CSCChamber *chamber = cscGeom->chamber(id);
00410         std::vector<const CSCLayer *> layers = chamber->layers();
00411         for ( unsigned int ilayer=0; ilayer<layers.size(); ilayer++ ) {
00412           CSCDetId lid = layers[ilayer]->id();
00413 
00414 #ifdef FAMOS_DEBUG
00415             std::cout << "    Extrapolated to CSC (" 
00416                       << lid.endcap() << "," 
00417                       << lid.ring() << "," 
00418                       << lid.station() << "," 
00419                       << lid.layer() << ")" << std::endl;
00420 #endif
00421 
00422           const GeomDetUnit *det = cscGeom->idToDetUnit(lid);
00423           HelixArbitraryPlaneCrossing crossing(propagatedState.globalPosition().basicVector(),
00424                                                propagatedState.globalMomentum().basicVector(),
00425                                                propagatedState.transverseCurvature(),
00426                                                anyDirection);
00427           std::pair<bool,double> path = crossing.pathLength(det->surface());
00428           if ( ! path.first ) continue;
00429           LocalPoint lpos = det->toLocal(GlobalPoint(crossing.position(path.second)));
00430           // For CSCs the Bounds are for chamber frames not gas regions
00431           //      if ( ! det->surface().bounds().inside(lpos) ) continue;
00432           // New function knows where the 'active' volume is:
00433           const CSCLayerGeometry* laygeom = layers[ilayer]->geometry();
00434           if ( ! laygeom->inside( lpos ) ) continue; 
00435           //double thickness = laygeom->thickness(); gives number which is about 20 times too big
00436           double thickness = det->surface().bounds().thickness(); // this one works much better...
00437           LocalVector lmom = det->toLocal(GlobalVector(crossing.direction(path.second)));
00438           lmom = lmom.unit()*propagatedState.localMomentum().mag();
00439            
00440           // Factor that takes into account the (rec)hits lost because of delta's, etc.:
00441           // (Not fully satisfactory patch, but it seems to work...)
00442           double pmu = lmom.mag();
00443           double theCSCHitIneff = pmu>0? exp(kCSC*log(pmu)+fCSC):0.;
00444           // Take into account the different geometry in ME11:
00445           if (id.station()==1 && id.ring()==1)  theCSCHitIneff = theCSCHitIneff*0.442;
00446           if (random->flatShoot()<theCSCHitIneff) continue;
00447 
00448           double eloss = 0;
00449           double pz = fabs(lmom.z());
00450           LocalPoint entry = lpos - 0.5*thickness*lmom/pz;
00451           LocalPoint exit = lpos + 0.5*thickness*lmom/pz;
00452           double dtof = path.second*rbeta;
00453           int trkid = mySimTrack.trackId();
00454           unsigned int id = lid.rawId();
00455           short unsigned int processType = 2;
00456           PSimHit hit(entry,exit,lmom.mag(),
00457                       tof+dtof,eloss,pid,id,trkid,lmom.theta(),lmom.phi(),processType);
00458           theCSCHits.push_back(hit);
00459         }
00460       }
00461       else if ( gd->subDetector() == GeomDetEnumerators::RPCBarrel ||
00462                 gd->subDetector() == GeomDetEnumerators::RPCEndcap ) {
00463         RPCDetId id(gd->geographicalId());
00464         const RPCChamber *chamber = rpcGeom->chamber(id);
00465         std::vector<const RPCRoll *> roll = chamber->rolls();
00466         for ( unsigned int iroll=0; iroll<roll.size(); iroll++ ) {
00467           RPCDetId rid = roll[iroll]->id();
00468 
00469 #ifdef FAMOS_DEBUG
00470           std::cout << "    Extrapolated to RPC (" 
00471                     << rid.ring() << "," 
00472                     << rid.station() << ","
00473                     << rid.sector() << ","
00474                     << rid.subsector() << ","
00475                     << rid.layer() << ","
00476                     << rid.roll() << ")" << std::endl;
00477 #endif
00478 
00479           const GeomDetUnit *det = rpcGeom->idToDetUnit(rid);
00480           HelixArbitraryPlaneCrossing crossing(propagatedState.globalPosition().basicVector(),
00481                                                propagatedState.globalMomentum().basicVector(),
00482                                                propagatedState.transverseCurvature(),
00483                                                anyDirection);
00484           std::pair<bool,double> path = crossing.pathLength(det->surface());
00485           if ( ! path.first ) continue;
00486           LocalPoint lpos = det->toLocal(GlobalPoint(crossing.position(path.second)));
00487           if ( ! det->surface().bounds().inside(lpos) ) continue; 
00488           double thickness = det->surface().bounds().thickness();
00489           LocalVector lmom = det->toLocal(GlobalVector(crossing.direction(path.second)));
00490           lmom = lmom.unit()*propagatedState.localMomentum().mag();
00491           double eloss = 0;
00492           double pz = fabs(lmom.z());
00493           LocalPoint entry = lpos - 0.5*thickness*lmom/pz;
00494           LocalPoint exit = lpos + 0.5*thickness*lmom/pz;
00495           double dtof = path.second*rbeta;
00496           int trkid = mySimTrack.trackId();
00497           unsigned int id = rid.rawId();
00498           short unsigned int processType = 2;
00499           PSimHit hit(entry,exit,lmom.mag(),
00500                       tof+dtof,eloss,pid,id,trkid,lmom.theta(),lmom.phi(),processType);
00501           theRPCHits.push_back(hit);
00502         }
00503       }
00504       else {
00505         std::cout << "Extrapolated to unknown subdetector '" << gd->subDetector() << "'..." << std::endl;
00506       }
00507     }
00508   }
00509   }
00510 
00511   std::auto_ptr<edm::PSimHitContainer> pcsc(new edm::PSimHitContainer);
00512   int n = 0;
00513   for ( std::vector<PSimHit>::const_iterator i = theCSCHits.begin();
00514         i != theCSCHits.end(); i++ ) {
00515     pcsc->push_back(*i);
00516     n += 1;
00517   }
00518   iEvent.put(pcsc,"MuonCSCHits");
00519 
00520   std::auto_ptr<edm::PSimHitContainer> pdt(new edm::PSimHitContainer);
00521   n = 0;
00522   for ( std::vector<PSimHit>::const_iterator i = theDTHits.begin();
00523         i != theDTHits.end(); i++ ) {
00524     pdt->push_back(*i);
00525     n += 1;
00526   }
00527   iEvent.put(pdt,"MuonDTHits");
00528 
00529   std::auto_ptr<edm::PSimHitContainer> prpc(new edm::PSimHitContainer);
00530   n = 0;
00531   for ( std::vector<PSimHit>::const_iterator i = theRPCHits.begin();
00532         i != theRPCHits.end(); i++ ) {
00533     prpc->push_back(*i);
00534     n += 1;
00535   }
00536   iEvent.put(prpc,"MuonRPCHits");
00537 
00538 }
00539 
00540 
00541 // ------------ method called once each job just after ending the event loop  ------------
00542 void 
00543 MuonSimHitProducer::endJob() 
00544 {
00545 }
00546 
00547 
00548 void 
00549 MuonSimHitProducer::readParameters(const edm::ParameterSet& fastMuons, 
00550                                    const edm::ParameterSet& fastTracks,
00551                                    const edm::ParameterSet& matEff) {
00552   // Muons
00553   theSimModuleLabel_   = fastMuons.getParameter<std::string>("simModuleLabel");
00554   theSimModuleProcess_ = fastMuons.getParameter<std::string>("simModuleProcess");
00555   theTrkModuleLabel_   = fastMuons.getParameter<std::string>("trackModuleLabel");
00556   std::vector<double> simHitIneffDT  = fastMuons.getParameter<std::vector<double> >("simHitDTIneffParameters");
00557   std::vector<double> simHitIneffCSC = fastMuons.getParameter<std::vector<double> >("simHitCSCIneffParameters");
00558   kDT = simHitIneffDT[0];
00559   fDT = simHitIneffDT[1];
00560   kCSC = simHitIneffCSC[0];
00561   fCSC = simHitIneffCSC[1];  
00562 
00563   // Tracks
00564   fullPattern_  = fastTracks.getUntrackedParameter<bool>("FullPatternRecognition");
00565 
00566   // The following should be on LogInfo
00567   //  std::cout << " MUON SIM HITS: FastSimulation parameters " << std::endl;
00568   //  std::cout << " ============================================== " << std::endl;
00569   //  if ( fullPattern_ ) 
00570   //    std::cout << " The FULL pattern recognition option is turned ON" << std::endl;
00571   //  else
00572   //    std::cout << " The FAST tracking option is turned ON" << std::endl;
00573 
00574   // Material Effects
00575   theMaterialEffects = 0;
00576   if ( matEff.getParameter<bool>("PairProduction") || 
00577        matEff.getParameter<bool>("Bremsstrahlung") ||
00578        matEff.getParameter<bool>("EnergyLoss") || 
00579        matEff.getParameter<bool>("MultipleScattering") )
00580     theMaterialEffects = new MaterialEffects(matEff,random);
00581 
00582 }
00583 
00584 void    
00585 MuonSimHitProducer::applyMaterialEffects(TrajectoryStateOnSurface& tsosWithdEdx,
00586                                          TrajectoryStateOnSurface& tsos,
00587                                          double radPath) { 
00588 
00589   // The energy loss simulator
00590   EnergyLossSimulator* energyLoss = theMaterialEffects->energyLossSimulator();
00591 
00592   // The multiple scattering simulator
00593   MultipleScatteringSimulator* multipleScattering = theMaterialEffects->multipleScatteringSimulator();
00594 
00595   // Initialize the Particle position, momentum and energy
00596   const Surface& nextSurface = tsos.surface();
00597   GlobalPoint gPos = energyLoss ? tsos.globalPosition() : tsosWithdEdx.globalPosition();
00598   GlobalVector gMom = energyLoss ? tsos.globalMomentum() : tsosWithdEdx.globalMomentum();  
00599   double mu = 0.1056583692;
00600   double en = std::sqrt(gMom.mag2()+mu*mu);
00601 
00602   // And now create the Particle
00603   XYZTLorentzVector position(gPos.x(),gPos.y(),gPos.z(),0.);
00604   XYZTLorentzVector momentum(gMom.x(),gMom.y(),gMom.z(),en);
00605   float charge = (float)(tsos.charge());
00606   ParticlePropagator theMuon(momentum,position,charge,0);
00607   theMuon.setID(-(int)charge*13);
00608 
00609   // Recompute the energy loss to get the fluctuations
00610   if ( energyLoss ) { 
00611     // Difference between with and without dE/dx (average only)
00612     // (for corrections once fluctuations are applied)
00613     GlobalPoint gPosWithdEdx = tsosWithdEdx.globalPosition();
00614     GlobalVector gMomWithdEdx = tsosWithdEdx.globalMomentum();
00615     double enWithdEdx = std::sqrt(gMomWithdEdx.mag2()+mu*mu);
00616     XYZTLorentzVector 
00617       deltaPos(gPosWithdEdx.x()-gPos.x(),gPosWithdEdx.y()-gPos.y(),
00618                gPosWithdEdx.z()-gPos.z(),0.);
00619     XYZTLorentzVector 
00620       deltaMom(gMomWithdEdx.x()-gMom.x(),gMomWithdEdx.y()-gMom.y(),
00621                gMomWithdEdx.z()-gMom.z(), enWithdEdx      -en);
00622 
00623     // Energy loss in iron (+ fluctuations)
00624     energyLoss->updateState(theMuon,radPath);
00625 
00626     // Correcting factors to account for slight differences in material descriptions
00627     // (Material description is more accurate in the stepping helix propagator)
00628     radPath *= -deltaMom.E()/energyLoss->mostLikelyLoss();
00629     double fac = energyLoss->deltaMom().E()/energyLoss->mostLikelyLoss();
00630 
00631     // Particle momentum & position after energy loss + fluctuation
00632     XYZTLorentzVector theNewMomentum = theMuon.momentum() + energyLoss->deltaMom() + fac * deltaMom;
00633     XYZTLorentzVector theNewPosition = theMuon.vertex() + fac * deltaPos;
00634     fac  = (theNewMomentum.E()*theNewMomentum.E()-mu*mu)/theNewMomentum.Vect().Mag2();
00635     fac  = fac>0.? std::sqrt(fac) : 1E-9;
00636     theMuon.SetXYZT(theNewMomentum.Px()*fac,theNewMomentum.Py()*fac,
00637                     theNewMomentum.Pz()*fac,theNewMomentum.E());    
00638     theMuon.setVertex(theNewPosition);
00639 
00640   }
00641 
00642   // Does the actual mutliple scattering
00643   if ( multipleScattering ) {
00644     // Pass the vector normal to the "next" surface 
00645     GlobalVector normal = nextSurface.tangentPlane(tsos.globalPosition())->normalVector();
00646     multipleScattering->setNormalVector(normal);
00647     // Compute the amount of multiple scattering after a given path length
00648     multipleScattering->updateState(theMuon,radPath);
00649   }
00650   
00651   // Fill the propagated state
00652   GlobalPoint propagatedPosition(theMuon.X(),theMuon.Y(),theMuon.Z());
00653   GlobalVector propagatedMomentum(theMuon.Px(),theMuon.Py(),theMuon.Pz());
00654   GlobalTrajectoryParameters propagatedGtp(propagatedPosition,propagatedMomentum,(int)charge,magfield);
00655   tsosWithdEdx = TrajectoryStateOnSurface(propagatedGtp,nextSurface);
00656 
00657 }
00658 
00659 
00660 
00661 //define this as a plug-in
00662 DEFINE_FWK_MODULE(MuonSimHitProducer);