54 for (
auto & t : result.
tracks()) t.DeleteTrack();
79 for (
auto const & t : trk_input.
tracks())
84 if ((t.Track()->GetT0() != 0) ||
91 double l = t.Track()->Length();
112 std::vector< pma::VtxCandidate > candidates;
124 candidates.push_back(candidate);
133 std::vector< pma::VtxCandidate > candidates;
146 candidates.push_back(candidate);
156 while (merged && (candidates.size() > 1))
158 size_t k_best, l_best, k = 0;
159 while (k < candidates.size() - 1)
162 while (l < candidates.size())
164 if (candidates[l].Has(candidates[k]))
166 candidates[k] = candidates[l];
167 candidates.erase(candidates.begin() + l);
169 else if (candidates[k].Has(candidates[l]))
171 candidates.erase(candidates.begin() + l);
180 double d, dmin = d_thr;
183 while (k < candidates.size() - 1)
186 while (l < candidates.size())
188 d = candidates[k].Test(candidates[l]);
189 if (d < dmin) { dmin =
d; k_best = k; l_best = l; }
194 if ((dmin < d_thr) && candidates[k_best].MergeWith(candidates[l_best]))
196 candidates.erase(candidates.begin() + l_best);
201 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"*** Vtx candidates: " << candidates.size();
202 std::vector< pma::VtxCandidate > toJoin;
206 int s, nmax = 0, c_best = -1;
207 double a, amax = 0.0;
209 for (
size_t v = 0; v < candidates.size(); v++)
211 if (candidates[v].HasLoops())
continue;
213 bool maybeCorrelated =
false;
214 for (
size_t u = 0; u < toJoin.size(); u++)
215 if (toJoin[u].IsAttached(candidates[v]) ||
216 (
pma::Dist2(toJoin[u].Center(), candidates[v].Center()) < 15.0*15.0))
218 maybeCorrelated =
true;
break;
220 if (maybeCorrelated)
continue;
223 a = candidates[v].MaxAngle(1.0);
225 if ((s > nmax) || ((s == nmax) && (a > amax)))
227 nmax =
s; amax = a; c_best = v;
248 toJoin.push_back(candidates[c_best]);
249 candidates.erase(candidates.begin() + c_best);
253 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"*** Vtx selected to join: " << toJoin.size();
256 for (
auto & c : toJoin)
269 if (trk_input.
size() < 2)
271 mf::LogWarning(
"pma::PMAlgVertexing") <<
"need min two source tracks!";
286 if (candidates.size())
297 else mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" ...short tracks only.";
307 if (candidates.size())
329 const std::vector< TVector3 >& vtx_input)
344 std::vector< std::pair<double, double> > result;
347 unsigned int nhits = trk.
NHits(view);
348 unsigned int max = nhits;
351 if (nhits > max) { max = nhits; view =
geo::kV; }
354 if (nhits > max) { max = nhits; view =
geo::kU; }
358 std::map< size_t, std::vector<double> > dqdx;
361 for (
size_t i = 0; i < trk.
size(); i++)
363 auto it = dqdx.find(i);
364 if (it != dqdx.end())
366 if (it->second[6] > 0.0)
368 double dvalue = it->second[5] / it->second[6];
369 result.emplace_back(std::pair<double, double>(dvalue, it->second[7]));
381 size_t half = len >> 1;
382 double v,
mean = 0.0, stdev = 0.0;
383 for (
size_t i = 0; i < len; i++)
385 v = adc[idx - half + i];
386 mean += v; stdev += v * v;
393 for (
size_t i = 0; i < len; i++)
394 sum += (adc[idx - half + i] - mean) * shape[i];
396 return sum / sqrt(stdev);
401 const double minCos = 0.996194698;
402 double segCos = trk1->
Segments().back()->GetDirection3D().Dot( trk2->
Segments().front()->GetDirection3D() );
405 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" has large angle, cos: " << segCos;
409 const size_t stepShapeLen = 16;
410 const size_t stepShapeHalf = stepShapeLen >> 1;
411 const double stepShape[stepShapeLen] =
412 { -1., -1., -1., -1., -1., -1., -1., -1.,
413 1., 1., 1., 1., 1., 1., 1., 1. };
415 auto dqdx1 =
getdQdx(*trk1);
if (dqdx1.size() < stepShapeHalf)
return false;
416 auto dqdx2 =
getdQdx(*trk2);
if (dqdx2.size() < stepShapeHalf)
return false;
418 const size_t adcLen = stepShapeLen + 2;
419 const size_t adcHalf = adcLen >> 1;
422 for (
size_t i = 0; i < adcLen; i++) dqdx[i] = 0.0;
425 for (
int i = adcHalf - 1, j = dqdx1.size() - 1; i >= 0; i--, j--)
427 if (j >= 0) dqdx[i] = dqdx1[j].first;
428 else { dqdx[i] = dqdx[i+1]; has_m =
false; }
431 for (
size_t i = adcHalf, j = 0; i < adcLen; i++, j++)
433 if (j < dqdx2.size()) dqdx[i] = dqdx2[j].first;
434 else { dqdx[i] = dqdx[i-1]; has_p =
false; }
437 double sum_m = 0.0;
if (has_m) sum_m =
convolute(adcHalf - 1, stepShapeLen, dqdx, stepShape);
438 double sum_0 =
convolute(adcHalf, stepShapeLen, dqdx, stepShape);
439 double sum_p = 0.0;
if (has_p) sum_p =
convolute(adcHalf + 1, stepShapeLen, dqdx, stepShape);
441 const double convMin = 0.8;
442 if ((fabs(sum_m) >= convMin) ||
443 (fabs(sum_0) >= convMin) ||
444 (fabs(sum_p) >= convMin))
447 << sum_m <<
", " << sum_0 <<
", " << sum_p;
452 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" single particle, conv.values: " 453 << sum_m <<
", " << sum_0 <<
", " << sum_p;
460 if (trk_input.
size() < 2)
return;
462 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"Find and merge tracks broken by vertices.";
467 for (
size_t t = 0; t < trk_input.
size(); t++)
485 double c, maxc = 0.0;
487 node = trk1->
Nodes().back();
494 c = dir1.Dot( tst->
Segments().front()->GetDirection3D() );
495 if (c > maxc) { maxc = c; trk2 = tst; }
511 if (trk_input.
size() < 1)
return;
513 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"Find missed vtx by dQ/dx steps along merged tracks.";
515 while (t < trk_input.
size())
525 if (trk_input.
size() < 1)
return;
527 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"Find kinks on tracks, reopt with no penalty on angle where kinks.";
528 for (
size_t t = 0; t < trk_input.
size(); ++t)
531 if (trk->
Nodes().size() < 5)
continue;
535 std::vector<size_t> tested_nodes;
536 bool kinkFound =
true;
539 int kinkIdx = -1, nnodes = 0;
540 double mean = 0.0, stdev = 0.0,
min = 1.0, max_a = 0.0;
541 for (
size_t n = 1;
n < trk->
Nodes().size() - 1; ++
n)
543 auto const & node = *(trk->
Nodes()[
n]);
545 if (node.IsVertex() || node.IsTPCEdge())
continue;
548 double c = -node.SegmentCosTransverse();
549 double a = 180.0 * (1 - std::acos(node.SegmentCosTransverse()) / TMath::Pi());
550 mean += c; stdev += c * c;
551 if ((c <
min) && !
has(tested_nodes,
n))
553 if ((
n > 1) && (
n < trk->
Nodes().size() - 2)) kinkIdx =
n;
559 if ((nnodes > 2) && (kinkIdx > 0) && (max_a >
fKinkMinDeg))
561 mean /= nnodes; stdev /= nnodes;
562 stdev -= mean *
mean;
567 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" kink a: " << max_a <<
"deg";
568 trk->
Nodes()[kinkIdx]->SetVertex(
true);
569 tested_nodes.push_back(kinkIdx);
573 double c = -trk->
Nodes()[kinkIdx]->SegmentCosTransverse();
574 double a = 180.0 * (1 - std::acos(trk->
Nodes()[kinkIdx]->SegmentCosTransverse()) / TMath::Pi());
578 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" -> tag removed after reopt";
579 trk->
Nodes()[kinkIdx]->SetVertex(
false);
590 std::vector< std::pair< TVector3, std::vector< std::pair< size_t, bool > > > >
593 std::vector< std::pair< TVector3, std::vector< std::pair< size_t, bool > > > > vsel;
594 std::vector< pma::Node3D const * > bnodes;
596 for (
size_t t = 0; t < tracks.
size(); ++t)
602 std::vector< std::pair< size_t, bool > > tidx;
603 tidx.emplace_back(std::pair< size_t, bool >(t,
true));
604 vsel.emplace_back(std::pair< TVector3,
std::vector< std::pair< size_t, bool > > >(trk->
front()->
Point3D(), tidx));
608 for (
auto node : trk->
Nodes())
609 if (node->IsBranching())
612 for (
size_t n = 0;
n < bnodes.size();
n++)
613 if (node == bnodes[
n])
615 vsel[
n].second.emplace_back(std::pair< size_t, bool >(t, pri));
620 std::vector< std::pair< size_t, bool > > tidx;
621 tidx.emplace_back(std::pair< size_t, bool >(t, pri));
622 vsel.emplace_back(std::pair< TVector3,
std::vector< std::pair< size_t, bool > > >(node->Point3D(), tidx));
623 bnodes.push_back(node);
633 std::vector< std::pair< TVector3, size_t > >
636 std::vector< std::pair< TVector3, size_t > > ksel;
637 for (
size_t t = 0; t < tracks.
size(); ++t)
640 for (
size_t n = 1;
n < trk->
Nodes().size() - 1; ++
n)
645 ksel.emplace_back(std::pair< TVector3, size_t >(node->
Point3D(), t));
pma::TrkCandidateColl fEmTracks
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
pma::TrkCandidateColl fShortTracks
bool IsVertex(void) const
Check fIsVertex flag.
double Dist2(const TVector2 &v1, const TVector2 &v2)
std::vector< std::pair< TVector3, size_t > > getKinks(const pma::TrkCandidateColl &tracks) const
TVector3 const & Point3D(void) const
void collectTracks(pma::TrkCandidateColl &result)
std::vector< pma::Node3D * > const & Nodes(void) const
void reconfigure(const Config &config)
virtual unsigned int NextCount(void) const
Planes which measure Z direction.
fhicl::Atom< double > MinTrackLength
std::vector< TrkCandidate > const & tracks(void) const
std::vector< std::pair< TVector3, std::vector< std::pair< size_t, bool > > > > getVertices(const pma::TrkCandidateColl &tracks, bool onlyBranching=false) const
std::vector< pma::Segment3D * > const & Segments(void) const
recob::tracking::Vector_t Vector3D
PMAlgVertexing(const Config &config)
void findKinksOnTracks(pma::TrkCandidateColl &trk_input) const
Remove penalty on the angle if kink detected and reopt track.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
unsigned int NHits(unsigned int view) const
fhicl::Atom< bool > FindKinks
std::vector< std::pair< double, double > > getdQdx(const pma::Track3D &trk) const
Get dQ/dx sequence to detect various features.
pma::TrkCandidateColl fOutTracks
double Optimize(int nNodes=-1, double eps=0.01, bool selAllHits=true, bool setAllNodes=true, size_t selSegHits=0, size_t selVtxHits=0)
Main optimization method.
fhicl::Atom< double > KinkMinStd
pma::TrkCandidateColl fExcludedTracks
bool IsBranching(void) const
Belongs to more than one track?
size_t makeVertices(std::vector< pma::VtxCandidate > &candidates)
TVector3 const & Point3D(void) const
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
Implementation of the Projection Matching Algorithm.
double convolute(size_t idx, size_t len, double *adc, double const *shape) const
Get convolution value.
virtual pma::SortedObjectBase * Next(unsigned int index=0) const
bool Add(const pma::TrkCandidate &trk)
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
void sortTracks(const pma::TrkCandidateColl &trk_input)
double GetRawdEdxSequence(std::map< size_t, std::vector< double > > &dedx, unsigned int view=geo::kZ, unsigned int skip=0, bool inclDisabled=false) const
virtual ~PMAlgVertexing(void)
TrackCollectionProxyElement< TrackCollProxy > Track
Proxy to an element of a proxy collection of recob::Track objects.
bool isSingleParticle(pma::Track3D *trk1, pma::Track3D *trk2) const
Check if colinear in 3D and dQ/dx with no significant step.
std::vector< pma::VtxCandidate > secondPassCandidates(void)
void splitMergedTracks(pma::TrkCandidateColl &trk_input) const
Split track and add vertex and reoptimize when dQ/dx step detected.
virtual pma::SortedObjectBase * Prev(void) const
fhicl::Atom< double > KinkMinDeg
size_t run(pma::TrkCandidateColl &trk_input)
pma::Track3D * Parent(void) const
std::vector< pma::VtxCandidate > firstPassCandidates(void)
void push_back(const TrkCandidate &trk)
bool has(const std::vector< size_t > &v, size_t idx) const
void mergeBrokenTracks(pma::TrkCandidateColl &trk_input) const