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