Belle II Software  release-06-02-00
NDFinder.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <string>
10 #include <cmath>
11 #include <iostream>
12 #include <fstream>
13 #include "framework/logging/Logger.h"
14 #include "boost/iostreams/filter/gzip.hpp"
15 #include "boost/iostreams/filtering_streambuf.hpp"
16 #include "boost/iostreams/filtering_stream.hpp"
17 #include "trg/cdc/NDFinder.h"
18 
19 using namespace Belle2;
20 using namespace std;
21 
22 
23 void NDFinder::init(int minweight, int minpts,
24  bool diagonal, int minhits, int minhits_axial,
25  double thresh,
26  double minassign,
27  int mincells, bool verbose,
28  string& axialFile, string& stereoFile)
29 {
30  m_params.minhits = (long unsigned int) minhits;
31  m_params.minhits_axial = (long unsigned int) minhits_axial;
32  m_params.thresh = (float) thresh;
33  m_params.minassign = (float) minassign;
34  m_params.mincells = (long unsigned int) mincells;
35  m_params.axialFile = axialFile;
36  m_params.stereoFile = stereoFile;
37  m_clusterer_params.minweight = (unsigned short) minweight;
38  m_clusterer_params.minpts = (unsigned short) minpts;
39  m_clusterer_params.diagonal = diagonal;
40  m_verbose = verbose;
41 
42 
43  initBins();
44  B2DEBUG(55, "initialized binnings");
45 
46  initHitModAxSt(*m_parrayHitMod);
47  B2DEBUG(55, "initialized HitMod, a map of tsid to (orient, relid, letter).");
48 
50  loadArray(m_params.axialFile, m_compaxbins, *m_pcompAxial);
51  B2DEBUG(55, "loaded zero suppressed axial array ");
52  loadArray(m_params.stereoFile, m_compstbins, *m_pcompStereo);
53  B2DEBUG(55, "loaded zero suppressed stereo array ");
54 
56  restoreZeros(m_expaxbins, m_compaxbins, *m_parrayAxialExp, *m_pcompAxial);
57  B2DEBUG(55, "restored expanded axial array (11/32 phi) ");
58  restoreZeros(m_expstbins, m_compstbins, *m_parrayStereoExp, *m_pcompStereo);
59  B2DEBUG(55, "restored expanded stereo array (11/32 phi) ");
60  squeezeAll(m_axbins, *m_parrayAxial, *m_parrayAxialExp, m_params.parcels, m_params.parcelsExp);
61  B2DEBUG(55, "squeezed axial array (11/32 phi) --> (7/32 phi): ");
62  squeezeAll(m_stbins, *m_parrayStereo, *m_parrayStereoExp, m_params.parcels, m_params.parcelsExp);
63  B2DEBUG(55, "squeezed stereo array (11/32 phi) --> (7/32 phi)");
64 
65  reset();
66  m_clusterer = Clusterizend(m_clusterer_params);
67  m_clusterer.setPlaneShape(m_planeShape);
68 }
69 
71 {
82  m_nTS = 2336;
83  m_nSL = 9;
84  m_params.phigeo = 32;
85 
86  m_nAx = 41;
87  m_nSt = 32;
88  m_nPrio = 3;
89 
90  m_nOmega = 40;
91  m_nPhiFull = 384;
92  m_nTheta = 9;
93  m_nPhiOne = m_nPhiFull / m_params.phigeo; // 384/32 = 12
95  m_nPhiComp = 15;
97  m_nPhiUse = m_params.parcels * m_nPhiOne;
99  m_nPhiExp = m_params.parcelsExp * m_nPhiOne;
100 
101  m_axbins.hitid = m_nAx;
102  m_stbins.hitid = m_nSt;
103  m_axbins.phi = m_nPhiUse; //84
104  m_stbins.phi = m_nPhiUse; //84
105  m_compaxbins.hitid = m_nAx;
106  m_compstbins.hitid = m_nSt;
107  m_compaxbins.phi = m_nPhiComp;
108  m_compstbins.phi = m_nPhiComp;
109  m_compaxbins.theta = 1;
110  m_expaxbins.hitid = m_nAx;
111  m_expstbins.hitid = m_nSt;
112  m_expaxbins.phi = m_nPhiExp; //132
113  m_expstbins.phi = m_nPhiExp; //132
114 
115  m_fullbins.hitid = m_nTS;
116  m_fullbins.phi = m_nPhiFull;
117 
118  m_pc5shapeax = {{ m_nAx, m_nPrio, m_nOmega, m_nPhiUse, m_nTheta }};
119  m_pc5shapest = {{ m_nSt, m_nPrio, m_nOmega, m_nPhiUse, m_nTheta }};
120  m_pc3shape = {{ m_nOmega, m_nPhiFull, m_nTheta }};
121  m_pc2shapeHitMod = {{ m_nTS, m_nPrio}};
122  m_pc5shapeCompAx = {{ m_nAx, m_nPrio, m_nOmega, m_nPhiComp, 1 }};
123  m_pc5shapeCompSt = {{ m_nSt, m_nPrio, m_nOmega, m_nPhiComp, m_nTheta }};
124  m_pc5shapeExpAx = {{ m_nAx, m_nPrio, m_nOmega, m_nPhiExp, m_nTheta }};
125  m_pc5shapeExpSt = {{ m_nSt, m_nPrio, m_nOmega, m_nPhiExp, m_nTheta }};
126 
127  m_parrayAxial = new c5array(m_pc5shapeax);
128  m_parrayStereo = new c5array(m_pc5shapest);
129  m_phoughPlane = new c3array(m_pc3shape);
130  m_parrayHitMod = new c2array(m_pc2shapeHitMod);
131  m_pcompAxial = new c5array(m_pc5shapeCompAx);
132  m_pcompStereo = new c5array(m_pc5shapeCompSt);
133  m_parrayAxialExp = new c5array(m_pc5shapeExpAx);
134  m_parrayStereoExp = new c5array(m_pc5shapeExpSt);
135 
136  m_nWires = {160, 160, 192, 224, 256, 288, 320, 352, 384};
137 
138  m_planeShape = {m_nOmega, m_nPhiFull, m_nTheta}; //{40, 384, 9};
139 
141  vector<float> omegaRange = { -5., 5.};
142  vector<float> phiRange = {0., 11.25};
143  vector<float> thetaRange = {19., 140.};
144  float ssOmega = (omegaRange[1] - omegaRange[0]) / m_nOmega; //40;
145  float ssPhi = (phiRange[1] - phiRange[0]) / m_nPhiOne; //12;
146  float ssTheta = (thetaRange[1] - thetaRange[0]) / m_nTheta; //9;
147  m_acceptRanges.push_back(omegaRange);
148  m_acceptRanges.push_back(phiRange);
149  m_acceptRanges.push_back(thetaRange);
150  m_slotsizes.push_back(ssOmega);
151  m_slotsizes.push_back(ssPhi);
152  m_slotsizes.push_back(ssTheta);
153 }
154 
155 
156 
157 void NDFinder::loadArray(const std::string& filename, ndbinning bins, c5array& hitsToTracks)
158 {
159  vector<c5elem> flatArray;
160  ifstream arrayFileGZ(filename, ios_base::in | ios_base::binary);
161  boost::iostreams::filtering_istream arrayStream;
162  arrayStream.push(boost::iostreams::gzip_decompressor());
163  arrayStream.push(arrayFileGZ);
164  c5elem uline;
165  if (arrayFileGZ.is_open()) {
166  while (arrayStream >> uline) {
167  flatArray.push_back(uline);
168  }
169  arrayFileGZ.close();
170  } else {
171  B2ERROR("could not open array file: " << filename);
172  }
173  B2DEBUG(55, "loaded array from file " << filename);
174  unsigned long icount = 0;
175  for (c5index ihit = 0; ihit < bins.hitid; ihit++) {
176  for (c5index iprio = 0; iprio < bins.prio; iprio++) {
177  for (c5index iomega = 0; iomega < bins.omega; iomega++) {
178  for (c5index iphi = 0; iphi < bins.phi; iphi++) {
179  for (c5index itheta = 0; itheta < bins.theta; itheta++) {
180  hitsToTracks[ihit][iprio][iomega][iphi][itheta] = flatArray[icount];
181  icount++;
182  }
183  }
184  }
185  }
186  }
187 }
188 
189 
190 void NDFinder::initHitModAxSt(c2array& hitMod)
191 {
192  unsigned short phigeo = m_params.phigeo; // 32
193  std::vector<int> modSLs; //nWires per SL in 1/32 sector (9)
194  std::vector<int> toslid; //tsid to sl map (2336)
195  std::vector<int> sloffsets = {0}; // integrated number of wires in inner SLs (9);
196  std::vector<int> modoffsetsAxSt = {0, 0}; // integrated number of wires in inner SLs in 1/32 sector, separate for axial and stereo SLs (9);
197  for (int isl = 0; isl < m_nSL; isl++) {
198  modSLs.push_back(m_nWires[isl] / phigeo);
199  for (int itsrel = 0; itsrel < m_nWires[isl]; itsrel++) {
200  toslid.push_back(isl);
201  }
202  sloffsets.push_back(sloffsets[isl] + m_nWires[isl]);
203  int last = modoffsetsAxSt[isl];
204  modoffsetsAxSt.push_back(last + m_nWires[isl] / phigeo);
205  }
206  for (int its = 0; its < m_nTS; its++) { // 2336
207  int sl = toslid[its];
208  bool isAxial = (sl % 2 == 0);
209  int idInSL = its - sloffsets[sl];
210  int modSL = modSLs[sl];
211  int modId = idInSL % modSL;
212  int letter = (int) floor(idInSL / modSL);
213  int relId = (int)(modoffsetsAxSt[sl] + modId);
214  hitMod[its][0] = (int)(isAxial);
215  hitMod[its][1] = relId;
216  hitMod[its][2] = letter;
217  }
218 }
219 
220 
221 void NDFinder::squeezeOne(c5array& writeArray, c5array& readArray, int outparcels, int inparcels, c5index ihit, c5index iprio,
222  c5index itheta, c5elem nomega)
223 {
224  int outnphi = (int)(12 * outparcels);
225  c5index trafstart = (c5index)((inparcels - outparcels) / 2 * 12);
226  c5index trafend = (c5index)(trafstart + outnphi);
227  for (c5index iomega = 0; iomega < nomega; iomega++) {
228  for (c5index iphi = 0; iphi < outnphi; iphi++) {
229  c5index readPhi = trafstart + iphi;
230  writeArray[ihit][iprio][iomega][iphi][itheta] = readArray[ihit][iprio][iomega][readPhi][itheta];
231  }
232  for (c5index iphi = 0; iphi < trafstart; iphi++) {
233  c5index writePhi = (c5index)(outnphi - trafstart + iphi);
234  writeArray[ihit][iprio][iomega][writePhi][itheta] += readArray[ihit][iprio][iomega][iphi][itheta];
235  }
236  for (c5index iphi = 0; iphi < trafstart; iphi++) {
237  c5index readPhi = trafend + iphi;
238  writeArray[ihit][iprio][iomega][iphi][itheta] += readArray[ihit][iprio][iomega][readPhi][itheta];
239  }
240  }
241 }
242 
243 
244 void NDFinder::squeezeAll(ndbinning writebins, c5array& writeArray, c5array& readArray, int outparcels, int inparcels)
245 {
246  for (c5index ihit = 0; ihit < writebins.hitid; ihit++) {
247  for (c5index iprio = 0; iprio < writebins.prio; iprio++) {
248  for (c5index itheta = 0; itheta < writebins.theta; itheta++) {
249  squeezeOne(writeArray, readArray, outparcels, inparcels, ihit, iprio, itheta, writebins.omega);
250  }
251  }
252  }
253 }
254 
255 
256 void NDFinder::restoreZeros(ndbinning zerobins, ndbinning compbins, c5array& expArray, const c5array& compArray)
257 {
258  B2DEBUG(55, "restoreZeros: zerobins.theta " << zerobins.theta << ", combins.theta " << compbins.theta);
259  for (c5index ihit = 0; ihit < compbins.hitid; ihit++) {
260  for (c5index iprio = 0; iprio < compbins.prio; iprio++) {
261  for (c5index iomega = 0; iomega < compbins.omega; iomega++) {
262  for (c5index itheta = 0; itheta < compbins.theta; itheta++) {
263  c5elem phiStart = compArray[ihit][iprio][iomega][0][itheta];
264  c5elem phiWidth = compArray[ihit][iprio][iomega][1][itheta];
265  for (c5index iphi = 0; iphi < phiWidth; iphi++) {
266  c5elem phiCur = phiStart + iphi;
267  expArray[ihit][iprio][iomega][phiCur][itheta] = compArray[ihit][iprio][iomega][iphi + 2][itheta];
268  if (compbins.theta == 1) { // case axial, expand in theta
269  for (c5index jtheta = 1; jtheta < zerobins.theta; jtheta++) {
270  expArray[ihit][iprio][iomega][phiCur][jtheta] = compArray[ihit][iprio][iomega][iphi + 2][itheta];
271  }
272  }
273  }
274  }
275  }
276  }
277  }
278 }
279 
280 
281 void NDFinder::printArray3D(c3array& hitsToTracks, ndbinning bins, ushort phi_inc = 1, ushort om_inc = 1, ushort divide = 4,
282  ushort minweightShow = 1)
283 {
284  ushort phistart = 0;
285  ushort phiend = bins.phi;
286  bool started = false;
287  unsigned long phiSlice = 0;
288  for (c3index iphi = 0; iphi < bins.phi; iphi++) {
289  for (c3index itheta = 0; itheta < bins.theta; itheta++) {
290  for (c3index iomega = 0; iomega < bins.omega; iomega++) {
291  phiSlice += hitsToTracks[iomega][iphi][itheta];
292  }
293  }
294  if (phiSlice == 0 and not started) {
295  phistart = iphi + 1;
296  } else if (phiSlice != 0 and not started) {
297  started = true;
298  } else if (phiSlice != 0 and started) {
299  phiend = iphi;
300  } else if (phiSlice == 0 and started) {
301  phiend = iphi;
302  break;
303  }
304  }
305 
306  B2DEBUG(55, "printArray3D, phistart = " << phistart << ", phiend = " << phiend);
307  auto d3shp = hitsToTracks.shape();
308  B2DEBUG(55, "printArray shape: " << d3shp[0] << ", " << d3shp[1] << ", " << d3shp[2]);
309 
310  if (phiend == phistart) {
311  return;
312  }
313  c3index itheta = 4; // only print itheta = 4
314  for (c3index iomega = 0; iomega < bins.omega; iomega += om_inc) {
315  for (c3index iphi = phistart; iphi < phiend; iphi += phi_inc) {
316  // reduce printed weight
317  ushort valRed = (ushort)((hitsToTracks[iomega][iphi][itheta]) / divide);
318  if (valRed <= minweightShow) // skip small weights
319  cout << " ";
320  else
321  cout << valRed;
322  }
323  cout << "|" << endl;
324  }
325 }
326 
327 
329 void NDFinder::addLookup(unsigned short ihit)
330 {
331  c2array& arrayHitMod = *m_parrayHitMod;
332 
333  c2elem orient = arrayHitMod[m_hitIds[ihit]][0];
334  c2elem hitr = arrayHitMod[m_hitIds[ihit]][1];
335  c2elem letter = arrayHitMod[m_hitIds[ihit]][2];
336 
337  unsigned short prio = m_prioPos[ ihit ];
338  short letterShort = (short) letter;
339 
340  // Get hit contribution to cluster:
341  // 7 of 32 phi parcels: center = 3
342  short DstartShort = (letterShort - 3) % m_params.phigeo * m_nPhiOne;
343  if (DstartShort < 0) {DstartShort = m_nPhiFull + DstartShort;}
344  // Add hit to hough plane
345  // 11 of 32 phi parcels: center = 5
346  short DstartComp = (letterShort - 5) % m_params.phigeo * m_nPhiOne;
347  if (DstartComp < 0) {DstartComp = m_nPhiFull + DstartComp;}
348 
349  m_vecDstart.push_back(DstartShort);
350  m_hitOrients.push_back(orient);
351 
352  if (orient == 1) {
353  addC3Comp(hitr, prio, *m_pcompAxial, DstartComp, m_compaxbins);
354  } else {
355  addC3Comp(hitr, prio, *m_pcompStereo, DstartComp, m_compstbins);
356  }
357 }
358 
359 
360 void NDFinder::addC3Comp(ushort hitr,
361  ushort prio, const c5array& hitsToTracks,
362  short Dstart, ndbinning bins)
363 {
364  ushort ntheta = 0;
365  c3array& houghPlane = *m_phoughPlane;
366  for (ushort itheta = 0; itheta < m_nTheta; itheta++) { //9
367  if (bins.theta > 1) { //stereo
368  ntheta = itheta;
369  }
370  for (ushort iomega = 0; iomega < m_nOmega; iomega++) { //40
371  ushort startfield = 0;
372  ushort lenfield = 1;
373  ushort xstart = hitsToTracks[hitr][prio][iomega][startfield][ntheta];
374  ushort xlen = hitsToTracks[hitr][prio][iomega][lenfield][ntheta];
375  for (ushort iphiz = 0; iphiz < xlen; iphiz++) {
376  ushort iphix = iphiz + 2;
377  ushort iphi = iphiz + xstart;
378  ushort iHoughPhi = (iphi + Dstart) % m_nPhiFull;
379  houghPlane[iomega][iHoughPhi][itheta] += hitsToTracks[hitr][prio][iomega][iphix][ntheta];
380  }
381  }
382  }
383 }
384 
385 
387 {
389  for (unsigned short ihit = 0; ihit < m_nHits; ihit++) {
390  addLookup(ihit);
391  }
392  if (m_verbose) {
393  B2DEBUG(55, "m_houghPlane, 2");
394  printArray3D(*m_phoughPlane, m_fullbins);
395  }
396  getCM();
397 }
398 
399 
400 std::vector<std::vector<unsigned short>> NDFinder::getHitsVsClusters(std::vector<SimpleCluster>& clusters)
401 {
402  unsigned short nClusters = clusters.size();
403  unsigned short default_value = 0;
404  std::vector<unsigned short> hitElem(m_nHits, default_value);
405  std::vector<std::vector<unsigned short>> hitsVsClusters(nClusters, hitElem);
406 
407  for (unsigned long iclus = 0; iclus < clusters.size(); iclus++) {
408  SimpleCluster cli = clusters[iclus];
409  vector<cell_index> entries = cli.getEntries();
410  cell_index maxid = getMax(entries);
411  for (unsigned long ihit = 0; ihit < m_hitIds.size(); ihit++) {
412  ushort contrib = hitContrib(maxid, ihit);
413  hitsVsClusters[iclus][ihit] = contrib;
414  }
415  }
416  return hitsVsClusters;
417 }
418 
419 vector<SimpleCluster>
420 NDFinder::relateHitsToClusters(std::vector<std::vector<unsigned short>>& hitsVsClusters, std::vector<SimpleCluster>& clusters)
421 {
422  vector<SimpleCluster> useclusters;
423  vector<unsigned long> restHits;
424  if (hitsVsClusters.size() > 0) {
425  for (unsigned long ihit = 0; ihit < m_hitIds.size(); ihit++) {
426  int cid = hitToCluster(hitsVsClusters, ihit);
427  if (cid != -1) { // add hit to cluster
428  clusters[cid].add_hit(ihit, hitsVsClusters[cid][ihit], m_hitOrients[ihit]);
429  } else {
430  restHits.push_back(ihit);
431  }
432  }
433 
434  // select clusters, try to reassign rest hits
435  vector<bool> processed(hitsVsClusters.size(), false);
436  for (long unsigned int iround = 0; iround <= (m_params.minhits - 2); iround++) {
437  if (iround > 0) {
438  vector<unsigned long> stillRest;
439  for (unsigned long irhit = 0; irhit < restHits.size(); irhit++) {
440  unsigned long ihit = restHits[irhit];
441  int cid = hitToCluster(hitsVsClusters, ihit);
442  if (cid != -1) { // add hit to cluster
443  clusters[cid].add_hit(ihit, hitsVsClusters[cid][ihit], m_hitOrients[ihit]);
444  } else {
445  stillRest.push_back(ihit);
446  }
447  }
448  restHits = stillRest;
449  }
450  stringstream msg;
451  for (long unsigned int iclus = 0; iclus < hitsVsClusters.size(); iclus++) {
452  if (processed[iclus])
453  continue;
454  SimpleCluster& clu = clusters[iclus];
455  //if (clu.get_hits().size() >= m_params.minhits) {
456  if (clu.get_hits().size() >= m_params.minhits && clu.get_naxial() >= m_params.minhits_axial) {
457  useclusters.push_back(clusters[iclus]);
458  processed[iclus] = true;
459  msg << ", add iclu=" << iclus << "(nHits=" << clu.get_hits().size() << ",round=" << iround << ")";
460  } else if (clu.get_hits().size() < ((m_params.minhits - 2) + iround)) { //remove small clusters
461  msg << ", skip iclu=" << iclus << "(nHits=" << clu.get_hits().size() << ",round=" << iround << ")";
462  for (unsigned long int ihics = 0; ihics < hitsVsClusters[0].size(); ihics++) {
463  hitsVsClusters[iclus][ihics] = 0;
464  }
465  processed[iclus] = true;
466  for (unsigned short ihirs : clu.get_hits()) {
467  restHits.push_back(ihirs);
468  }
469  }
470  }
471  if (m_verbose) {
473  B2DEBUG(55, "iround=" << iround <<
474  ", restHits: " << restHits.size() << ", useclusters: " <<
475  useclusters.size() << ", msg=" << msg.str());
476  }
477  }
478  }
479  return useclusters;
480 }
481 
482 
484 {
485  c3array& houghPlane = *m_phoughPlane;
486  m_clusterer.setNewPlane(houghPlane);
487  std::vector<SimpleCluster> allClusters = m_clusterer.dbscan();
488  std::vector<SimpleCluster> clusters;
489  for (SimpleCluster& clu : allClusters) {
490  if (clu.getEntries().size() > m_params.mincells) {
491  clusters.push_back(clu);
492  }
493  }
494 
495  std::vector<std::vector<unsigned short>> hitsVsClusters = getHitsVsClusters(clusters);
496  vector<SimpleCluster> useclusters = relateHitsToClusters(hitsVsClusters, clusters);
497 
498  for (unsigned long iclus = 0; iclus < useclusters.size(); iclus++) {
499  SimpleCluster cli = useclusters[iclus];
500  vector<cell_index> entries = cli.getEntries();
501  cell_index maxid = getMax(entries);
502  ushort maxval = houghPlane[maxid[0]][maxid[1]][maxid[2]];
503  float cutoff = m_params.thresh * maxval;
504  vector<cellweight> highWeight = getHighWeight(entries, cutoff);
505  vector<vector<long int>> flatHW;
506  for (auto cx : highWeight) {
507  flatHW.push_back({cx.index[0], cx.index[1], cx.index[2], (unsigned short int)cx.weight});
508  }
509  vector<double> result = getWeightedMean(highWeight);
510  vector<double> estimate = getBinToVal(result);
511  vector<double> transformed = transform(estimate);
513  m_NDFinderTracks.push_back(NDFinderTrack(transformed, cli));
514  }
515 }
516 
517 float NDFinder::transformVar(float estVal, int idx)
518 {
519  if (idx == 0) { //omega
520  if (estVal == 0.) {
521  return estVal;
522  } else {
523  return - 1 / cdc_track_radius(1. / estVal);
524  }
525  } else if (idx == 1) { // phi
526  float phiMod = estVal;
527  if (estVal > 180) {
528  phiMod -= 360.;
529  }
530  return phiMod * m_pi_deg;
531  } else { // theta
532  float thetRad = estVal * m_pi_deg;
533  return cos(thetRad) / sin(thetRad);
534  }
535 }
536 std::vector<double> NDFinder::transform(std::vector<double> estimate)
537 {
538  std::vector<double> transformed;
539  for (int idx = 0; idx < 3; idx++) {
540  transformed.push_back(transformVar(estimate[idx], idx));
541  }
542  return transformed;
543 }
544 
545 
546 std::vector<double> NDFinder::getBinToVal(std::vector<double> thisAv)
547 {
548  vector<double> estimate;
549  for (ushort idim = 0; idim < 3; idim++) {
550  double trafd = m_acceptRanges[idim][0] + (thisAv[idim] + 0.5) * m_slotsizes[idim];
551  estimate.push_back(trafd);
552  }
553  return estimate;
554 }
555 
556 std::vector<double> NDFinder::getWeightedMean(std::vector<cellweight> highWeight)
557 {
558  double axomega = 0.;
559  double axphi = 0.;
560  double axtheta = 0.;
561  int ncells = 0;
562  long weightSum = 0;
563 
564  for (cellweight& elem : highWeight) {
565  axomega += elem.index[0] * elem.weight;
566  axphi += elem.index[1] * elem.weight;
567  axtheta += elem.index[2] * elem.weight;
568  ncells++;
569  weightSum += elem.weight;
570  }
571  axomega /= weightSum;
572  axphi /= weightSum;
573  axtheta /= weightSum;
574  vector<double> result = {axomega, axphi, axtheta};
575  return result;
576 }
577 
578 int NDFinder::hitToCluster(std::vector<std::vector<unsigned short>>& hitsVsClusters, unsigned short ihit)
579 {
580  int cur_clus = -1;
581  std::vector<std::vector<ushort>> candWeights;
582 
583  for (unsigned long iclus = 0; iclus < hitsVsClusters.size(); iclus++) {
584  std::vector<ushort> cwEntry = {(ushort) iclus, hitsVsClusters[iclus][ihit]};
585  candWeights.push_back(cwEntry);
586  }
587  if (candWeights.size() == 1) { // single cluster case
588  if (candWeights[0][1] > 0) { // hit contributes non-zero weight
589  cur_clus = 0;
590  }
591  } else if (candWeights.size() > 1) {
592  struct mySortClass {
593  bool operator()(vector<ushort> i, vector<ushort> j) {return (i[1] > j[1]);}
594  } mySortObject;
595  sort(candWeights.begin(), candWeights.end(), mySortObject);
596 
597  if (candWeights[0][1] > 0) { // the hit contributes non-zero weight
598  float crit = fabs((float)candWeights[0][1] - (float)candWeights[1][1]) / ((float)candWeights[0][1]);
599  if (crit > m_params.minassign) {
600  cur_clus = candWeights[0][0];
601  }
602  }
603  }
604  return cur_clus;
605 }
606 
607 
608 cell_index NDFinder::getMax(const std::vector<cell_index>& entries)
609 {
610  ushort cur_weight = 0;
611  cell_index cur_max_index = {0, 0, 0};
612  const c3array& houghPlane = *m_phoughPlane;
613 
614  for (const cell_index& entry : entries) {
615  if (houghPlane[entry[0]][entry[1]][entry[2]] > cur_weight) {
616  cur_weight = houghPlane[entry[0]][entry[1]][entry[2]];
617  cur_max_index = entry;
618  }
619  }
620  return cur_max_index;
621 }
622 
623 
624 vector<cellweight> NDFinder::getHighWeight(std::vector<cell_index> entries, float cutoff)
625 {
626  vector<cellweight> cellsAndWeight;
627  const c3array& houghPlane = *m_phoughPlane;
628  for (cell_index& entry : entries) {
629  ushort cellWeight = houghPlane[entry[0]][entry[1]][entry[2]];
630  if (cellWeight > cutoff) {
631  cellweight cur_elem;
632  cur_elem.index = entry;
633  cur_elem.weight = cellWeight;
634  cellsAndWeight.push_back(cur_elem);
635  }
636  }
637  return cellsAndWeight;
638 }
639 
640 
641 ushort NDFinder::hitContrib(cell_index peak, ushort ihit)
642 {
643  ushort contrib = 0;
644  ushort iHoughPhi = peak[1];
645  short Dstart = m_vecDstart[ihit];
646  ushort iphi = iHoughPhi - Dstart;
647  if (Dstart > iHoughPhi && Dstart > 300) {
648  iphi = m_nPhiFull - Dstart + iHoughPhi;
649  }
650  ushort iomega = peak[0];
651  ushort itheta = peak[2];
652  ushort orient = m_hitOrients[ihit];
653 
654  const c2array& arrayHitMod = *m_parrayHitMod;
655  c2elem hitr = arrayHitMod[m_hitIds[ihit]][1];
656  unsigned short prio = m_prioPos[ ihit ];
657  if (Dstart > m_nPhiFull) {
658  B2ERROR("phi overflow: iHoughPhi = " << iHoughPhi << ", Dstart = " << Dstart << ", iphi=" << iphi);
659  }
660  if (iphi < m_nPhiUse) { // hit covers current phi area, get contribution
661  if (orient == 1) { // axial
662  contrib = (*m_parrayAxial)[hitr][prio][iomega][iphi][itheta];
663  } else { // stereo
664  contrib = (*m_parrayStereo)[hitr][prio][iomega][iphi][itheta];
665  }
666  }
667  return contrib;
668 }
669 
670 
671 void
673 {
674  clusterer_params cpa = m_clusterer.getParams();
675  B2DEBUG(55, "clusterer_params minweight=" << cpa.minweight << ", minpts=" << cpa.minpts << ", diagonal=" << cpa.diagonal);
676  B2DEBUG(55, "ndFinderParams minhits=" << m_params.minhits <<
677  ", minhits_axial=" << m_params.minhits_axial << ", thresh=" << m_params.thresh << ", minassign=" <<
678  m_params.minassign <<
679  ", mincells=" << m_params.mincells);
680 }
Clustering module.
Definition: Clusterizend.h:114
Store track parameters of found tracks.
Definition: NDFinder.h:28
std::vector< cellweight > getHighWeight(std::vector< cell_index > entries, float cutoff)
Candidate cells as seed for the clustering.
Definition: NDFinder.cc:624
std::vector< SimpleCluster > relateHitsToClusters(std::vector< std::vector< unsigned short >> &hitsVsClusters, std::vector< SimpleCluster > &clusters)
Use confusion matrix to related hits to clusters.
Definition: NDFinder.cc:420
void initBins()
Initialize the binnings and reserve the arrays.
Definition: NDFinder.cc:70
void initHitModAxSt(c2array &hitMod)
Initialize hit modulo mappings.
Definition: NDFinder.cc:190
void getCM()
NDFinder internal functions for track finding.
Definition: NDFinder.cc:483
void squeezeAll(ndbinning writebins, c5array &writeArray, c5array &readArray, int outparcels, int inparcels)
Loop over all hits and theta bins and squeeze all 2D (omega,phi) planes.
Definition: NDFinder.cc:244
void loadArray(const std::string &filename, ndbinning bins, c5array &hitsToTracks)
Load an NDFinder array of hit representations in track phase space.
Definition: NDFinder.cc:157
void restoreZeros(ndbinning zerobins, ndbinning compbins, c5array &expArray, const c5array &compArray)
Restore non-zero suppressed hit curves.
Definition: NDFinder.cc:256
ushort hitContrib(cell_index peak, ushort ihit)
Determine weight contribution of a single hit to a single cell.
Definition: NDFinder.cc:641
void squeezeOne(c5array &writeArray, c5array &readArray, int outparcels, int inparcels, c5index ihit, c5index iprio, c5index itheta, c5elem nomega)
Squeeze phi-axis in a 2D (omega,phi) plane.
Definition: NDFinder.cc:221
std::vector< double > getBinToVal(std::vector< double >)
Scale the weighted center to track parameter values.
Definition: NDFinder.cc:546
void addC3Comp(ushort hitr, ushort prio, const c5array &hitsToTracks, short Dstart, ndbinning bins)
In place array addition to houghmap Comp: A = A + B.
Definition: NDFinder.cc:360
void printParams()
Debug: print configured parameters.
Definition: NDFinder.cc:672
void addLookup(unsigned short ihit)
Add a single axial or stereo hit to the houghmap.
Definition: NDFinder.cc:329
int hitToCluster(std::vector< std::vector< unsigned short >> &hitsVsClusters, unsigned short hit)
Determine the best cluster for a single hit, given hitsVsClusters confusion matrix.
Definition: NDFinder.cc:578
void findTracks()
main function for track finding
Definition: NDFinder.cc:386
std::vector< std::vector< unsigned short > > getHitsVsClusters(std::vector< SimpleCluster > &clusters)
Create hits to clusters confusion matrix.
Definition: NDFinder.cc:400
std::vector< double > getWeightedMean(std::vector< cellweight >)
Calculate the weighted center of a cluster.
Definition: NDFinder.cc:556
float transformVar(float estVal, int idx)
Calculate physical units.
Definition: NDFinder.cc:517
void printArray3D(c3array &hitsToTracks, ndbinning bins, ushort, ushort, ushort, ushort)
Debug Tool: Print part of the houghmap.
Definition: NDFinder.cc:281
cell_index getMax(const std::vector< cell_index > &)
Peak cell in cluster.
Definition: NDFinder.cc:608
void init(int minweight, int minpts, bool diagonal, int minhits, int minhits_axial, double thresh, double minassign, int mincells, bool verbose, std::string &axialFile, std::string &stereoFile)
initialization
Definition: NDFinder.cc:23
Type for found clusters.
Definition: Clusterizend.h:34
unsigned long get_naxial()
Get number related axial hits.
Definition: Clusterizend.h:79
std::vector< unsigned short > get_hits()
Get ids of related hits (indices of the TS StoreArray)
Definition: Clusterizend.h:89
std::vector< cell_index > getEntries()
Get member cells in the cluster.
Definition: Clusterizend.h:62
unsigned short c2elem
TS-Id to 1/32 phi-sector mapping is stored in a 2D array.
Definition: NDFinderDefs.h:34
unsigned short c5elem
Store hit patterns in a 5D array (hitid, prio, omega, phi, theta)
Definition: NDFinderDefs.h:23
Abstract base class for different kinds of events.
unsigned short minweight
minimum weight for a cluster cell
Definition: Clusterizend.h:22
bool diagonal
Consider diagonal adjacent cells as neighbors.
Definition: Clusterizend.h:26
unsigned short minpts
minimum number of neighbours for a cluster core cell
Definition: Clusterizend.h:24
Default binning in a (7/32) phi-sector.
Definition: NDFinderDefs.h:41