tracker2algs.cxx
Go to the documentation of this file.
1 #include "Reco/tracker2algs.h"
3 #include "cetlib_except/exception.h"
4 
5 // these two methods are also duplicated in patrec. Maybe we can use the patrec tracks as the
6 // initial guess of the track parameters. Make sure we get them in the right order
7 
8 int gar::rec::initial_trackpar_estimate(const std::vector<gar::rec::TPCCluster> &TPCClusters,
9  std::vector<int> &TPCClusterlist,
10  float &curvature_init,
11  float &lambda_init,
12  float &phi_init,
13  float &xpos,
14  float &ypos,
15  float &zpos,
16  float &x_other_end,
17  unsigned int initialtpnTPCClusters,
18  int printlevel)
19 {
20 
21  size_t nTPCClusters = TPCClusterlist.size();
22  size_t firstTPCCluster = 0;
23  size_t farTPCCluster = TMath::Min(nTPCClusters-1, (size_t) initialtpnTPCClusters);;
24  size_t intTPCCluster = farTPCCluster/2;
25  size_t lastTPCCluster = nTPCClusters-1;
26 
27  float trackbeg[3] = {TPCClusters[TPCClusterlist[firstTPCCluster]].Position()[0],
28  TPCClusters[TPCClusterlist[firstTPCCluster]].Position()[1],
29  TPCClusters[TPCClusterlist[firstTPCCluster]].Position()[2]};
30 
31  float tp1[3] = {TPCClusters[TPCClusterlist[intTPCCluster]].Position()[0],
32  TPCClusters[TPCClusterlist[intTPCCluster]].Position()[1],
33  TPCClusters[TPCClusterlist[intTPCCluster]].Position()[2]};
34 
35  float tp2[3] = {TPCClusters[TPCClusterlist[farTPCCluster]].Position()[0],
36  TPCClusters[TPCClusterlist[farTPCCluster]].Position()[1],
37  TPCClusters[TPCClusterlist[farTPCCluster]].Position()[2]};
38 
39  if (printlevel>1)
40  {
41  std::cout << "TPCCluster Dump in initial_trackpar_estimate: " << std::endl;
42  for (size_t i=0;i<nTPCClusters;++i)
43  {
44  size_t ihf = i;
45  std::cout << i << " : " <<
46  TPCClusters[TPCClusterlist[ihf]].Position()[0] << " " <<
47  TPCClusters[TPCClusterlist[ihf]].Position()[1] << " " <<
48  TPCClusters[TPCClusterlist[ihf]].Position()[2] << std::endl;
49  }
50  }
51  if (printlevel>0)
52  {
53  std::cout << "first TPCCluster: " << firstTPCCluster << ", inter TPCCluster: " << intTPCCluster << " " << " far TPCCluster: " << farTPCCluster << std::endl;
54  std::cout << "in the TPCCluster list: " << TPCClusterlist[firstTPCCluster] << " " << TPCClusterlist[intTPCCluster] << " " << TPCClusterlist[farTPCCluster] << std::endl;
55  std::cout << "First TPCCluster x, y, z: " << trackbeg[0] << " " << trackbeg[1] << " " << trackbeg[2] << std::endl;
56  std::cout << "Inter TPCCluster x, y, z: " << tp1[0] << " " << tp1[1] << " " << tp1[2] << std::endl;
57  std::cout << "Far TPCCluster x, y, z: " << tp2[0] << " " << tp2[1] << " " << tp2[2] << std::endl;
58  }
59 
60  xpos = trackbeg[0];
61  ypos = trackbeg[1];
62  zpos = trackbeg[2];
63  x_other_end = TPCClusters[TPCClusterlist[lastTPCCluster]].Position()[0];
64 
65 
66  float ycc=0;
67  float zcc=0;
68  curvature_init = gar::rec::capprox(trackbeg[1],trackbeg[2],tp1[1],tp1[2],tp2[1],tp2[2],ycc,zcc);
69  //std::cout << " inputs to trackpar circ fit (y,z): " << trackbeg[1] << " " << trackbeg[2] << " : "
70  // << tp1[1] << " " << tp1[2] << " : " << tp2[1] << " " << tp2[2] << std::endl;
71  //std::cout << "curvature output: " << curvature_init << std::endl;
72 
73  // redo calc with a circle fit to all points, not just three
74 
75  double dycc=0;
76  double dzcc=0;
77  double drcc=0;
78  double dchisq=0;
79  int ifail=0;
80  std::vector<double> dtpcclusy;
81  std::vector<double> dtpcclusz;
82  for (size_t i=0;i<nTPCClusters; ++i)
83  {
84  dtpcclusy.push_back(TPCClusters[TPCClusterlist[i]].Position()[1]);
85  dtpcclusz.push_back(TPCClusters[TPCClusterlist[i]].Position()[2]);
86  }
87  int ict = nTPCClusters;
88  ouchef(dtpcclusy.data(),dtpcclusz.data(),ict,dycc,dzcc,drcc,dchisq,ifail);
89  if (ifail == 0 && drcc != 0)
90  {
91  ycc = dycc;
92  zcc = dzcc;
93  if (curvature_init < 0) drcc = -std::abs(drcc);
94  //if (ict > 3)
95  // {
96  // std::cout << "updating curvature " << ict << " " << curvature_init << " with " << 1.0/drcc << std::endl;
97  // }
98  curvature_init = 1.0/drcc;
99  }
100 
101 
102  phi_init = TMath::ATan2( trackbeg[2] - zcc, ycc - trackbeg[1] );
103  float phi2 = phi_init;
104  if (curvature_init<0) phi_init += TMath::Pi();
105  float radius_init = 10000;
106  if (curvature_init != 0) radius_init = 1.0/curvature_init;
107 
108  float dx1 = tp2[0] - xpos;
109  if (dx1 != 0)
110  {
111  float dphi2 = TMath::ATan2(tp2[2]-zcc,ycc-tp2[1])-phi2;
112  if (dphi2 > TMath::Pi()) dphi2 -= 2.0*TMath::Pi();
113  if (dphi2 < -TMath::Pi()) dphi2 += 2.0*TMath::Pi();
114  lambda_init = TMath::ATan(1.0/((radius_init/dx1)*dphi2));
115  }
116  else
117  {
118  //std::cout << "initial track par estimate failure" << std::endl;
119  lambda_init = 0;
120  return 1;
121  } // got fMinNumTPCClusters all at exactly the same value of x (they were sorted). Reject track.
122 
123  if (printlevel>0)
124  {
125  std::cout << "phi calc: dz, dy " << tp2[2]-trackbeg[2] << " " << tp2[1]-trackbeg[1] << std::endl;
126  std::cout << "initial curvature, phi, lambda: " << curvature_init << " " << phi_init << " " << lambda_init << std::endl;
127  }
128  return 0;
129 
130 }
131 
132 
133 float gar::rec::capprox(float x1,float y1,
134  float x2,float y2,
135  float x3,float y3,
136  float &xc, float &yc)
137 {
138  //-----------------------------------------------------------------
139  // Initial approximation of the track curvature -- copied from ALICE
140  // here x is y and y is z for us
141  //-----------------------------------------------------------------
142  x3 -=x1;
143  x2 -=x1;
144  y3 -=y1;
145  y2 -=y1;
146  //
147  float det = x3*y2-x2*y3;
148  if (TMath::Abs(det)<1e-10){
149  return 100;
150  }
151  //
152  float u = 0.5* (x2*(x2-x3)+y2*(y2-y3))/det;
153  float x0 = x3*0.5-y3*u;
154  float y0 = y3*0.5+x3*u;
155  float c2 = 1/TMath::Sqrt(x0*x0+y0*y0);
156  xc = x0 + x1;
157  yc = y0 + y1;
158  if (det<0) c2*=-1;
159  return c2;
160 }
161 
162 
163 // given a set of TPC Clusters, find sort orders hlf and hlb, which are vectors of indices into TPC Clusters,
164 // that run along the track as best as we can. Which way is "forwards" and which "backwards" is arbitrary
165 
166 // sorttransweight is the fraction of additional distance given to the transverse displacement from the
167 // local line candidate in addtion to the longitudinal component of the distance used to pick the closest next hit
168 // sortdisback is the turnover point for negative longitudinal distances so we can go back and pick up mis-sorted hits.
169 
170 void gar::rec::sort_TPCClusters_along_track(const std::vector<gar::rec::TPCCluster> &TPCClusters,
171  std::vector<int> &hlf,
172  std::vector<int> &hlb,
173  int printlevel,
174  float &lengthforwards,
175  float &lengthbackwards,
176  float /* sorttransweight */,
177  float /* sortdistback */)
178 {
179 
180  // this sorting code appears in the patrec stage too, if only to make tracks that can be drawn
181  // on the event display
182 
183  // find candidate endpoints and sort TPCClusters
184 
185  float cmin[3]; // min x, y, and z coordinates over all TPCClusters
186  float cmax[3]; // max x, y, and z coordinates over all TPCClusters
187  size_t ihex[6]; // index of TPCCluster which gave the min or max ("extreme") 0-2: (min xyz) 3-5 (max xyz)
188 
189 
190  for (size_t iTPCCluster=0; iTPCCluster < TPCClusters.size(); ++iTPCCluster)
191  {
192  for (int i=0; i<3; ++i)
193  {
194  float c = TPCClusters[iTPCCluster].Position()[i];
195  if (iTPCCluster==0)
196  {
197  cmin[i] = c;
198  cmax[i] = c;
199  ihex[i] = 0;
200  ihex[i+3] = 0;
201  }
202  else
203  {
204  if (c<cmin[i])
205  {
206  cmin[i] = c;
207  ihex[i] = iTPCCluster;
208  }
209  if (c>cmax[i])
210  {
211  cmax[i] = c;
212  ihex[i+3] = iTPCCluster;
213  }
214  }
215  }
216  }
217  // now we have six TPCClusters that have the min and max x, y, and z values. Find out which of these six
218  // TPCClusters has the biggest sum of distances to all the other TPCClusters (the most extreme)
219  float sumdmax = 0;
220  size_t imax = 0;
221  for (size_t i=0; i<6; ++i)
222  {
223  float sumd = 0;
224  TVector3 poshc(TPCClusters[ihex[i]].Position());
225  for (size_t iTPCCluster=0; iTPCCluster<TPCClusters.size(); ++iTPCCluster)
226  {
227  TVector3 hp(TPCClusters[iTPCCluster].Position());
228  sumd += (poshc - hp).Mag();
229  }
230  if (sumd > sumdmax)
231  {
232  sumdmax = sumd;
233  imax = i;
234  }
235  }
236 
237  // Use this TPCCluster, indexed by ihex[imax] as a starting point
238  // For cases with less than dmindir length, sort TPCClusters in order of how
239  // far they are from the first TPCCluster. If longer, calculate a curdir vector
240  // and add hits that are a minimum step along curdir
241 
242  hlf.clear();
243  lengthforwards = 0;
244  hlf.push_back(ihex[imax]);
245  TVector3 lpos(TPCClusters[hlf[0]].Position());
246  TVector3 lastpos=lpos;
247  TVector3 cdpos=lpos; // position of the beginning of the direction vector
248  size_t cdposindex=0; // and its index in the hlf vector
249  TVector3 hpadd;
250  TVector3 curdir(0,0,0);
251  bool havecurdir = false;
252  float dmindir=10; // promote to a fcl parameter someday. Distance over which to compute curdir
253 
254  for (size_t inh=1;inh<TPCClusters.size();++inh)
255  {
256  float dmin=0;
257  int jmin=-1;
258  for (size_t jh=0;jh<TPCClusters.size();++jh)
259  {
260  bool found = false;
261  for (size_t kh=0;kh<hlf.size();++kh)
262  {
263  if (hlf[kh] == (int) jh)
264  {
265  found = true;
266  break;
267  }
268  }
269  if (found) continue; // skip if we've already assigned this TPCCluster on this track
270  TVector3 hpos(TPCClusters[jh].Position());
271 
272  float d=0;
273  if (havecurdir)
274  {
275  float dtmp = (hpos-lastpos).Dot(curdir);
276  if (dtmp<-2)
277  {
278  dtmp = -4 - dtmp;
279  }
280  d= dtmp + 0.1 * ((hpos-lastpos).Cross(curdir)).Mag();
281  }
282  else
283  {
284  d=(hpos-lpos).Mag();
285  }
286  if (jmin == -1)
287  {
288  jmin = jh;
289  dmin = d;
290  hpadd = hpos;
291  }
292  else
293  {
294  if (d<dmin)
295  {
296  jmin = jh;
297  dmin = d;
298  hpadd = hpos;
299  }
300  }
301  }
302  // std::cout << "dmin: " << dmin << std::endl;
303  hlf.push_back(jmin);
304  lengthforwards += (hpadd-lastpos).Mag(); // add up track length
305  lastpos = hpadd;
306  if ( (hpadd-cdpos).Mag() > dmindir)
307  {
308  TVector3 cdcand(TPCClusters[hlf[cdposindex]].Position());
309  size_t itctmp = cdposindex;
310  for (size_t itc=cdposindex+1; itc<hlf.size(); ++itc)
311  {
312  TVector3 cdcandt(TPCClusters[hlf[itc]].Position());
313  if ( (hpadd-cdcandt).Mag() < dmindir )
314  {
315  break;
316  }
317  else
318  {
319  itctmp = itc;
320  cdcand = cdcandt;
321  }
322  }
323  //std::cout << "Updated curdir: " << cdposindex << " " << itctmp << " " << curdir.X() << " " << curdir.Y() << " " << curdir.Z() << " ";
324  cdposindex = itctmp;
325  cdpos = cdcand;
326  curdir = hpadd - cdcand;
327  curdir *= (1.0/curdir.Mag());
328  //std::cout << "To: " << curdir.X() << " " << curdir.Y() << " " << curdir.Z() << std::endl;
329  havecurdir = true;
330  }
331  }
332 
333  if (printlevel>2)
334  {
335  for (size_t iTPCCluster=0; iTPCCluster<TPCClusters.size(); ++iTPCCluster)
336  {
337  printf("Sort compare: %5d %10.3f %10.3f %10.3f %5d %10.3f %10.3f %10.3f\n",
338  (int) iTPCCluster,
339  TPCClusters[iTPCCluster].Position()[0],
340  TPCClusters[iTPCCluster].Position()[1],
341  TPCClusters[iTPCCluster].Position()[2],
342  hlf[iTPCCluster],
343  TPCClusters[hlf[iTPCCluster]].Position()[0],
344  TPCClusters[hlf[iTPCCluster]].Position()[1],
345  TPCClusters[hlf[iTPCCluster]].Position()[2]);
346  }
347  }
348 
349  // now go backwards -- just invert the sort order
350 
351  hlb.clear();
352  for (size_t i=0; i< hlf.size(); ++i)
353  {
354  hlb.push_back(hlf[hlf.size()-1-i]); // just invert the order for the backward sort
355  }
356  lengthbackwards = lengthforwards;
357 
358  if (printlevel>2)
359  {
360  for (size_t iTPCCluster=0; iTPCCluster<TPCClusters.size(); ++iTPCCluster)
361  {
362  printf("Backward Sort compare: %5d %10.3f %10.3f %10.3f %5d %10.3f %10.3f %10.3f\n",
363  (int) iTPCCluster,
364  TPCClusters[iTPCCluster].Position()[0],
365  TPCClusters[iTPCCluster].Position()[1],
366  TPCClusters[iTPCCluster].Position()[2],
367  hlb[iTPCCluster],
368  TPCClusters[hlb[iTPCCluster]].Position()[0],
369  TPCClusters[hlb[iTPCCluster]].Position()[1],
370  TPCClusters[hlb[iTPCCluster]].Position()[2]);
371  }
372  }
373 }
374 
375 
376 // check if we add a link between i and j, do we induce a cycle?
377 
378 bool gar::rec::sort2_check_cyclic(std::vector<int> &link1, std::vector<int> &link2, int i, int j)
379 {
380  if (i == j) return true;
381 
382  int prev = i;
383  int next = (link1.at(i) == -1) ? link2.at(i) : link1.at(i);
384  while (next != -1)
385  {
386  if (next == j) return true;
387  int ptmp = next;
388  next = (link1.at(next) == prev) ? link2.at(next) : link1.at(next);
389  prev = ptmp;
390  }
391  return false;
392 }
393 
394 
395 // try another method to sort TPC clusters -- a greedy algorithm that associates nearby TPC clusters first
396 // stranded hits may be not included if the best path skirts around them. hlf and hlb might have a shorter
397 // length than TPCClusters.
398 
399 void gar::rec::sort_TPCClusters_along_track2(const std::vector<gar::rec::TPCCluster> &TPCClusters,
400  std::vector<int> &hlf,
401  std::vector<int> &hlb,
402  int /* printlevel */,
403  float &lengthforwards,
404  float &lengthbackwards,
405  float dcut)
406 {
407  size_t nclus = TPCClusters.size();
408  hlf.clear();
409  hlb.clear();
410  lengthforwards = 0;
411  lengthbackwards = 0;
412  if (nclus == 0) return;
413  if (nclus == 1)
414  {
415  hlf.push_back(0);
416  hlb.push_back(0);
417  return;
418  }
419 
420  size_t ndists = nclus*(nclus-1)/2;
421  std::vector<float> dists(ndists);
422  std::vector<int> dsi(ndists);
423  std::vector<int> link1(nclus,-1);
424  std::vector<int> link2(nclus,-1);
425  for (size_t i=0; i<nclus-1; ++i)
426  {
427  TVector3 iclus(TPCClusters.at(i).Position());
428  for (size_t j=i+1; j<nclus; ++j)
429  {
430  TVector3 jclus(TPCClusters.at(j).Position());
431  float d = (iclus-jclus).Mag();
432  dists.at(ij2idxsort2(nclus,i,j)) = d;
433  }
434  }
435  TMath::Sort( (int) ndists, dists.data(), dsi.data(), false );
436  //std::cout << "Dists sorting: " << std::endl;
437  //for (size_t i=0; i<ndists; ++i)
438  // {
439  // std::cout << i << " " << dists[i] << " " << dists[dsi[i]] << std::endl;
440  // }
441 
442  // greedy pairwise association -- may end up leaving some hits stranded
443 
444  for (size_t k=0; k<ndists; ++k)
445  {
446  size_t i = 0;
447  size_t j = 0;
448  size_t k2 = dsi.at(k);
449  if (dists.at(k2) > dcut) break;
450  idx2ijsort2(nclus,k2,i,j);
451  TVector3 iclus(TPCClusters.at(i).Position());
452  TVector3 jclus(TPCClusters.at(j).Position());
453 
454  if (link1.at(i) == -1)
455  {
456  if (link1.at(j) == -1)
457  {
458  link1.at(i) = j;
459  link1.at(j) = i;
460  }
461  else // already have a link on j'th cluster, add a second one only if it's on the other side
462  {
463  if (link2.at(j) == -1)
464  {
465  TVector3 j2clus(TPCClusters.at(link1.at(j)).Position());
466 
467  // old test on angle instead of cyclicness
468  //if ( (j2clus-jclus).Angle(iclus-jclus) > TMath::Pi()/2)
469 
470  if (!sort2_check_cyclic(link1,link2,j,i))
471  {
472  link1.at(i) = j;
473  link2.at(j) = i;
474  }
475  }
476  }
477  }
478  else
479  {
480  if (link2.at(i) == -1)
481  {
482  if (link1.at(j) == -1)
483  {
484  link2.at(i) = j;
485  link1.at(j) = i;
486  }
487  else // already have a link on j'th cluster, add a second one only if it's on the other side
488  {
489  if (link2.at(j) == -1)
490  {
491  TVector3 j2clus(TPCClusters.at(link1.at(j)).Position());
492 
493  // old test on angle instead of cyclicness
494  //if ( (j2clus-jclus).Angle(iclus-jclus) > TMath::Pi()/2)
495 
496  if (!sort2_check_cyclic(link1,link2,j,i))
497  {
498  link2.at(i) = j;
499  link2.at(j) = i;
500  }
501  }
502  }
503  }
504  }
505  }
506 
507  //std::cout << "sorting clusters and links" << std::endl;
508  //for (size_t i=0; i<nclus; ++i)
509  // {
510  // std::cout << i << " " << link1.at(i) << " " << link2.at(i) << " " <<
511  // TPCClusters.at(i).Position()[0] << " " <<
512  // TPCClusters.at(i).Position()[1] << " " <<
513  // TPCClusters.at(i).Position()[2] << std::endl;
514  //}
515 
516  std::vector<int> used(nclus,-1);
517  std::vector<std::vector<int> > clistv;
518 
519  // find the first tpc cluster with just one link
520 
521  int ifirst = -1;
522  for (size_t i=0; i<nclus; ++i)
523  {
524  int il1 = link1.at(i);
525  int il2 = link2.at(i);
526 
527  if ( (il1 == -1 && il2 != -1) || (il1 != -1 && il2 == -1) )
528  {
529  ifirst = i;
530  break;
531  }
532  }
533  // this can happen if all TPC clusters are singletons -- no links anywhere. Happens if
534  // there are no TPC clusters at all or just one.
535  if (ifirst == -1)
536  {
537  return;
538  }
539 
540  // follow the chains
541 
542  for (size_t i=ifirst; i<nclus; ++i)
543  {
544  if (used.at(i) == 1) continue;
545  std::vector<int> clist;
546  clist.push_back(i);
547  used.at(i) = 1;
548 
549  int idx = i;
550  int il1 = link1.at(idx);
551  int il2 = link2.at(idx);
552 
553  int u1 = -2;
554  if (il1 != -1) u1 = used.at(il1);
555  int u2 = -2;
556  if (il2 != -1) u2 = used.at(il2);
557 
558  while (u1 == -1 || u2 == -1)
559  {
560  idx = (u1 == -1) ? il1 : il2;
561  clist.push_back(idx);
562  used.at(idx) = 1;
563  il1 = link1.at(idx);
564  il2 = link2.at(idx);
565  u1 = -2;
566  if (il1 != -1) u1 = used.at(il1);
567  u2 = -2;
568  if (il2 != -1) u2 = used.at(il2);
569  }
570  clistv.push_back(clist);
571  }
572 
573  // temporary solution -- think about what to do. Report the longest chain
574 
575  size_t msize=0;
576  int ibest=-1;
577  for (size_t ichain=0; ichain<clistv.size(); ++ichain)
578  {
579  size_t cursize = clistv.at(ichain).size();
580  if (cursize > msize)
581  {
582  ibest = ichain;
583  msize = cursize;
584  }
585  }
586  if (ibest == -1) return;
587 
588  for (size_t i=0; i<clistv.at(ibest).size(); ++i)
589  {
590  hlf.push_back(clistv[ibest].at(i));
591  if (i>0)
592  {
593  TVector3 lastpoint(TPCClusters.at(hlf.at(i-1)).Position());
594  TVector3 curpoint(TPCClusters.at(hlf.at(i)).Position());
595  lengthforwards += (curpoint-lastpoint).Mag();
596  }
597  }
598  for (size_t i=0; i< hlf.size(); ++i)
599  {
600  hlb.push_back(hlf[hlf.size()-1-i]); // just invert the order for the backward sort
601  }
602  lengthbackwards = lengthforwards;
603 
604 }
605 
606 // this method and the next come from formulas on
607 // https://stackoverflow.com/questions/27086195/linear-index-upper-triangular-matrix
608 
609 size_t gar::rec::ij2idxsort2(size_t n, size_t i_in, size_t j_in)
610 {
611  if (i_in >= n)
612  {
613  throw cet::exception("gar::rec::ij2idxsort2 i_in >= n");
614  }
615  if (j_in >= n)
616  {
617  throw cet::exception("gar::rec::ij2idxsort2 j_in >= n");
618  }
619  size_t i = TMath::Min(i_in,j_in);
620  size_t j = TMath::Max(i_in,j_in);
621  size_t k = (n*(n-1)/2) - (n-i)*((n-i)-1)/2 + j - i - 1;
622  return k;
623 }
624 
625 // j > i
626 
627 void gar::rec::idx2ijsort2(size_t n, size_t k, size_t &i, size_t &j)
628 {
629  if (n<2)
630  {
631  i=0;
632  j=0;
633  return;
634  }
635  if (k > n*(n-1)/2)
636  {
637  throw cet::exception("gar::rec::idx2ijsort2: k too big. ") << k << " " << n;
638  }
639  i = n - 2 - TMath::Floor(TMath::Sqrt( (double) (-8*k + 4*n*(n-1)-7) )/2.0 - 0.5);
640  j = k + i + 1 - n*(n-1)/2 + (n-i)*((n-i)-1)/2;
641 }
642 
643 void gar::rec::ouchef(double *x, double *y, int np, double &xcirccent, double &ycirccent,
644  double &rcirc, double &chisq, int &ifail)
645 {
646 
647  // converted from the original Fortran by T. Junk and de-OPALified -- apologies for the gotos
648 
649  // SUBROUTINE OUCHEF(X,Y,NP,XCIRCCENT,YCIRCCENT,RCIRC,CHISQ,IFAIL)
650  // *
651  // *...OUCHEF circle fit by linear regression method
652  // *.
653  // *. OUCHEF(X,Y,NP,XCIRCCENT,YCIRCCENT,RCIRC,CHISQ,IFAIL)
654  // *.
655  // *. INPUT
656  // *. X(.) x coordinates of points
657  // *. Y(.) y coordinates of points
658  // *. NP number of points
659  // *.
660  // *. OUTPUT
661  // *. XMED, YMED center of circle
662  // *. R radius of circle
663  // *. CHISQ residual sum of squares : to be a chi**2 ,it should
664  // *. be divided by (NP-3)*(mean residual)**2
665  // *.
666  // *. IFAIL error flag : 0 OK
667  // *. 1 less than 3 points
668  // *. 2 no convergence
669  // *. 5 number of points exceeding
670  // *. arrays dimensions -> fit performed
671  // *. with allowed maximum (NPTMAX)
672  // *.
673  // *. AUTHOR : N.Chernov, G.Ososkov
674  // *.
675  // *. written by N. Chernov and G. Ososkov, Dubna,
676  // *. reference: computer physics communications vol 33, p329
677  // *. adapted slightly by F. James, March, 1986
678  // *. further adapted slightly by M.Hansroul May,1989
679  // *.
680  // *. CALLED : any
681  // *.
682  // *. CREATED : 31 May 1989
683  // *. LAST MOD : 11 January 1996
684  // *.
685  // *. Modification Log.:
686  // *. 11-jan-96 M.Hansroul preset chisq to 9999.
687  // *. 12-oct-95 M.Hansroul clean up
688  // *. 12-jul-93 M.Hansroul protection against huge d0
689  // *. put OUATG2 in line
690  // *. 31-May-89 M.Hansroul use OPAL output parameters
691  // *.*********************************************************************
692 
693  const double eps = 1.0e-10;
694  const int itmax=20;
695  const int nptmax=1000;
696  //const double twopi=8.0*atan(1.0);
697  //const double piby2=2.0*atan(1.0);
698 
699  int nptlim=0;
700  int npf=0;
701  int n=0;
702  int ihalf=0;
703  int i=0;
704  int iter=0;
705  int iswap=0;
706  //double sfi0=0;
707  //double cfi0=0;
708  double xmid=0;
709  double ymid=0;
710  double *xf;
711  double *yf;
712  double vlf[2];
713  double vmf[2];
714  //double vlm[2];
715 
716  double alf=0;
717  double alm=0;
718  double a0=0;
719  double a1=0;
720  double a2=0;
721  double a22=0;
722  double bem=0;
723  double bet=0;
724  double cur=0;
725  double cu2=0;
726  double dd=0;
727  double den=0;
728  double det=0;
729  double dy=0;
730  double d2=0;
731  double f=0;
732  double fact=0;
733  double fg=0;
734  double f1=0;
735  double g=0;
736  double gam=0;
737  double gam0=0;
738  double gmm=0;
739  double g1=0;
740  double h=0;
741  double h2=0;
742  double p2=0;
743  double q2=0;
744  double rm=0;
745  double rn=0;
746  double xa=0;
747  double xb=0;
748  double xd=0;
749  double xi=0;
750  double xm=0;
751  double xx=0;
752  double xy=0;
753  double x1=0;
754  double x2=0;
755  double ya=0;
756  double yb=0;
757  double yd=0;
758  double yi=0;
759  double ym=0;
760  double yy=0;
761  double y1=0;
762  double y2=0;
763  double xcd=0;
764  double ycd=0;
765  //double xcycsq=0;
766  //double rcd;
767 
768  //* -----------------------------------------------------------------
769  //* xmid,ymid = centre of fitted circle of radius radfit
770  //* chisq = residual sum of squares per point
771  //* alf,bet,gam,cur = internal parameters of the circle
772 
773  ifail = 0;
774  chisq = 9999.;
775 
776  nptlim = np;
777  if (nptlim>nptmax)
778  {
779  nptlim = nptmax;
780  ifail = 5;
781  return;
782  }
783 
784  npf = nptlim + 1;
785  label_12:
786  npf = npf - 1;
787  if (npf < 2)
788  {
789  ifail = 1;
790  return;
791  }
792  vlf[0] = x[npf-1] - x[0];
793  vlf[1] = y[npf-1] - y[0];
794 
795  //* get a point near the middle
796 
797  ihalf = (npf+1)/2;
798 
799  vmf[0] = x[ihalf-1] - x[0];
800  vmf[1] = y[ihalf-1] - y[0];
801  //vlm[0] = x[npf-1] - x[ihalf-1];
802  //vlm[1] = y[npf-1] - y[ihalf-1];
803 
804  //* check for more than half a cicle of points
805 
806  if (vlf[0]*vmf[0] + vlf[1]*vmf[1] < 0.) goto label_12;
807 
808  //* if the track is nearer to the y axis
809  //* interchange x and y
810 
811  if (fabs(y[npf-1] - y[0]) > fabs(x[npf-1]-x[0]))
812  {
813  yf = x;
814  xf = y;
815  iswap = 1;
816  }
817  else
818  {
819  xf = x;
820  yf = y;
821  iswap = 0;
822  }
823 
824  n = npf;
825  rn = 1./((float) n);
826  xm = 0.;
827  ym = 0.;
828  for (i=0;i<n;++i)
829  {
830  xm = xm + xf[i];
831  ym = ym + yf[i];
832  }
833 
834  xm = xm * rn;
835  ym = ym * rn;
836  x2 = 0.;
837  y2 = 0.;
838  xy = 0.;
839  xd = 0.;
840  yd = 0.;
841  d2 = 0.;
842  for (i=0; i<n; ++i)
843  {
844  xi = xf[i] - xm;
845  yi = yf[i] - ym;
846  xx = xi*xi;
847  yy = yi*yi;
848  x2 = x2 + xx;
849  y2 = y2 + yy;
850  xy = xy + xi*yi;
851  dd = xx + yy;
852  xd = xd + xi*dd;
853  yd = yd + yi*dd;
854  d2 = d2 + dd*dd;
855  }
856 
857  x2 = x2*rn;
858  y2 = y2*rn;
859  xy = xy*rn;
860  d2 = d2*rn;
861  xd = xd*rn;
862  yd = yd*rn;
863  f = 3.*x2 + y2;
864  g = 3.*y2 + x2;
865  fg = f*g;
866  h = xy + xy;
867  h2 = h*h;
868  p2 = xd*xd;
869  q2 = yd*yd;
870  gam0 = x2 + y2;
871  fact = gam0*gam0;
872  a2 = (fg-h2-d2)/fact;
873  fact = fact*gam0;
874  a1 = (d2*(f+g) - 2.*(p2+q2))/fact;
875  fact = fact*gam0;
876  a0 = (d2*(h2-fg) + 2.*(p2*g + q2*f) - 4.*xd*yd*h)/fact;
877  a22 = a2 + a2;
878  yb = 1.0e30;
879  iter = 0;
880  xa = 1.;
881  //* main iteration
882  label_3:
883  ya = a0 + xa*(a1 + xa*(a2 + xa*(xa-4.0)));
884  if (fabs(ya) > fabs(yb)) goto label_4;
885  if (iter >= itmax) goto label_4;
886  dy = a1 + xa*(a22 + xa*(4.*xa - 12.));
887  xb = xa - ya/dy;
888  if (fabs(xa-xb) <= eps) goto label_5;
889  xa = xb;
890  yb = ya;
891  iter = iter + 1;
892  goto label_3;
893 
894  label_4:
895  ifail = 2;
896  //* print 99, iter
897  //* 99 format (' circle - no convergence after',i4,' iterations.')
898  xb = 1.;
899 
900  label_5:
901  gam = gam0*xb;
902  f1 = f - gam;
903  g1 = g - gam;
904  x1 = xd*g1 - yd*h;
905  y1 = yd*f1 - xd*h;
906  det = f1*g1 - h2;
907  den = 1./sqrt(x1*x1 + y1*y1 + gam*det*det);
908  cur = det*den;
909  alf = -(xm*det + x1)*den;
910  bet = -(ym*det + y1)*den;
911  rm = xm*xm + ym*ym;
912  gam = ((rm-gam)*det + 2.*(xm*x1 + ym*y1))*den*0.5;
913  alm = alf + cur*xm;
914  bem = bet + cur*ym;
915 
916  gmm = gam + alf*xm + bet*ym + 0.5*cur*rm;
917  chisq = ((0.5*cur)*(0.5*cur)*d2 + cur*(alm*xd + bem*yd + gmm*gam0)
918  + alm*alm*x2 + bem*bem*y2 + 2.*alm*bem*xy + gmm*gmm) /rn;
919  cu2 = 0.;
920  if (cur != 0.)
921  {
922  cu2 = 1./cur;
923  xcd = -alf*cu2;
924  ycd = -bet*cu2;
925  //rcd = fabs(cu2);
926  xmid = xcd;
927  ymid = ycd;
928  xcirccent = xmid;
929  ycirccent = ymid;
930  if (iswap == 1)
931  {
932  xcirccent = ymid;
933  ycirccent = xmid;
934  }
935  rcirc = cu2;
936  }
937  else
938  {
939  rcirc = 1e6;
940  }
941 
942  return;
943 }
bool sort2_check_cyclic(std::vector< int > &link1, std::vector< int > &link2, int i, int j)
void ouchef(double *x, double *y, int np, double &xcirccent, double &ycirccent, double &rcirc, double &chisq, int &ifail)
static constexpr double g
Definition: Units.h:144
TH3F * xpos
Definition: doAna.cpp:29
#define a0
float capprox(float x1, float y1, float x2, float y2, float x3, float y3, float &xc, float &yc)
TH3F * ypos
Definition: doAna.cpp:30
#define a2
T abs(T value)
TH3F * zpos
Definition: doAna.cpp:31
const double e
std::void_t< T > n
int imax
Definition: tracks.py:195
void sort_TPCClusters_along_track(const std::vector< gar::rec::TPCCluster > &TPCClusters, std::vector< int > &hlf, std::vector< int > &hlb, int printlevel, float &lengthforwards, float &lengthbackwards, float sorttransweight, float sortdistback)
void sort_TPCClusters_along_track2(const std::vector< gar::rec::TPCCluster > &TPCClusters, std::vector< int > &hlf, std::vector< int > &hlb, int printlevel, float &lengthforwards, float &lengthbackwards, float dcut)
list x
Definition: train.py:276
size_t ij2idxsort2(size_t nclus, size_t i, size_t j)
void idx2ijsort2(size_t nclus, size_t idx, size_t &i, size_t &j)
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)
#define a1
int initial_trackpar_estimate(const std::vector< gar::rec::TPCCluster > &TPCClusters, std::vector< int > &TPCClusterlist, float &curvature_init, float &lambda_init, float &phi_init, float &xpos, float &ypos, float &zpos, float &x_other_end, unsigned int initialtpnTPCClusters, int printlevel)
Definition: tracker2algs.cxx:8