LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
Segmentation2D.cxx
Go to the documentation of this file.
1 
9 #include "Segmentation2D.h"
10 
11 #include "fhiclcpp/ParameterSet.h"
14 
16 {
17  fRadiusMin = p.get<double>("RadiusMin");
18  fRadiusMax = p.get<double>("RadiusMax");
19  fMaxLineDist = p.get<double>("MaxLineDist");
20 
21  fDenseVtxRadius = p.get<double>("DenseVtxRadius");
22  fDenseMinN = p.get<unsigned int>("DenseMinNVtx");
23 
24  fDenseHitRadius = p.get<double>("DenseHitRadius");
25  fDenseMinH = p.get<unsigned int>("DenseMinNHits");
26 }
27 
28 std::vector<tss::Cluster2D> tss::Segmentation2D::run(tss::Cluster2D& inp) const
29 {
30  std::vector<tss::Cluster2D> result;
31  while (inp.size() > 1) {
32  size_t idx;
33  const tss::Hit2D* hFirst = inp.outermost(idx);
34  if (!hFirst) break;
35 
36  std::vector<TVector2> centers;
37  centers.emplace_back(hFirst->Point2D());
38 
39  while (centers.size()) {
40  run(inp, result, centers);
41  }
42  }
43 
44  tagDenseEnds(result);
45  mergeDenseParts(result);
46 
47  return result;
48 }
49 // ------------------------------------------------------
50 
52  std::vector<tss::Cluster2D>& result,
53  std::vector<TVector2>& centers) const
54 {
55  if (!centers.size()) return;
56 
57  TVector2 center(centers.front());
58  centers.erase(centers.begin());
59 
60  size_t idx;
61  const tss::Hit2D* hFirst = inp.closest(center, idx);
62 
63  const double dmax2 = 0.5 * 0.5; // does not look like startpoint selected before
64  if (!hFirst || (pma::Dist2(hFirst->Point2D(), center) > dmax2)) return;
65  center = hFirst->Point2D();
66 
67  tss::Cluster2D ring = selectRing(inp, center);
68  if (ring.size()) {
69  std::vector<tss::Cluster2D> seeds = fSimpleClustering.run(ring);
70  while (seeds.size()) {
71  size_t seedIdx = 0, hitIdx, h;
72  double d2, min_d2 = seeds.front().dist2(center, hitIdx);
73  for (size_t i = 1; i < seeds.size(); i++) {
74  d2 = seeds[i].dist2(center, h);
75  if (d2 < min_d2) {
76  min_d2 = d2;
77  seedIdx = i;
78  hitIdx = h;
79  }
80  }
81 
82  tss::Cluster2D segment = buildSegment(inp, center, seeds[seedIdx][hitIdx].Point2D());
83  if (segment.size()) {
84  result.emplace_back(segment);
85  if (segment.size() > 1) {
86  const tss::Hit2D* hEnd = segment.end();
87  if (hEnd) centers.emplace_back(hEnd->Point2D());
88  }
89  }
90 
91  seeds.erase(seeds.begin() + seedIdx);
92  }
93  }
94  else {
95  result.emplace_back(tss::Cluster2D());
96  result.back().push_back(hFirst);
97  inp.release(hFirst);
98  }
99 }
100 // ------------------------------------------------------
101 
103  TVector2 center,
104  TVector2 end) const
105 {
106  const double max_d2 = fMaxLineDist * fMaxLineDist;
107  TVector2 segDir = end - center;
108 
109  double dc, min_dc = 1.0e9;
110  size_t firstIdx = 0;
111 
112  tss::Cluster2D candidates;
113  for (auto h : inp.hits()) {
114  TVector2 proj = pma::GetProjectionToSegment(h->Point2D(), center, end);
115  if (pma::Dist2(h->Point2D(), proj) < max_d2) {
116  TVector2 hDir = h->Point2D() - center;
117  dc = hDir.Mod();
118  if ((hDir * segDir >= 0.0) || (dc < 0.1)) {
119  candidates.push_back(h);
120  if (dc < min_dc) {
121  min_dc = dc;
122  firstIdx = candidates.size() - 1;
123  }
124  }
125  }
126  }
127  if (candidates.size() > 1) {
128  const tss::Hit2D* hFirst = candidates.hits()[firstIdx];
129  candidates.hits()[firstIdx] = candidates.hits()[0];
130  candidates.hits()[0] = hFirst;
131  candidates.sort();
132  }
133 
134  tss::Cluster2D segment;
135  if (candidates.size()) {
136  segment.push_back(candidates.start());
137  if (!inp.release(segment.start())) {
138  mf::LogError("Segmentation2D") << "Hit not found in the input cluster.";
139  }
140 
141  size_t i = 1;
142  while ((i < candidates.size()) && fSimpleClustering.hitsTouching(segment, candidates[i])) {
143  segment.push_back(candidates.hits()[i++]);
144  if (!inp.release(segment.end())) {
145  mf::LogError("Segmentation2D") << "Hit not found in the input cluster.";
146  }
147  }
148  }
149 
150  return segment;
151 }
152 // ------------------------------------------------------
153 
155 {
156  double d2_min = fRadiusMin * fRadiusMin;
157  double d2_max = fRadiusMax * fRadiusMax;
158 
159  tss::Cluster2D ring;
160  for (size_t h = 0; h < inp.size(); h++) {
161  double d2 = pma::Dist2(center, inp[h].Point2D());
162  if ((d2 >= d2_min) && (d2 <= d2_max)) ring.push_back(inp.hits()[h]);
163  }
164  return ring;
165 }
166 // ------------------------------------------------------
167 
168 void tss::Segmentation2D::tagDenseEnds(std::vector<tss::Cluster2D>& group) const
169 {
170  const double rad2 = fDenseVtxRadius * fDenseVtxRadius;
171 
172  for (size_t i = 0; i < group.size(); i++) {
173  bool denseStart = false, denseEnd = false;
174  TVector2 start0(group[i].start()->Point2D()), end0(group[i].end()->Point2D());
175 
176  for (size_t j = 0; j < group.size(); j++) {
177  if (i == j) continue;
178 
179  TVector2 start1(group[j].start()->Point2D()), end1(group[j].end()->Point2D());
180 
181  if (!group[j].isDenseStart()) {
182 
183  if (pma::Dist2(start1, start0) < rad2) {
184  group[j].tagDenseStart(true);
185  denseStart = true;
186  }
187  if (pma::Dist2(start1, end0) < rad2) {
188  group[j].tagDenseStart(true);
189  denseEnd = true;
190  }
191  }
192 
193  if (!group[j].isDenseEnd()) {
194  if (pma::Dist2(end1, start0) < rad2) {
195  group[j].tagDenseEnd(true);
196  denseStart = true;
197  }
198  if (pma::Dist2(end1, end0) < rad2) {
199  group[j].tagDenseEnd(true);
200  denseEnd = true;
201  }
202  }
203  }
204 
205  if (denseStart) group[i].tagDenseStart(true);
206  if (denseEnd) group[i].tagDenseEnd(true);
207  }
208 }
209 // ------------------------------------------------------
210 
211 void tss::Segmentation2D::mergeDenseParts(std::vector<tss::Cluster2D>& group) const
212 {
213  const double rad2 = fDenseVtxRadius * fDenseVtxRadius;
214 
215  bool merged = true;
216  while (merged) {
217  merged = false;
218 
219  size_t maxS = fDenseMinN, maxE = fDenseMinN;
220  std::vector<size_t> toMergeS, toMergeE;
221  int idxMaxS = -1, idxMaxE = -1;
222 
223  for (size_t i = 0; i < group.size(); i++) {
224 
225  if (group[i].isEM()) continue;
226 
227  if (group[i].isDenseStart()) {
228 
229  size_t ns = 0;
230  std::vector<size_t> toMerge;
231  TVector2 start0(group[i].start()->Point2D());
232  for (size_t j = 0; j < group.size(); j++) {
233  if (group[j].isEM()) continue;
234 
235  if (i == j) {
236  if ((group[j].size() > 1) && (group[j].length2() < rad2)) ns++;
237  }
238  else {
239  bool tagged = false;
240  if (pma::Dist2(start0, group[j].start()->Point2D()) < rad2) {
241  ns++;
242  toMerge.push_back(j);
243  tagged = true;
244  }
245  if ((group[j].size() > 1) && (pma::Dist2(start0, group[j].end()->Point2D()) < rad2)) {
246  ns++;
247  if (!tagged) toMerge.push_back(j);
248  }
249  }
250  }
251  if (ns > maxS) {
252  maxS = ns;
253  idxMaxS = i;
254  toMergeS = toMerge;
255  }
256  }
257 
258  if ((group[i].size() > 1) && group[i].isDenseEnd()) {
259  size_t ne = 0;
260  std::vector<size_t> toMerge;
261  TVector2 end0(group[i].end()->Point2D());
262  for (size_t j = 0; j < group.size(); j++) {
263  if (group[j].isEM()) continue;
264 
265  if (i == j) {
266  if ((group[j].size() > 1) && (group[j].length2() < rad2)) ne++;
267  }
268  else {
269  bool tagged = false;
270  if (pma::Dist2(end0, group[j].start()->Point2D()) < rad2) {
271  ne++;
272  toMerge.push_back(j);
273  tagged = true;
274  }
275  if ((group[j].size() > 1) && (pma::Dist2(end0, group[j].end()->Point2D()) < rad2)) {
276  ne++;
277  if (!tagged) toMerge.push_back(j);
278  }
279  }
280  }
281  if (ne > maxE) {
282  maxE = ne;
283  idxMaxE = i;
284  toMergeE = toMerge;
285  }
286  }
287  }
288 
289  int idx = idxMaxS;
290  std::vector<size_t> toMergeIdxs = toMergeS;
291  if (idxMaxE > idx) {
292  idx = idxMaxE;
293  toMergeIdxs = toMergeE;
294  }
295  if (idx > -1) {
296  toMergeIdxs.push_back(idx);
297  idx = mergeClusters(group, toMergeIdxs);
298 
299  if (idx > -1) group[idx].tagEM(true);
300 
301  merged = true;
302  }
303  }
304 }
305 // ------------------------------------------------------
306 
307 int tss::Segmentation2D::mergeClusters(std::vector<tss::Cluster2D>& group,
308  const std::vector<size_t>& idxs) const
309 {
310  if (idxs.size() < 2) return 0;
311 
312  for (const auto i : idxs) {
313  if (i < group.size())
314  group[i].setTag(true);
315  else {
316  mf::LogError("Segmentation2D") << "Merging index out of group range.";
317  return -1;
318  }
319  }
320 
321  size_t k = idxs.front(), i = idxs.front() + 1;
322  while (i < group.size()) {
323  if (group[i].isTagged()) {
324  group[k].merge(group[i]);
325  group.erase(group.begin() + i);
326  }
327  else
328  ++i;
329  }
330  group[k].setTag(false);
331 
332  return k;
333 }
334 // ------------------------------------------------------
335 
336 void tss::Segmentation2D::splitHits(const std::vector<tss::Cluster2D>& inp,
337  std::vector<const tss::Hit2D*>& trackHits,
338  std::vector<const tss::Hit2D*>& emHits) const
339 {
340 
341  trackHits.clear();
342  emHits.clear();
343 
344  for (const auto& cx : inp) {
345  if (!cx.size()) continue;
346 
347  if (cx.isEM()) {
348  for (auto h : cx.hits())
349  emHits.push_back(h);
350  }
351  else {
352  for (auto h : cx.hits())
353  trackHits.push_back(h);
354  }
355  }
356 }
357 // ------------------------------------------------------
358 
360  std::vector<const tss::Hit2D*>& trackHits,
361  std::vector<const tss::Hit2D*>& emHits) const
362 {
363  const double rad2 = fDenseHitRadius * fDenseHitRadius;
364 
365  trackHits.clear();
366  emHits.clear();
367 
368  for (const auto hx : inp.hits()) {
369  size_t n = 0;
370  for (const auto hy : inp.hits()) {
371  if (hx->Hit2DPtr() == hy->Hit2DPtr()) continue;
372 
373  if (pma::Dist2(hx->Point2D(), hy->Point2D()) < rad2) n++;
374  }
375 
376  if (n > fDenseMinH) { emHits.push_back(hx); }
377  else {
378  trackHits.push_back(hx);
379  }
380  }
381 }
382 // ------------------------------------------------------
383 
384 void tss::Segmentation2D::splitHitsNaive(const std::vector<tss::Cluster2D>& inp,
385  std::vector<const tss::Hit2D*>& trackHits,
386  std::vector<const tss::Hit2D*>& emHits) const
387 {
388  const double rad2 = fDenseHitRadius * fDenseHitRadius;
389 
390  trackHits.clear();
391  emHits.clear();
392 
393  for (const auto& cx : inp) {
394  if (!cx.size()) continue;
395 
396  for (const auto hx : cx.hits()) {
397  size_t n = 0;
398  for (const auto& cy : inp) {
399  if (!cy.size()) continue;
400 
401  for (const auto hy : cy.hits()) {
402  if (hx->Hit2DPtr() == hy->Hit2DPtr()) continue;
403 
404  if (pma::Dist2(hx->Point2D(), hy->Point2D()) < rad2) n++;
405  }
406  }
407 
408  if (n > fDenseMinH) { emHits.push_back(hx); }
409  else {
410  trackHits.push_back(hx);
411  }
412  }
413  }
414 }
415 // ------------------------------------------------------
416 
417 // ------------------------------------------------------
418 
420 {
421  bool clover = false;
422  bool clunder = false;
423  bool clleft = false;
424  bool clright = false;
425 
426  if (cl2.isEM()) return false;
427 
428  float shift = 5; // shift!
429 
430  TVector2 point((cl2.max()).X(), (cl2.min()).Y());
431  float width = (cl2.max()).X() - (cl2.min()).X();
432  float height = (cl2.max()).Y() - (cl2.min()).Y();
433 
434  for (unsigned int h = 0; h < cl1.size(); h++) {
435  float wire = cl1[h].Point2D().X();
436  float drift = cl1[h].Point2D().Y();
437 
438  if ((wire <= (point.X() + shift)) && (wire >= (point.X() - width - shift))) {
439  if (drift < point.Y()) { clover = true; }
440  else if (drift > (point.Y() + height)) {
441  clunder = true;
442  }
443 
444  if (wire > point.X()) { clleft = true; }
445  else if (wire < (point.X() - width)) {
446  clright = true;
447  }
448  }
449  }
450 
451  if (clover && clunder && clleft && clright)
452  return true;
453  else
454  return false;
455 }
TVector2 const & Point2D() const
Definition: TssHit2D.h:31
int mergeClusters(std::vector< tss::Cluster2D > &group, const std::vector< size_t > &idxs) const
double Dist2(const TVector2 &v1, const TVector2 &v2)
Definition: Utilities.cxx:39
const tss::Hit2D * start(void) const
void mergeDenseParts(std::vector< tss::Cluster2D > &group) const
void push_back(const tss::Hit2D *hit)
Float_t Y
Definition: plot.C:37
const std::vector< const tss::Hit2D * > & hits(void) const
void splitHitsNaive(const tss::Cluster2D &inp, std::vector< const tss::Hit2D * > &trackHits, std::vector< const tss::Hit2D * > &emHits) const
Split into linear clusters.
const Hit2D * outermost(size_t &idx) const
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
const Hit2D * closest(const TVector2 &p2d, size_t &idx) const
tss::Cluster2D selectRing(const tss::Cluster2D &inp, TVector2 center) const
void reconfigure(const fhicl::ParameterSet &p)
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:101
TVector2 GetProjectionToSegment(const TVector2 &p, const TVector2 &p0, const TVector2 &p1)
Definition: Utilities.cxx:144
bool Cl2InsideCl1(tss::Cluster2D &cl1, tss::Cluster2D &cl2) const
T get(std::string const &key) const
Definition: ParameterSet.h:314
std::vector< tss::Cluster2D > run(const std::vector< tss::Hit2D > &inp) const
const tss::Hit2D * end(void) const
std::vector< tss::Cluster2D > run(tss::Cluster2D &inp) const
tss::Cluster2D buildSegment(tss::Cluster2D &inp, TVector2 center, TVector2 end) const
bool isEM(void) const
std::vector< TrajPoint > seeds
Definition: DataStructs.cxx:14
bool hitsTouching(const tss::Hit2D &h1, const tss::Hit2D &h2) const
Implementation of the Projection Matching Algorithm.
void tagDenseEnds(std::vector< tss::Cluster2D > &group) const
bool release(const tss::Hit2D *hit)
const TVector2 max(void) const
Float_t proj
Definition: plot.C:35
const TVector2 min(void) const
tss::SimpleClustering fSimpleClustering
Char_t n[5]
double maxE
Definition: plot_hist.C:8
Float_t X
Definition: plot.C:37
size_t size(void) const
void splitHits(const std::vector< tss::Cluster2D > &inp, std::vector< const tss::Hit2D * > &trackHits, std::vector< const tss::Hit2D * > &emHits) const