StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
StMinuitVertexFinder.cxx
1 /***************************************************************************
2  *
3  * $Id: StMinuitVertexFinder.cxx,v 1.59 2017/05/09 12:29:40 smirnovd Exp $
4  *
5  * Author: Thomas Ullrich, Feb 2002
6  ***************************************************************************
7  *
8  * Description:
9  *
10  **************************************************************************/
11 #include <vector>
12 
13 #include "StEmcUtil/geometry/StEmcGeom.h"
14 #include "StEvent/StCtbTriggerDetector.h"
15 #include "StEvent/StDcaGeometry.h"
16 #include "StEvent/StEmcCollection.h"
17 #include "StEvent/StEmcDetector.h"
18 #include "StEvent/StEmcModule.h"
19 #include "StEvent/StEmcRawHit.h"
20 #include "StEvent/StEvent.h"
21 #include "StEvent/StGlobalTrack.h"
22 #include "StEvent/StTrackDetectorInfo.h"
23 #include "StEvent/StTrackNode.h"
24 #include "StEvent/StTriggerDetectorCollection.h"
25 #include "StGenericVertexMaker/Minuit/StMinuitVertexFinder.h"
26 #include "StGenericVertexMaker/Minuit/St_VertexCutsC.h"
27 #include "StGenericVertexMaker/StCtbMatcher.h"
28 #include "St_base/StMessMgr.h"
29 
30 
31 std::vector<StPhysicalHelixD> StMinuitVertexFinder::mHelices;
32 std::vector<UShort_t> StMinuitVertexFinder::mHelixFlags;
33 std::vector<Double_t > StMinuitVertexFinder::mZImpact;
34 Bool_t StMinuitVertexFinder::requireCTB;
35 Int_t StMinuitVertexFinder::nCTBHits;
36 //==========================================================
37 //==========================================================
38 void StMinuitVertexFinder::Clear(){
39  StGenericVertexFinder::Clear();
40  mStatusMin = 0;
41  mNSeed = 0;
42 }
43 
44 void
45 StMinuitVertexFinder::setExternalSeed(const StThreeVectorD& s)
46 {
47  mExternalSeedPresent = kTRUE;
48  mExternalSeed = s;
49 }
50 
51 
52 StMinuitVertexFinder::StMinuitVertexFinder(VertexFit_t fitMode) :
53  StGenericVertexFinder(SeedFinder_t::MinuitVF, fitMode)
54 {
55  mExternalSeedPresent = kFALSE;
56  mRequireCTB = kFALSE;
57  requireCTB = kFALSE;
58  mFXT = kFALSE;
59  mUseITTF = kFALSE;
60  mUseOldBEMCRank = kFALSE;
61  mLowerSplitVtxRank = kFALSE;
62  mVertexOrderMethod = orderByRanking; // change ordering by ranking
63  mMinTrack = -1;
64  mCTBSum = 0;
65 }
66 
67 
68 StMinuitVertexFinder::~StMinuitVertexFinder()
69 {
70  LOG_WARN << "Skipping delete Minuit in StMinuitVertexFinder::~StMinuitVertexFinder()" << endm;
71  mHelices.clear();
72  mHelixFlags.clear();
73  mZImpact.clear();
74 }
75 //________________________________________________________________________________
76 void StMinuitVertexFinder::InitRun(int run_number, const St_db_Maker* db_maker)
77 {
78  StGenericVertexFinder::InitRun(run_number, db_maker);
79 
80  St_VertexCutsC *cuts = St_VertexCutsC::instance();
81  mMinNumberOfFitPointsOnTrack = cuts->MinNumberOfFitPointsOnTrack();
82  mDcaZMax = cuts->DcaZMax(); // Note: best to use integer numbers
83  mMinTrack = (mMinTrack<0 ? cuts->MinTrack() : mMinTrack);
84  mRImpactMax = cuts->RImpactMax();
85  mZMin = cuts->ZMin(); // note: best to use integer numbers
86  mZMax = cuts->ZMax(); // note: best to use integer numbers
87  if (mZMin == mZMax) {
88  // historical defaults
89  mZMin = -200.0;
90  mZMax = 200.0;
91  }
92  LOG_INFO << "Set cuts: MinNumberOfFitPointsOnTrack = " << mMinNumberOfFitPointsOnTrack
93  << " DcaZMax = " << mDcaZMax
94  << " MinTrack = " << mMinTrack
95  << " RImpactMax = " << mRImpactMax
96  << " ZMin = " << mZMin
97  << " ZMax = " << mZMax
98  << endm;
99 }
100 //________________________________________________________________________________
101 
102 
103 void
104 StMinuitVertexFinder::setFlagBase(){
105  if(mUseITTF){
106  mFlagBase = 8000;
107  } else {
108  mFlagBase = 1000;
109  }
110 }
111 
112 Int_t StMinuitVertexFinder::findSeeds() {
113  mNSeed = 0;
114 
115  int zIdxMax = (int) (mZMax - mZMin);
116  Int_t zImpactArr[zIdxMax]; // simple array to 'histogram' zImpacts
117  for (Int_t i=0; i < zIdxMax; i++)
118  zImpactArr[i]=0;
119 
120  Int_t nTrk = mZImpact.size();
121  for (Int_t iTrk=0; iTrk < nTrk; iTrk++) {
122  if ((mZImpact[iTrk] > mZMin) &&
123  (mZImpact[iTrk] < mZMax))
124  zImpactArr[int(mZImpact[iTrk]-mZMin)]++;
125  }
126 
127  // Search for maxima using sliding 3-bin window
128  Int_t nOldBin = 0;
129  Int_t slope = 0;
130  Int_t nBinZ = 3;
131  for (Int_t iBin=0; iBin < zIdxMax - nBinZ; iBin++) {
132  Int_t nTrkBin = 0;
133  for (Int_t iBin2=0; iBin2 < nBinZ; iBin2++) {
134  nTrkBin += zImpactArr[iBin + iBin2];
135  }
136  if (nTrkBin > nOldBin)
137  slope = 1;
138  else if (nTrkBin < nOldBin) {
139  if (slope == 1) {
140  if (mNSeed < maxSeed) {
141  Float_t seed_z = mZMin + iBin + (Float_t)nBinZ / 2 - 1;
142  Double_t meanZ = 0;
143  Int_t nTrkZ = 0;
144  for (Int_t iTrk = 0; iTrk < nTrk; iTrk ++ ) {
145  if ( fabs(mZImpact[iTrk] - seed_z ) < mDcaZMax ) {
146  meanZ += mZImpact[iTrk];
147  nTrkZ++;
148  }
149  }
150  if (nTrkZ >= mMinTrack) {
151  if (mDebugLevel) {
152  LOG_INFO << "Seed " << mNSeed << ", z " << seed_z << " nTrk " << nTrkZ << " meanZ/nTrkZ " << meanZ/nTrkZ << endm;
153  }
154  seed_z = meanZ/nTrkZ;
155  mSeedZ[mNSeed] = seed_z;
156  mNSeed++;
157  }
158  }
159  else {
160  LOG_WARN << "Too many vertex seeds, limit=" << maxSeed << endm;
161  }
162  }
163  slope = -1;
164  }
165  if (mDebugLevel > 1) {
166  LOG_INFO << "iBin " << iBin << " nTrkBin " << nTrkBin << " nOldBin " << nOldBin << ", slope " << slope << " mNSeed " << mNSeed << endm;
167  }
168  nOldBin = nTrkBin;
169  }
170 
171  LOG_INFO << "Found " << mNSeed << " seeds" << endm;
172  return mNSeed;
173 }
174 
175 void StMinuitVertexFinder::fillBemcHits(StEvent *event){
176  static Int_t nMod = 120;
177  static Int_t nEta = 20;
178  static Int_t nSub = 2;
179  static Float_t mEmcThres = 0.15;
180  for (Int_t m=0; m < nMod; m++)
181  for (Int_t e=0; e < nEta; e++)
182  for (Int_t s=0; s < nSub; s++)
183  mBemcHit[m][e][s]=0;
184 
185  Int_t n_emc_hit=0;
186  if (event->emcCollection() && event->emcCollection()->detector(kBarrelEmcTowerId)) {
187  StEmcDetector* bemcDet = event->emcCollection()->detector(kBarrelEmcTowerId);
188  for (Int_t iMod=0; iMod < nMod; iMod++) {
189  if (!bemcDet->module(iMod))
190  continue;
191  StEmcModule *mod = bemcDet->module(iMod);
192  StSPtrVecEmcRawHit& hits = mod->hits();
193  for (StEmcRawHitIterator hitIter = hits.begin(); hitIter != hits.end(); hitIter++) {
194  StEmcRawHit *hit = *hitIter;
195  if (hit->energy() > mEmcThres) {
196  mBemcHit[hit->module()-1][hit->eta()-1][hit->sub()-1]=1;
197  n_emc_hit++;
198  }
199  }
200  }
201  }
202  if (mDebugLevel) {
203  LOG_INFO << "Found " << n_emc_hit << " emc hits" << endm;
204  }
205 }
206 
207 Int_t
208 StMinuitVertexFinder::matchTrack2BEMC(const StTrack *track){
209  static const Double_t rBemc = 242; // middle of tower
210  static StEmcGeom *bemcGeom = StEmcGeom::getEmcGeom("bemc");
211  //static Double_t rBemc = bemcGeom->Radius(); // front face??
212  //LOG_INFO << "rBemc: " << rBemc << endm;
213 
214  if (track->outerGeometry()==0) {
215  if (mDebugLevel) { // Happens only rarely
216  LOG_INFO << "No outer track geom" << endm;
217  }
218  return 0;
219  }
220 
221  StPhysicalHelixD helix = track->outerGeometry()->helix();
222 
223  if (!helix.valid()) {
224  if (mDebugLevel) { // Happens only rarely
225  LOG_INFO << "Invalid helix" << endm;
226  }
227  return 0;
228  }
229 
230  pairD d2;
231  d2 = helix.pathLength(rBemc);
232  if (d2.first > 99999999 && d2.second > 99999999)
233  return 0;
234  Double_t path=d2.second;
235  if (d2.first >= 0 && d2.first < d2.second)
236  path = d2.first;
237  else if(d2.first>=0 || d2.second<=0) {
238  LOG_WARN << "Unexpected solution for track crossing Cyl:"
239  << " track mom = "
240  << track->geometry()->momentum().mag()
241  << ", d2.first=" << d2.first
242  << ", second=" << d2.second <<", trying first" << endm;
243  path=d2.first;
244  }
245  StThreeVectorD posCyl = helix.at(path);
246 
247  Float_t phi=posCyl.phi();
248  Float_t eta=posCyl.pseudoRapidity();
249 
250  if (fabs(eta) < 1) {
251  Int_t mod, ieta, sub;
252  if (bemcGeom->getBin(phi, eta, mod, ieta, sub) == 0) {
253  // There is some edge effect leading to sub=-1.
254  // Strange, but leave in for now// HOW CAN IT be: sub == -1????
255  if (sub > 0 && mBemcHit[mod-1][ieta-1][sub-1]) {
256  return 1;
257  }
258  }
259  }
260  return 0;
261 }
262 
263 Int_t StMinuitVertexFinder::checkCrossMembrane(const StTrack *track) {
264  Int_t n_pnt_neg=0, n_pnt_pos=0;
265 
266  StPtrVecHit hits = track->detectorInfo()->hits(kTpcId);
267  for (StHitIterator hitIter = hits.begin(); hitIter != hits.end(); hitIter++) {
268  if ((*hitIter)->position().z() < 0)
269  n_pnt_neg++;
270  if ((*hitIter)->position().z() > 0)
271  n_pnt_pos++;
272  }
273  return (n_pnt_pos > 5 && n_pnt_neg > 5);
274 }
275 
276 void StMinuitVertexFinder::calculateRanks() {
277 
278  // Calculation of veretx ranks to select 'best' (i.e. triggered)
279  // vertex
280  // Three ranks are used, based on average dip, number of BEMC matches
281  // and tarcks crossing central membrane
282  // Each rank is normalised to be 0 for 'average' valid vertices and
283  // has a sigma of 1.
284  //
285  // Values are limited to [-5,1] for each rank
286  //
287  // Note that the average dip angle ranking is naturally peaked to 1,
288  // while the others are peaked at 1 (intentionally) due to rounding.
289 
290  // A fancier way would be to calculate something more like
291  // a likelihood based on the expected distributions.
292  // That's left as an excercise to the reader.
293 
294  // Added by Ant: split vertices have 3 rank units deducted near the
295  // end of function (if mLowerSplitVtxRank). See hypernews post:
296  // http://www.star.bnl.gov/HyperNews-star/get/vertex/127.html
297 
298  Int_t nBemcMatchTot = 0;
299  Int_t nVtxTrackTot = 0;
300  for (Int_t iVertex=0; iVertex < size(); iVertex++) {
301  StPrimaryVertex *primV = getVertex(iVertex);
302  nVtxTrackTot += primV->numTracksUsedInFinder();
303  nBemcMatchTot += primV->numMatchesWithBEMC();
304  }
305 
306  mBestRank = -999;
307  mBestVtx = 0;
308  for (Int_t iVertex=0; iVertex < size(); iVertex++) {
309  StPrimaryVertex *primV = getVertex(iVertex);
310  // expected values based on Cu+Cu data
311  Float_t avg_dip_expected = -0.0033*primV->position().z();
312  Float_t n_bemc_expected = 0;
313  if (nVtxTrackTot) {
314  if (mUseOldBEMCRank)
315  n_bemc_expected = (1-0.25*(1-(float)primV->numTracksUsedInFinder()/nVtxTrackTot))*nBemcMatchTot;
316  else
317  n_bemc_expected = (float)primV->numTracksUsedInFinder()/nVtxTrackTot*nBemcMatchTot;
318  }
319 
320  Float_t n_cross_expected = fabs(primV->position().z())*0.0020*primV->numTracksUsedInFinder(); // old coeff 0.0016 with dca 3 and 10 points on track
321 
322  if (mDebugLevel) {
323  LOG_INFO << "vertex z " << primV->position().z() << " dip expected " << avg_dip_expected << " bemc " << n_bemc_expected << " cross " << n_cross_expected << endm;
324  }
325 
326  Float_t rank_avg_dip = 1 - fabs(primV->meanDip() - avg_dip_expected)*sqrt((float)primV->numTracksUsedInFinder())/0.67; // Sigma was 0.8 for old cuts
327 
328  Float_t rank_bemc = 0;
329  if (n_bemc_expected >= 1) {
330  //Float_t sigma = 0.12*n_bemc_match_tot;
331  Float_t sigma = 0.5*sqrt(n_bemc_expected);
332 
333  // limit sigma to avoid large weights at small multiplicity
334  sigma = ( sigma < 0.75 ? 0.75 : sigma);
335 
336  rank_bemc = (primV->numMatchesWithBEMC() - n_bemc_expected)/sigma;
337  if (mUseOldBEMCRank)
338  rank_bemc += 0.5; // distribution is asymmetric; add 0.5
339  }
340 
341  Float_t rank_cross = 0;
342  if ( n_cross_expected >= 1 ) {
343  Float_t sigma=1.1*sqrt(n_cross_expected);
344  rank_cross = (primV->numTracksCrossingCentralMembrane() - n_cross_expected)/sigma;
345  }
346 
347  // Handle possible overflows
348  rank_avg_dip = ( rank_avg_dip < -5 ? -5 : rank_avg_dip );
349  rank_bemc = ( rank_bemc < -5 ? -5 : (rank_bemc > 1 ? 1 : rank_bemc) );
350  rank_cross = ( rank_cross < -5 ? -5 : (rank_cross > 1 ? 1 : rank_cross) );
351 
352  if (mDebugLevel) {
353  LOG_INFO << "rankings: " << rank_avg_dip << " " << rank_bemc << " " << rank_cross << endm;
354  }
355 
356  //Give split vertices a lower rank...
357  if (mLowerSplitVtxRank && mCTBSum > 6000.0*primV->numTracksUsedInFinder()/80. + 2000)
358  primV->setRanking(rank_cross+rank_bemc+rank_avg_dip-3);
359  else
360  primV->setRanking(rank_cross+rank_bemc+rank_avg_dip);
361 
362  if (primV->ranking() > mBestRank) {
363  mBestRank = primV->ranking();
364  mBestVtx = primV;
365  }
366  }
367 }
368 
369 
370 int StMinuitVertexFinder::fit(StEvent* event)
371 {
372  setFlagBase();
373 
374  // get CTB info
375  StCtbTriggerDetector* ctbDet = 0;
376  std::vector<ctbHit> ctbHits;
377 
378  StTriggerDetectorCollection* trigCol = event->triggerDetectorCollection();
379  mCTBSum = 0;
380  if(trigCol){
381  ctbDet = &(trigCol->ctb());
382 
383  for (UInt_t slat = 0; slat < ctbDet->numberOfSlats(); slat++) {
384  for (UInt_t tray = 0; tray < ctbDet->numberOfTrays(); tray++) {
385  ctbHit curHit;
386  curHit.adc = ctbDet->mips(tray,slat,0);
387  if(curHit.adc > 0){
388  mCTBSum += curHit.adc;
389  ctb_get_slat_from_data(slat, tray, curHit.phi, curHit.eta);
390  ctbHits.push_back(curHit);
391  }
392  }
393  }
394  }
395 
396  // Loop over all global tracks (TPC) and store the refering helices and
397  // their estimated DCA resolution in vectors. Quality cuts are applied (see
398  // StMinuitVertexFinder::accept()). The helices and the sigma are used in
399  // fcn to calculate the fit potential which gets minimized by Minuit.
400  mDCAs.clear();
401  mHelices.clear();
402  mHelixFlags.clear();
403  mZImpact.clear();
404 
405  fillBemcHits(event);
406 
407  Int_t n_ctb_match_tot = 0;
408  Int_t n_bemc_match_tot = 0;
409  Int_t n_cross_tot = 0;
410 
411  // In FXT mode, we want to have a bias = -2 cm below the z-axis
412  // for the approximate physical target location. This could
413  // potentially be a database table (PrimaryVertexCuts) parameter,
414  // but the bias is approximate and highly unlikely to change/finetune.
415  StThreeVectorD beamAxis(0.0, mFXT ? -2.0 : 0.0, 0.0);
416  double RImpactMax2 = mRImpactMax*mRImpactMax;
417 
418  for (const StTrackNode* stTrack : event->trackNodes())
419  {
420  StGlobalTrack* g = ( StGlobalTrack*) stTrack->track(global);
421  if (!accept(g)) continue;
422  StDcaGeometry* gDCA = g->dcaGeometry();
423  if (! gDCA) continue;
424  StPhysicalHelixD gHelix = gDCA->helix();
425  StThreeVectorD DCAPosition = gHelix.at(gHelix.pathLength(beamAxis.x(),beamAxis.y())) - beamAxis;
426  double RImpact2 = DCAPosition.perp2();
427  if (RImpact2 > RImpactMax2) continue; // calculate square once instead of sqrt N times
428  mDCAs.push_back(gDCA);
429  // StPhysicalHelixD helix = gDCA->helix();
430  // mHelices.push_back(helix);
431  mHelices.push_back(g->geometry()->helix());
432  mHelixFlags.push_back(1);
433  Double_t z_lin = DCAPosition.z();
434  mZImpact.push_back(z_lin);
435 
436  Bool_t shouldHitCTB = kFALSE;
437  Double_t etaInCTBFrame = -999;
438  bool ctb_match = EtaAndPhiToOrriginAtCTB(g,&ctbHits,shouldHitCTB,etaInCTBFrame);
439  if (ctb_match) {
440  mHelixFlags[mHelixFlags.size()-1] |= kFlagCTBMatch;
441  n_ctb_match_tot++;
442  }
443 
444  if (matchTrack2BEMC(g)) {
445  mHelixFlags[mHelixFlags.size()-1] |= kFlagBEMCMatch;
446  n_bemc_match_tot++;
447  }
448 
449  if (checkCrossMembrane(g)) {
450  mHelixFlags[mHelixFlags.size()-1] |= kFlagCrossMembrane;
451  n_cross_tot++;
452  }
453  }
454 
455  if (mDebugLevel) {
456  LOG_INFO << "Found " << n_ctb_match_tot << " ctb matches, " << n_bemc_match_tot << " bemc matches, " << n_cross_tot << " tracks crossing central membrane" << endm;
457  }
458 
459  // In case there are no tracks left we better quit
460  if (mHelices.empty()) {
461  LOG_WARN << "StMinuitVertexFinder::fit: no tracks to fit." << endm;
462  mStatusMin = -1;
463  return 0;
464  }
465 
466  LOG_INFO << "StMinuitVertexFinder::fit size of helix vector: " << mHelices.size() << endm;
467 
468  // Set some global pars
469  if (mRequireCTB) requireCTB = kTRUE;
470 
471  // Reset and clear Minuit parameters mStatusMin
472  mMinuit->mnexcm("CLEar", 0, 0, mStatusMin);
473 
474  // Make sure the global pointer points to valid object so Minuit uses correct data
476 
477  // Set parameters and start values. We do constrain the parameters since it
478  // harms the fit quality (see Minuit documentation).
479  //
480  // Initialize the seed with a z value which is not one of the discrete
481  // values which it can tend to, implies zero not allowed. Also need
482  // different initialization when vertex constraint.
483 
484  static Double_t step[3] = {0.03, 0.03, 0.03};
485 
486  // Scan z to find best seed for the actual fit.
487  // Skip this step if an external seed is given.
488  if (!mExternalSeedPresent) {
489  findSeeds();
490  }
491  else {
492  mNSeed = 1;
493  }
494 
495  Float_t old_vtx_z = -999;
496  Double_t seed_z = -999;
497  Double_t chisquare = 0;
498 
499  for (Int_t iSeed = 0; iSeed < mNSeed; iSeed++) {
500 
501  // Reset and clear Minuit parameters mStatusMin
502  mMinuit->mnexcm("CLEar", 0, 0, mStatusMin);
503 
504  seed_z= mSeedZ[iSeed];
505 
506  if (mExternalSeedPresent)
507  seed_z = mExternalSeed.z();
508  if (mDebugLevel) {
509  LOG_INFO << "Vertex seed = " << seed_z << endm;
510  }
511 
512  if (mVertexFitMode == VertexFit_t::Beamline1D){
513  mMinuit->mnparm(0, "z", seed_z, step[2], 0, 0, mStatusMin);
514  }
515  else {
516  mMinuit->mnparm(0, "x", 0, step[0], 0, 0, mStatusMin);
517  mMinuit->mnparm(1, "y", 0, step[1], 0, 0, mStatusMin);
518  mMinuit->mnparm(2, "z", seed_z, step[2], 0, 0, mStatusMin);
519  }
520 
521  Int_t done = 0;
522  Int_t iter = 0;
523 
524  Int_t n_trk_vtx = 0;
525  Int_t n_helix = mHelices.size();
526  do {
527  // For most vertices one pass is fine, but multiple passes can be done
528  n_trk_vtx = 0;
529  for (Int_t i=0; i < n_helix; i++) {
530  if (fabs(mZImpact[i]-seed_z) < mDcaZMax) {
531  mHelixFlags[i] |= kFlagDcaz;
532  n_trk_vtx++;
533  }
534  else
535  mHelixFlags[i] &= ~kFlagDcaz;
536  }
537 
538  if (mDebugLevel) {
539  LOG_INFO << n_trk_vtx << " tracks within dcaZ cut (iter " << iter <<" )" << endm;
540  }
541  if (n_trk_vtx < mMinTrack) {
542  if (mDebugLevel) {
543  LOG_INFO << "Less than mMinTrack (=" << mMinTrack << ") tracks, skipping vtx" << endm;
544  }
545  continue;
546  }
547  mMinuit->mnexcm("MINImize", 0, 0, mStatusMin);
548  done = 1;
549 
550  // Check fit result
551  if (mStatusMin) {
552  LOG_WARN << "StMinuitVertexFinder::fit: error in Minuit::mnexcm(), check status flag. ( iter=" << iter << ")" << endm;
553  done = 0; // refit
554  }
555 
556  Double_t fedm, errdef;
557  Int_t npari, nparx;
558 
559  mMinuit->mnstat(chisquare, fedm, errdef, npari, nparx, mStatusMin);
560 
561  if (mStatusMin != 3) {
562  LOG_INFO << "Warning: Minuit Status: " << mStatusMin << ", func val " << chisquare<< endm;
563  done = 0; // refit
564  }
565  mMinuit->mnhess();
566 
567  Double_t new_z, zerr;
568  if (mVertexFitMode == VertexFit_t::Beamline1D) {
569  mMinuit->GetParameter(0, new_z, zerr);
570  }
571  else {
572  mMinuit->GetParameter(2, new_z, zerr);
573  }
574 
575  if (fabs(new_z - seed_z) > 1) // refit if vertex shifted
576  done = 0;
577 
578  Int_t n_trk = 0;
579  for (Int_t i=0; i < n_helix; i++) {
580  if ( fabs(mZImpact[i] - new_z) < mDcaZMax ) {
581  n_trk++;
582  }
583  }
584  if ( 10 * abs(n_trk - n_trk_vtx) >= n_trk_vtx ) // refit if number of track changed by more than 10%
585  done = 0;
586 
587  iter++;
588  seed_z = new_z; // seed for next iteration
589  } while (!done && iter < 5 && n_trk_vtx >= mMinTrack);
590 
591  if (n_trk_vtx < mMinTrack)
592  continue;
593 
594  if (!done) {
595  LOG_WARN << "Vertex unstable: no convergence after " << iter << " iterations. Skipping vertex " << endm;
596  continue;
597  }
598 
599  if (!mExternalSeedPresent && fabs(seed_z-mSeedZ[iSeed]) > mDcaZMax) {
600  LOG_WARN << "Vertex walks during fits: seed was " << mSeedZ[iSeed] << ", vertex at " << seed_z << endm;
601  }
602 
603  if (fabs(seed_z - old_vtx_z) < mDcaZMax) {
604  if (mDebugLevel) {
605  LOG_INFO << "Vertices too close (<mDcaZMax). Skipping" << endm;
606  }
607  continue;
608  }
609 
610  // Store vertex
611  StThreeVectorD XVertex;
612  Float_t cov[6];
613  memset(cov,0,sizeof(cov));
614 
615  Double_t val, verr;
616  if (mVertexFitMode == VertexFit_t::Beamline1D) {
617  mMinuit->GetParameter(0, val, verr);
618  XVertex.setZ(val); cov[5]=verr*verr;
619 
620  // LSB Really error in x and y should come from error on constraint
621  // At least this way it is clear that those were fixed paramters
622  XVertex.setX(beamX(val)); cov[0]=0.1; // non-zero error values needed for Sti
623  XVertex.setY(beamY(val)); cov[2]=0.1;
624  }
625  else {
626  XVertex = StThreeVectorD(mMinuit->fU[0],mMinuit->fU[1],mMinuit->fU[2]);
627  Double_t emat[9];
628  /* 0 1 2
629  3 4 5
630  6 7 8 */
631  mMinuit->mnemat(emat,3);
632  cov[0] = emat[0];
633  cov[1] = emat[3];
634  cov[2] = emat[4];
635  cov[3] = emat[6];
636  cov[4] = emat[7];
637  cov[5] = emat[8];
638  }
639  StPrimaryVertex primV;
640  primV.setPosition(XVertex);
641  primV.setChiSquared(chisquare); // this is not really a chisquare, but anyways
642  primV.setCovariantMatrix(cov);
643  primV.setVertexFinderId(minuitVertexFinder);
644  primV.setFlag(1); // was not set earlier by this vertex finder ?? Jan
645  primV.setRanking(333);
646  primV.setNumTracksUsedInFinder(n_trk_vtx);
647 
648  Int_t n_ctb_match = 0;
649  Int_t n_bemc_match = 0;
650  Int_t n_cross = 0;
651  n_trk_vtx = 0;
652 
653  Double_t mean_dip = 0;
654  Double_t sum_pt = 0;
655  for (UInt_t i=0; i < mHelixFlags.size(); i++) {
656  if (!(mHelixFlags[i] & kFlagDcaz))
657  continue;
658  n_trk_vtx++;
659  if (mHelixFlags[i] & kFlagCTBMatch)
660  n_ctb_match++;
661  if (mHelixFlags[i] & kFlagBEMCMatch)
662  n_bemc_match++;
663  if (mHelixFlags[i] & kFlagCrossMembrane)
664  n_cross++;
665  mean_dip += mHelices[i].dipAngle();
666  sum_pt += mHelices[i].momentum(0).perp();
667  }
668 
669  mean_dip /= n_trk_vtx;
670 
671  if (mDebugLevel) {
672  LOG_INFO << "check n_trk_vtx " << n_trk_vtx << ", found "
673  << n_ctb_match << " ctb matches, "
674  << n_bemc_match << " bemc matches, "
675  << n_cross << " tracks crossing central membrane\n"
676  << "mean dip " << mean_dip << endm;
677  }
678  primV.setNumMatchesWithCTB(n_ctb_match);
679  primV.setNumMatchesWithBEMC(n_bemc_match);
680  primV.setNumTracksCrossingCentralMembrane(n_cross);
681  primV.setMeanDip(mean_dip);
682  primV.setSumOfTrackPt(sum_pt);
683 
684  //..... add vertex to the list
685  addVertex(primV);
686 
687  old_vtx_z = XVertex.z();
688  }
689 
690  calculateRanks();
691 
692  // Reset the flag which tells us about external
693  // seeds. This needs to be provided for every event.
694  mExternalSeedPresent = kFALSE;
695 
696  requireCTB = kFALSE;
697 
698  return 1;
699 }
700 
701 
702 //________________________________________________________________________________
703 double StMinuitVertexFinder::CalcChi2DCAs(const StThreeVectorD &vtx) {
704  Double_t f = 0;
705  Double_t e;
706  nCTBHits = 0;
707  if (fabs(vtx.x())> 10) return 1e6;
708  if (fabs(vtx.y())> 10) return 1e6;
709  if (fabs(vtx.z())>300) return 1e6;
710  for (UInt_t i=0; i<mDCAs.size(); i++) {
711 
712  if ( !(mHelixFlags[i] & kFlagDcaz) || (requireCTB && !(mHelixFlags[i] & kFlagCTBMatch)) )
713  continue;
714 
715  const StDcaGeometry* gDCA = mDCAs[i];
716  if (! gDCA) continue;
717  const StPhysicalHelixD helix = gDCA->helix();
718  e = helix.distance(vtx, kFALSE); // false: don't do multiple loops
719  //VP version
720  //VP Double_t chi2 = e*e/(errMatrix[0] + errMatrix[2]);
721  Double_t err2;
722  Double_t chi2 = gDCA->thelix().Dca(&(vtx.x()),&err2);
723  chi2*=chi2/err2;
724  //EndVP
725  static double scale = 100;
726  f += scale*(1. - TMath::Exp(-chi2/scale)); // robust potential
727  // f -= scale*TMath::Exp(-chi2/scale); // robust potential
728  if((mHelixFlags[i] & kFlagCTBMatch) && e<3.0) nCTBHits++;
729  }
730  return f;
731 }
732 
733 
737 bool StMinuitVertexFinder::accept(StTrack* track) const
738 {
739  return (track &&
740  track->flag() >= 0 &&
741  track->fitTraits().numberOfFitPoints() >= mMinNumberOfFitPointsOnTrack &&
742  !track->topologyMap().trackFtpc() &&
743  finite(track->length()) && //LSB another temporary check
744  track->geometry()->helix().valid());
745 }
746 
747 
750 {
751  mMinuit->SetPrintLevel(level);
752 }
753 
754 
755 void StMinuitVertexFinder::printInfo(ostream& os) const
756 {
757  os << "StMinuitVertexFinder - Statistics:" << endl;
758  os << "Number of vertices found ......." << size() << endl;
759  os << "Rank of best vertex ............" << mBestRank << endl;
760  if(mBestVtx) {
761  os << "Properties of best vertex:" << endl;
762  os << "position ..................... " << mBestVtx->position() << endl;
763  os << "position errors .............. " << mBestVtx->positionError()<< endl;
764  os << "# of used tracks ............. " << mBestVtx->numTracksUsedInFinder() << endl;
765  os << "Chisquare .................... " << mBestVtx->chiSquared() << endl;
766  }
767  os << "min # of fit points for tracks . " << mMinNumberOfFitPointsOnTrack << endl;
768 }
769 
770 
771 Int_t StMinuitVertexFinder::NCtbMatches() {
772  return nCTBHits;
773 }
bool valid(double world=1.e+5) const
checks for valid parametrization
Definition: StHelix.hh:128
double beamX(double z) const
double beamY(double z) const
double distance(const StThreeVector< double > &p, bool scanPeriods=true) const
minimal distance between point and helix
Definition: StHelix.cc:240
pair< double, double > pathLength(double r) const
path length at given r (cylindrical r)
Definition: StHelix.cc:351
void setPrintLevel(Int_t=0)
Use mMinuit print level.
VertexFit_t mVertexFitMode
The type of vertex fit to use in derived concrete implementation.
static StGenericVertexFinder * sSelf
By default point to invalid object.
Int_t getBin(const Float_t phi, const Float_t eta, Int_t &m, Int_t &e, Int_t &s) const
Definition: StEmcGeom.h:321
double Dca(const double point[3], double *dcaErr=0) const
DCA to given space point (with error matrix)