CMS 3D CMS Logo

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