ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitCommon/VertexFit/src/MultiVertexFitterD.cc
Revision: 1.2
Committed: Fri Mar 20 13:33:03 2009 UTC (16 years, 1 month ago) by loizides
Content type: text/plain
Branch: MAIN
CVS Tags: Mit_011, Mit_010a, Mit_010, Mit_009c, Mit_009b, Mit_009a, Mit_009, Mit_008
Changes since 1.1: +71 -60 lines
Log Message:
Cleanup

File Contents

# Content
1 // $Id: MultiVertexFitterD.cc,v 1.1 2008/11/13 16:34:29 paus Exp $
2
3 #include "MitCommon/VertexFit/interface/MultiVertexFitterD.h"
4 #include <algorithm>
5 #include <math.h>
6 #include <iostream>
7 #include <csignal>
8 #include <csetjmp>
9 #include <TMath.h>
10 #include <CLHEP/Matrix/Matrix.h>
11
12 extern "C" void dctvmft_(int&, int&, int&);
13 extern "C" bool dmcalc_ (int&, int*, float&, float&, double*);
14 extern "C" void ddcalc_ (int&, int&, float*, float&, float&, float*);
15
16 using namespace std;
17 using namespace mithep;
18
19 jmp_buf denv;
20
21 //--------------------------------------------------------------------------------------------------
22 extern "C" void MultiVertexFitterDSetStatus(int i) {
23 cout << "Warning, you are handling a severe error in MultiVertexFitterD" << endl;
24 longjmp(denv,-66);
25 }
26
27 //--------------------------------------------------------------------------------------------------
28 MultiVertexFitterD::MultiVertexFitterD() :
29 _bField (3.8), // default B field for running
30 _currentAllocatedVertexNumber(0), // facilitates CandNode recursion
31 _referencePoint (0,0,0), // set reference point to (0,0,0) initially
32 _primaryVertex (0,0,0), // set primary vertex to (0,0,0) initially
33 _cdfPrimaryVertex (0,0,0) // set pv in CMS coords to (0,0,0) initially
34 {
35 // Set name and email of MultiVertexFitterD expert
36 _expert="Christoph Paus (paus@mit.edu)";
37
38 // First get pointers to various FORTAN common blocks
39 _ctvmq_com = (CTVMQ*) dctvmq_address_(); //printf(" Common: _ctvmq_com %p\n", _ctvmq_com );
40 _ctvmfr_com = (CTVMFR*) dctvmfr_address_(); //printf(" Common: _ctvmfr_com %p\n", _ctvmfr_com);
41 _fiddle_com = (FIDDLE*) dfiddle_address_(); //printf(" Common: _fiddle_com %p\n", _fiddle_com);
42 _trkprm_com = (TRKPRM*) dtrkprm_address_(); //printf(" Common: _trkprm_com %p\n", _trkprm_com);
43
44 // Initialize various arrays
45 init();
46 // Don't bomb program on error.
47 _fiddle.excuse = 1;
48 // Don't extrapolate track errors by default
49 _extrapolateTrackErrors = false;
50 }
51
52 //--------------------------------------------------------------------------------------------------
53 void MultiVertexFitterD::init(double bField)
54 {
55 // Set internal variable which keeps track of the b field
56 _bField = bField;
57
58 // Now initialize CTVMQ common. Run and trigger numbers are dummies - they are not used.
59 _ctvmq.runnum = 1;
60 _ctvmq.trgnum = 100;
61 // Eventually, we have to get the magnetic field from the right place.
62 // Origignal with bmag = 14.116 [kGauss]:
63 // _ctvmq.pscale = 0.000149896 * bmag;
64 // New bfield in Tesla bmag = 1.4116 [T]:
65 _ctvmq.pscale = 0.00149896 * bField;
66 // Set the default maximum chi-square per dof.
67 _fiddle.chisqmax = 225.0;
68 // We also need to get the primary vertex from the right place, but for now we put in (0,0,0).
69 setPrimaryVertex(0.0,0.0,0.0);
70 float xverr[3][3];
71 for (int j = 0; j<3; j++) {
72 for (int k = 0; k<3; k++) {
73 xverr[j][k] = 0.;
74 }
75 }
76 xverr[0][0] = 0.005;
77 xverr[1][1] = 0.005;
78 xverr[2][2] = 1.0;
79 setPrimaryVertexError(xverr);
80 // Zero number of tracks, vertices and mass constraints
81 _ctvmq.ntrack = 0;
82 _ctvmq.nvertx = 0;
83 _ctvmq.nmassc = 0;
84 // Zero track list and arrays containing the vertex and mass constraint configuration
85 for (int j=0; j<_maxtrk; ++j) {
86 _ctvmq.list[j]=0;
87 for (int jv=0; jv<_maxvtx; ++jv)
88 _ctvmq.trkvtx[jv][j] = false;
89 for (int jmc=0; jmc<_maxmcn; ++jmc)
90 _ctvmq.trkmcn[jmc][j] = false;
91 }
92 // Initialize the conversion and vertex pointing arrays
93 for (int jv=0; jv<_maxvtx; ++jv) {
94 _ctvmq.cvtx[jv] = 0;
95 _ctvmq.vtxpnt[0][jv] = -1;
96 _ctvmq.vtxpnt[1][jv] = 0;
97 }
98 _ctvmq.drmax = 2.0;
99 _ctvmq.dzmax = 20.0;
100 _ctvmq.rvmax = 70.0;
101 _ctvmq.trnmax = 0.5;
102 _ctvmq.dsmin = -100.0; // for CDF used -2, for CMS fuzzing around.
103 // Set _stat to -999 and chisqq to -1 to symbolize that no fit has yet been done.
104 _stat = -999;
105 _ctvmq.chisqr[0] = -1.0;
106
107 _primaryVertex = Hep3Vector(0,0,0);
108 _cdfPrimaryVertex = Hep3Vector(0,0,0);
109 _referencePoint = ThreeVector(0,0,0);
110 }
111
112 //--------------------------------------------------------------------------------------------------
113 bool MultiVertexFitterD::addTrack(const HepVector &v, const HepSymMatrix &cov,
114 int trackId, float mass, vertexNumber jv)
115 {
116 // Check that this vertex number is within the allowed range.
117 if (jv<VERTEX_1 || jv>_maxvtx)
118 return false;
119 _ctvmq.nvertx = jv>_ctvmq.nvertx ? jv : _ctvmq.nvertx;
120
121 // Add track extrapolation, if the user set it
122 HepVector w = v;
123 HepSymMatrix m = cov;
124 //if (_extrapolateTrackErrors)
125 // // This will move the reference point
126 // moveReferencePoint(w, m);
127
128 // Check that we have not exceeded the maximum number of tracks.
129 if (_ctvmq.ntrack>=_maxtrk)
130 return false;
131
132 // Add this track
133 _ctvmq.list [_ctvmq.ntrack] = trackId;
134 _ctvmq.tkbank[_ctvmq.ntrack][0] = 'Q';
135 _ctvmq.tkbank[_ctvmq.ntrack][1] = 'T';
136 _ctvmq.tkbank[_ctvmq.ntrack][2] = 'R';
137 _ctvmq.tkbank[_ctvmq.ntrack][3] = 'K';
138 _ctvmq.tmass [_ctvmq.ntrack] = mass;
139 _ctvmq.trkvtx[jv-1][_ctvmq.ntrack] = true;
140
141 // Put this track's helix parameters and error matrix into a fortran common block so that they
142 // can be accessed by gettrk. This is a dummy for now.
143 _trkprm.trhelix[_ctvmq.ntrack][0] = w[0];
144 _trkprm.trhelix[_ctvmq.ntrack][1] = w[1];
145 _trkprm.trhelix[_ctvmq.ntrack][2] = w[2];
146 _trkprm.trhelix[_ctvmq.ntrack][3] = w[3];
147 _trkprm.trhelix[_ctvmq.ntrack][4] = w[4];
148
149 for (int j=0; j<5; ++j) {
150 for (int k=0; k<5; ++k)
151 _trkprm.trem[_ctvmq.ntrack][j][k]=m[j][k];
152 }
153 _ctvmq.ntrack++;
154
155 return true;
156 }
157
158 //--------------------------------------------------------------------------------------------------
159 bool MultiVertexFitterD::addTrack(const TVectorD &v, const TMatrixDSym &cov,
160 int trackId, double mass, vertexNumber jv)
161 {
162 // Check that this vertex number is within the allowed range.
163 if (jv<VERTEX_1 || jv>_maxvtx)
164 return false;
165 _ctvmq.nvertx = jv>_ctvmq.nvertx ? jv : _ctvmq.nvertx;
166
167 //// Add track extrapolation, if the user set it
168 //HepVector w = v;
169 //HepSymMatrix m = cov;
170 TVectorD w(v);
171 TMatrixDSym m(cov);
172 ////if (_extrapolateTrackErrors)
173 //// // This will move the reference point
174 //// moveReferencePoint(w, m);
175
176 // Check that we have not exceeded the maximum number of tracks.
177 if (_ctvmq.ntrack>=_maxtrk)
178 return false;
179
180 // Add this track
181 _ctvmq.list [_ctvmq.ntrack] = trackId;
182 _ctvmq.tkbank[_ctvmq.ntrack][0] = 'Q';
183 _ctvmq.tkbank[_ctvmq.ntrack][1] = 'T';
184 _ctvmq.tkbank[_ctvmq.ntrack][2] = 'R';
185 _ctvmq.tkbank[_ctvmq.ntrack][3] = 'K';
186 _ctvmq.tmass [_ctvmq.ntrack] = mass;
187 _ctvmq.trkvtx[jv-1][_ctvmq.ntrack] = true;
188
189 // Put this track's helix parameters and error matrix into a fortran common block so that they
190 // can be accessed by gettrk. This is a dummy for now.
191 _trkprm.trhelix[_ctvmq.ntrack][0] = w[0];
192 _trkprm.trhelix[_ctvmq.ntrack][1] = w[1];
193 _trkprm.trhelix[_ctvmq.ntrack][2] = w[2];
194 _trkprm.trhelix[_ctvmq.ntrack][3] = w[3];
195 _trkprm.trhelix[_ctvmq.ntrack][4] = w[4];
196
197 for (int j=0; j<5; ++j) {
198 for (int k=0; k<5; ++k)
199 _trkprm.trem[_ctvmq.ntrack][j][k]=m[j][k];
200 }
201 _ctvmq.ntrack++;
202
203 return true;
204 }
205
206 //--------------------------------------------------------------------------------------------------
207 bool MultiVertexFitterD::vertexPoint_2d(vertexNumber jv1, vertexNumber jv2)
208 {
209 // Check that these vertex numbers are within allowed range and that the vertices are unique.
210 if (jv1>_maxvtx || jv1<VERTEX_1)
211 return false;
212 if (jv2>_maxvtx || jv2<PRIMARY_VERTEX)
213 return false;
214 if (jv1 <= jv2)
215 return false;
216
217 // Setup vertex pointing.
218 _ctvmq.vtxpnt[0][jv1-1] = jv2;
219 _ctvmq.vtxpnt[1][jv1-1] = 1; // 2d pointing.
220
221 return true;
222 }
223
224 //--------------------------------------------------------------------------------------------------
225 bool MultiVertexFitterD::vertexPoint_3d(vertexNumber jv1, vertexNumber jv2)
226 {
227 // Check that these vertex numbers are within allowed range and that the vertices are distinct
228 if (jv1>_maxvtx || jv1<VERTEX_1)
229 return false;
230 if (jv2>_maxvtx || jv2<PRIMARY_VERTEX)
231 return false;
232 if (jv1 <= jv2)
233 return false;
234
235 // Setup vertex pointing
236 _ctvmq.vtxpnt[0][jv1-1] = jv2;
237 _ctvmq.vtxpnt[1][jv1-1] = 2; // 3d pointing
238
239 return true;
240 }
241
242 //--------------------------------------------------------------------------------------------------
243 bool MultiVertexFitterD::vertexPoint_1track(vertexNumber jv1, vertexNumber jv2)
244 {
245 // Check that these vertex numbers are within allowed range and are distinct
246 if (jv1>_maxvtx || jv1<VERTEX_1)
247 return false;
248 if (jv2>_maxvtx || jv2<PRIMARY_VERTEX)
249 return false;
250 if (jv1 <= jv2)
251 return false;
252
253 // Setup vertex pointing
254 _ctvmq.vtxpnt[0][jv1-1] = jv2;
255 _ctvmq.vtxpnt[1][jv1-1] = 3; // Point to 1 track vertex
256
257 return true;
258 }
259
260 //--------------------------------------------------------------------------------------------------
261 bool MultiVertexFitterD::vertexPoint_0track(vertexNumber jv1, vertexNumber jv2)
262 {
263 // jv2 is the zero track vertex. jv1 is the multi track vertex which points to jv2
264
265 // Note: You must call this routine at least twice in order for ctvmft_zerotrackvtx to work ie
266 // there must be at least 2 vertices pointed at a zero track vertex. ctvmft for this, but the
267 // error message may not make it to your log file (look at the local variables in the stack frame
268 // especially IJKERR(2). The significance of this error code is documented at the top of whatever
269 // routine chucked you out (ctvmf00 in this case)
270
271 // see ctvmft.f source file for discussion. See especially comments at the top of subroutines:
272 // ctvmft and ctvmfa
273
274 // Check that these vertex numbers are within allowed range and are distinct.
275 if (jv1>_maxvtx || jv1<VERTEX_1)
276 return false;
277 if (jv2>_maxvtx || jv2<PRIMARY_VERTEX)
278 return false;
279 if (jv1 <= jv2)
280 return false;
281
282 // Setup vertex pointing.
283 _ctvmq.vtxpnt[0][jv1-1] = jv2;
284 _ctvmq.vtxpnt[1][jv1-1] = 4; // Point to 0 track vertex.
285
286 return true;
287 }
288
289 //--------------------------------------------------------------------------------------------------
290 bool MultiVertexFitterD::conversion_2d(vertexNumber jv)
291 {
292 if (jv<VERTEX_1 || jv>_ctvmq.nvertx)
293 return false;
294
295 _ctvmq.cvtx[jv-1] = 1;
296
297 return true;
298 }
299
300 //--------------------------------------------------------------------------------------------------
301 bool MultiVertexFitterD::conversion_3d(vertexNumber jv)
302 {
303 if (jv<VERTEX_1 || jv>_ctvmq.nvertx)
304 return false;
305
306 _ctvmq.cvtx[jv-1] = 2;
307
308 return true;
309 }
310
311 //--------------------------------------------------------------------------------------------------
312 bool MultiVertexFitterD::massConstrain(int ntrk, const int trkIds[], float mass)
313 {
314 // Check that we have not exceeded the allowed number of mass constraints.
315 if (_ctvmq.nmassc>=_maxmcn)
316 return false;
317
318 // Set constraint mass
319 _ctvmq.cmass[_ctvmq.nmassc]=mass;
320
321 // For each track in contraint, set trkmcn true. Since the number in tracks[] is the track
322 // number, we have to find each track in the list of tracks.
323 for (int jt=0; jt<ntrk; ++jt) {
324 bool found=false;
325 for (int kt=0; kt<_ctvmq.ntrack; ++kt) {
326 if (trkIds[jt] == _ctvmq.list[kt]) {
327 _ctvmq.trkmcn[_ctvmq.nmassc][kt]=true;
328 found=true;
329 }
330 }
331 if (!found)
332 return false;
333 }
334
335 // Increment number of mass constraints.
336 _ctvmq.nmassc++;
337
338 return true;
339 }
340
341 //--------------------------------------------------------------------------------------------------
342 bool MultiVertexFitterD::beamlineConstraint(float xb, float yb, HepSymMatrix berr,
343 float xzbslope, float yzbslope)
344 {
345 // Set beam position at z=0
346 setPrimaryVertex(xb,yb,0);
347 //if (_extrapolateTrackErrors) {
348 // float newXb = xb - _referencePoint.x() + _referencePoint.z() * xzbslope;
349 // float newYb = yb - _referencePoint.y() + _referencePoint.z() * yzbslope;
350 // setPrimaryVertex(newXb, newYb, 0);
351 //}
352
353 bool success = setPrimaryVertexError(berr);
354
355 // Set the beamline slope values
356 _ctvmq.xzslope = xzbslope;
357 _ctvmq.yzslope = yzbslope;
358
359 // Turn ON beamline constraint
360 _ctvmq.vtxpnt[0][0] = -100;
361
362 return success;
363 }
364
365 //--------------------------------------------------------------------------------------------------
366 bool MultiVertexFitterD::beamlineConstraint(Hep3Vector pv, HepSymMatrix berr, float xzbslope,
367 float yzbslope)
368 {
369 // Check if input beam position coordinates are at z=0
370 if (pv.z() != 0)
371 return false;
372
373 return beamlineConstraint(pv.x(),pv.y(),berr,xzbslope,yzbslope);
374 }
375
376 //--------------------------------------------------------------------------------------------------
377 void MultiVertexFitterD::setPrimaryVertex(float xv, float yv, float zv)
378 {
379 // Set x,y,z position of the primary vertex.
380 _ctvmq.xyzpv0[0] = xv;
381 _ctvmq.xyzpv0[1] = yv;
382 _ctvmq.xyzpv0[2] = zv;
383
384 _primaryVertex = Hep3Vector( xv, yv, zv );
385 }
386
387 //--------------------------------------------------------------------------------------------------
388 void MultiVertexFitterD::setPrimaryVertex(Hep3Vector pv)
389 {
390 // Set x,y,z position of the primary vertex.
391 _ctvmq.xyzpv0[0] = pv.x();
392 _ctvmq.xyzpv0[1] = pv.y();
393 _ctvmq.xyzpv0[2] = pv.z();
394
395 _primaryVertex = pv;
396 }
397
398 //--------------------------------------------------------------------------------------------------
399 void MultiVertexFitterD::setPrimaryVertexError(const float xverr[3][3])
400 {
401 // Set the error matrix for the primary vertex.
402 for (int j=0; j<3; ++j) {
403 for (int k=0; k<3; ++k)
404 _ctvmq.exyzpv[j][k]=xverr[j][k];
405 }
406 }
407
408 //--------------------------------------------------------------------------------------------------
409 bool MultiVertexFitterD::setPrimaryVertexError(const HepSymMatrix &xverr)
410 {
411 // Set the error matrix for the primary vertex using a HepSymMatrix. First check that the matrix
412 // is the correct size.
413 if (xverr.num_row() != 3)
414 return false;
415 for (int j=0; j<3; j++) {
416 for (int k=0; k<3; k++)
417 _ctvmq.exyzpv[j][k]=xverr[j][k];
418 }
419 return true;
420 }
421
422 //--------------------------------------------------------------------------------------------------
423 bool MultiVertexFitterD::fit()
424 {
425 // Check that the diagonal elements of all the track error matrices are positive
426 bool mstat = true;
427 for (int trk=0; trk<_ctvmq.ntrack; ++trk) {
428 for (int j=0; j<5; ++j) {
429 // Check diagonal elements of error matrix.
430 if (_trkprm.trem[trk][j][j] < 0.) {
431 // The covariance matrix could not be inverted: Set the error codes and fail this fit
432 mstat = false;
433 _ctvmq.ijkerr[0] = 3;
434 _ctvmq.ijkerr[1] = 2;
435 _ctvmq.ijkerr[2] = trk + 1;
436 }
437 }
438 // Check that curvature of track is reasonable: Pt is above ~10MeV/c. If not, set the error
439 // codes and fail this fit
440 if (fabs(_trkprm.trhelix[trk][1]) > 0.1) {
441 //if (fabs(_trkprm.trhelix[trk][1]) > 0.01) {
442 mstat = false;
443 _ctvmq.ijkerr[0] = 3;
444 _ctvmq.ijkerr[1] = 5;
445 _ctvmq.ijkerr[2] = trk + 1;
446 }
447 }
448 // If there was a problem with any track, fail the fit
449 if (!mstat) {
450 _stat = 1;
451 return false;
452 }
453
454 // First copy information into CTVMFT common blocks
455 *_ctvmq_com = _ctvmq;
456 *_ctvmfr_com = _ctvmfr;
457 *_fiddle_com = _fiddle;
458 *_trkprm_com = _trkprm;
459 // Do the vertex fit.
460 int print = 0;
461 int level = 0;
462
463 // #if ( defined(LINUX) && defined(__USE_BSD) ) || defined(OSF1)
464 // struct sigaction myaction = {MultiVertexFitterDSetStatus, 0, 0, 0}, oldaction;
465 // sigaction(SIGFPE, &myaction, &oldaction);
466 // if (setjmp(denv)!=0) {
467 // sigaction(SIGFPE, &oldaction,0);
468 // return -999;
469 // }
470 // #endif
471
472 dctvmft_(print,level,_stat);
473
474 // #if ( defined(LINUX) && defined(__USE_BSD) ) || defined(OSF1)
475 // sigaction(SIGFPE, &oldaction,0);
476 // #endif
477
478 // Now copy information from CTVMFT common blocks to local storage
479 _ctvmq = *_ctvmq_com;
480 _ctvmfr = *_ctvmfr_com;
481 _fiddle = *_fiddle_com;
482 _trkprm = *_trkprm_com;
483
484 return (_stat == 0);
485 }
486
487 //--------------------------------------------------------------------------------------------------
488 void MultiVertexFitterD::print() const
489 {
490 print(cout);
491 }
492
493 //--------------------------------------------------------------------------------------------------
494 void MultiVertexFitterD::print(ostream& os) const
495 {
496 os << "****************************** MultiVertexFitterD "
497 << "******************************" << endl;
498 os << "Number of tracks: " << _ctvmq.ntrack << endl;
499 os << " Tracks: ";
500 for (int jt=0; jt<_ctvmq.ntrack; ++jt) {
501 if (jt != 0) os << ", ";
502 os << _ctvmq.list[jt];
503 }
504 os << endl;
505 os << "Number of vertices: " << _ctvmq.nvertx << endl;
506 for (int jv=0; jv<_ctvmq.nvertx; ++jv) {
507 os << " Vertex " << jv+1 << " tracks: ";
508 for (int jt=0; jt<_ctvmq.ntrack; ++jt) {
509 if (_ctvmq.trkvtx[jv][jt]) {
510 os << " " << _ctvmq.list[jt];
511 }
512 }
513 os << endl;
514 }
515 for (int jv=0; jv<_ctvmq.nvertx; ++jv) {
516 if (_ctvmq.vtxpnt[0][jv]==0) {
517 os << " Vertex " << jv+1 << " points to the primary vertex ";
518 }
519 else if (_ctvmq.vtxpnt[0][jv]>0) {
520 os << " Vertex " << jv+1 << " points to vertex "
521 << _ctvmq.vtxpnt[0][jv];
522 }
523 if (_ctvmq.vtxpnt[1][jv]==1) {
524 os << " in 2 dimensions" << endl;
525 }
526 else if (_ctvmq.vtxpnt[1][jv]==2) {
527 os << " in 3 dimensions" << endl;
528 }
529 else if (_ctvmq.vtxpnt[1][jv]==3) {
530 os << ", a single track vertex" << endl;
531 }
532 if (_ctvmq.cvtx[jv]>0) {
533 os << " Vertex " << jv+1 << " is a conversion" << endl;
534 }
535 }
536 os << "Number of mass constraints: " << _ctvmq.nmassc << endl;
537 for (int jmc=0; jmc<_ctvmq.nmassc; ++jmc) {
538 os << " Tracks ";
539 for (int jt=0; jt<_ctvmq.ntrack; ++jt) {
540 if (_ctvmq.trkmcn[jmc][jt]) {
541 os << " " << _ctvmq.list[jt];
542 }
543 }
544 os << " constrained to mass " << _ctvmq.cmass[jmc]
545 << " Gev/c^2" << endl;
546 }
547 if (_stat==-999) {
548 os << "No fit has been done." << endl;
549 }
550 else {
551 os << "***** Results of Fit *****" << endl;
552 printErr(os);
553 os << " Status = " << _stat << endl;
554 os.precision(7);
555 os << " Chi-square = " << scientific << _ctvmq.chisqr[0]
556 << " for " << _ctvmq.ndof << " degrees of freedom." << endl;
557 os << " => probability = " << prob() << endl;
558 for (int jv=0; jv<_ctvmq.nvertx; ++jv) {
559 os << "Vertex " << jv+1
560 << " position: " << scientific
561 << _ctvmq.xyzvrt[jv+1][0] << " "
562 << _ctvmq.xyzvrt[jv+1][1] << " "
563 << _ctvmq.xyzvrt[jv+1][2] << endl;
564 }
565 for (int jt=0; jt<_ctvmq.ntrack; ++jt) {
566 os << "Track " << _ctvmq.list[jt]
567 << " - P4: " << scientific
568 << _ctvmq.trkp4[0][jt] << " "
569 << _ctvmq.trkp4[1][jt] << " "
570 << _ctvmq.trkp4[2][jt] << " "
571 << _ctvmq.trkp4[3][jt] << " "
572 << " - PT: " << scientific
573 << sqrt(_ctvmq.trkp4[0][jt]*_ctvmq.trkp4[0][jt]+
574 _ctvmq.trkp4[1][jt]*_ctvmq.trkp4[1][jt]) << endl;
575 }
576 }
577 os << "****************************************"
578 << "**************************" << endl;
579
580 return;
581 }
582
583 //--------------------------------------------------------------------------------------------------
584 void MultiVertexFitterD::printErr() const
585 {
586 printErr(cout);
587 }
588
589 //--------------------------------------------------------------------------------------------------
590 void MultiVertexFitterD::printErr(ostream& os) const
591 {
592 os << "MultiVertexFitterD: IJKERR = " << _ctvmq.ijkerr[0] << ", "
593 << _ctvmq.ijkerr[1] << ", "
594 << _ctvmq.ijkerr[2] << endl;
595 if (status()==0 && _ctvmq.ijkerr[0]==0) return;
596 if (_ctvmq.ijkerr[0] == -1) {
597 os << " Problem with GETTRK: track requested is not in list."
598 << endl
599 << " This should not happen - Contact MultiVertexFitterD expert "
600 << _expert << "." <<endl;
601 }
602 else if (_ctvmq.ijkerr[0]==1) {
603 os << " Problem in CTVM00:" << endl;
604 if (_ctvmq.ijkerr[1]==1) {
605 os << " Number of tracks is " << _ctvmq.ntrack
606 << "." << endl;
607 if (_ctvmq.ntrack < 2) {
608 os << ", which is too few (must be at least 2)." << endl;
609 }
610 else if (_ctvmq.ntrack > _maxtrk) {
611 os << ", which is too many (maximum is " << _maxtrk
612 << ")." << endl;
613 }
614 else {
615 os << " Problem with number of tracks"
616 << " for unknown reasons." << endl;
617 }
618 }
619 else if (_ctvmq.ijkerr[1]==2) {
620 os << " Number of vertices is " << _ctvmq.nvertx
621 << "." << endl;
622 if (_ctvmq.nvertx < 1) {
623 os << ", which is too few (must be at least 1)." << endl;
624 }
625 else if (_ctvmq.nvertx > _maxvtx) {
626 os << ", which is too many (maximum is " << _maxvtx
627 << ")." << endl;
628 }
629 else {
630 os << endl << " Problem with number of vertices"
631 << " for unknown reasons." << endl;
632 }
633 }
634 else if (_ctvmq.ijkerr[1]==3) {
635 os << " Number of mass constraints is " << _ctvmq.nmassc
636 << "." << endl;
637 if (_ctvmq.nmassc < 0) {
638 os << ", which is negative." << endl;
639 }
640 else if (_ctvmq.nmassc > _maxmcn) {
641 os << ", which is too many (maximum is " << _maxmcn
642 << ")." << endl;
643 }
644 else {
645 os << endl << " Problem with number of mass"
646 << " constraints for unknown reasons." << endl;
647 }
648 }
649 else if (_ctvmq.ijkerr[1]==11) {
650 os << " Vertex " << _ctvmq.ijkerr[2]
651 << " has less than one track." << endl;
652 }
653 else if (_ctvmq.ijkerr[1]==12) {
654 os << " Vertex " << _ctvmq.ijkerr[2]
655 << " is a conversion vertex with a number of tracks"
656 << " different than two." << endl;
657 }
658 else if (_ctvmq.ijkerr[1]==13) {
659 os << " Vertex " << _ctvmq.ijkerr[2]
660 << " is a one track vertex that has no multi-track"
661 << " descendents." << endl;
662 }
663 else if (_ctvmq.ijkerr[1]==14) {
664 os << " Vertex " << _ctvmq.ijkerr[2]
665 << " does not point at a vertex with a lower number."
666 << endl;
667 }
668 else if (_ctvmq.ijkerr[1]==15) {
669 os << " Vertex " << _ctvmq.ijkerr[2]
670 << " has a parent vertex that is a conversion." << endl;
671 }
672 else if (_ctvmq.ijkerr[1]==16) {
673 os << " Vertex " << _ctvmq.ijkerr[2]
674 << " does 1 track pointing to a vertex with"
675 << " more than 1 track." << endl;
676 }
677 else if (_ctvmq.ijkerr[1]==17) {
678 os << " Vertex " << _ctvmq.ijkerr[2]
679 << " does 0 track pointing to a vertex with"
680 << " more than 0 track (?)." << endl;
681 }
682 else if (_ctvmq.ijkerr[1]==19) {
683 os << " Primary vertex error matrix is singular." << endl;
684 }
685 else if (_ctvmq.ijkerr[1]==21) {
686 os << " Track with Id " << _ctvmq.ijkerr[2]
687 << "is not in any vertex." << endl;
688 }
689 else if (_ctvmq.ijkerr[1]==22) {
690 os << " Track with Id " << _ctvmq.ijkerr[2]
691 << "is in multiple vertices." << endl;
692 }
693 else if (_ctvmq.ijkerr[1]==23) {
694 os << " Track with Id " << _ctvmq.ijkerr[2]
695 << "occurs more than once." << endl;
696 }
697 else if (_ctvmq.ijkerr[1]==31) {
698 os << " A mass constraint has less than 2 tracks." << endl;
699 }
700 else if (_ctvmq.ijkerr[1]==32) {
701 os << " The sum masses of the tracks in a mass constraint"
702 << " exceeds the constraint mass." << endl;
703 }
704 else if (_ctvmq.ijkerr[1]==33) {
705 os << " Beamline constraint. Beam covariance not set properly."
706 << " Negative diagonal elements." << endl;
707 }
708 else if (_ctvmq.ijkerr[1]==34) {
709 os << " Beamline constraint. Beam covariance not set properly."
710 << " Off-diagonal elements not zero." << endl;
711 }
712 else if (_ctvmq.ijkerr[1]==36) {
713 os << " Beamline constraint. Number of vertices = "
714 << _ctvmq.nvertx << " Should be 1." << endl;
715 }
716 }
717 else if (_ctvmq.ijkerr[0] == 2) {
718 if (_ctvmq.ijkerr[1] == 20) {
719 os << " Problem in CTVM00: " << endl;
720 os << " Track has negative Id = "
721 << _ctvmq.list[_ctvmq.ijkerr[2]-1] << "." << endl;
722 }
723 else {
724 os << " Problem in CTVMFA with vertex "
725 << _ctvmq.ijkerr[2] << ": " << endl;
726 os << " Failure in vertex first approximation." << endl;
727 if (_ctvmq.ijkerr[1] == 1) {
728 os << " Tracks are concentric circles." << endl;
729 }
730 if (_ctvmq.ijkerr[1] == 2) {
731 os << " Conversion vertex has widely separated"
732 << " exterior circles at midpoint." << endl;
733 }
734 if (_ctvmq.ijkerr[1] == 3) {
735 os << " Conversion vertex has widely separated"
736 << " interior circles at midpoint." << endl;
737 }
738 if (_ctvmq.ijkerr[1] == 4) {
739 os << " Vertex has widely separated"
740 << " exterior circles at approximate vertex." << endl;
741 }
742 if (_ctvmq.ijkerr[1] == 5) {
743 os << " Vertex has widely separated"
744 << " interior circles at approximate vertex." << endl;
745 }
746 if (_ctvmq.ijkerr[1] == 6) {
747 os << " Rv is too large at the chosen"
748 << " intersection point." << endl;
749 }
750 if (_ctvmq.ijkerr[1] == 7) {
751 os << " Delta z is too large at the chosen"
752 << " intersection point." << endl;
753 }
754 if (_ctvmq.ijkerr[1] == 8) {
755 os << " A track's turning to the chosen vertex"
756 << " is too large." << endl;
757 }
758 if (_ctvmq.ijkerr[1] == 9) {
759 os << " There is no solution with an adequately"
760 << " positive arc length." << endl;
761 }
762 if (_ctvmq.ijkerr[1] == 21) {
763 os << " zero-track vertexing: either/both vertex "
764 << " momenta are too small (<0.01 MeV)." << endl;
765 }
766 if (_ctvmq.ijkerr[1] == 22) {
767 os << " zero-track vertexing: Two lines (tracks) are "
768 << " parallel/antiparallel." << endl;
769 }
770 }
771 }
772 else if (_ctvmq.ijkerr[0] == 3) {
773 os << " Problem in CTVM01 with track with Id = "
774 << _ctvmq.list[_ctvmq.ijkerr[2]-1] << ": " << endl;
775 if (_ctvmq.ijkerr[1] == 1) {
776 os << " GETTRK cannot find Id in list." << endl;
777 }
778 if (_ctvmq.ijkerr[1] == 2) {
779 os << " Covariance matrix could not be inverted." << endl
780 << " Offending track number (in order addded) is "
781 << _ctvmq.ijkerr[2] << "." << endl;
782 }
783 if (_ctvmq.ijkerr[1] == 3) {
784 os << " Track turns through too large an angle"
785 << " to the vertex." << endl;
786 }
787 if (_ctvmq.ijkerr[1] == 4) {
788 os << " Track moves too far backward to vertex." << endl;
789 }
790 if (_ctvmq.ijkerr[1] == 5) {
791 os << " Track with curvature > 0.01." << endl
792 << " Offending track number is "
793 << _ctvmq.ijkerr[2] << "." << endl;
794 }
795 }
796 else if (status() == 9) {
797 os << " General fit problem: " << endl;
798 if (_ctvmq.ijkerr[1] == 1) {
799 os << " Singular solution matrix." << endl;
800 }
801 if (_ctvmq.ijkerr[1] == 2 || _ctvmq.ijkerr[1] == 3) {
802 os << " Too many iterations ( "
803 << _ctvmq.ijkerr[2] << "(." << endl;
804 }
805 if (_ctvmq.ijkerr[1] == 4) {
806 os << " Convergence failure." << endl;
807 }
808 if (_ctvmq.ijkerr[1] == 5) {
809 os << " Bad convergence." << endl;
810 }
811 if (_ctvmq.ijkerr[1] == 9) {
812 os << " Ill-formed covariance matrix." << endl;
813 }
814 }
815 else {
816 os << " The error codes above are not recognized." << endl
817 << " Contact MultiVertexFitterD expert " << _expert << "." << endl;
818 }
819 return;
820 }
821
822 //--------------------------------------------------------------------------------------------------
823 void MultiVertexFitterD::getIJKErr(int& err0, int& err1, int& err2) const
824 {
825 err0 = _ctvmq.ijkerr[0];
826 err1 = _ctvmq.ijkerr[1];
827 err2 = _ctvmq.ijkerr[2];
828 return;
829 }
830
831 //--------------------------------------------------------------------------------------------------
832 int MultiVertexFitterD::getIJKErr0() const
833 {
834 return _ctvmq.ijkerr[0];
835 }
836
837 //--------------------------------------------------------------------------------------------------
838 int MultiVertexFitterD::getIJKErr1() const
839 {
840 return _ctvmq.ijkerr[1];
841 }
842
843 //--------------------------------------------------------------------------------------------------
844 int MultiVertexFitterD::getIJKErr2() const
845 {
846 return _ctvmq.ijkerr[2];
847 }
848
849 //--------------------------------------------------------------------------------------------------
850 int MultiVertexFitterD::getErrTrackId() const
851 {
852 if (status() == 0) return 0;
853 int trkId = 0;
854 // Problems with track in CTVM01 or track has negative id in CTVM00 See PrintErr() for a more
855 // detailed list of error codes.
856 if ((_ctvmq.ijkerr[0] == 2 && _ctvmq.ijkerr[1] == 20) ||
857 _ctvmq.ijkerr[0] == 3) {
858 trkId = _ctvmq.list[_ctvmq.ijkerr[2]-1];
859 }
860
861 return trkId;
862 }
863
864 //--------------------------------------------------------------------------------------------------
865 string MultiVertexFitterD::expert() const
866 {
867 return _expert;
868 }
869
870 //--------------------------------------------------------------------------------------------------
871 int MultiVertexFitterD::status() const
872 {
873 return _stat;
874 }
875
876 //--------------------------------------------------------------------------------------------------
877 float MultiVertexFitterD::chisq() const
878 {
879 // Chi-square of fit
880 return _ctvmq.chisqr[0];
881 }
882
883 //--------------------------------------------------------------------------------------------------
884 int MultiVertexFitterD::ndof() const
885 {
886 // Number of degrees of freedom of fit.
887 if (_ctvmq.chisqr[0] >= 0)
888 return _ctvmq.ndof;
889 else
890 return 0;
891 }
892
893 //--------------------------------------------------------------------------------------------------
894 float MultiVertexFitterD::prob() const
895 {
896 // Probability of chi-square of fit
897 if (_ctvmq.chisqr[0]>=0.) {
898 float chisq = _ctvmq.chisqr[0];
899 int nd = _ctvmq.ndof;
900 return TMath::Prob(chisq,nd);
901 }
902 else
903 return -999.;
904 }
905
906 //--------------------------------------------------------------------------------------------------
907 float MultiVertexFitterD::chisq(const int trkId) const
908 {
909 // This method returns the chisquare contribution for one track If fit not successful or not done
910 // yet, return -1.
911 if (_ctvmq.chisqr[0] < 0)
912 return -1.;
913 // Look for this track in the list of tracks.
914 for (int jt = 0; jt < _ctvmq.ntrack; ++jt) {
915 if (trkId == _ctvmq.list[jt]) {
916 // Found the track, so return its chisquare contribution.
917 return _ctvmq.chit[jt];
918 }
919 }
920 // If track is not in list, return -1.
921 return -1.;
922 }
923
924 //--------------------------------------------------------------------------------------------------
925 float MultiVertexFitterD::chisq_rphi() const
926 {
927 // This method returns the chisquare contribution in the r-phi plane.
928 int index[3] = {0,1,3};
929 // If fit not successful or not done yet, return -1.
930 if (_ctvmq.chisqr[0] < 0)
931 return -1.;
932 // Loop over the tracks in the event.
933 float chisq = 0.;
934 for (int jt=0; jt<_ctvmq.ntrack; ++jt) {
935 // Double loop over the relevant parameter indices.
936 for (int k1=0; k1<3; ++k1) {
937 for (int k2=0; k2<3; ++k2)
938 // Add contribution to chisquare.
939 chisq += _ctvmq.pardif[jt][index[k1]] *
940 _ctvmq.g[jt][index[k1]][index[k2]] *
941 _ctvmq.pardif[jt][index[k2]];
942 }
943 }
944 // Return the chisquare.
945 return chisq;
946 }
947
948 //--------------------------------------------------------------------------------------------------
949 float MultiVertexFitterD::chisq_z() const
950 {
951 // This method returns the chisquare contribution in the z direction.
952 int index[2] = {2,4};
953 // If fit not successful or not done yet, return -1.
954 if (_ctvmq.chisqr[0] < 0)
955 return -1.;
956 // Loop over the tracks in the event.
957 float chisq = 0.;
958 for (int jt=0; jt<_ctvmq.ntrack; ++jt) {
959 // Double loop over the relevant parameter indices.
960 for (int k1=0; k1<2; ++k1) {
961 for (int k2=0; k2<2; ++k2)
962 // Add contribution to chisquare.
963 chisq += _ctvmq.pardif[jt][index[k1]] *
964 _ctvmq.g[jt][index[k1]][index[k2]] *
965 _ctvmq.pardif[jt][index[k2]];
966 }
967 }
968 // Return the chisquare.
969 return chisq;
970 }
971
972 //--------------------------------------------------------------------------------------------------
973 float MultiVertexFitterD::chisq_rphiz() const
974 {
975 // This method returns the chisquare contribution of the cross
976 // terms in the r-phi and z directions.
977 int index1[2] = {2,4};
978 int index2[3] = {0,1,3};
979 // If fit not successful or not done yet, return -1.
980 if (_ctvmq.chisqr[0] < 0)
981 return -1.;
982 // Loop over the tracks in the event.
983 float chisq = 0.;
984 for (int jt=0; jt<_ctvmq.ntrack; ++jt) {
985 // Double loop over the relevant parameter indices.
986 for (int k1=0; k1<2; ++k1) {
987 for (int k2=0; k2<3; ++k2)
988 // Add contribution to chisquare.
989 chisq += _ctvmq.pardif[jt][index1[k1]] *
990 _ctvmq.g[jt][index1[k1]][index2[k2]] *
991 _ctvmq.pardif[jt][index2[k2]];
992 }
993 }
994
995 // Return the chisquare.
996 return 2.0 * chisq;
997 }
998
999 //--------------------------------------------------------------------------------------------------
1000 float MultiVertexFitterD::chisq_rphi(const int trkId) const
1001 {
1002 // This method returns the chisquare contribution in the r-phi plane.
1003 int index[3] = {0,1,3};
1004 // If fit not successful or not done yet, return -1.
1005 if (_ctvmq.chisqr[0] < 0)
1006 return -1.;
1007 // Loop over the tracks in the event, looking for the one we want
1008 for (int jt=0; jt<_ctvmq.ntrack; ++jt) {
1009 if (trkId == _ctvmq.list[jt]) {
1010 // Found the track, so calculate its chisquare contribution.
1011 float chisq = 0.;
1012 // Double loop over the relevant parameter indices.
1013 for (int k1=0; k1<3; ++k1) {
1014 for (int k2=0; k2<3; ++k2) {
1015 // Add contribution to chisquare.
1016 chisq += _ctvmq.pardif[jt][index[k1]] *
1017 _ctvmq.g[jt][index[k1]][index[k2]] *
1018 _ctvmq.pardif[jt][index[k2]];
1019 }
1020 }
1021 return chisq;
1022 }
1023 }
1024
1025 // Track not found, return -1.
1026 return -1.;
1027 }
1028
1029 //--------------------------------------------------------------------------------------------------
1030 float MultiVertexFitterD::chisq_z(const int trkId) const
1031 {
1032 // This method returns the chisquare contribution in the z direction.
1033 int index[2] = {2,4};
1034 // If fit not successful or not done yet, return -1.
1035 if (_ctvmq.chisqr[0] < 0)
1036 return -1.;
1037 // Loop over the tracks in the event, looking for the one we want.
1038 for (int jt=0; jt<_ctvmq.ntrack; ++jt) {
1039 if (trkId == _ctvmq.list[jt]) {
1040 // Found the track, so calculate its chisquare contribution.
1041 float chisq = 0.;
1042 // Double loop over the relevant parameter indices.
1043 for (int k1=0; k1<2; ++k1) {
1044 for (int k2=0; k2<2; ++k2)
1045 // Add contribution to chisquare.
1046 chisq += _ctvmq.pardif[jt][index[k1]] *
1047 _ctvmq.g[jt][index[k1]][index[k2]] *
1048 _ctvmq.pardif[jt][index[k2]];
1049 }
1050 return chisq;
1051 }
1052 }
1053
1054 // Track not found - return -1.
1055 return -1.;
1056 }
1057
1058 //--------------------------------------------------------------------------------------------------
1059 float MultiVertexFitterD::chisq_rphiz(const int trkId) const
1060 {
1061 // This method returns the chisquare contribution of the cross terms in the r-phi and z
1062 // directions
1063 int index1[2] = { 2,4 };
1064 int index2[3] = { 0,1,3 };
1065 // If fit not successful or not done yet, return -1
1066 if (_ctvmq.chisqr[0] < 0)
1067 return -1.;
1068 // Loop over the tracks in the event
1069 for (int jt=0; jt<_ctvmq.ntrack; ++jt) {
1070 if (trkId == _ctvmq.list[jt]) {
1071 // Found the track, so calculate its chisquare contribution
1072 float chisq = 0.;
1073 // Double loop over the relevant parameter indices
1074 for (int k1=0; k1<2; ++k1) {
1075 for (int k2=0; k2<3; ++k2)
1076 // Add contribution to chisquare
1077 chisq += _ctvmq.pardif[jt][index1[k1]] *
1078 _ctvmq.g[jt][index1[k1]][index2[k2]] *
1079 _ctvmq.pardif[jt][index2[k2]];
1080 }
1081 return 2.0 * chisq;
1082 }
1083 }
1084 // Track not found so return -1.
1085 return -1.;
1086 }
1087
1088 //--------------------------------------------------------------------------------------------------
1089 FourVector MultiVertexFitterD::getTrackP4(const int trkId) const
1090 {
1091 if (_stat != 0)
1092 return FourVector(0,0,0,0);
1093 // return four momentum of fit track
1094 for (int jt=0; jt<_ctvmq.ntrack; ++jt) {
1095 // Find which track matches this Id.
1096 if (trkId == _ctvmq.list[jt]) {
1097 FourVector p4((double)_ctvmq.trkp4[0][jt], (double)_ctvmq.trkp4[1][jt],
1098 (double)_ctvmq.trkp4[2][jt], (double)_ctvmq.trkp4[3][jt]);
1099 return p4;
1100 }
1101 }
1102 return FourVector(0,0,0,0);
1103 }
1104
1105 //--------------------------------------------------------------------------------------------------
1106 float MultiVertexFitterD::getMass(int ntrk, const int trkIds[], float &dmass) const
1107 {
1108 // #if (defined(LINUX) && defined(__USE_BSD)) || defined(OSF1)
1109 // struct sigaction myaction = {MultiVertexFitterDSetStatus, 0, 0, 0}, oldaction;
1110 // sigaction(SIGFPE, &myaction, &oldaction);
1111 // if (setjmp(denv)!=0) {
1112 // sigaction(SIGFPE, &oldaction,0);
1113 // return -999;
1114 // }
1115 // #endif
1116
1117 dmass = -999.;
1118 if (_stat!=0)
1119 return -999.;
1120 // Get fit invariant mass of ntrk tracks listed in array tracks. dmass is the error on the mass.
1121 dmass=-999.;
1122 if (ntrk <= 0)
1123 return 0;
1124 int jtrks[_maxtrk];
1125 for (int jt=0; jt<ntrk; ++jt) {
1126 bool found = false;
1127 for (int kt=0; kt<_ctvmq.ntrack; ++kt) {
1128 if (trkIds[jt] == _ctvmq.list[kt]) {
1129 found = true;
1130 jtrks[jt]=kt+1;
1131 }
1132 }
1133 if (!found)
1134 return 0;
1135 }
1136 // Copy information into CTVMFT common blocks
1137 *_ctvmq_com = _ctvmq;
1138 *_ctvmfr_com = _ctvmfr;
1139 int ntr = ntrk;
1140 float mass;
1141 double p4[4];
1142 dmcalc_(ntr, jtrks, mass, dmass, p4);
1143
1144 // #if (defined(LINUX) && defined(__USE_BSD)) || defined(OSF1)
1145 // sigaction(SIGFPE, &oldaction,0);
1146 // #endif
1147
1148 return mass;
1149 }
1150
1151 //--------------------------------------------------------------------------------------------------
1152 float MultiVertexFitterD::getDecayLength(vertexNumber nv, vertexNumber mv,
1153 const Hep3Vector& dir, float& dlerr) const
1154 {
1155 dlerr = -999.;
1156 if (_stat!=0)
1157 return -999.;
1158
1159 // Get the signed decay length from vertex nv to vertex mv along the x-y direction defined by the
1160 // 3 vector dir. dlerr is the error on the decay length including the full error matrix. Check
1161 // that vertices are within range.
1162 if (nv<0 || nv>=_ctvmq.nvertx)
1163 return -999.;
1164 if (mv<1 || mv>_ctvmq.nvertx)
1165 return -999.;
1166 if (nv>=mv)
1167 return -999.;
1168
1169 float dir_t = sqrt(dir.x()*dir.x()+dir.y()*dir.y());
1170 if (dir_t <= 0.)
1171 return -999.;
1172
1173 Hep3Vector dv = getVertexHep(mv)-getVertexHep(nv);
1174 float dl = (dv.x()*dir.x()+dv.y()*dir.y())/dir_t;
1175 // Set up the column matrix of derivatives
1176 HepMatrix A(4,1);
1177 A(1,1) = dir.x()/dir_t;
1178 A(2,1) = dir.y()/dir_t;
1179 A(3,1) = -dir.x()/dir_t;
1180 A(4,1) = -dir.y()/dir_t;
1181 // Check if first vertex (nv) is primary vertex. If it is, check if it was used in the primary
1182 // vertex. If not, all of the corresponding error matrix elements are those supplied for the
1183 // primary vertex.
1184 int nvf = 0;
1185 if (nv==0) {
1186 nvf=-1;
1187 for (int jv=0; jv<_ctvmq.nvertx; ++jv) {
1188 if (_ctvmq.vtxpnt[0][jv]==0)
1189 nvf=0;
1190 }
1191 }
1192 // Get the relevant submatrix of the full error matrix.
1193 HepMatrix V(4,4,0);
1194 if (nvf < 0) {
1195 V(1,1) = getErrorMatrixHep(_ctvmq.voff[mv-1]+1,_ctvmq.voff[mv-1]+1);
1196 V(1,2) = getErrorMatrixHep(_ctvmq.voff[mv-1]+1,_ctvmq.voff[mv-1]+2);
1197 V(2,1) = getErrorMatrixHep(_ctvmq.voff[mv-1]+2,_ctvmq.voff[mv-1]+1);
1198 V(2,2) = getErrorMatrixHep(_ctvmq.voff[mv-1]+2,_ctvmq.voff[mv-1]+2);
1199 V(3,3) = _ctvmq.exyzpv[0][0];
1200 V(3,4) = _ctvmq.exyzpv[0][1];
1201 V(4,3) = _ctvmq.exyzpv[1][0];
1202 V(4,4) = _ctvmq.exyzpv[1][1];
1203 }
1204 else {
1205 // Get the indices into the error matrix vmat
1206 int index[4] = { _ctvmq.voff[mv-1]+1,_ctvmq.voff[mv-1]+2,0,0 };
1207 if (nv==0) {
1208 index[2] = 1;
1209 index[3] = 2;
1210 }
1211 else {
1212 index[2] = _ctvmq.voff[nv-1]+1;
1213 index[3] = _ctvmq.voff[nv-1]+2;
1214 }
1215 for (int j=0; j<4; ++j) {
1216 for (int k=0; k<4; ++k) {
1217 V[j][k] = getErrorMatrixHep(index[j],index[k]);
1218 }
1219 }
1220 }
1221
1222 // Calculate square of dlerr
1223 dlerr = (A.T()*V*A)(1,1);
1224 if (dlerr >= 0.)
1225 dlerr = sqrt(dlerr);
1226 else
1227 dlerr = -sqrt(-dlerr);
1228
1229 return dl;
1230 }
1231
1232 //--------------------------------------------------------------------------------------------------
1233 float MultiVertexFitterD::getDecayLength(vertexNumber nv, vertexNumber mv,
1234 const ThreeVector& dir, float& dlerr) const
1235 {
1236 Hep3Vector dirHep(dir.x(),dir.y(),dir.z());
1237 return getDecayLength(nv, mv, dirHep, dlerr);
1238 }
1239
1240 //--------------------------------------------------------------------------------------------------
1241 float MultiVertexFitterD::getZDecayLength(vertexNumber nv, vertexNumber mv,
1242 const Hep3Vector& mom, float& dlerr) const
1243 {
1244 //----------------------------------------------------------------------------
1245 // Get the signed decay length from vertex nv to vertex mv along the
1246 // z direction of the momentum vector, mom.
1247 // dlerr is the error on the decay length including the full error
1248 // matrix.
1249 //----------------------------------------------------------------------------
1250 // Start with good initialization
1251 dlerr = -999.;
1252
1253 // Check that the fit worked
1254 if (_stat != 0)
1255 return -999.;
1256
1257 // Check that vertices are within range.
1258 if (nv<0 || nv>=_ctvmq.nvertx)
1259 return -999.;
1260 if (mv<1 || mv> _ctvmq.nvertx)
1261 return -999.;
1262 if (nv >= mv)
1263 return -999.;
1264
1265 // Calculate the vector length
1266 float length = fabs(mom.z());
1267 if (length <= 0.)
1268 return -999.;
1269
1270 // Get the vector pointing from first vertex (nv) to second vertex (mv)
1271 Hep3Vector dv = getVertexHep(mv) - getVertexHep(nv);
1272
1273 //----------------------------------------------------------------------------
1274 // Calculate the "decay distance"
1275 //----------------------------------------------------------------------------
1276 // Project the vertex vector onto the momentum vector direction
1277 float dl = (dv.z()*mom.z())/length;
1278
1279 //----------------------------------------------------------------------------
1280 // Calculate the error on that distance
1281 //----------------------------------------------------------------------------
1282 // Set up the column matrix of derivatives
1283 HepMatrix A(2,1);
1284 A(1,1) = mom.z()/length;
1285 A(2,1) = -mom.z()/length;
1286
1287 // Need to catch the special case if the first vertex is the primary
1288 int nvf = 0;
1289 if (nv == 0) {
1290 nvf = -1;
1291 for (int jv=0; jv<_ctvmq.nvertx; ++jv) {
1292 if (_ctvmq.vtxpnt[0][jv] == 0)
1293 nvf = 0;
1294 }
1295 }
1296 // Get the relevant submatrix of the full error matrix.
1297 HepMatrix V(2,2,0);
1298 if (nvf < 0) {
1299 // Geometric uncertainties (positions second vertex)
1300 V(1,1) = getErrorMatrixHep(_ctvmq.voff[mv-1]+3,_ctvmq.voff[mv-1]+3);
1301 // Geometric uncertainties (positions first vertex)
1302 V(2,2) = _ctvmq.exyzpv[2][2];
1303 }
1304 else {
1305 // Get the indices into the error matrix vmat
1306 int index[2] = { _ctvmq.voff[mv-1]+3,_ctvmq.voff[nv-1]+3 };
1307 // Handeling the case of the primary vertex
1308 if (nv == 0)
1309 index[1] = 3;
1310 // All right... copy
1311 for(int j=0; j<2; ++j)
1312 for(int k=0; k<2; ++k)
1313 V[j][k] = getErrorMatrixHep(index[j],index[k]);
1314 }
1315 // Calculate square of dlerr
1316 dlerr = (A.T() * V * A )(1,1);
1317 if (dlerr >= 0.)
1318 dlerr = sqrt(dlerr);
1319 else
1320 dlerr = -sqrt(-dlerr);
1321
1322 return dl;
1323 }
1324
1325 //--------------------------------------------------------------------------------------------------
1326 float MultiVertexFitterD::getZDecayLength(vertexNumber nv, vertexNumber mv,
1327 const ThreeVector& mom, float& dlerr) const
1328 {
1329 Hep3Vector momHep(mom.x(),mom.y(),mom.z());
1330 return getZDecayLength(nv, mv, momHep, dlerr);
1331 }
1332
1333 //--------------------------------------------------------------------------------------------------
1334 float MultiVertexFitterD::getImpactPar(vertexNumber prdV, vertexNumber dcyV,
1335 const Hep3Vector &v, float &dxyerr) const
1336 {
1337 Hep3Vector PVtx = getVertexHep (prdV);
1338 Hep3Vector DVtx = getVertexHep (dcyV);
1339 HepSymMatrix PVtxCv = getErrorMatrixHep(prdV);
1340 HepSymMatrix DVtxCv = getErrorMatrixHep(dcyV);
1341
1342 double norma = v.perp();
1343 if (norma <= 0) {
1344 dxyerr = -999.;
1345 return -999.0;
1346 }
1347 double dxy = ((v.cross(DVtx-PVtx)).z())/norma;
1348
1349 // Calculate error on B impact parameter:
1350 double cosPhi = cos(v.phi());
1351 double sinPhi = sin(v.phi());
1352 dxyerr = cosPhi * cosPhi * (DVtxCv[1][1] + PVtxCv[1][1])
1353 + sinPhi * sinPhi * (DVtxCv[0][0] + PVtxCv[0][0])
1354 - 2.0 * cosPhi * sinPhi * (DVtxCv[0][1] + PVtxCv[0][1]);
1355 dxyerr = (dxyerr>0.0) ? sqrt(dxyerr) : -999.;
1356
1357 return dxy;
1358 }
1359
1360 //--------------------------------------------------------------------------------------------------
1361 float MultiVertexFitterD::getImpactPar(vertexNumber prdV, vertexNumber dcyV,
1362 const ThreeVector &v, float &dxyerr) const
1363 {
1364 Hep3Vector vHep(v.x(),v.y(),v.z());
1365 return getImpactPar(prdV, dcyV, vHep, dxyerr);
1366 }
1367
1368 //--------------------------------------------------------------------------------------------------
1369 float MultiVertexFitterD::get_dr(vertexNumber nv, vertexNumber mv, float& drerr) const
1370 {
1371 drerr = -999.;
1372 if (_stat!=0)
1373 return -999.;
1374 // Get the transvese distance between vertices nv and mv and return it as the function value.
1375 // drerr is the uncertainty on the transverse distance, calculated from the full error matrix
1376 // including correlations.
1377 float dxyz[3];
1378 float dr;
1379 float dz;
1380 float dl[3];
1381
1382 int mvert = mv;
1383 int nvert = nv;
1384 // Copy information into CTVMFT common blocks
1385 *_ctvmq_com = _ctvmq;
1386 *_ctvmfr_com = _ctvmfr;
1387 // Do calculation
1388 ddcalc_(mvert,nvert,dxyz,dr,dz,dl);
1389 drerr = dl[0];
1390 return dr;
1391 }
1392
1393 //--------------------------------------------------------------------------------------------------
1394 float MultiVertexFitterD::get_dz(vertexNumber nv, vertexNumber mv, float& dzerr) const
1395 {
1396 dzerr = -999.;
1397 if (_stat!=0)
1398 return -999.;
1399 // Get the longitudinal distance between vertices nv and mv and return it as the function value.
1400 // dzerr is the uncertainty on the longitudinal distance, calculated from the full error matrix
1401 // including correlations.
1402 float dxyz[3];
1403 float dr;
1404 float dz;
1405 float dl[3];
1406
1407 int mvert = mv;
1408 int nvert = nv;
1409 // Copy information into CTVMFT common blocks
1410 *_ctvmq_com = _ctvmq;
1411 *_ctvmfr_com = _ctvmfr;
1412
1413 // Do calculation
1414 ddcalc_(mvert,nvert,dxyz,dr,dz,dl);
1415 dzerr = dl[1];
1416 return dz;
1417 }
1418
1419 //--------------------------------------------------------------------------------------------------
1420 Hep3Vector MultiVertexFitterD::getVertexHep(vertexNumber nv) const
1421 {
1422 if (_stat!=0)
1423 return Hep3Vector(-999,-999,-999);
1424 // Return x,y,z position of vertex nv.
1425 if (nv<0 || nv>_ctvmq.nvertx)
1426 return Hep3Vector(0,0,0);
1427 // Check if first vertex (nv) is primary vertex. If it is, check if it was used in the primary
1428 // vertex. If not, all of the corresponding error matrix elements are those supplied for the
1429 // primary vertex.
1430 int nvf=0;
1431 if (nv==0) {
1432 nvf=-1;
1433 for (int jv=0; jv<_ctvmq.nvertx; ++jv) {
1434 if (_ctvmq.vtxpnt[0][jv]==0)
1435 nvf=0;
1436 }
1437 }
1438 Hep3Vector vertex;
1439 // If primary vertex was not part of fit, take vertex location as supplied.
1440 if (nvf < 0) {
1441 vertex.setX(_ctvmq.xyzpv0[0]);
1442 vertex.setY(_ctvmq.xyzpv0[1]);
1443 vertex.setZ(_ctvmq.xyzpv0[2]);
1444 }
1445 else {
1446 vertex.setX(_ctvmq.xyzvrt[nv][0]);
1447 vertex.setY(_ctvmq.xyzvrt[nv][1]);
1448 vertex.setZ(_ctvmq.xyzvrt[nv][2]);
1449 }
1450 //// If we have a different reference point, need to add it back in
1451 //vertex += _referencePoint;
1452 return vertex;
1453 }
1454
1455 //--------------------------------------------------------------------------------------------------
1456 ThreeVector MultiVertexFitterD::getVertex(vertexNumber nv) const
1457 {
1458 if (_stat!=0)
1459 return ThreeVector(-999,-999,-999);
1460 // Return x,y,z position of vertex nv.
1461 if (nv<0 || nv>_ctvmq.nvertx)
1462 return ThreeVector(0,0,0);
1463 // Check if first vertex (nv) is primary vertex. If it is, check if it was used in the primary
1464 // vertex. If not, all of the corresponding error matrix elements are those supplied for the
1465 // primary vertex.
1466 int nvf=0;
1467 if (nv==0) {
1468 nvf=-1;
1469 for (int jv=0; jv<_ctvmq.nvertx; ++jv) {
1470 if (_ctvmq.vtxpnt[0][jv]==0)
1471 nvf=0;
1472 }
1473 }
1474 ThreeVector vertex;
1475 // If primary vertex was not part of fit, take vertex location as supplied.
1476 if (nvf < 0) {
1477 vertex.SetX(_ctvmq.xyzpv0[0]);
1478 vertex.SetY(_ctvmq.xyzpv0[1]);
1479 vertex.SetZ(_ctvmq.xyzpv0[2]);
1480 }
1481 else {
1482 vertex.SetX(_ctvmq.xyzvrt[nv][0]);
1483 vertex.SetY(_ctvmq.xyzvrt[nv][1]);
1484 vertex.SetZ(_ctvmq.xyzvrt[nv][2]);
1485 }
1486 // If we have a different reference point, need to add it back in
1487 vertex += _referencePoint;
1488 return vertex;
1489 }
1490
1491 //--------------------------------------------------------------------------------------------------
1492 ThreeSymMatrix MultiVertexFitterD::getErrorMatrix(MultiVertexFitterD::vertexNumber nv) const
1493 {
1494 // return errors for vertex nv
1495 ThreeSymMatrix cov;
1496
1497 // if this is the primary vertex, return the error matrix the user supplied
1498 if (nv==PRIMARY_VERTEX) {
1499 for (int j=0; j<3; j++)
1500 for (int k=0; k<3; k++)
1501 cov(j,k) = _ctvmq.exyzpv[j][k];
1502 return cov;
1503 }
1504
1505 if (_stat!=0)
1506 return cov;
1507 // return x,y,z position of vertex nv
1508 if (nv<VERTEX_1 || nv>_ctvmq.nvertx)
1509 return cov;
1510 // get offset for vertex nv
1511 int voff = _ctvmq.voff[nv-1];
1512 // fill matrix
1513 for (int i=0; i<3; ++i)
1514 for (int j=i; j<3; ++j)
1515 cov(i,j) = _ctvmfr.vmat[voff+i][voff+j];
1516 return cov;
1517 }
1518
1519 //--------------------------------------------------------------------------------------------------
1520 double MultiVertexFitterD::getErrorMatrixHep(int j, int k) const
1521 {
1522 if (_stat!=0)
1523 return -999.;
1524 // Return the j,k element of the full error matrix VMAT. Since the CTVMFT documentation assumes
1525 // the indices start from 1 (ala Fortran), we will also assume this and convert the C++ indices.
1526 // Note also the that order of Fortran and C++ indices is different. We assume that j and k are
1527 // in the Fortran order.
1528 if (j<1 || k<1 || j>_maxdim+1 || k>_maxdim)
1529 return -999.;
1530
1531 return _ctvmfr.vmat[k-1][j-1];
1532 }
1533
1534 //--------------------------------------------------------------------------------------------------
1535 HepSymMatrix MultiVertexFitterD::getErrorMatrixHep(MultiVertexFitterD::vertexNumber nv) const
1536 {
1537 // return errors for vertex nv
1538 HepSymMatrix cov(3,0);
1539
1540 // if this is the primary vertex, return the error matrix the user supplied
1541 if (nv==PRIMARY_VERTEX) {
1542 for (int j=0; j<3; j++)
1543 for (int k=0; k<3; k++)
1544 cov[j][k] = _ctvmq.exyzpv[j][k];
1545 return cov;
1546 }
1547
1548 if (_stat!=0)
1549 return cov;
1550 // return x,y,z position of vertex nv
1551 if (nv<VERTEX_1 || nv>_ctvmq.nvertx)
1552 return cov;
1553 // get offset for vertex nv
1554 int voff = _ctvmq.voff[nv-1];
1555 // fill matrix
1556 for (int i=0; i<3; ++i)
1557 for (int j=i; j<3; ++j)
1558 cov[i][j] = _ctvmfr.vmat[voff+i][voff+j];
1559 return cov;
1560 }
1561
1562 //--------------------------------------------------------------------------------------------------
1563 HepSymMatrix MultiVertexFitterD::getErrorMatrixHep(const int trkId) const
1564 {
1565 HepSymMatrix cov(3,0);
1566 if (_stat != 0)
1567 return cov;
1568
1569 for (int nt=0; nt<_ctvmq.ntrack; ++nt) {
1570
1571 // Find which track matches this Id
1572 if (trkId == _ctvmq.list[nt]) {
1573
1574 // Position of track nt get offset for track nt
1575 int toff = _ctvmq.toff[nt];
1576
1577 // Fill matrix -- Crv,Phi,Ctg
1578 for (int i=0; i<3; ++i)
1579 for (int j=i; j<3; ++j)
1580 cov[i][j] = _ctvmfr.vmat[toff+i][toff+j];
1581 }
1582 }
1583 return cov;
1584 }
1585
1586 //--------------------------------------------------------------------------------------------------
1587 float MultiVertexFitterD::getPtError(const int trkId) const
1588 {
1589 if (_stat != 0)
1590 return 0;
1591
1592 int toff;
1593 float pt,curv,curvErr,ptErr;
1594
1595 for (int nt=0; nt<_ctvmq.ntrack; ++nt) {
1596
1597 // Find which track matches this Id
1598 if (trkId == _ctvmq.list[nt]) {
1599
1600 // Position of track nt get offset for track nt
1601 toff = _ctvmq.toff[nt];
1602
1603 // Curvature error
1604 pt = sqrt(_ctvmq.trkp4[0][nt]*_ctvmq.trkp4[0][nt] +
1605 _ctvmq.trkp4[1][nt]*_ctvmq.trkp4[1][nt]);
1606 curv = _ctvmq.pscale/pt;
1607 curvErr = sqrt(_ctvmfr.vmat[toff+0][toff+0]);
1608 ptErr = _ctvmq.pscale/curv/curv*curvErr;
1609 return ptErr;
1610 }
1611 }
1612
1613 return 0;
1614 }
1615
1616 //--------------------------------------------------------------------------------------------------
1617 void MultiVertexFitterD::getPosMomErr(HepMatrix& errors) const
1618 {
1619 // A c++ rewrite of the FORTRAN MASSAG function The result of this function is an error matrix in
1620 // position-momentum basis. A 7x7 matrix of errors where the rows/columns are x, y, z, px, py,
1621 // pz, e.
1622
1623 double cosph [_maxtrk];
1624 double sinph [_maxtrk];
1625 double cosdph[_maxtrk];
1626 double sindph[_maxtrk];
1627 Hep3Vector mom3 [_maxtrk];
1628 HepLorentzVector pmom [_maxtrk];
1629 HepLorentzVector total_mom;
1630
1631 for (int lvtx = 0; lvtx < _ctvmq.nvertx; lvtx++) {
1632 for (int ltrk = 0; ltrk < _ctvmq.ntrack; ltrk++) {
1633 if (!_ctvmq.trkvtx[lvtx][ltrk])
1634 continue;
1635 cosph[ltrk] = cos(_ctvmq.par[ltrk][1]);
1636 sinph[ltrk] = sin(_ctvmq.par[ltrk][1]);
1637 double dphi = 0;
1638 sindph[ltrk] = 2 * _ctvmq.par[ltrk][0] *
1639 (_ctvmq.xyzvrt[lvtx + 1][0] * cosph[ltrk] +
1640 _ctvmq.xyzvrt[lvtx + 1][1] * sinph[ltrk]);
1641 cosdph[ltrk] = sqrt(1.0 - sindph[ltrk] * sindph[ltrk]);
1642 if (fabs(sindph[ltrk]) <= 1.0){
1643 dphi = asin(sindph[ltrk]);
1644 }
1645 double pt = _ctvmq.pscale * fabs(1./_ctvmq.par[ltrk][0]);
1646 mom3[ltrk].setX(pt * cos(_ctvmq.par[ltrk][1] + dphi));
1647 mom3[ltrk].setY(pt * sin(_ctvmq.par[ltrk][1] + dphi));
1648 mom3[ltrk].setZ(pt * _ctvmq.par[ltrk][2]);
1649 double e = sqrt(_ctvmq.tmass[ltrk] * _ctvmq.tmass[ltrk]
1650 + mom3[ltrk].mag2());
1651 pmom[ltrk].setVect(mom3[ltrk]);
1652 pmom[ltrk].setE(e);
1653
1654 total_mom += pmom[ltrk];
1655 }
1656 }
1657
1658 // Easy so far, but now it gets ugly: fill dp_dpar with the derivatives of the position and
1659 // momentum with respect to the parameters
1660
1661 int ctvmft_dim = 3 * (_ctvmq.nvertx + _ctvmq.ntrack);
1662 HepMatrix deriv(ctvmft_dim, 7, 0);
1663 //HepMatrix dp_dpar[_maxvtx] = { deriv, deriv, deriv };
1664 HepMatrix dp_dpar[_maxvtx] = { deriv };
1665
1666 // Fill the x, y, z rows:
1667 for (int nvtx = 0; nvtx < _ctvmq.nvertx; nvtx++) {
1668 for (int lcomp = 0; lcomp < 3; lcomp++){
1669 dp_dpar[nvtx][(3 * nvtx) + lcomp][lcomp] = 1.0;
1670 }
1671
1672 // Fill the px, py, pz, e rows:
1673 for (int lvtx = 0; lvtx < _ctvmq.nvertx; lvtx++){
1674 for (int ltrk = 0; ltrk < _ctvmq.ntrack; ltrk++){
1675 if (!_ctvmq.trkvtx[lvtx][ltrk])
1676 continue;
1677
1678 // Find the derivatives of dphi with respect to x, y, curvature, and phi0:
1679 double dphi_dx = 2.0 * _ctvmq.par[ltrk][0] * cosph[ltrk]/cosdph[ltrk];
1680 double dphi_dy = 2.0 * _ctvmq.par[ltrk][0] * sinph[ltrk]/cosdph[ltrk];
1681 double dphi_dc = 2.0 *
1682 (_ctvmq.xyzvrt[lvtx + 1][0] * cosph[ltrk] +
1683 _ctvmq.xyzvrt[lvtx + 1][1] * sinph[ltrk])/cosdph[ltrk];
1684 double dphi_dp = 2.0 * _ctvmq.par[ltrk][0] *
1685 (-_ctvmq.xyzvrt[lvtx + 1][0] * sinph[ltrk] +
1686 _ctvmq.xyzvrt[lvtx + 1][1] * cosph[ltrk])/cosdph[ltrk];
1687
1688 // Now load the derivative matrix
1689 int lvele = 3 * lvtx;
1690 // dPx/dx:
1691 dp_dpar[nvtx][lvele][3] += -pmom[ltrk].y() * dphi_dx;
1692 // dPy/dx:
1693 dp_dpar[nvtx][lvele][4] += pmom[ltrk].x() * dphi_dx;
1694 // dPz/dx:
1695 dp_dpar[nvtx][lvele][5] = 0.;
1696 // dPy/dx:
1697 dp_dpar[nvtx][lvele][6] = 0.;
1698
1699 lvele++;
1700 // dPx/dy:
1701 dp_dpar[nvtx][lvele][3] += -pmom[ltrk].y() * dphi_dy;
1702 // dPy/dy:
1703 dp_dpar[nvtx][lvele][4] += pmom[ltrk].x() * dphi_dy;
1704 // dPz/dy:
1705 dp_dpar[nvtx][lvele][5] = 0.;
1706 // dE/dy:
1707 dp_dpar[nvtx][lvele][6] = 0.;
1708
1709 lvele++;
1710 // dPx/dz:
1711 dp_dpar[nvtx][lvele][3] = 0.;
1712 // dPy/dz:
1713 dp_dpar[nvtx][lvele][4] = 0.;
1714 // dPz/dz:
1715 dp_dpar[nvtx][lvele][5] = 0.;
1716 // dE/dz:
1717 dp_dpar[nvtx][lvele][6] = 0.;
1718
1719 lvele = 3 * (ltrk + _ctvmq.nvertx);
1720 // dPx/dcurv[ltrk]:
1721 dp_dpar[nvtx][lvele][3] = -(pmom[ltrk].x()/_ctvmq.par[ltrk][0])
1722 - pmom[ltrk].y() * dphi_dc;
1723 // dPy/dcurv[ltrk]:
1724 dp_dpar[nvtx][lvele][4] = -(pmom[ltrk].y()/_ctvmq.par[ltrk][0])
1725 + pmom[ltrk].x() * dphi_dc;
1726 // dPz/dcurv[ltrk]:
1727 dp_dpar[nvtx][lvele][5] = -(pmom[ltrk].z()/_ctvmq.par[ltrk][0]);
1728 // dE/dcurv[ltrk]:
1729 dp_dpar[nvtx][lvele][6] =
1730 -mom3[ltrk].mag2()/(_ctvmq.par[ltrk][0] * pmom[ltrk].e());
1731
1732 lvele++;
1733 // dPx/dphi[ltrk]:
1734 dp_dpar[nvtx][lvele][3] = -pmom[ltrk].y() * (1.0 + dphi_dp);
1735 // dPy/dphi[ltrk]:
1736 dp_dpar[nvtx][lvele][4] = pmom[ltrk].x() * (1.0 + dphi_dp);
1737 // dPz/dphi[ltrk]:
1738 dp_dpar[nvtx][lvele][5] = 0.;
1739 // dE/dphi[ltrk]:
1740 dp_dpar[nvtx][lvele][6] = 0.;
1741
1742 lvele++;
1743 // dPx/dcot[ltrk]:
1744 dp_dpar[nvtx][lvele][3] = 0;
1745 // dPy/dcot[ltrk]:
1746 dp_dpar[nvtx][lvele][4] = 0;
1747 // dPz/dcot[ltrk]:
1748 dp_dpar[nvtx][lvele][5] = pmom[ltrk].perp();
1749 // dE/dcot[ltrk]:
1750 dp_dpar[nvtx][lvele][6] =
1751 pmom[ltrk].perp2() * _ctvmq.par[ltrk][2] / pmom[ltrk].e();
1752 }
1753 }
1754 }
1755
1756 // -----------------------------------------------------------------------------------------------
1757 // Now calculate the new error matrix
1758 // -----------------------------------------------------------------------------------------------
1759 // Extract the interesting bits from VMAT
1760 HepMatrix vmat(ctvmft_dim,ctvmft_dim,0);
1761 for (int lpar = 0; lpar < ctvmft_dim; lpar++){
1762 int l = lpar%3;
1763 int lvele = 0;
1764 if (lpar < 3 * _ctvmq.nvertx){
1765 int lvtx = lpar/3;
1766 lvele = _ctvmq.voff[lvtx] + l;
1767 }
1768 else {
1769 int ltrk = (lpar - 3 * _ctvmq.nvertx)/3;
1770 lvele = _ctvmq.toff[ltrk] + l;
1771 }
1772 for (int kpar = 0; kpar < ctvmft_dim; kpar++) {
1773 int k = kpar%3;
1774 int kvele = 0;
1775 if (kpar < 3 * _ctvmq.nvertx) {
1776 int kvtx = kpar/3;
1777 kvele = _ctvmq.voff[kvtx] + k;
1778 }
1779 else{
1780 int ktrk = (kpar - 3 * _ctvmq.nvertx)/3;
1781 kvele = _ctvmq.toff[ktrk] + k;
1782 }
1783 vmat[kpar][lpar] = _ctvmfr.vmat[kvele][lvele];
1784 }
1785 }
1786
1787 // Just about done
1788 HepMatrix ans(7,7,0);
1789 //HepMatrix answer[_maxvtx] = { ans, ans, ans };
1790 HepMatrix answer[_maxvtx] = { ans };
1791 for (int nvtx = 0; nvtx < _ctvmq.nvertx; nvtx++)
1792 answer[nvtx] = (dp_dpar[nvtx].T() * vmat) * dp_dpar[nvtx];
1793 errors = answer[0];
1794 }
1795
1796 //--------------------------------------------------------------------------------------------------
1797 int MultiVertexFitterD::vOff(vertexNumber jv) const
1798 {
1799 if (jv < VERTEX_1 || jv > _maxvtx)
1800 return -999;
1801 else
1802 return _ctvmq.voff[jv-1];
1803 }
1804
1805 //--------------------------------------------------------------------------------------------------
1806 int MultiVertexFitterD::tOff(const int trkId) const
1807 {
1808 for (int kt=0; kt<_ctvmq.ntrack; ++kt) {
1809 if (trkId == _ctvmq.list[kt])
1810 return _ctvmq.toff[kt];
1811 }
1812 return -999;
1813 }
1814
1815 //--------------------------------------------------------------------------------------------------
1816 int MultiVertexFitterD::pOff(int lp) const
1817 {
1818 if (lp < 1)
1819 return -999;
1820 else
1821 return _ctvmq.poff[lp-1];
1822 }
1823
1824 //--------------------------------------------------------------------------------------------------
1825 int MultiVertexFitterD::cOff(int lc) const
1826 {
1827 if (lc < 1)
1828 return -999;
1829 else
1830 return _ctvmq.coff[lc-1];
1831 }
1832
1833 //--------------------------------------------------------------------------------------------------
1834 int MultiVertexFitterD::mOff() const
1835 {
1836 return _ctvmq.moff;
1837 }
1838
1839 //--------------------------------------------------------------------------------------------------
1840 double MultiVertexFitterD::VMat(int i, int j) const
1841 {
1842 if (i <0 || j < 0)
1843 return -999.;
1844 else
1845 return _ctvmfr.vmat[i][j];
1846 }
1847
1848 // Facilitates CandNode recursion. CandNodes have no way of deciding which vertex they are, and
1849 // these trivial functions help them do that.
1850 //--------------------------------------------------------------------------------------------------
1851 MultiVertexFitterD::vertexNumber MultiVertexFitterD::allocateVertexNumber()
1852 {
1853 if ((_currentAllocatedVertexNumber < PRIMARY_VERTEX) ||
1854 (_currentAllocatedVertexNumber > _maxvtx)) {
1855 cout << "MultiVertexFitterD::allocateVertexNumber: out of range!" << endl;
1856 return PRIMARY_VERTEX;
1857 }
1858 return vertexNumber(++_currentAllocatedVertexNumber);
1859 }
1860
1861 //--------------------------------------------------------------------------------------------------
1862 void MultiVertexFitterD::resetAllocatedVertexNumber()
1863 {
1864 _currentAllocatedVertexNumber = 0;
1865 }
1866
1867 //--------------------------------------------------------------------------------------------------
1868 void MultiVertexFitterD::restoreFromCommons()
1869 {
1870 _stat = 0;
1871 _ctvmq_com = (CTVMQ*) dctvmq_address_();
1872 _ctvmfr_com = (CTVMFR*) dctvmfr_address_();
1873 _fiddle_com = (FIDDLE*) dfiddle_address_();
1874 _trkprm_com = (TRKPRM*) dtrkprm_address_();
1875 _ctvmq = *_ctvmq_com;
1876 _ctvmfr = *_ctvmfr_com;
1877 _fiddle = *_fiddle_com;
1878 _trkprm = *_trkprm_com;
1879 }