ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitCommon/VertexFit/src/MultiVertexFitter.cc
Revision: 1.5
Committed: Mon Oct 12 21:39:22 2009 UTC (15 years, 6 months ago) by loizides
Content type: text/plain
Branch: MAIN
CVS Tags: Mit_032, Mit_031, Mit_025c_branch2, Mit_025c_branch1, Mit_030, Mit_029c, Mit_030_pre1, Mit_029a, Mit_029, Mit_029_pre1, Mit_028a, Mit_025c_branch0, Mit_028, Mit_027a, Mit_027, Mit_026, Mit_025e, Mit_025d, Mit_025c, Mit_025b, Mit_025a, Mit_025, Mit_025pre2, Mit_024b, Mit_025pre1, Mit_024a, Mit_024, Mit_023, Mit_022a, Mit_022, Mit_020d, TMit_020d, Mit_020c, Mit_021, Mit_021pre2, Mit_021pre1, Mit_020b, Mit_020a, Mit_020, Mit_020pre1, Mit_018, Mit_017, Mit_017pre3, Mit_017pre2, Mit_017pre1, V07-05-00, Mit_016, Mit_015b, Mit_015a, Mit_015, Mit_014e, Mit_014d, Mit_014c, Mit_014b, ConvRejection-10-06-09, Mit_014a, Mit_014, Mit_014pre3, Mit_014pre2, Mit_014pre1, Mit_013d, Mit_013c, Mit_013b, Mit_013a, Mit_013, Mit_013pre1, Mit_012i, Mit_012g, Mit_012f, Mit_012e, Mit_012d, Mit_012c, Mit_012b, Mit_012a, Mit_012, Mit_011a, HEAD
Branch point for: Mit_025c_branch
Changes since 1.4: +2 -1 lines
Log Message:
Use CLHEP namespace.

File Contents

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