NaiveStriper.cxx
Go to the documentation of this file.
2 #include "WireCellImg/ImgData.h"
3 
5 
6 #include <boost/graph/graph_traits.hpp>
7 #include <boost/graph/adjacency_list.hpp>
8 #include <boost/graph/connected_components.hpp>
9 
10 
13 
14 
15 using namespace WireCell;
16 
18 {
19 }
20 
21 WireCell::Configuration Img::NaiveStriper::default_configuration() const
22 {
24 
25  // The number of intersticial wires which must exist without
26  // activity to consider two wires to be non-adjacent.
27  cfg["gap"] = 1;
28 
29  return cfg;
30 }
31 
32 
34 {
35  m_gap = get(cfg, "gap", 1);
36 }
37 
38 
39 bool Img::NaiveStriper::operator()(const input_pointer& slice, output_pointer& out)
40 {
41  out = nullptr;
42  if (!slice) {
43  return true; // eos
44  }
45 
46  // The graph connects channels to attached wires and wires to
47  // their adjacent neighbor in the plane and along the positive
48  // pitch direction.
49 
50  typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> graph_t;
51  typedef boost::graph_traits<graph_t>::vertex_descriptor vertex_t;
52  graph_t graph;
53 
54  // Boost graph uses simple numbers as the "node object". We could
55  // attach vertex properties to nodes to hold either the IWire or
56  // the IChannel+charge values or we can keep or own lookup tables.
57  // The former is probably faster but for now, we these lookups out
58  // in the open.
59  std::unordered_map<IWire::pointer, IChannel::pointer> wire_to_chan;
60  std::unordered_map<IChannel::pointer, vertex_t> chan_to_node;
61  std::unordered_map<vertex_t, ISlice::pair_t> node_to_chanval;
62  std::unordered_map<int, IWireIndexSet> hit_wires;
63 
64  // Fill channel nodes in graph and group wires by plane
65  for (const auto& cv : slice->activity()) {
66  auto ichan = cv.first;
67  auto node = boost::add_vertex(graph);
68  chan_to_node[ichan] = node;
69  node_to_chanval[node] = cv;
70  for (auto iwire : ichan->wires()) {
71  const auto pid = iwire->planeid();
72  hit_wires[pid.ident()].insert(iwire);
73  wire_to_chan[iwire] = ichan;
74  }
75  }
76 
77  // Loop over ordered wires per plane and make edges.
78  for (const auto& phw : hit_wires) {
79  int last_ind = -1;
80  vertex_t last_wire = 0;
81  for (auto iwire : phw.second) {
82  auto ichan = wire_to_chan[iwire];
83  vertex_t chan_node = chan_to_node[ichan];
84  vertex_t wire_node = boost::add_vertex(graph);
85  const int this_index = iwire->index();
86 
87  // no matter what, chan->node.
88  boost::add_edge(chan_node, wire_node, graph);
89 
90  const size_t dind = this_index - last_ind;
91  if (last_ind >= 0 and dind <= m_gap) {
92  boost::add_edge(last_wire, wire_node, graph);
93  }
94  last_ind = this_index;
95  last_wire = wire_node;
96  }
97  }
98 
99  // Here's the heavy lifing. Stripes are understood to be formed as
100  // the channels found by looking for the "connected subgraphs".
101  // Like the graph itself, this neesds some looksup to translate
102  // between Boost Graph's subgraph index and a corresponding stripe.
103  std::unordered_map<vertex_t, int> subclusters;
104  std::unordered_map<int, Img::Data::Stripe*> cluster_to_stripe;
105  boost::connected_components(graph, boost::make_assoc_property_map(subclusters));
106 
107  // Collect channels of like cluster number into stripes
108  for (auto& p : subclusters) {
109  auto ncvit = node_to_chanval.find(p.first);
110  if (ncvit == node_to_chanval.end()) {
111  continue;
112  }
113  auto& cv = ncvit->second;
114  auto stripe = cluster_to_stripe[p.second];
115  if (!stripe) {
116  cluster_to_stripe[p.second] = stripe = new Img::Data::Stripe(p.first);
117  }
118  stripe->append(cv.first, cv.second);
119  }
120 
121  auto sliceset = new Img::Data::StripeSet(slice->ident());
122  for (auto ss : cluster_to_stripe) {
123  sliceset->push_back(IStripe::pointer(ss.second));
124  }
125 
126  out = IStripeSet::pointer(sliceset);
127  return true;
128 }
std::shared_ptr< const IStripe > pointer
Definition: IData.h:19
def graph(desc, maker=maker)
Definition: apa.py:294
cfg
Definition: dbjson.py:29
std::shared_ptr< const ISlice > input_pointer
Definition: IFunctionNode.h:39
def configure(cfg)
Definition: cuda.py:34
WIRECELL_FACTORY(NaiveStriper, WireCell::Img::NaiveStriper, WireCell::ISliceStriper, WireCell::IConfigurable) using namespace WireCell
void push_back(const IStripe::pointer &s)
Definition: ImgData.h:95
std::shared_ptr< const IStripeSet > output_pointer
Definition: IFunctionNode.h:40
Definition: Main.h:22
p
Definition: test.py:223
Json::Value Configuration
Definition: Configuration.h:50
const GenericPointer< typename T::ValueType > & pointer
Definition: pointer.h:1124