CMS 3D CMS Logo

MuonDTLocalMillepedeAlgorithm.cc
Go to the documentation of this file.
1 #include <fstream>
2 
3 #include "TFile.h"
4 #include "TTree.h"
5 #include "TKey.h"
6 #include "TMatrixD.h"
7 #include "TF1.h"
8 
9 
12 
13 
18 
19 
22 
35 
38 
39 // Constructor ----------------------------------------------------------------
40 
43 {
44 
45  edm::LogInfo("Alignment") << "[MuonDTLocalMillepedeAlgorithm] constructed.";
46 
47  //Parse parameters. In the future this section should be completed with more options
48  ntuplePath = cfg.getParameter<std::string>( "ntuplePath" );
49  numberOfRootFiles = cfg.getParameter<int>( "numberOfRootFiles" );
50  ptMax = cfg.getParameter<double>( "ptMax" );
51  ptMin = cfg.getParameter<double>( "ptMin" );
52  numberOfSigmasX = cfg.getParameter<double>( "numberOfSigmasX" );
53  numberOfSigmasDXDZ = cfg.getParameter<double>( "numberOfSigmasDXDZ" );
54  numberOfSigmasY = cfg.getParameter<double>( "numberOfSigmasY" );
55  numberOfSigmasDYDZ = cfg.getParameter<double>( "numberOfSigmasDYDZ" );
56  nPhihits = cfg.getParameter<double>( "nPhihits" );
57  nThetahits = cfg.getParameter<double>( "nThetahits" );
58  workingmode = cfg.getParameter<int>( "workingMode" );
59  nMtxSection = cfg.getParameter<int>( "nMtxSection" );
60 
61 
62  //The algorithm has three working modes:
63  //0.- aligment information is extracted from the events and stored in root files
64  //1.- The SLtoSl algorithm
65  //2.- The local MuonMillepede algorithm
66  if(workingmode == 0) {
67  edm::LogInfo("Alignment") << "[MuonDTLocalMillepedeAlgorithm] Running on production mode.";
68  char nameOfFile[200];
69  snprintf(nameOfFile, sizeof(nameOfFile), "%s/MyNtupleResidual.root", ntuplePath.c_str());
70  f = new TFile(nameOfFile, "RECREATE");
71  f->cd();
73  } else if (workingmode == 1) {
74  edm::LogInfo("Alignment") << "[MuonDTLocalMillepedeAlgorithm] Running SLToSL algorithm.";
75  } else {
76  edm::LogInfo("Alignment") << "[MuonDTLocalMillepedeAlgorithm] Running Local Millepede algorithm.";
77  }
78 
79 }
80 
81 
82 
83 
84 // Call at beginning of job ---------------------------------------------------
85 void
89 {
90 
91  // accessor Det->AlignableDet
92  if ( !muon )
94  else if ( !tracker )
96  else
97  theAlignableDetAccessor = new AlignableNavigator(tracker,muon);
98 
99  // set alignmentParameterStore
101 
102  // get alignables
104 
105 }
106 
107 
108 
109 // Call at end of job ---------------------------------------------------------
111 {
112 
113  //If workingmode equals 1 or 2, the algorithms are run before saving.
114  if(workingmode == 1) {
115  edm::LogInfo("Alignment") << "[MuonDTLocalMillepedeAlgorithm] Starting SLToSL algorithm";
117  } else if(workingmode >= 2) {
118  edm::LogInfo("Alignment") << "[MuonDTLocalMillepedeAlgorithm] Starting local MuonMillepede algorithm";
120  }
121 
122  if (workingmode==0) {
123  f->Write();
124  f->Close();
125  }
126 
127 }
128 
129 
130 
131 // Run the algorithm on trajectories and tracks -------------------------------
133 //void MuonDTLocalMillepedeAlgorithm::run( const edm::EventSetup& setup, const ConstTrajTrackPairCollection& tracks)
134 {
135 
136  //Only important in the production mode
137  if(workingmode != 0) return;
138 
140  for( ConstTrajTrackPairCollection::const_iterator it=tracks.begin();
141  it!=tracks.end();it++) {
142 
143  const Trajectory *traj = (*it).first;
144  const reco::Track *track = (*it).second;
145 
146  p = track->p();
147  pt = track->pt();
148  eta = track->eta();
149  phi = track->phi();
150  charge = track->charge();
151 
152 
153  if(pt < ptMin || pt > ptMax) continue;
154 
155  vector<const TransientTrackingRecHit*> hitvec;
156  vector<TrajectoryMeasurement> measurements = traj->measurements();
157 
158  //In this loop the measurements and hits are extracted and put into two vectors
159  int ch_muons = 0;
160  for (vector<TrajectoryMeasurement>::iterator im=measurements.begin();
161  im!=measurements.end(); im++) {
162  TrajectoryMeasurement meas = *im;
163  const TransientTrackingRecHit* hit = &(*meas.recHit());
164  //We are not very strict at this point
165  if (hit->isValid()) {
166  if(hit->det()->geographicalId().det() == 2 && hit->det()->geographicalId().subdetId() == 1) {
167  hitvec.push_back(hit);
168  ch_muons++;
169  }
170  }
171  }
172 
173 
174  vector<const TransientTrackingRecHit*>::const_iterator ihit=hitvec.begin();
175  //Information is stored temporally in the myTrack1D object, which is analyzed
176  //in the build4DSegments method in order to associate hits to segments.
177  int ch_counter = 0;
178  while (ihit != hitvec.end())
179  {
180  const GeomDet* det=(*ihit)->det();
181  if(det->geographicalId().det() == 2) {
182  if(det->geographicalId().subdetId() == 1) {
183  DTLayerId mLayer(det->geographicalId().rawId());
184  DTChamberId mChamber(mLayer.wheel(), mLayer.station(), mLayer.sector());
185  AlignableDet *aliDet = theAlignableDetAccessor->alignableDetFromDetId(mChamber);
186  myTrack1D.wh[ch_counter] = mLayer.wheel();
187  myTrack1D.st[ch_counter] = mLayer.station();
188  myTrack1D.sr[ch_counter] = mLayer.sector();
189  myTrack1D.sl[ch_counter] = mLayer.superlayer();
190  myTrack1D.la[ch_counter] = mLayer.layer();
191  myTrack1D.erx[ch_counter] = (*ihit)->localPositionError().xx();
192  align::GlobalPoint globhit = det->toGlobal((*ihit)->localPosition());
193  align::LocalPoint seghit = aliDet->surface().toLocal(globhit);
194  myTrack1D.xc[ch_counter] = seghit.x();
195  myTrack1D.yc[ch_counter] = seghit.y();
196  myTrack1D.zc[ch_counter] = seghit.z();
197  ch_counter++;
198  }
199  }
200  ihit++;
201  }
202  myTrack1D.nhits = ch_counter;
203  if(build4DSegments()) ttreeOutput->Fill();
204  }
205 
206 }
207 
208 
209 
210 //This method separates the hits depending on the chamber and builds the 4D segments
211 //through linear fits.
212 //It returns true if 4Dsegments were correctly built and false otherwise.
213 //--------------------------------------------------------------------------------------------------------------
215 
216  bool saveThis = false;
217 
218  //Set to 0
219  int id[20][5];
220  int numlayer[20][12];
221  for(int s = 0; s < 20; ++s) {
222  for(int k = 0; k < 5; ++k) id[s][k] = 0;
223  for(int k = 0; k < 12; ++k) numlayer[s][k] = 0;
224  }
225 
226 
227  int nChambers = 0;
228  for(int counter = 0; counter < myTrack1D.nhits; ++counter) {
229  bool isNew = true;
230  for(int counterCham = 0; counterCham < nChambers; counterCham++) {
231  if(myTrack1D.wh[counter] == id[counterCham][0] &&
232  myTrack1D.st[counter] == id[counterCham][1] &&
233  myTrack1D.sr[counter] == id[counterCham][2]) {
234  if(myTrack1D.sl[counter] == 2) {
235  id[counterCham][4]++;
236  } else {
237  id[counterCham][3]++;
238  }
239  for (int ila = 1; ila<=4; ila++)
240  if (myTrack1D.la[counter]==ila) {
241  int jla = (myTrack1D.sl[counter]-1)*4 + ila -1;
242  numlayer[counterCham][jla]++;
243  }
244  isNew = false;
245  }
246  }
247  if(isNew) {
248  id[nChambers][0] = myTrack1D.wh[counter];
249  id[nChambers][1] = myTrack1D.st[counter];
250  id[nChambers][2] = myTrack1D.sr[counter];
251  if(myTrack1D.sl[counter] == 2) {
252  id[nChambers][4]++;
253  } else {
254  id[nChambers][3]++;
255  }
256  for (int ila = 1; ila<=4; ila++)
257  if (myTrack1D.la[counter]==ila) {
258  int jla = (myTrack1D.sl[counter]-1)*4 + ila -1;
259  numlayer[nChambers][jla]++;
260  }
261  nChambers++;
262  }
263  }
264 
265  for (int iseg = 0; iseg<MAX_SEGMENT; iseg++)
266  for (int ihit = 0; ihit<MAX_HIT_CHAM; ihit++) {
267  xc[iseg][ihit] = -250.;
268  yc[iseg][ihit] = -250.;
269  zc[iseg][ihit] = -250.;
270  ex[iseg][ihit] = -250.;
271  xcp[iseg][ihit] = -250.;
272  ycp[iseg][ihit] = -250.;
273  excp[iseg][ihit] = -250.;
274  eycp[iseg][ihit] = -250.;
275  sl[iseg][ihit] = 0;
276  la[iseg][ihit] = 0;
277  }
278 
279  nseg = 0;
280  for(int counter = 0; counter < nChambers; ++counter) {
281 
282  bool GoodPhiChamber = true, GoodThetaChamber = true;
283  for (int ila = 1; ila<=12; ila++) {
284  if (numlayer[counter][ila-1]!=1 && (ila<5 || ila>8)) GoodPhiChamber = false;
285  if (numlayer[counter][ila-1]!=1 && (ila<9 || ila>4) && id[counter][1]!=4) GoodThetaChamber = false;
286  }
287 
288  if(id[counter][3] >= nPhihits && (id[counter][4] >= nThetahits || id[counter][1] == 4) &&
289  GoodPhiChamber && GoodThetaChamber) {
290 
291  TMatrixD phiProjection(2,2);
292  TMatrixD thetaProjection(2,2);
293  TMatrixD bphiProjection(2,1);
294  TMatrixD bthetaProjection(2,1);
295 
296  TMatrixD phiProjectionSL1(2,2);
297  TMatrixD bphiProjectionSL1(2,1);
298  TMatrixD phiProjectionSL3(2,2);
299  TMatrixD bphiProjectionSL3(2,1);
300 
301  float SL1_z_ave = 0;
302  float SL3_z_ave = 0;
303 
304  int numh1 = 0, numh2 = 0, numh3 = 0;
305  for(int counterH = 0; counterH < myTrack1D.nhits; ++counterH) {
306  if(myTrack1D.wh[counterH] == id[counter][0] && myTrack1D.st[counterH] == id[counter][1] &&
307  myTrack1D.sr[counterH] == id[counter][2]) {
308  if(myTrack1D.sl[counterH] == 2) {
309  numh2++;
310  thetaProjection(0,0) += 1.0/myTrack1D.erx[counterH];
311  thetaProjection(0,1) += myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
312  thetaProjection(1,0) += myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
313  thetaProjection(1,1) += myTrack1D.zc[counterH]*myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
314  bthetaProjection(0,0) += myTrack1D.yc[counterH]/myTrack1D.erx[counterH];
315  bthetaProjection(1,0) += myTrack1D.yc[counterH]*myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
316  } else {
317  phiProjection(0,0) += 1.0/myTrack1D.erx[counterH];
318  phiProjection(0,1) += myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
319  phiProjection(1,0) += myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
320  phiProjection(1,1) += myTrack1D.zc[counterH]*myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
321  bphiProjection(0,0) += myTrack1D.xc[counterH]/myTrack1D.erx[counterH];
322  bphiProjection(1,0) += myTrack1D.xc[counterH]*myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
323  if(myTrack1D.sl[counterH] == 1) {
324  numh1++;
325  phiProjectionSL1(0,0) += 1.0/myTrack1D.erx[counterH];
326  phiProjectionSL1(0,1) += myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
327  phiProjectionSL1(1,0) += myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
328  phiProjectionSL1(1,1) += myTrack1D.zc[counterH]*myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
329  bphiProjectionSL1(0,0) += myTrack1D.xc[counterH]/myTrack1D.erx[counterH];
330  bphiProjectionSL1(1,0) += myTrack1D.xc[counterH]*myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
331  SL1_z_ave += myTrack1D.zc[counterH];
332  } else {
333  numh3++;
334  phiProjectionSL3(0,0) += 1.0/myTrack1D.erx[counterH];
335  phiProjectionSL3(0,1) += myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
336  phiProjectionSL3(1,0) += myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
337  phiProjectionSL3(1,1) += myTrack1D.zc[counterH]*myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
338  bphiProjectionSL3(0,0) += myTrack1D.xc[counterH]/myTrack1D.erx[counterH];
339  bphiProjectionSL3(1,0) += myTrack1D.xc[counterH]*myTrack1D.zc[counterH]/myTrack1D.erx[counterH];
340  SL3_z_ave += myTrack1D.zc[counterH];
341  }
342  }
343  }
344  }
345 
346  SL1_z_ave /= 4.0;
347  SL3_z_ave /= 4.0;
348 
349  if (phiProjection(0,0) != 0 && phiProjectionSL1(0,0) != 0 && phiProjectionSL3(0,0) != 0 &&
350  (thetaProjection(0,0) != 0 || id[counter][1] == 4)) {
351 
352  wh[nseg] = id[counter][0];
353  st[nseg] = id[counter][1];
354  sr[nseg] = id[counter][2];
355 
356  if(thetaProjection(0,0) != 0 && id[counter][1] != 4) { // Already asked (almost)
357  thetaProjection.Invert();
358  TMatrixD solution = thetaProjection*bthetaProjection;
359  ySl[nseg] = solution(0,0);
360  dydzSl[nseg] = solution(1,0);
361  eySl[nseg] = thetaProjection(0,0);
362  edydzSl[nseg] = thetaProjection(1,1);
363  eydydzSl[nseg] = thetaProjection(0,1);
364  }
365  phiProjection.Invert();
366  phiProjectionSL1.Invert();
367  phiProjectionSL3.Invert();
368  TMatrixD solution = phiProjection*bphiProjection;
369  TMatrixD solutionSL1 = phiProjectionSL1*bphiProjectionSL1;
370  TMatrixD solutionSL3 = phiProjectionSL3*bphiProjectionSL3;
371  xSl[nseg] = solution(0,0);
372  dxdzSl[nseg] = solution(1,0);
373  exSl[nseg] = phiProjection(0,0);
374  edxdzSl[nseg] = phiProjection(1,1);
375  exdxdzSl[nseg] = phiProjection(0,0);
376  xSlSL1[nseg] = solutionSL1(0,0);
377  dxdzSlSL1[nseg] = solutionSL1(1,0);
378  exSlSL1[nseg] = phiProjectionSL1(0,0);
379  edxdzSlSL1[nseg] = phiProjectionSL1(1,1);
380  exdxdzSlSL1[nseg] = phiProjectionSL1(0,0);
381  xSL1SL3[nseg] = solutionSL1(0,0) + SL3_z_ave * solutionSL1(1,0);
382  xSlSL3[nseg] = solutionSL3(0,0);
383  dxdzSlSL3[nseg] = solutionSL3(1,0);
384  exSlSL3[nseg] = phiProjectionSL3(0,0);
385  edxdzSlSL3[nseg] = phiProjectionSL3(1,1);
386  exdxdzSlSL3[nseg] = phiProjectionSL3(0,0);
387  xSL3SL1[nseg] = solutionSL3(0,0) + SL1_z_ave * solutionSL3(1,0);
388  int hitcounter = 0;
389  for(int counterH = 0; counterH < myTrack1D.nhits; ++counterH) {
390  if(myTrack1D.wh[counterH] == wh[nseg] && myTrack1D.st[counterH] == st[nseg] &&
391  myTrack1D.sr[counterH] == sr[nseg]) {
392  xc[nseg][hitcounter] = myTrack1D.xc[counterH];
393  yc[nseg][hitcounter] = myTrack1D.yc[counterH];
394  zc[nseg][hitcounter] = myTrack1D.zc[counterH];
395  ex[nseg][hitcounter] = myTrack1D.erx[counterH];
396  xcp[nseg][hitcounter] = xSl[nseg]+dxdzSl[nseg]*myTrack1D.zc[counterH];
397  ycp[nseg][hitcounter] = ySl[nseg]+dydzSl[nseg]*myTrack1D.zc[counterH];
398  excp[nseg][hitcounter] = exSl[nseg]*exSl[nseg]+ (edxdzSl[nseg]*edxdzSl[nseg])*myTrack1D.zc[counterH];
399  eycp[nseg][hitcounter] = eySl[nseg]*eySl[nseg]+ (edydzSl[nseg]*edydzSl[nseg])*myTrack1D.zc[counterH];
400  sl[nseg][hitcounter] = myTrack1D.sl[counterH];
401  la[nseg][hitcounter] = myTrack1D.la[counterH];
402  saveThis = true;
403  hitcounter++;
404  }
405  }
406  nphihits[nseg] = id[counter][3];
407  nthetahits[nseg] = id[counter][4];
408  nhits[nseg] = hitcounter;
409  nseg++;
410  }
411  }
412  }
413  return saveThis;
414 }
415 
416 
417 
418 //The tree structure is defined and the variables associated ---------------------------------
420 
421  ttreeOutput = new TTree("InfoTuple", "InfoTuple");
422 
423  ttreeOutput->Branch("p", &p, "p/F");
424  ttreeOutput->Branch("pt", &pt, "pt/F");
425  ttreeOutput->Branch("eta", &eta, "eta/F");
426  ttreeOutput->Branch("phi", &phi, "phi/F");
427  ttreeOutput->Branch("charge", &charge, "charge/F");
428  ttreeOutput->Branch("nseg", &nseg, "nseg/I");
429  ttreeOutput->Branch("nphihits", nphihits, "nphihits[nseg]/I");
430  ttreeOutput->Branch("nthetahits", nthetahits, "nthetahits[nseg]/I");
431  ttreeOutput->Branch("nhits", nhits, "nhits[nseg]/I");
432  ttreeOutput->Branch("xSl", xSl, "xSl[nseg]/F");
433  ttreeOutput->Branch("dxdzSl", dxdzSl, "dxdzSl[nseg]/F");
434  ttreeOutput->Branch("exSl", exSl, "exSl[nseg]/F");
435  ttreeOutput->Branch("edxdzSl", edxdzSl, "edxdzSl[nseg]/F");
436  ttreeOutput->Branch("exdxdzSl", edxdzSl, "exdxdzSl[nseg]/F");
437  ttreeOutput->Branch("ySl", ySl, "ySl[nseg]/F");
438  ttreeOutput->Branch("dydzSl", dydzSl, "dydzSl[nseg]/F");
439  ttreeOutput->Branch("eySl", eySl, "eySl[nseg]/F");
440  ttreeOutput->Branch("edydzSl", edydzSl, "edydzSl[nseg]/F");
441  ttreeOutput->Branch("eydydzSl", eydydzSl, "eydydzSl[nseg]/F");
442  ttreeOutput->Branch("xSlSL1", xSlSL1, "xSlSL1[nseg]/F");
443  ttreeOutput->Branch("dxdzSlSL1", dxdzSlSL1, "dxdzSlSL1[nseg]/F");
444  ttreeOutput->Branch("exSlSL1", exSlSL1, "exSlSL1[nseg]/F");
445  ttreeOutput->Branch("edxdzSlSL1", edxdzSlSL1, "edxdzSlSL1[nseg]/F");
446  ttreeOutput->Branch("xSL1SL3", xSL1SL3, "xSL1SL3[nseg]/F");
447  ttreeOutput->Branch("xSlSL3", xSlSL3, "xSlSL3[nseg]/F");
448  ttreeOutput->Branch("dxdzSlSL3", dxdzSlSL3, "dxdzSlSL3[nseg]/F");
449  ttreeOutput->Branch("exSlSL3", exSlSL3, "exSlSL3[nseg]/F");
450  ttreeOutput->Branch("edxdzSlSL3", edxdzSlSL3, "edxdzSlSL3[nseg]/F");
451  ttreeOutput->Branch("xSL3SL1", xSL3SL1, "xSL3SL1[nseg]/F");
452  ttreeOutput->Branch("xc", xc, "xc[nseg][14]/F");
453  ttreeOutput->Branch("yc", yc, "yc[nseg][14]/F");
454  ttreeOutput->Branch("zc", zc, "zc[nseg][14]/F");
455  ttreeOutput->Branch("ex", ex, "ex[nseg][14]/F");
456  ttreeOutput->Branch("xcp", xcp, "xcp[nseg][14]/F");
457  ttreeOutput->Branch("ycp", ycp, "ycp[nseg][14]/F");
458  ttreeOutput->Branch("excp", excp, "excp[nseg][14]/F");
459  ttreeOutput->Branch("eycp", eycp, "eycp[nseg][14]/F");
460  ttreeOutput->Branch("wh", wh, "wh[nseg]/I");
461  ttreeOutput->Branch("st", st, "st[nseg]/I");
462  ttreeOutput->Branch("sr", sr, "sr[nseg]/I");
463  ttreeOutput->Branch("sl", sl, "sl[nseg][14]/I");
464  ttreeOutput->Branch("la", la, "la[nseg][14]/I");
465 
466 }
467 
468 
470 
double p() const
momentum vector magnitude
Definition: TrackBase.h:615
T getParameter(std::string const &) const
#define MAX_SEGMENT
ConstRecHitPointer const & recHit() const
GlobalPoint toGlobal(const Local2DPoint &lp) const
Conversion to the global R.F. from the R.F. of the GeomDet.
Definition: GeomDet.h:54
constexpr uint32_t rawId() const
get the raw id
Definition: DetId.h:47
T y() const
Definition: PV3DBase.h:63
def setup(process, global_tag, zero_tesla=False)
Definition: GeneralSetup.py:1
double phi() const
azimuthal angle of momentum vector
Definition: TrackBase.h:645
const ConstTrajTrackPairCollection & trajTrackPairs() const
define event information passed to algorithms
DataContainer const & measurements() const
Definition: Trajectory.h:196
double eta() const
pseudorapidity of momentum vector
Definition: TrackBase.h:651
const GeomDet * det() const
void initialize(const edm::EventSetup &setup, AlignableTracker *tracker, AlignableMuon *muon, AlignmentParameterStore *store)
Call at beginning of job.
double pt() const
track transverse momentum
Definition: TrackBase.h:621
T z() const
Definition: PV3DBase.h:64
constexpr int subdetId() const
get the contents of the subdetector field (not cast into any detector&#39;s numbering enum) ...
Definition: DetId.h:41
DetId geographicalId() const
The label of this GeomDet.
Definition: GeomDet.h:79
MuonDTLocalMillepedeAlgorithm(const edm::ParameterSet &cfg)
Constructor.
int k[5][pyjets_maxn]
void run(const edm::EventSetup &setup, const EventInfo &eventInfo)
Run the algorithm on trajectories and tracks.
bool isValid() const
static std::atomic< unsigned int > counter
int charge() const
track electric charge
Definition: TrackBase.h:567
#define DEFINE_EDM_PLUGIN(factory, type, name)
eventInfo
add run, event number and lumi section
#define MAX_HIT_CHAM
Constructor of the full muon geometry.
Definition: AlignableMuon.h:37
T x() const
Definition: PV3DBase.h:62
AlignmentParameterStore * theAlignmentParameterStore
const align::Alignables & alignables(void) const
get all alignables
std::vector< ConstTrajTrackPair > ConstTrajTrackPairCollection
void terminate(void)
Call at end of job.
constexpr Detector det() const
get the detector field from this detid
Definition: DetId.h:39