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 collection_for_XF = conf_.getParameter<std::string>("InputCollection");
00126
00127
00128 geometryType = conf_.getParameter<std::string>("GeometryType");
00129 }
00130
00131
00132 DTDigitizer::~DTDigitizer(){
00133 delete theGaussianDistribution;
00134 delete theFlatDistribution;
00135 }
00136
00137
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
00144
00145
00146
00147
00148
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
00156 auto_ptr<DTDigiCollection> output(new DTDigiCollection());
00157
00158 auto_ptr<DTDigiSimLinkCollection> outputLinks(new DTDigiSimLinkCollection());
00159
00160
00161 ESHandle<DTGeometry> muonGeom;
00162 iSetup.get<MuonGeometryRecord>().get(geometryType,muonGeom);
00163
00164
00165 ESHandle<MagneticField> magnField;
00166 iSetup.get<IdealMagneticFieldRecord>().get(magnField);
00167
00168
00169
00170
00171
00172 DTWireIdMap wireMap;
00173
00174 for(MixCollection<PSimHit>::MixItr simHit = simHits->begin();
00175 simHit != simHits->end(); simHit++){
00176
00177
00178
00179 DTWireId wireId( (*simHit).detUnitId() );
00180
00181 wireMap[wireId].push_back(&(*simHit));
00182 }
00183
00184 pair<float,bool> time(0.,false);
00185
00186
00187
00188 for(DTWireIdMapConstIter wire = wireMap.begin(); wire!=wireMap.end(); wire++){
00189
00190 const vector<const PSimHit*> & vhit = (*wire).second;
00191 if(vhit.size()!=0) {
00192 TDContainer tdCont;
00193
00194
00195 DTWireId wireId = (*wire).first;
00196
00197
00198 const DTLayer* layer = muonGeom->layer(wireId.layerId());
00199
00200
00201 for (vector<const PSimHit*>::const_iterator hit=vhit.begin();
00202 hit != vhit.end(); hit++){
00203
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
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
00219
00220
00221
00222
00223 storeDigis(wireId,tdCont,*output,*outputLinks);
00224 }
00225
00226 }
00227
00228
00229
00230
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
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
00264 pair<float,bool> driftTime(0.,false);
00265
00266
00267
00268
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
00279
00280
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
00290
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
00303
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
00318 bool noParametrisation =
00319 ( ( entrySide == DTTopology::none || exitSide == DTTopology::none )
00320 || (entrySide == exitSide)
00321 || ((entrySide == DTTopology::xMin && exitSide == DTTopology::xMax) ||
00322 (entrySide == DTTopology::xMax && exitSide == DTTopology::xMin))
00323 );
00324
00325
00326
00327 if ( delta < 0.99996
00328 && (noParametrisation == false)) {
00329 if (debug) cout << "*** WARNING: hit is not straight, type = " << partType << endl;
00330 }
00331
00332
00333
00334 if (!noParametrisation) {
00335
00336 LocalVector dir = hit->momentumAtEntry();
00337 float theta = atan(dir.x()/-dir.z())*180/M_PI;
00338
00339
00340
00341
00342
00343 float x;
00344
00345 Local3DPoint pt = hit->localPosition();
00346
00347 if(fabs(pt.z()) < 0.002) {
00348
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
00362 driftTime = driftTimeFromTimeMap();
00363 }
00364
00365
00366
00367
00368 if (driftTime.second) {
00369 driftTime.first += externalDelays(layer,wireId,hit);
00370 }
00371 return driftTime;
00372 }
00373
00374
00375
00376 pair<float,bool> DTDigitizer::driftTimeFromParametrization(float x, float theta, float By, float Bz) const {
00377
00378
00379 x *= 10.;
00380
00381
00382
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
00390
00391
00392 float By_par = Bz;
00393 float Bz_par = -By;
00394 float theta_par = theta;
00395
00396
00397
00398 if (fabs(theta_par)>45.) {
00399 if (debug) cout << "*** WARNING: extrapolating theta > 45: "
00400 << theta << endl;
00401
00402 }
00403 if (fabs(By_par)>0.75) {
00404 if (debug) cout << "*** WARNING: extrapolating Bnorm > 0.75: "
00405 << By_par << endl;
00406
00407 }
00408 if (fabs(Bz_par)>0.4) {
00409 if (debug) cout << "*** WARNING: extrapolating Bwire >0.4: "
00410 << Bz_par << endl;
00411
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
00431 float time = asymGausSmear(DT.t_drift, DT.t_width_m, DT.t_width_p);
00432
00433
00434 time = max(time,0.f);
00435
00436
00437
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
00464 if (debug) cout << " TimeMap " << endl;
00465 return pair<float,bool>(0.,false);
00466 }
00467
00468
00469
00470 float DTDigitizer::externalDelays(const DTLayer* layer,
00471 const DTWireId &wireId,
00472 const PSimHit *hit) const {
00473
00474
00475
00476 float wireCoord = hit->localPosition().y();
00477 float halfL = (layer->specificTopology().cellLenght())/2.;
00478 float propgL = halfL - wireCoord;
00479
00480 float propDelay = propgL/vPropWire;
00481
00482
00483 float tof = hit->tof();
00484
00485
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
00502
00503 void DTDigitizer::storeDigis(DTWireId &wireId,
00504 TDContainer &hits,
00505 DTDigiCollection &output, DTDigiSimLinkCollection &outputLinks){
00506
00507
00508
00509
00510 sort(hits.begin(),hits.end(),hitLessT());
00511
00512
00513
00514 float wakeTime = -999999.0;
00515 float resolTime = -999999.0;
00516 int digiN = -1;
00517 DTDigi digi;
00518
00519
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
00526
00527 float time = (*hit).second;
00528 if ( time > wakeTime ) {
00529
00530 int wireN = wireId.wire();
00531 digiN++;
00532 digi = DTDigi(wireN, time, digiN);
00533
00534
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
00548 if(digi.countsTDC() < pow(2.,16)){
00549 DTLayerId layerID = wireId.layerId();
00550 output.insertDigi(layerID, digi);
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
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
00594 << " trackId = " << hit->trackId() << endl
00595
00596 << " |p| = " << hit->pabs() << endl
00597 << " Energy loss = " << hit->energyLoss() << endl
00598
00599
00600
00601 << " localDirection = " << hit->momentumAtEntry().unit() << endl
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