CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/SimMuon/DTDigitizer/src/DTDigitizer.cc

Go to the documentation of this file.
00001 
00008 // system include files
00009 #include <memory>
00010 
00011 //C++ headers
00012 #include <cmath>
00013 
00014 //Random generator
00015 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
00016 #include <CLHEP/Random/RandGaussQ.h>
00017 #include <CLHEP/Random/RandFlat.h>
00018 
00019 // Framework
00020 #include "FWCore/Framework/interface/Frameworkfwd.h"
00021 #include "FWCore/Framework/interface/EventSetup.h"
00022 #include "FWCore/Framework/interface/Event.h"
00023 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00024 #include "FWCore/Framework/interface/ESHandle.h"
00025 #include "DataFormats/Common/interface/Handle.h"
00026 #include "FWCore/ServiceRegistry/interface/Service.h"
00027 
00028 // Geometry
00029 #include "Geometry/Records/interface/MuonGeometryRecord.h"
00030 #include "Geometry/DTGeometry/interface/DTGeometry.h"
00031 #include "Geometry/DTGeometry/interface/DTLayer.h"
00032 #include "Geometry/DTGeometry/interface/DTTopology.h"
00033 
00034 #include "DataFormats/GeometryVector/interface/LocalPoint.h"
00035 
00036 // Magnetic Field
00037 #include "MagneticField/Engine/interface/MagneticField.h"
00038 #include "MagneticField/Records/interface/IdealMagneticFieldRecord.h"
00039 
00040 // SimHits
00041 #include "SimDataFormats/TrackingHit/interface/PSimHitContainer.h"
00042 #include "SimDataFormats/TrackingHit/interface/PSimHit.h"
00043 #include "SimDataFormats/CrossingFrame/interface/CrossingFrame.h"
00044 #include "SimDataFormats/CrossingFrame/interface/MixCollection.h"
00045 
00046 // Digis
00047 #include "DataFormats/DTDigi/interface/DTDigiCollection.h"
00048 #include "DataFormats/MuonDetId/interface/DTWireId.h"
00049 #include "DataFormats/MuonDetId/interface/DTLayerId.h"
00050 
00051 // DTDigitizer
00052 #include "SimMuon/DTDigitizer/interface/DTDigiSyncFactory.h"
00053 #include "SimMuon/DTDigitizer/interface/DTDigiSyncBase.h"
00054 
00055 #include "SimMuon/DTDigitizer/src/DTDriftTimeParametrization.h"
00056 #include "SimMuon/DTDigitizer/src/DTDigitizer.h"
00057 
00058 // namespaces
00059 using namespace edm;
00060 using namespace std;
00061 
00062 // Constructor
00063 DTDigitizer::DTDigitizer(const ParameterSet& conf_) {
00064   
00065   // Set verbose output
00066   debug=conf_.getUntrackedParameter<bool>("debug"); 
00067     
00068   if (debug) cout<<"Creating a DTDigitizer"<<endl;
00069   
00070   //register the Producer with a label
00071   //produces<DTDigiCollection>("MuonDTDigis"); // FIXME: Do I pass it by ParameterSet?
00072   produces<DTDigiCollection>(); // FIXME: Do I pass it by ParameterSet?
00073   //  produces<DTDigiSimLinkCollection>("MuonDTDigiSimLinks");
00074   produces<DTDigiSimLinkCollection>();
00075   
00076   //Parameters:
00077 
00078   // build digis only for mu hits (for debug purposes) 
00079   onlyMuHits=conf_.getParameter<bool>("onlyMuHits");
00080   
00081   // interpolate parametrization function
00082   interpolate=conf_.getParameter<bool>("interpolate");
00083   
00084   // Velocity of signal propagation along the wire (cm/ns)
00085   // For the default value
00086   // cfr. CMS-IN 2000-021:   (2.56+-0.17)x1e8 m/s
00087   //      CMS NOTE 2003-17:  (0.244)  m/ns
00088   vPropWire=conf_.getParameter<double>("vPropWire"); //24.4
00089 
00090   // Dead time for signals on the same wire (number from M. Pegoraro)  
00091   deadTime=conf_.getParameter<double>("deadTime"); //150
00092   
00093   // further configurable smearing
00094   smearing=conf_.getParameter<double>("Smearing"); // 3.
00095 
00096   // Sync Algo
00097   syncName = conf_.getParameter<string>("SyncName");
00098   theSync = DTDigiSyncFactory::get()->create(syncName,conf_.getParameter<ParameterSet>("pset"));
00099 
00100   // Debug flag to switch to the Ideal model
00101   // it uses a constant drift velocity and doesn't set any external delay
00102   IdealModel = conf_.getParameter<bool>("IdealModel");
00103 
00104   // Constant drift velocity needed by the above flag
00105   if(IdealModel)
00106     theConstVDrift = conf_.getParameter<double>("IdealModelConstantDriftVelocity"); // 55 um/ns
00107   else theConstVDrift = 55.;
00108 
00109   // get random engine
00110   edm::Service<edm::RandomNumberGenerator> rng;
00111   if ( ! rng.isAvailable()) {
00112     throw cms::Exception("Configuration")
00113       << "RandomNumberGeneratorService for DTDigitizer missing in cfg file";
00114   }
00115   theGaussianDistribution = new CLHEP::RandGaussQ(rng->getEngine()); 
00116   theFlatDistribution = new CLHEP::RandFlat(rng->getEngine(), 0, 1); 
00117 
00118   // MultipleLinks=false ==> one-to-one correspondence between digis and SimHits 
00119   MultipleLinks = conf_.getParameter<bool>("MultipleLinks");
00120   // MultipleLinks=true ==> association of SimHits within a time window LinksTimeWindow 
00121   // (of the order of the resolution)
00122   LinksTimeWindow = conf_.getParameter<double>("LinksTimeWindow"); // (10 ns)
00123 
00124   //Name of Collection used for create the XF 
00125   mix_ = conf_.getParameter<std::string>("mixLabel");
00126   collection_for_XF = conf_.getParameter<std::string>("InputCollection");
00127 
00128   //String to choice between ideal (the deafult) and (mis)aligned geometry for the digitization step 
00129   geometryType = conf_.getParameter<std::string>("GeometryType");
00130 }
00131 
00132 // Destructor
00133 DTDigitizer::~DTDigitizer(){
00134   delete theGaussianDistribution;
00135   delete theFlatDistribution;
00136 }
00137 
00138 // method called to produce the data
00139 void DTDigitizer::produce(Event& iEvent, const EventSetup& iSetup){
00140   if(debug)
00141     cout << "--- Run: " << iEvent.id().run()
00142          << " Event: " << iEvent.id().event() << endl;
00143   
00144   //************ 1 ***************
00145    // create the container for the SimHits
00146   //  Handle<PSimHitContainer> simHits; 
00147   //  iEvent.getByLabel("g4SimHits","MuonDTHits",simHits);
00148     
00149   // use MixCollection instead of the previous
00150   Handle<CrossingFrame<PSimHit> > xFrame;
00151   iEvent.getByLabel(mix_,collection_for_XF,xFrame);
00152   
00153   auto_ptr<MixCollection<PSimHit> > 
00154     simHits( new MixCollection<PSimHit>(xFrame.product()) );
00155 
00156    // create the pointer to the Digi container
00157   auto_ptr<DTDigiCollection> output(new DTDigiCollection());
00158    // pointer to the DigiSimLink container
00159   auto_ptr<DTDigiSimLinkCollection> outputLinks(new DTDigiSimLinkCollection());
00160   
00161   // Muon Geometry
00162   ESHandle<DTGeometry> muonGeom;
00163   iSetup.get<MuonGeometryRecord>().get(geometryType,muonGeom);
00164 
00165   // Magnetic Field  
00166   ESHandle<MagneticField> magnField;
00167   iSetup.get<IdealMagneticFieldRecord>().get(magnField);
00168 
00169   //************ 2 ***************
00170 
00171   // These are sorted by DetId, i.e. by layer and then by wire #
00172   //  map<DTDetId, vector<const PSimHit*> > wireMap;     
00173   DTWireIdMap wireMap;     
00174   
00175   for(MixCollection<PSimHit>::MixItr simHit = simHits->begin();
00176        simHit != simHits->end(); simHit++){
00177     
00178     // Create the id of the wire, the simHits in the DT known also the wireId
00179  
00180     DTWireId wireId( (*simHit).detUnitId() );
00181     // Fill the map
00182     wireMap[wireId].push_back(&(*simHit));
00183   }
00184   
00185   pair<float,bool> time(0.,false);
00186 
00187   //************ 3 ***************
00188   // Loop over the wires
00189   for(DTWireIdMapConstIter wire = wireMap.begin(); wire!=wireMap.end(); wire++){
00190     // SimHit Container associated to the wire
00191     const vector<const PSimHit*> & vhit = (*wire).second; 
00192     if(vhit.size()!=0) {
00193       TDContainer tdCont; // It is a vector<pair<const PSimHit*,float> >;
00194       
00195       //************ 4 ***************
00196       DTWireId wireId = (*wire).first;
00197 
00198       //const DTLayer* layer = dynamic_cast< const DTLayer* > (muonGeom->idToDet(wireId.layerId()));
00199       const DTLayer* layer = muonGeom->layer(wireId.layerId()); 
00200 
00201       // Loop on the hits of this wire    
00202       for (vector<const PSimHit*>::const_iterator hit=vhit.begin();
00203            hit != vhit.end(); hit++){
00204         //************ 5 ***************
00205         LocalPoint locPos = (*hit)->localPosition();
00206 
00207         const LocalVector BLoc=layer->surface().toLocal(magnField->inTesla(layer->surface().toGlobal(locPos)));
00208 
00209         time = computeTime(layer, wireId, *hit, BLoc); 
00210 
00211         //************ 6 ***************
00212         if (time.second) {
00213           tdCont.push_back(make_pair((*hit),time.first));
00214         } else {
00215           if (debug) cout << "hit discarded" << endl;
00216         }
00217       }
00218 
00219       //************ 7 ***************
00220 
00221       // the loading must be done by layer but
00222       // the digitization must be done by wire (in order to take into account the dead time)
00223 
00224       storeDigis(wireId,tdCont,*output,*outputLinks);
00225     }
00226     
00227   }
00228 
00229   //************ 8 ***************  
00230   // Load the Digi Container in the Event
00231   //iEvent.put(output,"MuonDTDigis");
00232   iEvent.put(output);
00233   iEvent.put(outputLinks);
00234 
00235 }
00236 
00237 pair<float,bool> DTDigitizer::computeTime(const DTLayer* layer, const DTWireId &wireId, 
00238                                           const PSimHit *hit, const LocalVector &BLoc){ 
00239  
00240   LocalPoint entryP = hit->entryPoint();
00241   LocalPoint exitP = hit->exitPoint();
00242   int partType = hit->particleType();
00243 
00244   const DTTopology &topo = layer->specificTopology();
00245 
00246   // Pay attention: in CMSSW the rf of the SimHit is in the layer's rf
00247   
00248   if(debug)  cout<<"Hit local entry point: "<<entryP<<endl
00249                  <<"Hit local exit point: "<<exitP<<endl;
00250 
00251   float xwire = topo.wirePosition(wireId.wire()); 
00252   float xEntry = entryP.x() - xwire;
00253   float xExit  = exitP.x() - xwire;
00254 
00255   if(debug) cout<<"wire position: "<<xwire
00256                 <<" x entry in cell rf: "<<xEntry
00257                 <<" x exit in cell rf: "<<xExit<<endl;
00258   
00259   DTTopology::Side entrySide = topo.onWhichBorder(xEntry,entryP.y(),entryP.z());
00260   DTTopology::Side exitSide  = topo.onWhichBorder(xExit,exitP.y(),exitP.z());
00261 
00262    if (debug) dumpHit(hit, xEntry, xExit,topo);
00263 
00264   // The bolean is used to flag the drift time computation
00265   pair<float,bool> driftTime(0.,false);  
00266 
00267   // if delta in gas->ignore, since it is included in the parametrisation.
00268   // FIXME: should check that it is actually a delta ray produced by a nearby
00269   // muon hit. 
00270 
00271   if (partType == 11 && entrySide == DTTopology::none) {
00272      if (debug) cout << "    e- hit in gas; discarding " << endl;
00273     return driftTime;
00274   }
00275 
00276   float By = BLoc.y();
00277   float Bz = BLoc.z();
00278 
00279   // Radius and sagitta according to direction of momentum
00280   // (just for printing)
00281   // NOTE: in cmsim, d is always taken // pHat!
00282   LocalVector d = (exitP-entryP);
00283   LocalVector pHat = hit->localDirection().unit();
00284   LocalVector hHat = (d.cross(pHat.cross(d))).unit();
00285   float cosAlpha = hHat.dot(pHat);
00286   float sinAlpha = sqrt(1.-cosAlpha*cosAlpha);
00287   float radius_P = (d.mag())/(2.*cosAlpha);
00288   float sagitta_P = radius_P*(1.-sinAlpha);
00289 
00290   // Radius, sagitta according to field bending
00291   // (just for printing)
00292   float halfd = d.mag()/2.;
00293   float BMag = BLoc.mag();
00294   LocalVector pT = (pHat - (BLoc.unit()*pHat.dot(BLoc.unit())))*(hit->pabs());
00295   float radius_B = (pT.mag()/(0.3*BMag))*100.;
00296   float sagitta_B;
00297   if (radius_B > halfd) {
00298     sagitta_B = radius_B - sqrt(radius_B*radius_B - halfd*halfd);
00299   } else {
00300     sagitta_B = radius_B;
00301   }
00302 
00303   // cos(delta), delta= angle between direction at entry and hit segment
00304   // (just for printing)
00305   float delta = pHat.dot(d.unit());
00306   if (debug) cout << "   delta                 = " << delta  << endl
00307                   << "   cosAlpha              = " << cosAlpha << endl
00308                   << "   sinAlpha              = " << sinAlpha << endl
00309                   << "   pMag                  = " << pT.mag() << endl
00310                   << "   bMag                  = " << BMag << endl
00311                   << "   pT                    = " << pT << endl
00312                   << "   halfd                 = " << halfd << endl
00313                   << "   radius_P  (cm)        = " << radius_P << endl
00314                   << "   sagitta_P (um)        = " << sagitta_P*10000. << endl
00315                   << "   radius_B  (cm)        = " << radius_B << endl
00316                   << "   sagitta_B (um)        = " << sagitta_B*10000. << endl;
00317 
00318   // Select cases where parametrization can not be used.
00319   bool noParametrisation = 
00320     ( ( entrySide == DTTopology::none || exitSide == DTTopology::none ) // case # 2,3,8,9 or 11
00321       || (entrySide == exitSide)                   // case # 4 or 10
00322       || ((entrySide == DTTopology::xMin && exitSide == DTTopology::xMax) || 
00323           (entrySide == DTTopology::xMax && exitSide == DTTopology::xMin)) // Hit is case # 7
00324       );
00325 
00326   // FIXME: now, debug warning only; consider treating those 
00327   // with TM algo. 
00328   if ( delta < 0.99996 // Track is not straight. FIXME: use sagitta?
00329        && (noParametrisation == false)) {
00330     if (debug) cout << "*** WARNING: hit is not straight, type = " << partType << endl;
00331   }
00332 
00333   //************ 5A ***************
00334 
00335   if (!noParametrisation) {
00336    
00337     LocalVector dir = hit->momentumAtEntry(); // ex Measurement3DVector dir = hit->measurementDirection(); //FIXME?
00338     float theta = atan(dir.x()/-dir.z())*180/M_PI;
00339 
00340     // FIXME: use dir if M.S. is included as GARFIELD option...
00341     //        otherwise use hit segment dirction.
00342     //    LocalVector dir0 = (exitP-entryP).unit();
00343     //    float theta = atan(dir0.x()/-dir0.z())*180/M_PI;
00344     float x;
00345 
00346     Local3DPoint pt = hit->localPosition();  //ex Measurement3DPoint pt = hit->measurementPosition(); // FIXME?
00347      
00348     if(fabs(pt.z()) < 0.002) { 
00349       // hit center within 20 um from z=0, no need to extrapolate.
00350       x = pt.x() - xwire;
00351     } else {
00352       x = xEntry - (entryP.z()*(xExit-xEntry))/(exitP.z()-entryP.z());
00353     }
00354 
00355     if(IdealModel) return make_pair(fabs(x)/theConstVDrift,true);
00356     else driftTime = driftTimeFromParametrization(x, theta, By, Bz);
00357 
00358   }
00359 
00360  
00361   if ((driftTime.second)==false) {
00362     // Parametrisation not applicable, or failed. Use time map.
00363     driftTime = driftTimeFromTimeMap();
00364   }
00365   
00366   //************ 5B ***************
00367 
00368   // Signal propagation, TOF etc.
00369   if (driftTime.second) {
00370     driftTime.first += externalDelays(layer,wireId,hit);
00371   }
00372   return driftTime;
00373 } 
00374 
00375 //************ 5A ***************
00376 
00377 pair<float,bool> DTDigitizer::driftTimeFromParametrization(float x, float theta, float By, float Bz) const {
00378 
00379   // Convert from CMSSW frame/units r.f. to parametrization ones.
00380   x *= 10.;  //cm -> mm 
00381 
00382   // FIXME: Current parametrisation can extrapolate above 21 mm,
00383   // however a detailed study is needed before using this.
00384    if (fabs(x) > 21.) {
00385      if (debug) cout << "*** WARNING: parametrisation: x out of range = "
00386                      << x << ", skipping" << endl;
00387      return pair<float,bool>(0.f,false);
00388   }
00389 
00390   // Different r.f. of the parametrization:
00391   // X_par = X_ORCA; Y_par=Z_ORCA; Z_par = -Y_ORCA  
00392 
00393   float By_par = Bz;  // Bnorm
00394   float Bz_par = -By; // Bwire
00395   float theta_par = theta;
00396 
00397   // Parametrisation uses interpolation up to |theta|=45 deg,
00398   // |Bwire|=0.4, |Bnorm|=0.75; extrapolation above.
00399   if (fabs(theta_par)>45.) {
00400     if (debug) cout << "*** WARNING: extrapolating theta > 45: "
00401                     << theta << endl;
00402     // theta_par = min(fabs(theta_par),45.f)*((theta_par<0.)?-1.:1.);
00403   }
00404   if (fabs(By_par)>0.75) {
00405     if (debug) cout << "*** WARNING: extrapolating Bnorm > 0.75: "
00406                     << By_par << endl;
00407     // By_par = min(fabs(By_par),0.75f)*((By_par<0.)?-1.:1.);
00408   }
00409   if (fabs(Bz_par)>0.4) {
00410     if (debug) cout << "*** WARNING: extrapolating Bwire >0.4: "
00411                     << Bz_par << endl;
00412     // Bz_par = min(fabs(Bz_par),0.4)*((Bz_par<0.)?-1.:1.);
00413   }
00414 
00415   DTDriftTimeParametrization::drift_time DT;
00416   static DTDriftTimeParametrization par;
00417   unsigned short flag = par.MB_DT_drift_time (x, theta_par, By_par, Bz_par, 0, &DT, interpolate);
00418 
00419   if (debug) {
00420     cout << "    Parametrisation: x, theta, Bnorm, Bwire = "
00421          << x << " " <<  theta_par << " " << By_par << " " << Bz_par << endl
00422          << "  time=" << DT.t_drift
00423          << "  sigma_m=" <<  DT.t_width_m
00424          << "  sigma_p=" <<  DT.t_width_p << endl;
00425     if (flag!=1) {
00426       cout << "*** WARNING: call to parametrisation failed" << endl;
00427       return pair<float,bool>(0.f,false); 
00428     }
00429   }
00430 
00431   // Double half-gaussian smearing
00432   float time = asymGausSmear(DT.t_drift, DT.t_width_m, DT.t_width_p);
00433 
00434   // Do not allow the smearing to lead to negative values
00435   time = max(time,0.f);
00436 
00437   // Apply a Gaussian smearing to account for electronic effects (cf. 2004 TB analysis)
00438   // The width of the Gaussian can be configured with the "Smearing" parameter
00439 
00440   double u = theGaussianDistribution->fire(0.,smearing);
00441   time += u;
00442 
00443   if (debug) cout << "  drift time = " << time << endl;
00444   
00445   return pair<float,bool>(time,true); 
00446 }
00447 
00448 float DTDigitizer::asymGausSmear(double mean, double sigmaLeft, double sigmaRight) const {
00449 
00450   double f = sigmaLeft/(sigmaLeft+sigmaRight);
00451   double t;
00452 
00453   if (theFlatDistribution->fire() <= f) {
00454     t = theGaussianDistribution->fire(mean,sigmaLeft);
00455     t = mean - fabs(t - mean);
00456   } else {
00457     t = theGaussianDistribution->fire(mean,sigmaRight);
00458     t = mean + fabs(t - mean);
00459   }
00460   return static_cast<float>(t);
00461 }
00462 
00463 pair<float,bool> DTDigitizer::driftTimeFromTimeMap() const {
00464   // FIXME: not yet implemented.
00465   if (debug) cout << "   TimeMap " << endl;
00466   return pair<float,bool>(0.,false);
00467 }
00468 
00469 //************ 5B ***************
00470 
00471 float DTDigitizer::externalDelays(const DTLayer* layer,
00472                                   const DTWireId &wireId, 
00473                                   const PSimHit *hit) const {
00474   
00475   // Time of signal propagation along wire.
00476   
00477   float wireCoord = hit->localPosition().y();
00478   float halfL     = (layer->specificTopology().cellLenght())/2.;
00479   float propgL = halfL - wireCoord; // the FE is always located at the pos coord.
00480 
00481   float propDelay = propgL/vPropWire;
00482 
00483   // Real TOF.
00484   float tof = hit->tof();  
00485 
00486   // Delays and t0 according to theSync
00487 
00488   double sync= theSync->digitizerOffset(&wireId,layer);
00489 
00490 
00491   if (debug) {
00492     cout << "    propDelay =" << propDelay
00493          << "; TOF=" << tof
00494          << "; sync= " << sync
00495          << endl;
00496   }
00497   
00498   return propDelay + tof + sync;
00499 }
00500 
00501 
00502 // accumulate digis by layer
00503 
00504 void DTDigitizer::storeDigis(DTWireId &wireId, 
00505                              TDContainer &hits,
00506                              DTDigiCollection &output, DTDigiSimLinkCollection &outputLinks){
00507 
00508   //************ 7A ***************
00509 
00510   // sort signal times
00511   sort(hits.begin(),hits.end(),hitLessT());
00512 
00513   //************ 7B ***************
00514 
00515   float wakeTime = -999999.0;
00516   float resolTime = -999999.0;
00517   int digiN = -1; // Digi identifier within the cell (for multiple digis)
00518   DTDigi digi;
00519 
00520   // loop over signal times and drop signals inside dead time
00521   for ( TDContainer::const_iterator hit = hits.begin() ; hit != hits.end() ; 
00522         hit++ ) {
00523 
00524     if (onlyMuHits && abs((*hit).first->particleType())!=13) continue;
00525 
00526     //************ 7C ***************
00527         
00528     float time = (*hit).second;
00529     if ( time > wakeTime ) {
00530       // Note that digi is constructed with a float value (in ns)
00531       int wireN = wireId.wire();
00532       digiN++;
00533       digi = DTDigi(wireN, time, digiN);
00534 
00535       // Add association between THIS digi and the corresponding SimTrack
00536       unsigned int SimTrackId = (*hit).first->trackId();
00537       EncodedEventId evId = (*hit).first->eventId();
00538       DTDigiSimLink digisimLink(wireN, digiN, time, SimTrackId, evId);
00539 
00540       if(debug) {
00541         cout<<endl<<"---- DTDigitizer ----"<<endl;
00542         cout<<"wireId: "<<wireId<<endl;
00543         cout<<"sim. time = "<<time<<endl;
00544         cout<<"digi number = "<< digi.number()<<", digi time = "<<digi.time()
00545             <<", linked to SimTrack Id = "<<SimTrackId<<endl;
00546       }
00547 
00548       //************ 7D ***************
00549       if(digi.countsTDC() < pow(2.,16)){
00550         DTLayerId layerID = wireId.layerId();  //taking the layer in which reside the wire
00551         output.insertDigi(layerID, digi); // ordering Digis by layer
00552         outputLinks.insertDigi(layerID, digisimLink);
00553         wakeTime = time + deadTime;
00554         resolTime = time + LinksTimeWindow;
00555       } 
00556       else {
00557         digiN--;
00558       }
00559     }
00560     else if (MultipleLinks && time < resolTime){
00561       int wireN = wireId.wire();
00562       unsigned int SimTrackId = (*hit).first->trackId();
00563       EncodedEventId evId = (*hit).first->eventId();
00564       DTDigiSimLink digisimLink(wireN, digiN, time, SimTrackId, evId);
00565       DTLayerId layerID = wireId.layerId(); 
00566       outputLinks.insertDigi(layerID, digisimLink);
00567 
00568       if(debug) { 
00569         cout<<"\nAdded multiple link: \n"
00570             <<"digi number = "<<digi.number()<<", digi time = "<<digi.time()<<" (sim. time = "<<time<<")"
00571             <<", linked to SimTrack Id = "<<SimTrackId<<endl;
00572       }
00573     }
00574   }
00575   
00576 }
00577 
00578 void DTDigitizer::dumpHit(const PSimHit * hit,
00579                           float xEntry, float xExit,
00580                           const DTTopology &topo) {
00581   
00582   LocalPoint entryP = hit->entryPoint();
00583   LocalPoint exitP = hit->exitPoint();
00584   
00585   DTTopology::Side entrySide = topo.onWhichBorder(xEntry,entryP.y(),entryP.z());
00586   DTTopology::Side exitSide  = topo.onWhichBorder(xExit,exitP.y(),exitP.z());
00587   //  ProcessTypeEnumerator pTypes;
00588   
00589   cout << endl
00590        << "------- SimHit: " << endl
00591        << "   Particle type         = " << hit->particleType() << endl
00592        << "   process type          = " << hit->processType() << endl
00593        << "   process type          = " << hit->processType() << endl
00594     // << "   packedTrackId         = " << hit->packedTrackId() << endl
00595        << "   trackId               = " << hit->trackId() << endl // new,is the same as the
00596                                                                   // previous?? FIXME-Check
00597        << "   |p|                   = " << hit->pabs() << endl
00598        << "   Energy loss           = " << hit->energyLoss() << endl
00599     // << "   timeOffset            = " << hit->timeOffset() << endl
00600     // << "   measurementPosition   = " << hit->measurementPosition() << endl
00601     // << "   measurementDirection  = " << hit->measurementDirection() << endl      //FIXME
00602        << "   localDirection        = " << hit->momentumAtEntry().unit() << endl    //FIXME is it a versor?
00603        << "   Entry point           = " << entryP << " cell x = " << xEntry << endl
00604        << "   Exit point            = " << exitP << " cell x = " << xExit << endl
00605        << "   DR =                  = " << (exitP-entryP).mag() << endl
00606        << "   Dx =                  = " << (exitP-entryP).x() << endl
00607        << "   Cell w,h,l            = (" << topo.cellWidth()
00608        << " , " << topo.cellHeight() 
00609        << " , " << topo.cellLenght() << ") cm" << endl
00610        << "   DY entry from edge    = " << topo.cellLenght()/2.-fabs(entryP.y())
00611        << "   DY exit  from edge    = " << topo.cellLenght()/2.-fabs(exitP.y())
00612        << "   entrySide = "  << (int)entrySide
00613        << " ; exitSide = " << (int)exitSide << endl;
00614 
00615 }
00616