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

# User Rev Content
1 loizides 1.2 // $Id: MultiVertexFitterD.cc,v 1.1 2008/11/13 16:34:29 paus Exp $
2 paus 1.1
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 loizides 1.2
21     //--------------------------------------------------------------------------------------------------
22 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
28 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
53 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
113 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
159 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
207 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
225 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
243 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
261 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
290 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
301 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
312 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
342 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
366 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
377 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
388 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
399 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
409 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
423 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
488 paus 1.1 void MultiVertexFitterD::print() const
489     {
490     print(cout);
491     }
492    
493 loizides 1.2 //--------------------------------------------------------------------------------------------------
494 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
584 paus 1.1 void MultiVertexFitterD::printErr() const
585     {
586     printErr(cout);
587     }
588    
589 loizides 1.2 //--------------------------------------------------------------------------------------------------
590 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
823 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
832 paus 1.1 int MultiVertexFitterD::getIJKErr0() const
833     {
834     return _ctvmq.ijkerr[0];
835     }
836 loizides 1.2
837     //--------------------------------------------------------------------------------------------------
838 paus 1.1 int MultiVertexFitterD::getIJKErr1() const
839     {
840     return _ctvmq.ijkerr[1];
841     }
842 loizides 1.2
843     //--------------------------------------------------------------------------------------------------
844 paus 1.1 int MultiVertexFitterD::getIJKErr2() const
845     {
846     return _ctvmq.ijkerr[2];
847     }
848    
849 loizides 1.2 //--------------------------------------------------------------------------------------------------
850 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
865 paus 1.1 string MultiVertexFitterD::expert() const
866     {
867     return _expert;
868     }
869    
870 loizides 1.2 //--------------------------------------------------------------------------------------------------
871 paus 1.1 int MultiVertexFitterD::status() const
872     {
873     return _stat;
874     }
875    
876 loizides 1.2 //--------------------------------------------------------------------------------------------------
877 paus 1.1 float MultiVertexFitterD::chisq() const
878     {
879     // Chi-square of fit
880     return _ctvmq.chisqr[0];
881     }
882    
883 loizides 1.2 //--------------------------------------------------------------------------------------------------
884 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
894 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
907 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
925 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
949 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
973 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1000 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1030 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1059 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1089 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1106 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1152 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1233 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1241 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1326 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1334 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1361 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1369 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1394 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1420 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1456 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1492 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1520 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1535 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1563 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1587 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1617 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1797 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1806 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1816 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1825 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1834 paus 1.1 int MultiVertexFitterD::mOff() const
1835     {
1836     return _ctvmq.moff;
1837     }
1838    
1839 loizides 1.2 //--------------------------------------------------------------------------------------------------
1840 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1851 paus 1.1 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 loizides 1.2 //--------------------------------------------------------------------------------------------------
1862 paus 1.1 void MultiVertexFitterD::resetAllocatedVertexNumber()
1863     {
1864     _currentAllocatedVertexNumber = 0;
1865     }
1866    
1867 loizides 1.2 //--------------------------------------------------------------------------------------------------
1868 paus 1.1 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     }