54 for (
auto& t : result.
tracks())
87 for (
auto const& t : trk_input.
tracks()) {
91 if ((t.Track()->GetT0() != 0) ||
100 double l = t.Track()->Length();
125 std::vector<pma::VtxCandidate> candidates;
135 candidates.push_back(candidate);
144 std::vector<pma::VtxCandidate> candidates;
154 candidates.push_back(candidate);
162 std::vector<pma::VtxCandidate>& candidates)
165 while (merged && (candidates.size() > 1)) {
166 size_t k_best, l_best, k = 0;
167 while (k < candidates.size() - 1) {
169 while (l < candidates.size()) {
170 if (candidates[l].Has(candidates[k])) {
171 candidates[k] = candidates[l];
172 candidates.erase(candidates.begin() + l);
174 else if (candidates[k].Has(candidates[l])) {
175 candidates.erase(candidates.begin() + l);
185 double d, dmin = d_thr;
188 while (k < candidates.size() - 1) {
190 while (l < candidates.size()) {
191 d = candidates[k].Test(candidates[l]);
201 if ((dmin < d_thr) && candidates[k_best].MergeWith(candidates[l_best])) {
202 candidates.erase(candidates.begin() + l_best);
207 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"*** Vtx candidates: " << candidates.size();
208 std::vector<pma::VtxCandidate> toJoin;
211 int s, nmax = 0, c_best = -1;
212 double a, amax = 0.0;
214 for (
size_t v = 0; v < candidates.size(); v++) {
215 if (candidates[v].HasLoops())
continue;
217 bool maybeCorrelated =
false;
218 for (
size_t u = 0; u < toJoin.size(); u++)
219 if (toJoin[u].IsAttached(candidates[v]) ||
220 (
pma::Dist2(toJoin[u].Center(), candidates[v].Center()) < 15.0 * 15.0)) {
221 maybeCorrelated =
true;
224 if (maybeCorrelated)
continue;
227 a = candidates[v].MaxAngle(1.0);
229 if ((s > nmax) || ((s == nmax) && (a > amax))) {
252 toJoin.push_back(candidates[c_best]);
253 candidates.erase(candidates.begin() + c_best);
258 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"*** Vtx selected to join: " << toJoin.size();
261 for (
auto& c : toJoin) {
274 if (trk_input.
size() < 2) {
275 mf::LogWarning(
"pma::PMAlgVertexing") <<
"need min two source tracks!";
288 if (candidates.size()) {
294 }
while (nfound > 0);
307 if (candidates.size()) {
329 const std::vector<TVector3>& )
343 std::vector<std::pair<double, double>> result;
346 unsigned int nhits = trk.
NHits(view);
347 unsigned int max = nhits;
362 std::map<size_t, std::vector<double>> dqdx;
365 for (
size_t i = 0; i < trk.
size(); i++) {
366 auto it = dqdx.find(i);
367 if (it != dqdx.end()) {
368 if (it->second[6] > 0.0)
370 double dvalue = it->second[5] / it->second[6];
371 result.emplace_back(std::pair<double, double>(dvalue, it->second[7]));
384 double const* shape)
const 386 size_t half = len >> 1;
387 double v,
mean = 0.0, stdev = 0.0;
388 for (
size_t i = 0; i < len; i++) {
389 v = adc[idx - half + i];
398 for (
size_t i = 0; i < len; i++)
399 sum += (adc[idx - half + i] - mean) * shape[i];
401 return sum / sqrt(stdev);
406 const double minCos = 0.996194698;
408 trk1->
Segments().back()->GetDirection3D().Dot(trk2->
Segments().front()->GetDirection3D());
409 if (segCos < minCos) {
410 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" has large angle, cos: " << segCos;
414 const size_t stepShapeLen = 16;
415 const size_t stepShapeHalf = stepShapeLen >> 1;
416 const double stepShape[stepShapeLen] = {
417 -1., -1., -1., -1., -1., -1., -1., -1., 1., 1., 1., 1., 1., 1., 1., 1.};
420 if (dqdx1.size() < stepShapeHalf)
return false;
422 if (dqdx2.size() < stepShapeHalf)
return false;
424 const size_t adcLen =
426 const size_t adcHalf = adcLen >> 1;
429 for (
size_t i = 0; i < adcLen; i++)
433 for (
int i = adcHalf - 1, j = dqdx1.size() - 1; i >= 0; i--, j--) {
435 dqdx[i] = dqdx1[j].first;
437 dqdx[i] = dqdx[i + 1];
442 for (
size_t i = adcHalf, j = 0; i < adcLen; i++, j++) {
443 if (j < dqdx2.size())
444 dqdx[i] = dqdx2[j].first;
446 dqdx[i] = dqdx[i - 1];
452 if (has_m) sum_m =
convolute(adcHalf - 1, stepShapeLen, dqdx, stepShape);
453 double sum_0 =
convolute(adcHalf, stepShapeLen, dqdx, stepShape);
455 if (has_p) sum_p =
convolute(adcHalf + 1, stepShapeLen, dqdx, stepShape);
457 const double convMin = 0.8;
458 if ((fabs(sum_m) >= convMin) || (fabs(sum_0) >= convMin) || (fabs(sum_p) >= convMin)) {
460 <<
" has step in conv.values: " << sum_m <<
", " << sum_0 <<
", " << sum_p;
465 <<
" single particle, conv.values: " << sum_m <<
", " << sum_0 <<
", " << sum_p;
472 if (trk_input.
size() < 2)
return;
474 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"Find and merge tracks broken by vertices.";
478 for (
size_t t = 0; t < trk_input.
size(); t++) {
494 double c, maxc = 0.0;
496 node = trk1->
Nodes().back();
502 c = dir1.Dot(tst->
Segments().front()->GetDirection3D());
521 if (trk_input.
size() < 1)
return;
523 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"Find missed vtx by dQ/dx steps along merged tracks.";
525 while (t < trk_input.
size()) {
535 if (trk_input.
size() < 1)
return;
538 <<
"Find kinks on tracks, reopt with no penalty on angle where kinks.";
539 for (
size_t t = 0; t < trk_input.
size(); ++t) {
541 if (trk->
Nodes().size() < 5)
continue;
543 trk->
Optimize(detProp, 0, 1.0
e-5,
false);
545 std::vector<size_t> tested_nodes;
546 bool kinkFound =
true;
548 int kinkIdx = -1, nnodes = 0;
549 double mean = 0.0, stdev = 0.0, min = 1.0, max_a = 0.0;
550 for (
size_t n = 1;
n < trk->
Nodes().size() - 1; ++
n) {
551 auto const& node = *(trk->
Nodes()[
n]);
553 if (node.IsVertex() || node.IsTPCEdge())
continue;
556 double c = -node.SegmentCosTransverse();
557 double a = 180.0 * (1 - std::acos(node.SegmentCosTransverse()) / TMath::Pi());
560 if ((c < min) && !
has(tested_nodes,
n)) {
561 if ((
n > 1) && (
n < trk->
Nodes().size() - 2)) kinkIdx =
n;
568 if ((nnodes > 2) && (kinkIdx > 0) && (max_a >
fKinkMinDeg)) {
571 stdev -= mean *
mean;
575 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" kink a: " << max_a <<
"deg";
576 trk->
Nodes()[kinkIdx]->SetVertex(
true);
577 tested_nodes.push_back(kinkIdx);
580 trk->
Optimize(detProp, 0, 1.0
e-5,
false,
false);
581 double c = -trk->
Nodes()[kinkIdx]->SegmentCosTransverse();
583 180.0 * (1 - std::acos(trk->
Nodes()[kinkIdx]->SegmentCosTransverse()) / TMath::Pi());
587 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" -> tag removed after reopt";
588 trk->
Nodes()[kinkIdx]->SetVertex(
600 std::vector<std::pair<TVector3, std::vector<std::pair<size_t, bool>>>>
603 std::vector<std::pair<TVector3, std::vector<std::pair<size_t, bool>>>> vsel;
604 std::vector<pma::Node3D const*> bnodes;
606 for (
size_t t = 0; t < tracks.
size(); ++t) {
609 if (!(onlyBranching || firstNode->
IsBranching())) {
610 std::vector<std::pair<size_t, bool>> tidx;
611 tidx.emplace_back(std::pair<size_t, bool>(t,
true));
617 for (
auto node : trk->
Nodes())
618 if (node->IsBranching()) {
620 for (
size_t n = 0;
n < bnodes.size();
n++)
621 if (node == bnodes[
n]) {
622 vsel[
n].second.emplace_back(std::pair<size_t, bool>(t, pri));
627 std::vector<std::pair<size_t, bool>> tidx;
628 tidx.emplace_back(std::pair<size_t, bool>(t, pri));
630 std::pair<TVector3,
std::vector<std::pair<size_t, bool>>>(node->Point3D(), tidx));
631 bnodes.push_back(node);
644 std::vector<std::pair<TVector3, size_t>> ksel;
645 for (
size_t t = 0; t < tracks.
size(); ++t) {
647 for (
size_t n = 1;
n < trk->
Nodes().size() - 1; ++
n) {
650 ksel.emplace_back(std::pair<TVector3, size_t>(node->
Point3D(), t));
pma::TrkCandidateColl fEmTracks
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
TVector3 const & Point3D() const
pma::TrkCandidateColl fShortTracks
size_t run(const detinfo::DetectorPropertiesData &detProp, pma::TrkCandidateColl &trk_input)
double Dist2(const TVector2 &v1, const TVector2 &v2)
std::vector< pma::VtxCandidate > firstPassCandidates() const
std::vector< std::pair< TVector3, size_t > > getKinks(const pma::TrkCandidateColl &tracks) const
std::vector< pma::VtxCandidate > secondPassCandidates() const
pma::Hit3D const * front() const
Implementation of the Projection Matching Algorithm.
void collectTracks(pma::TrkCandidateColl &result)
virtual unsigned int NextCount(void) const
TVector3 const & Point3D() const
Planes which measure Z direction.
fhicl::Atom< double > MinTrackLength
std::vector< std::pair< TVector3, std::vector< std::pair< size_t, bool > > > > getVertices(const pma::TrkCandidateColl &tracks, bool onlyBranching=false) const
recob::tracking::Vector_t Vector3D
PMAlgVertexing(const Config &config)
double Optimize(const detinfo::DetectorPropertiesData &detProp, int nNodes=-1, double eps=0.01, bool selAllHits=true, bool setAllNodes=true, size_t selSegHits=0, size_t selVtxHits=0)
Main optimization method.
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< pma::Segment3D * > const & Segments() const noexcept
std::vector< std::pair< double, double > > getdQdx(const pma::Track3D &trk) const
Get dQ/dx sequence to detect various features.
pma::TrkCandidateColl fOutTracks
fhicl::Atom< double > KinkMinStd
bool IsVertex() const
Check fIsVertex flag.
pma::TrkCandidateColl fExcludedTracks
size_t makeVertices(detinfo::DetectorPropertiesData const &detProp, std::vector< pma::VtxCandidate > &candidates)
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
double GetRawdEdxSequence(std::map< size_t, std::vector< double >> &dedx, unsigned int view=geo::kZ, unsigned int skip=0, bool inclDisabled=false) const
bool Add(const pma::TrkCandidate &trk)
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
bool IsBranching() const
Belongs to more than one track?
void sortTracks(const pma::TrkCandidateColl &trk_input)
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::Node3D * > const & Nodes() const noexcept
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
void findKinksOnTracks(const detinfo::DetectorPropertiesData &detProp, pma::TrkCandidateColl &trk_input) const
Remove penalty on the angle if kink detected and reopt track.
pma::Track3D * Parent(void) const
void push_back(const TrkCandidate &trk)
bool has(const std::vector< size_t > &v, size_t idx) const
std::vector< TrkCandidate > const & tracks() const
void mergeBrokenTracks(pma::TrkCandidateColl &trk_input) const