11 #include "messagefacility/MessageLogger/MessageLogger.h"
25 pma::PMAlgVertexing::~PMAlgVertexing()
34 for (
auto& t : fOutTracks.tracks())
38 for (
auto& t : fShortTracks.tracks())
42 for (
auto& t : fEmTracks.tracks())
46 for (
auto& t : fExcludedTracks.tracks())
48 fExcludedTracks.clear();
55 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"clean input: " << result.
size() << std::endl;
56 for (
auto& t : result.
tracks())
60 mf::LogVerbatim(
"pma::PMAlgVertexing")
61 <<
"fill input from out: " << fOutTracks.size() << std::endl;
62 for (
auto const& t : fOutTracks.tracks())
66 mf::LogVerbatim(
"pma::PMAlgVertexing")
67 <<
"fill input from short: " << fShortTracks.size() << std::endl;
68 for (
auto const& t : fShortTracks.tracks())
72 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"fill input from em: " << fEmTracks.size() << std::endl;
73 for (
auto const& t : fEmTracks.tracks())
77 mf::LogVerbatim(
"pma::PMAlgVertexing")
78 <<
"copy back excluded tracks: " << fExcludedTracks.size() << std::endl;
79 for (
auto const& t : fExcludedTracks.tracks())
81 fExcludedTracks.clear();
90 for (
auto const& t : trk_input.
tracks()) {
94 if ((t.Track()->GetT0() != 0) ||
99 fExcludedTracks.tracks().emplace_back(copy, key);
103 double l = t.Track()->Length();
106 if (l > 2 * fMinTrackLength)
107 fOutTracks.tracks().emplace_back(copy, key);
109 fEmTracks.tracks().emplace_back(copy, key);
112 if (l > fMinTrackLength)
113 fOutTracks.tracks().emplace_back(copy, key);
115 fEmTracks.tracks().emplace_back(copy, key);
118 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"long tracks: " << fOutTracks.size() << std::endl;
119 mf::LogVerbatim(
"pma::PMAlgVertexing")
120 <<
"em and short tracks: " << fEmTracks.size() << std::endl;
121 mf::LogVerbatim(
"pma::PMAlgVertexing")
122 <<
"excluded cosmic tracks: " << fExcludedTracks.size() << std::endl;
126 std::vector<pma::VtxCandidate>
129 std::vector<pma::VtxCandidate> candidates;
130 for (
size_t t = 0; t < fOutTracks.size() - 1; t++) {
131 for (
size_t u = t + 1; u < fOutTracks.size(); u++) {
133 if (!candidate.
Add(fOutTracks[t]))
break;
136 if (candidate.
Add(fOutTracks[u]) && (sqrt(candidate.
Mse()) < 1.0))
139 candidates.push_back(candidate);
146 std::vector<pma::VtxCandidate>
149 std::vector<pma::VtxCandidate> candidates;
150 for (
size_t t = 0; t < fOutTracks.size(); t++)
151 if (fOutTracks[t].
Track()->Length() > fMinTrackLength) {
152 for (
size_t u = 0; u < fEmTracks.size(); u++) {
154 if (!candidate.
Add(fOutTracks[t]))
break;
156 if (fOutTracks[t].
Track() == fEmTracks[u].Track())
continue;
158 if (candidate.
Add(fEmTracks[u]) && (sqrt(candidate.
Mse()) < 1.0)) {
159 candidates.push_back(candidate);
168 std::vector<pma::VtxCandidate>& candidates)
171 while (merged && (candidates.size() > 1)) {
172 size_t k_best, l_best,
k = 0;
173 while (k < candidates.size() - 1) {
175 while (l < candidates.size()) {
176 if (candidates[l].Has(candidates[k])) {
177 candidates[
k] = candidates[l];
178 candidates.erase(candidates.begin() + l);
180 else if (candidates[k].Has(candidates[l])) {
181 candidates.erase(candidates.begin() + l);
191 double d, dmin = d_thr;
194 while (k < candidates.size() - 1) {
196 while (l < candidates.size()) {
197 d = candidates[
k].Test(candidates[l]);
207 if ((dmin < d_thr) && candidates[k_best].MergeWith(candidates[l_best])) {
208 candidates.erase(candidates.begin() + l_best);
213 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"*** Vtx candidates: " << candidates.size();
214 std::vector<pma::VtxCandidate> toJoin;
217 int s, nmax = 0, c_best = -1;
218 double a, amax = 0.0;
220 for (
size_t v = 0; v < candidates.size(); v++) {
221 if (candidates[v].HasLoops())
continue;
223 bool maybeCorrelated =
false;
224 for (
size_t u = 0; u < toJoin.size(); u++)
225 if (toJoin[u].IsAttached(candidates[v]) ||
226 (
pma::Dist2(toJoin[u].Center(), candidates[v].Center()) < 15.0 * 15.0)) {
227 maybeCorrelated =
true;
230 if (maybeCorrelated)
continue;
232 s = (int)candidates[v].Size(2 * fMinTrackLength);
233 a = candidates[v].MaxAngle(1.0);
235 if ((s > nmax) || ((s == nmax) && (a > amax))) {
258 toJoin.push_back(candidates[c_best]);
259 candidates.erase(candidates.begin() + c_best);
264 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"*** Vtx selected to join: " << toJoin.size();
267 for (
auto& c : toJoin) {
268 if (c.JoinTracks(detProp, fOutTracks, fEmTracks)) njoined++;
279 if (fFindKinks) findKinksOnTracks(detProp, trk_input);
281 if (trk_input.
size() < 2) {
282 mf::LogWarning(
"pma::PMAlgVertexing") <<
"need min two source tracks!";
286 sortTracks(trk_input);
289 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"Pass #1:";
291 if (fOutTracks.size() > 1) {
294 auto candidates = firstPassCandidates();
295 if (candidates.size()) {
296 nfound = makeVertices(detProp, candidates);
301 }
while (nfound > 0);
302 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" " << nvtx <<
" vertices.";
306 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" ...short tracks only.";
308 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"Pass #2:";
310 if (fOutTracks.size() && fEmTracks.size()) {
312 while (nfound && fEmTracks.size()) {
313 auto candidates = secondPassCandidates();
314 if (candidates.size()) {
315 nfound = makeVertices(detProp, candidates);
321 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" " << nvtx <<
" vertices.";
325 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" ...no tracks.";
327 collectTracks(trk_input);
329 mergeBrokenTracks(trk_input);
338 sortTracks(trk_input);
348 std::vector<std::pair<double, double>>
351 std::vector<std::pair<double, double>> result;
354 unsigned int nhits = trk.
NHits(view);
355 unsigned int max = nhits;
370 std::map<size_t, std::vector<double>> dqdx;
373 for (
size_t i = 0; i < trk.
size(); i++) {
374 auto it = dqdx.find(i);
375 if (it != dqdx.end()) {
376 if (it->second[6] > 0.0)
378 double dvalue = it->second[5] / it->second[6];
379 result.emplace_back(std::pair<double, double>(dvalue, it->second[7]));
392 size_t half = len >> 1;
393 double v,
mean = 0.0, stdev = 0.0;
394 for (
size_t i = 0; i < len; i++) {
395 v = adc[idx - half + i];
404 for (
size_t i = 0; i < len; i++)
405 sum += (adc[idx - half + i] - mean) * shape[i];
407 return sum / sqrt(stdev);
413 const double minCos = 0.996194698;
415 trk1->
Segments().back()->GetDirection3D().Dot(trk2->
Segments().front()->GetDirection3D());
416 if (segCos < minCos) {
417 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" has large angle, cos: " << segCos;
421 const size_t stepShapeLen = 16;
422 const size_t stepShapeHalf = stepShapeLen >> 1;
423 const double stepShape[stepShapeLen] = {
424 -1., -1., -1., -1., -1., -1., -1., -1., 1., 1., 1., 1., 1., 1., 1., 1.};
426 auto dqdx1 = getdQdx(*trk1);
427 if (dqdx1.size() < stepShapeHalf)
return false;
428 auto dqdx2 = getdQdx(*trk2);
429 if (dqdx2.size() < stepShapeHalf)
return false;
431 const size_t adcLen =
433 const size_t adcHalf = adcLen >> 1;
436 for (
size_t i = 0; i < adcLen; i++)
440 for (
int i = adcHalf - 1, j = dqdx1.size() - 1; i >= 0; i--, j--) {
442 dqdx[i] = dqdx1[j].first;
444 dqdx[i] = dqdx[i + 1];
449 for (
size_t i = adcHalf, j = 0; i < adcLen; i++, j++) {
450 if (j < dqdx2.size())
451 dqdx[i] = dqdx2[j].
first;
453 dqdx[i] = dqdx[i - 1];
459 if (has_m) sum_m = convolute(adcHalf - 1, stepShapeLen, dqdx, stepShape);
460 double sum_0 = convolute(adcHalf, stepShapeLen, dqdx, stepShape);
462 if (has_p) sum_p = convolute(adcHalf + 1, stepShapeLen, dqdx, stepShape);
464 const double convMin = 0.8;
465 if ((fabs(sum_m) >= convMin) || (fabs(sum_0) >= convMin) || (fabs(sum_p) >= convMin)) {
466 mf::LogVerbatim(
"pma::PMAlgVertexing")
467 <<
" has step in conv.values: " << sum_m <<
", " << sum_0 <<
", " << sum_p;
471 mf::LogVerbatim(
"pma::PMAlgVertexing")
472 <<
" single particle, conv.values: " << sum_m <<
", " << sum_0 <<
", " << sum_p;
480 if (trk_input.
size() < 2)
return;
482 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"Find and merge tracks broken by vertices.";
486 for (
size_t t = 0; t < trk_input.
size(); t++) {
494 if ((trk1 != trk2) && isSingleParticle(trk2, trk1))
502 double c, maxc = 0.0;
504 node = trk1->
Nodes().back();
510 c = dir1.Dot(tst->
Segments().front()->GetDirection3D());
517 if ((trk2) && isSingleParticle(trk1, trk2)) {
523 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"-------- done --------";
530 if (trk_input.
size() < 1)
return;
532 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"Find missed vtx by dQ/dx steps along merged tracks.";
534 while (t < trk_input.
size()) {
537 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"-------- done --------";
545 if (trk_input.
size() < 1)
return;
547 mf::LogVerbatim(
"pma::PMAlgVertexing")
548 <<
"Find kinks on tracks, reopt with no penalty on angle where kinks.";
549 for (
size_t t = 0; t < trk_input.
size(); ++t) {
551 if (trk->
Nodes().size() < 5)
continue;
553 trk->
Optimize(detProp, 0, 1.0
e-5,
false);
555 std::vector<size_t> tested_nodes;
556 bool kinkFound =
true;
558 int kinkIdx = -1, nnodes = 0;
559 double mean = 0.0, stdev = 0.0, min = 1.0, max_a = 0.0;
560 for (
size_t n = 1;
n < trk->
Nodes().size() - 1; ++
n) {
561 auto const& node = *(trk->
Nodes()[
n]);
563 if (node.IsVertex() || node.IsTPCEdge())
continue;
566 double c = -node.SegmentCosTransverse();
567 double a = 180.0 * (1 - std::acos(node.SegmentCosTransverse()) / TMath::Pi());
570 if ((c < min) && !has(tested_nodes,
n)) {
571 if ((
n > 1) && (
n < trk->
Nodes().size() - 2)) kinkIdx =
n;
578 if ((nnodes > 2) && (kinkIdx > 0) && (max_a > fKinkMinDeg)) {
581 stdev -= mean *
mean;
583 double thr = 1.0 - fKinkMinStd * stdev;
585 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" kink a: " << max_a <<
"deg";
586 trk->
Nodes()[kinkIdx]->SetVertex(
true);
587 tested_nodes.push_back(kinkIdx);
590 trk->
Optimize(detProp, 0, 1.0
e-5,
false,
false);
591 double c = -trk->
Nodes()[kinkIdx]->SegmentCosTransverse();
593 180.0 * (1 - std::acos(trk->
Nodes()[kinkIdx]->SegmentCosTransverse()) / TMath::Pi());
595 if ((a <= fKinkMinDeg) || (c >= thr))
597 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
" -> tag removed after reopt";
598 trk->
Nodes()[kinkIdx]->SetVertex(
605 mf::LogVerbatim(
"pma::PMAlgVertexing") <<
"-------- done --------";
610 std::vector<std::pair<TVector3, std::vector<std::pair<size_t, bool>>>>
613 std::vector<std::pair<TVector3, std::vector<std::pair<size_t, bool>>>> vsel;
614 std::vector<pma::Node3D const*> bnodes;
616 for (
size_t t = 0; t < tracks.
size(); ++t) {
619 if (!(onlyBranching || firstNode->
IsBranching())) {
620 std::vector<std::pair<size_t, bool>> tidx;
621 tidx.emplace_back(std::pair<size_t, bool>(t,
true));
627 for (
auto node : trk->
Nodes())
628 if (node->IsBranching()) {
630 for (
size_t n = 0;
n < bnodes.size();
n++)
631 if (node == bnodes[
n]) {
632 vsel[
n].second.emplace_back(std::pair<size_t, bool>(t, pri));
637 std::vector<std::pair<size_t, bool>> tidx;
638 tidx.emplace_back(std::pair<size_t, bool>(t, pri));
640 std::pair<TVector3,
std::vector<std::pair<size_t, bool>>>(node->Point3D(), tidx));
641 bnodes.push_back(node);
651 std::vector<std::pair<TVector3, size_t>>
654 std::vector<std::pair<TVector3, size_t>> ksel;
655 for (
size_t t = 0; t < tracks.
size(); ++t) {
657 for (
size_t n = 1;
n < trk->
Nodes().size() - 1; ++
n) {
660 ksel.emplace_back(std::pair<TVector3, size_t>(node->
Point3D(), t));
TVector3 const & Point3D() const
size_t run(const detinfo::DetectorPropertiesData &detProp, pma::TrkCandidateColl &trk_input)
ClusterModuleLabel join with tracks
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
std::vector< pma::Node3D * > const & Nodes() const noexcept
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
std::vector< pma::Segment3D * > const & Segments() const noexcept
fhicl::Atom< bool > FindKinks
std::vector< std::pair< double, double > > getdQdx(const pma::Track3D &trk) const
Get dQ/dx sequence to detect various features.
fhicl::Atom< double > KinkMinStd
bool IsVertex() const
Check fIsVertex flag.
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)
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)
then echo File list $list not found else cat $list while read file do echo $file sed s
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.
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)
std::vector< TrkCandidate > const & tracks() const
void mergeBrokenTracks(pma::TrkCandidateColl &trk_input) const