CMS 3D CMS Logo

MuonSegFit.cc
Go to the documentation of this file.
1 // ------------------------- //
2 // MuonSegFit.cc
3 // Created: 11.05.2015
4 // Based on CSCSegFit.cc
5 // ------------------------- //
6 
9 
12 
13 
14 bool MuonSegFit::fit(void) {
15  if ( fitdone() ) return fitdone_; // don't redo fit unnecessarily
16  short n = nhits();
17  if (n < 2){
18  edm::LogVerbatim("MuonSegFit") << "[MuonSegFit::fit] - cannot fit just 1 hit!!";
19  }
20  else if (n == 2){
21  fit2();
22  }
23  else if (2*n <= MaxHits2){
24  fitlsq();
25  }
26  else {
27  edm::LogVerbatim("MuonSegFit") << "[MuonSegFit::fit] - cannot fit more than "<< MaxHits2/2 <<" hits!!";
28  }
29  return fitdone_;
30 }
31 
32 void MuonSegFit::fit2(void) {
33  // Just join the two points
34  // Equation of straight line between (x1, y1) and (x2, y2) in xy-plane is
35  // y = mx + c
36  // with m = (y2-y1)/(x2-x1)
37  // and c = (y1*x2-x2*y1)/(x2-x1)
38  //
39  // Now we will make two straight lines
40  // one in xz-plane, another in yz-plane
41  // x = uz + c1
42  // y = vz + c2
43  // 1) Check whether hits are on the same layer
44  // should be done before, so removed
45  // -------------------------------------------
46 
47  MuonRecHitContainer::const_iterator ih = hits_.begin();
48  // 2) Global Positions of hit 1 and 2 and
49  // Local Positions of hit 1 and 2 w.r.t. reference GEM Eta Partition
50  // ---------------------------------------------------------------------
51  LocalPoint h1pos = (*ih)->localPosition();
52  ++ih;
53  LocalPoint h2pos = (*ih)->localPosition();
54 
55  // 3) Now make straight line between the two points in local coords
56  // ----------------------------------------------------------------
57  float dz = h2pos.z()-h1pos.z();
58  if(dz != 0.0) {
59  uslope_ = ( h2pos.x() - h1pos.x() ) / dz ;
60  vslope_ = ( h2pos.y() - h1pos.y() ) / dz ;
61  }
62 
63  float uintercept = ( h1pos.x()*h2pos.z() - h2pos.x()*h1pos.z() ) / dz;
64  float vintercept = ( h1pos.y()*h2pos.z() - h2pos.y()*h1pos.z() ) / dz;
65 
66  // calculate local position (variable: intercept_)
67  intercept_ = LocalPoint( uintercept, vintercept, 0.);
68 
69  // calculate the local direction (variable: localdir_)
70  setOutFromIP();
71 
72  //@@ NOT SURE WHAT IS SENSIBLE FOR THESE...
73  chi2_ = 0.;
74  ndof_ = 0;
75 
76  fitdone_ = true;
77 }
78 
79 
80 void MuonSegFit::fitlsq(void) {
81  // Linear least-squares fit to up to 6 GEM rechits, one per layer in a GEM chamber.
82  // Comments adapted from Tim Cox' comments in the original GEMSegAlgoSK algorithm.
83 
84  // Fit to the local x, y rechit coordinates in z projection
85  // The strip measurement controls the precision of x
86  // The wire measurement controls the precision of y.
87  // Typical precision: u (strip, sigma~200um), v (wire, sigma~1cm)
88 
89  // Set up the normal equations for the least-squares fit as a matrix equation
90 
91  // We have a vector of measurements m, which is a 2n x 1 dim matrix
92  // The transpose mT is (u1, v1, u2, v2, ..., un, vn) where
93  // ui is the strip-associated measurement and
94  // vi is the wire-associated measurement
95  // for a given rechit i.
96 
97  // The fit is to
98  // u = u0 + uz * z
99  // v = v0 + vz * z
100  // where u0, uz, v0, vz are the parameters to be obtained from the fit.
101 
102  // These are contained in a vector p which is a 4x1 dim matrix, and
103  // its transpose pT is (u0, v0, uz, vz). Note the ordering!
104 
105  // The covariance matrix for each pair of measurements is 2 x 2 and
106  // the inverse of this is the error matrix E.
107  // The error matrix for the whole set of n measurements is a diagonal
108  // matrix with diagonal elements the individual 2 x 2 error matrices
109  // (because the inverse of a diagonal matrix is a diagonal matrix
110  // with each element the inverse of the original.)
111 
112  // In function 'weightMatrix()', the variable 'matrix' is filled with this
113  // block-diagonal overall covariance matrix. Then 'matrix' is inverted to the
114  // block-diagonal error matrix, and returned.
115 
116  // Define the matrix A as
117  // 1 0 z1 0
118  // 0 1 0 z1
119  // 1 0 z2 0
120  // 0 1 0 z2
121  // .. .. .. ..
122  // 1 0 zn 0
123  // 0 1 0 zn
124 
125  // This matrix A is set up and returned by function 'derivativeMatrix()'.
126 
127  // Then the normal equations are described by the matrix equation
128  //
129  // (AT E A)p = (AT E)m
130  //
131  // where AT is the transpose of A.
132 
133  // Call the combined matrix on the LHS, M, and that on the RHS, B:
134  // M p = B
135 
136  // We solve this for the parameter vector, p.
137  // The elements of M and B then involve sums over the hits
138 
139  // The covariance matrix of the parameters is obtained by
140  // (AT E A)^-1 calculated in 'covarianceMatrix()'.
141 
142  SMatrix4 M; // 4x4, init to 0
143  SVector4 B; // 4x1, init to 0;
144 
145  MuonRecHitContainer::const_iterator ih = hits_.begin();
146 
147  // Loop over the GEMRecHits and make small (2x2) matrices used to fill the blockdiagonal covariance matrix E^-1
148  for (ih = hits_.begin(); ih != hits_.end(); ++ih) {
149  LocalPoint lp = (*ih)->localPosition();
150  // Local position of hit w.r.t. chamber
151  double u = lp.x();
152  double v = lp.y();
153  double z = lp.z();
154 
155  // Covariance matrix of local errors
156  SMatrixSym2 IC; // 2x2, init to 0
157 
158  IC(0,0) = (*ih)->localPositionError().xx();
159  IC(1,1) = (*ih)->localPositionError().yy();
160  //@@ NOT SURE WHICH OFF-DIAGONAL ELEMENT MUST BE DEFINED BUT (1,0) WORKS
161  //@@ (and SMatrix enforces symmetry)
162  IC(1,0) = (*ih)->localPositionError().xy();
163  // IC(0,1) = IC(1,0);
164 
165 #ifdef EDM_ML_DEBUG
166  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::fit] 2x2 covariance matrix for this GEMRecHit :: [[" << IC(0,0) <<", "<< IC(0,1) <<"]["<< IC(1,0) <<","<<IC(1,1)<<"]]";
167 #endif
168 
169  // Invert covariance matrix (and trap if it fails!)
170  bool ok = IC.Invert();
171  if ( !ok ) {
172  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::fit] Failed to invert covariance matrix: \n" << IC;
173  // return ok; //@@ SHOULD PASS THIS BACK TO CALLER?
174  }
175 
176  M(0,0) += IC(0,0);
177  M(0,1) += IC(0,1);
178  M(0,2) += IC(0,0) * z;
179  M(0,3) += IC(0,1) * z;
180  B(0) += u * IC(0,0) + v * IC(0,1);
181 
182  M(1,0) += IC(1,0);
183  M(1,1) += IC(1,1);
184  M(1,2) += IC(1,0) * z;
185  M(1,3) += IC(1,1) * z;
186  B(1) += u * IC(1,0) + v * IC(1,1);
187 
188  M(2,0) += IC(0,0) * z;
189  M(2,1) += IC(0,1) * z;
190  M(2,2) += IC(0,0) * z * z;
191  M(2,3) += IC(0,1) * z * z;
192  B(2) += ( u * IC(0,0) + v * IC(0,1) ) * z;
193 
194  M(3,0) += IC(1,0) * z;
195  M(3,1) += IC(1,1) * z;
196  M(3,2) += IC(1,0) * z * z;
197  M(3,3) += IC(1,1) * z * z;
198  B(3) += ( u * IC(1,0) + v * IC(1,1) ) * z;
199 
200  }
201 
202  SVector4 p;
203  bool ok = M.Invert();
204  if (!ok ){
205  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::fit] Failed to invert matrix: \n" << M;
206  // return ok; //@@ SHOULD PASS THIS BACK TO CALLER?
207  }
208  else {
209  p = M * B;
210  }
211 
212 #ifdef EDM_ML_DEBUG
213  LogTrace("MuonSegFitMatrixDetails") << "[MuonSegFit::fit] p = "
214  << p(0) << ", " << p(1) << ", " << p(2) << ", " << p(3);
215 #endif
216 
217  // fill member variables (note origin has local z = 0)
218  // intercept_
219  intercept_ = LocalPoint(p(0), p(1), 0.);
220 
221  // localdir_ - set so segment points outwards from IP
222  uslope_ = p(2);
223  vslope_ = p(3);
224  setOutFromIP();
225 
226  // calculate chi2 of fit
227  setChi2( );
228 
229  // flag fit has been done
230  fitdone_ = true;
231 }
232 
233 
234 
236 
237  double chsq = 0.;
238 
239  MuonRecHitContainer::const_iterator ih;
240 
241  for (ih = hits_.begin(); ih != hits_.end(); ++ih) {
242  LocalPoint lp = (*ih)->localPosition();
243 
244  double u = lp.x();
245  double v = lp.y();
246  double z = lp.z();
247 
248  double du = intercept_.x() + uslope_ * z - u;
249  double dv = intercept_.y() + vslope_ * z - v;
250 
251  SMatrixSym2 IC; // 2x2, init to 0
252 
253  IC(0,0) = (*ih)->localPositionError().xx();
254  // IC(0,1) = (*ih)->localPositionError().xy();
255  IC(1,0) = (*ih)->localPositionError().xy();
256  IC(1,1) = (*ih)->localPositionError().yy();
257  // IC(1,0) = IC(0,1);
258 
259 #ifdef EDM_ML_DEBUG
260  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::setChi2] IC before = \n" << IC;
261 #endif
262 
263  // Invert covariance matrix
264  bool ok = IC.Invert();
265  if (!ok ){
266  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::setChi2] Failed to invert covariance matrix: \n" << IC;
267  // return ok;
268  }
269  chsq += du*du*IC(0,0) + 2.*du*dv*IC(0,1) + dv*dv*IC(1,1);
270 
271 #ifdef EDM_ML_DEBUG
272  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::setChi2] IC after = \n" << IC;
273  edm::LogVerbatim("MuonSegFit") << "[GEM RecHit ] Contribution to Chi^2 of this hit :: du^2*Cov(0,0) + 2*du*dv*Cov(0,1) + dv^2*IC(1,1) = "<<du*du<<"*"<<IC(0,0)<<" + 2.*"<<du<<"*"<<dv<<"*"<<IC(0,1)<<" + "<<dv*dv<<"*"<<IC(1,1)<<" = "<<chsq;
274 #endif
275  }
276 
277  // fill member variables
278  chi2_ = chsq;
279  ndof_ = 2.*hits_.size() - 4;
280 
281 #ifdef EDM_ML_DEBUG
282  edm::LogVerbatim("MuonSegFit") << "[MuonSegFit::setChi2] chi2/ndof = " << chi2_ << "/" << ndof_ ;
283  edm::LogVerbatim("MuonSegFit") << "-----------------------------------------------------";
284 
285  // check fit quality ... maybe write a separate function later on
286  // that is there only for debugging issues
287 
288  edm::LogVerbatim("MuonSegFit") << "[GEM Segment with Local Direction = "<<localdir_<<" and Local Position "<<intercept_<<"] can be written as:";
289  edm::LogVerbatim("MuonSegFit") << "[ x ] = "<<localdir_.x()<<" * t + "<<intercept_.x();
290  edm::LogVerbatim("MuonSegFit") << "[ y ] = "<<localdir_.y()<<" * t + "<<intercept_.y();
291  edm::LogVerbatim("MuonSegFit") << "[ z ] = "<<localdir_.z()<<" * t + "<<intercept_.z();
292  edm::LogVerbatim("MuonSegFit") << "Now extrapolate to each of the GEMRecHits XY plane (so constant z = RH LP.z()) to obtain [x1,y1]";
293 #endif
294 }
295 
297 
298  bool ok = true;
299 
300  SMatrixSym12 matrix = ROOT::Math::SMatrixIdentity(); // 12x12, init to 1's on diag
301 
302  int row = 0;
303 
304  for (MuonRecHitContainer::const_iterator it = hits_.begin(); it != hits_.end(); ++it) {
305  // Note scaleXError allows rescaling the x error if necessary
306  matrix(row, row) = scaleXError()*(*it)->localPositionError().xx();
307  matrix(row, row+1) = (*it)->localPositionError().xy();
308  ++row;
309  matrix(row, row-1) = (*it)->localPositionError().xy();
310  matrix(row, row) = (*it)->localPositionError().yy();
311  ++row;
312  }
313 
314  ok = matrix.Invert(); // invert in place
315  if ( !ok ) {
316  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::weightMatrix] Failed to invert matrix: \n" << matrix;
317  // return ok; //@@ SHOULD PASS THIS BACK TO CALLER?
318  }
319  return matrix;
320 }
321 
322 
324 
325  SMatrix12by4 matrix; // 12x4, init to 0
326  int row = 0;
327 
328  for( MuonRecHitContainer::const_iterator it = hits_.begin(); it != hits_.end(); ++it) {
329  LocalPoint lp = (*it)->localPosition();
330 
331  float z = lp.z();
332 
333  matrix(row, 0) = 1.;
334  matrix(row, 2) = z;
335  ++row;
336  matrix(row, 1) = 1.;
337  matrix(row, 3) = z;
338  ++row;
339  }
340  return matrix;
341 }
342 
343 
345  // Set direction of segment to point from IP outwards
346  // (Incorrect for particles not coming from IP, of course.)
347 
348  double dxdz = uslope_;
349  double dydz = vslope_;
350  double dz = 1./sqrt(1. + dxdz*dxdz + dydz*dydz);
351  double dx = dz*dxdz;
352  double dy = dz*dydz;
353  LocalVector localDir(dx,dy,dz);
354 
355  localdir_ = ( localDir ).unit();
356 #ifdef EDM_ML_DEBUG
357  edm::LogVerbatim("MuonSegFit") << "[MuonSegFit::setOutFromIP] :: dxdz = uslope_ = "<<std::setw(9)<<uslope_<<" dydz = vslope_ = "<<std::setw(9)<<vslope_<<" local dir = "<<localDir;
358  edm::LogVerbatim("MuonSegFit") << "[MuonSegFit::setOutFromIP] :: ==> local dir = "<<localdir_<< " localdir.phi = "<<localdir_.phi();
359 #endif
360 }
361 
362 
363 
365 
368 #ifdef EDM_ML_DEBUG
369  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::covarianceMatrix] weights matrix W: \n" << weights;
370  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::covarianceMatrix] derivatives matrix A: \n" << A;
371 #endif
372 
373  // (AT W A)^-1
374  // e.g. See http://www.phys.ufl.edu/~avery/fitting.html, part I
375 
376  bool ok;
377  SMatrixSym4 result = ROOT::Math::SimilarityT(A, weights);
378 #ifdef EDM_ML_DEBUG
379  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::covarianceMatrix] (AT W A): \n" << result;
380 #endif
381 
382  ok = result.Invert(); // inverts in place
383  if ( !ok ) {
384  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::calculateError] Failed to invert matrix: \n" << result;
385  // return ok; //@@ SHOULD PASS THIS BACK TO CALLER?
386  }
387 #ifdef EDM_ML_DEBUG
388  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::covarianceMatrix] (AT W A)^-1: \n" << result;
389 #endif
390 
391  // reorder components to match TrackingRecHit interface (GEMSegment isa TrackingRecHit)
392  // i.e. slopes first, then positions
393  AlgebraicSymMatrix flipped = flipErrors( result );
394 
395  return flipped;
396 }
397 
398 
400 
401  // The GEMSegment needs the error matrix re-arranged to match
402  // parameters in order (uz, vz, u0, v0)
403  // where uz, vz = slopes, u0, v0 = intercepts
404 
405 #ifdef EDM_ML_DEBUG
406  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::flipErrors] input: \n" << a;
407 #endif
408 
409  AlgebraicSymMatrix hold(4, 0. );
410 
411  for ( short j=0; j!=4; ++j) {
412  for (short i=0; i!=4; ++i) {
413  hold(i+1,j+1) = a(i,j); // SMatrix counts from 0, AlgebraicMatrix from 1
414  }
415  }
416 
417 #ifdef EDM_ML_DEBUG
418  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::flipErrors] after copy:";
419  edm::LogVerbatim("MuonSegFitMatrixDetails") << "(" << hold(1,1) << " " << hold(1,2) << " " << hold(1,3) << " " << hold(1,4);
420  edm::LogVerbatim("MuonSegFitMatrixDetails") << " " << hold(2,1) << " " << hold(2,2) << " " << hold(2,3) << " " << hold(2,4);
421  edm::LogVerbatim("MuonSegFitMatrixDetails") << " " << hold(3,1) << " " << hold(3,2) << " " << hold(3,3) << " " << hold(3,4);
422  edm::LogVerbatim("MuonSegFitMatrixDetails") << " " << hold(4,1) << " " << hold(4,2) << " " << hold(4,3) << " " << hold(4,4) << ")";
423 #endif
424 
425  // errors on slopes into upper left
426  hold(1,1) = a(2,2);
427  hold(1,2) = a(2,3);
428  hold(2,1) = a(3,2);
429  hold(2,2) = a(3,3);
430 
431  // errors on positions into lower right
432  hold(3,3) = a(0,0);
433  hold(3,4) = a(0,1);
434  hold(4,3) = a(1,0);
435  hold(4,4) = a(1,1);
436 
437  // must also interchange off-diagonal elements of off-diagonal 2x2 submatrices
438  hold(4,1) = a(1,2);
439  hold(3,2) = a(0,3);
440  hold(2,3) = a(3,0); // = a(0,3)
441  hold(1,4) = a(2,1); // = a(1,2)
442 
443 #ifdef EDM_ML_DEBUG
444  edm::LogVerbatim("MuonSegFitMatrixDetails") << "[MuonSegFit::flipErrors] after flip:";
445  edm::LogVerbatim("MuonSegFitMatrixDetails") << "(" << hold(1,1) << " " << hold(1,2) << " " << hold(1,3) << " " << hold(1,4);
446  edm::LogVerbatim("MuonSegFitMatrixDetails") << " " << hold(2,1) << " " << hold(2,2) << " " << hold(2,3) << " " << hold(2,4);
447  edm::LogVerbatim("MuonSegFitMatrixDetails") << " " << hold(3,1) << " " << hold(3,2) << " " << hold(3,3) << " " << hold(3,4);
448  edm::LogVerbatim("MuonSegFitMatrixDetails") << " " << hold(4,1) << " " << hold(4,2) << " " << hold(4,3) << " " << hold(4,4) << ")";
449 #endif
450 
451  return hold;
452 }
453 
454 float MuonSegFit::xfit( float z ) const {
455  //@@ ADD THIS TO EACH ACCESSOR OF FIT RESULTS?
456  // if ( !fitdone() ) fit();
457  return intercept_.x() + uslope_ * z;
458 }
459 
460 float MuonSegFit::yfit( float z ) const {
461  return intercept_.y() + vslope_ * z;
462 }
463 
464 float MuonSegFit::xdev( float x, float z ) const {
465  return intercept_.x() + uslope_ * z - x;
466 }
467 
468 float MuonSegFit::ydev( float y, float z ) const {
469  return intercept_.y() + vslope_ * z - y;
470 }
471 
472 float MuonSegFit::Rdev(float x, float y, float z) const {
473  return sqrt ( xdev(x,z)*xdev(x,z) + ydev(y,z)*ydev(y,z) );
474 }
475 
static const int MaxHits2
Definition: MuonSegFit.h:44
AlgebraicSymMatrix covarianceMatrix(void)
Definition: MuonSegFit.cc:364
double scaleXError(void) const
Definition: MuonSegFit.h:91
LocalVector localdir_
Definition: MuonSegFit.h:125
Point3DBase< Scalar, LocalTag > LocalPoint
Definition: Definitions.h:32
double chi2_
Definition: MuonSegFit.h:126
float ydev(float y, float z) const
Definition: MuonSegFit.cc:468
float xfit(float z) const
Definition: MuonSegFit.cc:454
void fitlsq(void)
Definition: MuonSegFit.cc:80
ROOT::Math::SMatrix< double, 4, 4, ROOT::Math::MatRepSym< double, 4 > > SMatrixSym4
Definition: MuonSegFit.h:53
SMatrixSym12 weightMatrix(void)
Definition: MuonSegFit.cc:296
SMatrix12by4 derivativeMatrix(void)
Definition: MuonSegFit.cc:323
LocalPoint intercept_
Definition: MuonSegFit.h:124
float uslope_
Definition: MuonSegFit.h:122
float Rdev(float x, float y, float z) const
Definition: MuonSegFit.cc:472
double_binary B
Definition: DDStreamer.cc:248
Geom::Phi< T > phi() const
Definition: PV3DBase.h:69
T y() const
Definition: PV3DBase.h:63
ROOT::Math::SMatrix< double, MaxHits2, MaxHits2, ROOT::Math::MatRepSym< double, MaxHits2 > > SMatrixSym12
Definition: MuonSegFit.h:46
float xdev(float x, float z) const
Definition: MuonSegFit.cc:464
float vslope_
Definition: MuonSegFit.h:123
void setChi2(void)
Definition: MuonSegFit.cc:235
T sqrt(T t)
Definition: SSEVec.h:18
T z() const
Definition: PV3DBase.h:64
void setOutFromIP(void)
Definition: MuonSegFit.cc:344
bool fitdone() const
Definition: MuonSegFit.h:97
#define LogTrace(id)
void fit2(void)
Definition: MuonSegFit.cc:32
bool fitdone_
Definition: MuonSegFit.h:129
AlgebraicSymMatrix flipErrors(const SMatrixSym4 &)
Definition: MuonSegFit.cc:399
float yfit(float z) const
Definition: MuonSegFit.cc:460
MuonRecHitContainer hits_
Definition: MuonSegFit.h:121
ROOT::Math::SMatrix< double, 2, 2, ROOT::Math::MatRepSym< double, 2 > > SMatrixSym2
Definition: MuonSegFit.h:56
double a
Definition: hdecay.h:121
CLHEP::HepSymMatrix AlgebraicSymMatrix
ROOT::Math::SVector< double, 4 > SVector4
Definition: MuonSegFit.h:59
size_t nhits(void) const
Definition: MuonSegFit.h:92
T x() const
Definition: PV3DBase.h:62
ROOT::Math::SMatrix< double, 4 > SMatrix4
Definition: MuonSegFit.h:52
ROOT::Math::SMatrix< double, MaxHits2, 4 > SMatrix12by4
Definition: MuonSegFit.h:49
bool fit(void)
Definition: MuonSegFit.cc:14