BlobSolving.cxx
Go to the documentation of this file.
5 #include "WireCellUtil/Ress.h"
8 
9 
12 
13 
14 using namespace WireCell;
15 
17 {
18 }
19 
20 Img::BlobSolving::~BlobSolving()
21 {
22 }
23 
25 {
26 }
27 
28 WireCell::Configuration Img::BlobSolving::default_configuration() const
29 {
31  return cfg;
32 }
33 
34 static
35 double measure_sum(const IChannel::shared_vector& imeas, const ISlice::pointer& islice)
36 {
37  double value = 0;
38  const auto& activity = islice->activity();
39  for (const auto& ich : *(imeas.get())) {
40  const auto& it = activity.find(ich);
41  if (it == activity.end()) {
42  continue;
43  }
44  value += it->second;
45  }
46  return value;
47 }
48 
49 // Return a blob weight. For now we hard code this but in the future
50 // this function can be replaced with a functional object slected
51 // based on configuration.
52 static
54 {
55  // magic numbers!
56  const double default_weight = 9;
57  const double reduction = 3;
58  const size_t homer = 2; // Max Power
59 
60 
61  std::unordered_set<int> slices;
62  IBlob::vector blobs = neighbors_oftype<IBlob::pointer>(grind, iblob);
63  for (auto oblob : blobs) {
64  for (auto oslice : neighbors_oftype<ISlice::pointer>(grind, oblob)) {
65  slices.insert(oslice->ident());
66  }
67  }
68  return default_weight / pow(reduction, std::min(homer, slices.size()));
69 }
70 
71 static
73 {
74  std::vector< std::vector<int> > b2minds;
75  IndexedSet<IBlob::pointer> blobs;
76  IndexedSet<IChannel::shared_vector> measures;
77  for (IBlob::pointer iblob : neighbors_oftype<IBlob::pointer>(grind, islice)) {
78  blobs(iblob);
79  std::vector<int> minds;
80  for (auto neigh : grind.neighbors(iblob)) {
81  if (neigh.code() == 'm') {
82  IChannel::shared_vector imeas = std::get<IChannel::shared_vector>(neigh.ptr);
83  int mind = measures(imeas);
84  minds.push_back(mind);
85  continue;
86  }
87  }
88  b2minds.push_back(minds);
89  }
90 
91 
92  const size_t nmeasures = measures.size();
93  Ress::vector_t meas = Ress::vector_t::Zero(nmeasures);
94  Ress::vector_t sigma = Ress::vector_t::Zero(nmeasures);
95  for (size_t mind=0; mind<nmeasures; ++mind) {
96  const auto& imeas = measures.collection[mind];
97  const double value = measure_sum(imeas, islice);
98  if (value > 0.0) {
99  const double sig = sqrt(value); // Poisson uncertainty for now.
100  sigma(mind) = sig;
101  meas(mind) = value/sig; // yes, this is just sig.
102  }
103  }
104 
105  const size_t nblobs = blobs.size();
106  Ress::vector_t init = Ress::vector_t::Zero(nblobs);
107  Ress::vector_t weight = Ress::vector_t::Zero(nblobs);
108  Ress::matrix_t geom = Ress::matrix_t::Zero(nmeasures, nblobs);
109 
110  for (size_t bind = 0; bind < nblobs; ++bind) {
111  IBlob::pointer iblob = blobs.collection[bind];
112  init(bind) = iblob->value();
113  weight(bind) = blob_weight(iblob, islice, grind);
114  const auto& minds = b2minds[bind];
115  for (int mind : minds) {
116  const double sig = sigma(mind);
117  if (sig > 0.0) {
118  geom(mind, bind) = 1.0/sig;
119  }
120  }
121  }
122 
123  Ress::Params params;
124  params.model = Ress::lasso;
125  Ress::vector_t solved = Ress::solve(geom, meas, params, init, weight);
126 
127  for (size_t ind=0; ind < nblobs; ++ind) {
128  auto oblob = blobs.collection[ind];
129  const double value = solved[ind];
130  const double unc = 0.0; // fixme, derive from solution + covariance
131  IBlob::pointer nblob = std::make_shared<SimpleBlob>(oblob->ident(), value, unc,
132  oblob->shape(), islice, oblob->face());
133  grind.replace(oblob, nblob);
134  }
135 
136 }
137 
138 
139 bool Img::BlobSolving::operator()(const input_pointer& in, output_pointer& out)
140 {
141  if (!in) {
142  out = nullptr;
143  return true;
144  }
145 
146  // start with a writable copy.
147  cluster_indexed_graph_t grind(in->graph());
148  for (auto islice : oftype<ISlice::pointer>(grind)) {
149  solve_slice(grind, islice);
150  }
151 
152  out = std::make_shared<SimpleCluster>(grind.graph());
153  return true;
154 }
IndexedGraph< cluster_node_t > cluster_indexed_graph_t
Definition: ICluster.h:105
vector_t solve(matrix_t response, vector_t measured, const Params &params=Params(), vector_t source=Eigen::VectorXd(), vector_t weights=Eigen::VectorXd())
Definition: Ress.cxx:7
constexpr T pow(T x)
Definition: pow.h:72
Eigen::VectorXd vector_t
Definition: Ress.h:12
struct vector vector
cfg
Definition: dbjson.py:29
init
Definition: train.py:42
def blobs(cm, hist)
Definition: plots.py:79
WIRECELL_FACTORY(BlobSolving, WireCell::Img::BlobSolving, WireCell::IClusterFilter, WireCell::IConfigurable) using namespace WireCell
def activity(output, slices, slice_line, cluster_tap_file)
Definition: main.py:144
std::shared_ptr< const ICluster > input_pointer
Definition: IFunctionNode.h:39
Eigen::MatrixXd matrix_t
Definition: Ress.h:13
def configure(cfg)
Definition: cuda.py:34
std::shared_ptr< const ICluster > output_pointer
Definition: IFunctionNode.h:40
std::vector< TCSlice > slices
Definition: DataStructs.cxx:12
Definition: Main.h:22
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1225
Json::Value Configuration
Definition: Configuration.h:50
static double blob_weight(IBlob::pointer iblob, ISlice::pointer islice, const cluster_indexed_graph_t &grind)
Definition: BlobSolving.cxx:53
static void solve_slice(cluster_indexed_graph_t &grind, ISlice::pointer islice)
Definition: BlobSolving.cxx:72
weight
Definition: test.py:257
const GenericPointer< typename T::ValueType > & pointer
Definition: pointer.h:1124
static double measure_sum(const IChannel::shared_vector &imeas, const ISlice::pointer &islice)
Definition: BlobSolving.cxx:35