00001
00008
00009 #include <memory>
00010
00011
00012 #include <cmath>
00013
00014
00015 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
00016 #include <CLHEP/Random/RandGaussQ.h>
00017 #include <CLHEP/Random/RandFlat.h>
00018
00019
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
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
00037 #include "MagneticField/Engine/interface/MagneticField.h"
00038 #include "MagneticField/Records/interface/IdealMagneticFieldRecord.h"
00039
00040
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
00047 #include "DataFormats/DTDigi/interface/DTDigiCollection.h"
00048 #include "DataFormats/MuonDetId/interface/DTWireId.h"
00049 #include "DataFormats/MuonDetId/interface/DTLayerId.h"
00050
00051
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
00059 using namespace edm;
00060 using namespace std;
00061
00062
00063 DTDigitizer::DTDigitizer(const ParameterSet& conf_) {
00064
00065
00066 debug=conf_.getUntrackedParameter<bool>("debug");
00067
00068 if (debug) cout<<"Creating a DTDigitizer"<<endl;
00069
00070
00071
00072 produces<DTDigiCollection>();
00073
00074 produces<DTDigiSimLinkCollection>();
00075
00076
00077
00078
00079 onlyMuHits=conf_.getParameter<bool>("onlyMuHits");
00080
00081
00082 interpolate=conf_.getParameter<bool>("interpolate");
00083
00084
00085
00086
00087
00088 vPropWire=conf_.getParameter<double>("vPropWire");
00089
00090
00091 deadTime=conf_.getParameter<double>("deadTime");
00092
00093
00094 smearing=conf_.getParameter<double>("Smearing");
00095
00096
00097 syncName = conf_.getParameter<string>("SyncName");
00098 theSync = DTDigiSyncFactory::get()->create(syncName,conf_.getParameter<ParameterSet>("pset"));
00099
00100
00101
00102 IdealModel = conf_.getParameter<bool>("IdealModel");
00103
00104
00105 if(IdealModel)
00106 theConstVDrift = conf_.getParameter<double>("IdealModelConstantDriftVelocity");
00107 else theConstVDrift = 55.;
00108
00109
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
00119 MultipleLinks = conf_.getParameter<bool>("MultipleLinks");
00120
00121
00122 LinksTimeWindow = conf_.getParameter<double>("LinksTimeWindow");
00123
00124
00125 mix_ = conf_.getParameter<std::string>("mixLabel");
00126 collection_for_XF = conf_.getParameter<std::string>("InputCollection");
00127
00128
00129 geometryType = conf_.getParameter<std::string>("GeometryType");
00130 }
00131
00132
00133 DTDigitizer::~DTDigitizer(){
00134 delete theGaussianDistribution;
00135 delete theFlatDistribution;
00136 }
00137
00138
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
00145
00146
00147
00148
00149
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
00157 auto_ptr<DTDigiCollection> output(new DTDigiCollection());
00158
00159 auto_ptr<DTDigiSimLinkCollection> outputLinks(new DTDigiSimLinkCollection());
00160
00161
00162 ESHandle<DTGeometry> muonGeom;
00163 iSetup.get<MuonGeometryRecord>().get(geometryType,muonGeom);
00164
00165
00166 ESHandle<MagneticField> magnField;
00167 iSetup.get<IdealMagneticFieldRecord>().get(magnField);
00168
00169
00170
00171
00172
00173 DTWireIdMap wireMap;
00174
00175 for(MixCollection<PSimHit>::MixItr simHit = simHits->begin();
00176 simHit != simHits->end(); simHit++){
00177
00178
00179
00180 DTWireId wireId( (*simHit).detUnitId() );
00181
00182 wireMap[wireId].push_back(&(*simHit));
00183 }
00184
00185 pair<float,bool> time(0.,false);
00186
00187
00188
00189 for(DTWireIdMapConstIter wire = wireMap.begin(); wire!=wireMap.end(); wire++){
00190
00191 const vector<const PSimHit*> & vhit = (*wire).second;
00192 if(vhit.size()!=0) {
00193 TDContainer tdCont;
00194
00195
00196 DTWireId wireId = (*wire).first;
00197
00198
00199 const DTLayer* layer = muonGeom->layer(wireId.layerId());
00200
00201
00202 for (vector<const PSimHit*>::const_iterator hit=vhit.begin();
00203 hit != vhit.end(); hit++){
00204
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
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
00220
00221
00222
00223
00224 storeDigis(wireId,tdCont,*output,*outputLinks);
00225 }
00226
00227 }
00228
00229
00230
00231
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
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
00265 pair<float,bool> driftTime(0.,false);
00266
00267
00268
00269
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
00280
00281
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
00291
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
00304
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
00319 bool noParametrisation =
00320 ( ( entrySide == DTTopology::none || exitSide == DTTopology::none )
00321 || (entrySide == exitSide)
00322 || ((entrySide == DTTopology::xMin && exitSide == DTTopology::xMax) ||
00323 (entrySide == DTTopology::xMax && exitSide == DTTopology::xMin))
00324 );
00325
00326
00327
00328 if ( delta < 0.99996
00329 && (noParametrisation == false)) {
00330 if (debug) cout << "*** WARNING: hit is not straight, type = " << partType << endl;
00331 }
00332
00333
00334
00335 if (!noParametrisation) {
00336
00337 LocalVector dir = hit->momentumAtEntry();
00338 float theta = atan(dir.x()/-dir.z())*180/M_PI;
00339
00340
00341
00342
00343
00344 float x;
00345
00346 Local3DPoint pt = hit->localPosition();
00347
00348 if(fabs(pt.z()) < 0.002) {
00349
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
00363 driftTime = driftTimeFromTimeMap();
00364 }
00365
00366
00367
00368
00369 if (driftTime.second) {
00370 driftTime.first += externalDelays(layer,wireId,hit);
00371 }
00372 return driftTime;
00373 }
00374
00375
00376
00377 pair<float,bool> DTDigitizer::driftTimeFromParametrization(float x, float theta, float By, float Bz) const {
00378
00379
00380 x *= 10.;
00381
00382
00383
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
00391
00392
00393 float By_par = Bz;
00394 float Bz_par = -By;
00395 float theta_par = theta;
00396
00397
00398
00399 if (fabs(theta_par)>45.) {
00400 if (debug) cout << "*** WARNING: extrapolating theta > 45: "
00401 << theta << endl;
00402
00403 }
00404 if (fabs(By_par)>0.75) {
00405 if (debug) cout << "*** WARNING: extrapolating Bnorm > 0.75: "
00406 << By_par << endl;
00407
00408 }
00409 if (fabs(Bz_par)>0.4) {
00410 if (debug) cout << "*** WARNING: extrapolating Bwire >0.4: "
00411 << Bz_par << endl;
00412
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
00432 float time = asymGausSmear(DT.t_drift, DT.t_width_m, DT.t_width_p);
00433
00434
00435 time = max(time,0.f);
00436
00437
00438
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
00465 if (debug) cout << " TimeMap " << endl;
00466 return pair<float,bool>(0.,false);
00467 }
00468
00469
00470
00471 float DTDigitizer::externalDelays(const DTLayer* layer,
00472 const DTWireId &wireId,
00473 const PSimHit *hit) const {
00474
00475
00476
00477 float wireCoord = hit->localPosition().y();
00478 float halfL = (layer->specificTopology().cellLenght())/2.;
00479 float propgL = halfL - wireCoord;
00480
00481 float propDelay = propgL/vPropWire;
00482
00483
00484 float tof = hit->tof();
00485
00486
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
00503
00504 void DTDigitizer::storeDigis(DTWireId &wireId,
00505 TDContainer &hits,
00506 DTDigiCollection &output, DTDigiSimLinkCollection &outputLinks){
00507
00508
00509
00510
00511 sort(hits.begin(),hits.end(),hitLessT());
00512
00513
00514
00515 float wakeTime = -999999.0;
00516 float resolTime = -999999.0;
00517 int digiN = -1;
00518 DTDigi digi;
00519
00520
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
00527
00528 float time = (*hit).second;
00529 if ( time > wakeTime ) {
00530
00531 int wireN = wireId.wire();
00532 digiN++;
00533 digi = DTDigi(wireN, time, digiN);
00534
00535
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
00549 if(digi.countsTDC() < pow(2.,16)){
00550 DTLayerId layerID = wireId.layerId();
00551 output.insertDigi(layerID, digi);
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
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
00595 << " trackId = " << hit->trackId() << endl
00596
00597 << " |p| = " << hit->pabs() << endl
00598 << " Energy loss = " << hit->energyLoss() << endl
00599
00600
00601
00602 << " localDirection = " << hit->momentumAtEntry().unit() << endl
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