DBScan3DAlg.cxx
Go to the documentation of this file.
6 #include "larcorealg/CoreUtils/NumericUtils.h" // util::absDiff()
9 
11 #include "cetlib/pow.h"
12 #include "fhiclcpp/ParameterSet.h"
13 
14 #include <algorithm>
15 #include <stdio.h>
16 #include <stdlib.h>
17 
19  : epsilon(pset.get< float >("epsilon"))
20  , minpts(pset.get<unsigned int>("minpts"))
21  , badchannelweight(pset.get<double>("badchannelweight"))
22  , neighbors(pset.get<unsigned int>("neighbors"))
23 {
24  // square epsilon to eliminate the use of sqrt later on
25  epsilon *= epsilon;
26 }
27 
28 //----------------------------------------------------------
29 void cluster::DBScan3DAlg::init(const std::vector<art::Ptr<recob::SpacePoint>>& sps, art::FindManyP<recob::Hit>& hitFromSp)
30 {
31 
32  if (badchannelmap.empty()){
35  // build a map to count bad channels around each wire ID
36  for (auto &pid : geom->IteratePlaneIDs()){
37  for (auto& wid1: geom->IterateWireIDs(pid)) {
38  unsigned int nbadchs = 0;
39  for (auto& wid2: geom->IterateWireIDs(pid)) {
40  if (wid1==wid2) continue;
41  if (util::absDiff(wid1.Wire,wid2.Wire)<neighbors &&
42  !channelStatus.IsGood(geom->PlaneWireToChannel(wid2))) ++nbadchs;
43  }
44  badchannelmap[wid1] = nbadchs;
45  }
46  }
47  std::cout<<"Done building bad channel map."<<std::endl;
48  }
49 
50  points.clear();
51  for (auto& spt : sps){
52  point_t point;
53  point.sp = spt;
54  point.cluster_id = UNCLASSIFIED;
55  // count bad channels
56  point.nbadchannels = 0;
57  auto &hits = hitFromSp.at(spt.key());
58  for (auto & hit : hits){
59  point.nbadchannels += badchannelmap[hit->WireID()];
60  }
61  points.push_back(point);
62  }
63 }
64 
66 {
67  node_t *n = (node_t *) calloc(1, sizeof(node_t));
68  if (n == NULL)
69  perror("Failed to allocate node.");
70  else {
71  n->index = index;
72  n->next = NULL;
73  }
74  return n;
75 }
76 
79 {
80  node_t *n = create_node(index);
81  if (n == NULL) {
82  free(en);
83  return FAILURE;
84  }
85  if (en->head == NULL) {
86  en->head = n;
87  en->tail = n;
88  } else {
89  en->tail->next = n;
90  en->tail = n;
91  }
92  ++(en->num_members);
93  return SUCCESS;
94 }
95 
97 {
99  calloc(1, sizeof(epsilon_neighbours_t));
100  if (en == NULL) {
101  perror("Failed to allocate epsilon neighbours.");
102  return en;
103  }
104  for (unsigned int i = 0; i < points.size(); ++i) {
105  if (i == index)
106  continue;
107  if (dist(&points[index], &points[i]) > epsilon)
108  continue;
109  else {
110  if (append_at_end(i, en) == FAILURE) {
112  en = NULL;
113  break;
114  }
115  }
116  }
117  return en;
118 }
119 
121 {
122  if (en) {
123  node_t *t, *h = en->head;
124  while (h) {
125  t = h->next;
126  free(h);
127  h = t;
128  }
129  free(en);
130  }
131 }
132 
134 {
135  unsigned int i, cluster_id = 0;
136  for (i = 0; i < points.size(); ++i) {
137  if (points[i].cluster_id == UNCLASSIFIED) {
138  if (expand(i, cluster_id) == CORE_POINT)
139  ++cluster_id;
140  }
141  }
142 }
143 
145  unsigned int cluster_id)
146 {
147  int return_value = NOT_CORE_POINT;
149  get_epsilon_neighbours(index);
150  if (seeds == NULL)
151  return FAILURE;
152 
153  if (seeds->num_members < minpts)
154  points[index].cluster_id = NOISE;
155  else {
156  points[index].cluster_id = cluster_id;
157  node_t *h = seeds->head;
158  while (h) {
159  points[h->index].cluster_id = cluster_id;
160  h = h->next;
161  }
162 
163  h = seeds->head;
164  while (h) {
165  spread(h->index, seeds, cluster_id);
166  h = h->next;
167  }
168 
169  return_value = CORE_POINT;
170  }
172  return return_value;
173 }
174 
177  unsigned int cluster_id)
178 {
180  get_epsilon_neighbours(index);
181  if (spread == NULL)
182  return FAILURE;
183  if (spread->num_members >= minpts) {
184  node_t *n = spread->head;
185  point_t *d;
186  while (n) {
187  d = &points[n->index];
188  if (d->cluster_id == NOISE ||
189  d->cluster_id == UNCLASSIFIED) {
190  if (d->cluster_id == UNCLASSIFIED) {
191  if (append_at_end(n->index, seeds)
192  == FAILURE) {
194  return FAILURE;
195  }
196  }
197  d->cluster_id = cluster_id;
198  }
199  n = n->next;
200  }
201  }
202 
204  return SUCCESS;
205 }
206 
208 {
209  Double32_t const* a_xyz = a->sp->XYZ();
210  Double32_t const* b_xyz = b->sp->XYZ();
211  auto const nbadchannels = a->nbadchannels + b->nbadchannels;
212  float const dx = a_xyz[0] - b_xyz[0];
213  float const dy = a_xyz[1] - b_xyz[1];
214  float const dz = a_xyz[2] - b_xyz[2];
215  float const dist = cet::sum_of_squares(dx, dy, dz) - cet::square(nbadchannels * badchannelweight);
216  // Do not return a distance smaller than 0.
217  return std::max(dist, 0.f);
218 }
std::map< geo::WireID, int > badchannelmap
Definition: DBScan3DAlg.h:95
unsigned int minpts
Definition: DBScan3DAlg.h:92
Functions to help with numbers.
art::Ptr< recob::SpacePoint > sp
Definition: DBScan3DAlg.h:57
unsigned int index
Definition: DBScan3DAlg.h:64
node_t * next
Definition: DBScan3DAlg.h:65
constexpr T sum_of_squares(T x, T y)
Definition: pow.h:139
epsilon_neighbours_t * get_epsilon_neighbours(unsigned int index)
Definition: DBScan3DAlg.cxx:96
struct vector vector
unsigned int num_members
Definition: DBScan3DAlg.h:70
constexpr T square(T x)
Definition: pow.h:21
art framework interface to geometry description
IteratorBox< plane_id_iterator,&GeometryCore::begin_plane_id,&GeometryCore::end_plane_id > IteratePlaneIDs() const
Enables ranged-for loops on all plane IDs of the detector.
IteratorBox< wire_id_iterator,&GeometryCore::begin_wire_id,&GeometryCore::end_wire_id > IterateWireIDs() const
Enables ranged-for loops on all wire IDs of the detector.
int cluster_id
Definition: DBScan3DAlg.h:59
void init(const std::vector< art::Ptr< recob::SpacePoint >> &sps, art::FindManyP< recob::Hit > &hitFromSp)
Definition: DBScan3DAlg.cxx:29
std::void_t< T > n
const double a
#define UNCLASSIFIED
Definition: DBScan3DAlg.h:33
float dist(point_t *a, point_t *b) const
virtual bool IsGood(raw::ChannelID_t channel) const
Returns whether the specified channel is physical and good.
int expand(unsigned int index, unsigned int cluster_id)
#define NOT_CORE_POINT
Definition: DBScan3DAlg.h:37
Class providing information about the quality of channels.
static int max(int a, int b)
Description of geometry of one entire detector.
Detector simulation of raw signals on wires.
constexpr auto absDiff(A const &a, B const &b)
Returns the absolute value of the difference between two values.
Definition: NumericUtils.h:43
node_t * create_node(unsigned int index)
Definition: DBScan3DAlg.cxx:65
#define CORE_POINT
Definition: DBScan3DAlg.h:36
int append_at_end(unsigned int index, epsilon_neighbours_t *en)
Definition: DBScan3DAlg.cxx:77
std::vector< TrajPoint > seeds
Definition: DataStructs.cxx:13
#define FAILURE
Definition: DBScan3DAlg.h:40
raw::ChannelID_t PlaneWireToChannel(WireID const &wireid) const
Returns the ID of the TPC channel connected to the specified wire.
Declaration of signal hit object.
DBScan3DAlg(fhicl::ParameterSet const &pset)
Definition: DBScan3DAlg.cxx:18
Interface for experiment-specific channel quality info provider.
const Double32_t * XYZ() const
Definition: SpacePoint.h:76
static bool * b
Definition: config.cpp:1043
Access the description of detector geometry.
unsigned int neighbors
Definition: DBScan3DAlg.h:94
std::vector< point_t > points
Definition: DBScan3DAlg.h:83
int spread(unsigned int index, epsilon_neighbours_t *seeds, unsigned int cluster_id)
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
Interface for experiment-specific service for channel quality info.
unsigned int nbadchannels
Definition: DBScan3DAlg.h:58
#define NOISE
Definition: DBScan3DAlg.h:34
QTextStream & endl(QTextStream &s)
void destroy_epsilon_neighbours(epsilon_neighbours_t *en)
#define SUCCESS
Definition: DBScan3DAlg.h:39