ATTPCROOT  0.3.0-alpha
A ROOT-based framework for analyzing data from active target detectors
main.cxx
Go to the documentation of this file.
1 //
2 // main.cpp
3 // Main file for reference implementation of the TriplClust algorithm.
4 //
5 // Author: Jens Wilberg, Lukas Aymans, Christoph Dalitz
6 // Date: 2019-04-02
7 // License: see ../LICENSE
8 //
9 
10 #include "cluster.h"
11 #include "dnn.h"
12 #include "graph.h"
13 #include "option.h"
14 #include "output.h"
15 #include "pointcloud.h"
16 #include "triplet.h" // for triplet, generate_triplets
17 
18 #include <cmath>
19 #include <exception> // for exception
20 #include <fstream>
21 #include <iostream>
22 #include <stdexcept>
23 #include <string> // for operator+, basic_string, string
24 #include <vector>
25 
26 // usage message
27 const char *usage = "Usage:\n"
28  "\ttriplclust [options] <infile>\n"
29  "Options (defaults in brackets):\n"
30  "\t-r <radius> radius for point smoothing [2dNN]\n"
31  "\t (can be numeric or multiple of dNN)\n"
32  "\t-k <n> number of neighbours in triplet creation [19]\n"
33  "\t-n <n> number of the best triplets to use [2]\n"
34  "\t-a <alpha> maximum value for the angle between the\n"
35  "\t triplet branches [0.03]\n"
36  "\t-s <scale> scalingfactor for clustering [0.33dNN]\n"
37  "\t (can be numeric or multiple of dNN)\n"
38  "\t-t <dist> best cluster distance [auto]\n"
39  "\t (can be numeric or 'auto')\n"
40  "\t-m <n> minimum number of triplets for a cluster [5]\n"
41  "\t-dmax <n> max gapwidth within a triplet [none]\n"
42  "\t (can be numeric, multiple of dNN or 'none')\n"
43  "\t-link <method> linkage method for clustering [single]\n"
44  "\t (can be 'single', 'complete', 'average')\n"
45  "\t-oprefix <prefix>\n"
46  "\t write result not to stdout, but to <prefix>.csv\n"
47  "\t and (if -gnuplot is set) to <prefix>.gnuplot\n"
48  "\t-gnuplot print result as a gnuplot command\n"
49  "\t-delim <char> single char delimiter for csv input [' ']\n"
50  "\t-skip <n> number of lines skipped at head of infile [0]\n"
51  "\t-v be verbose\n"
52  "\t-vv be more verbose and write debug trace files\n"
53  "Version:\n"
54  "\t1.3 from 2019-04-02";
55 
56 int main(int argc, char **argv)
57 {
58  // parse commandline
59  Opt opt_params;
60  if (opt_params.parse_args(argc, argv) != 0) {
61  std::cerr << usage << std::endl;
62  return 1;
63  }
64  const char *infile_name = opt_params.get_ifname();
65  const char *outfile_prefix = opt_params.get_ofprefix();
66  int opt_verbose = opt_params.get_verbosity();
67 
68  // plausibility checks
69  if (!infile_name) {
70  std::cerr << "[Error] no infile given!\n" << usage << std::endl;
71  return 1;
72  }
73 
74  // load data
75  PointCloud cloud_xyz;
76  try {
77  load_csv_file(infile_name, cloud_xyz, opt_params.get_delimiter(), opt_params.get_skip());
78  } catch (const std::invalid_argument &e) {
79  std::cerr << "[Error] in file'" << infile_name << "': " << e.what() << std::endl;
80  return 2;
81  }
82 #ifdef WEBDEMO
83  // maximum pointcloud size error for webdemo
84  catch (const std::length_error &e) {
85  std::cerr << "[Error] in file'" << infile_name << "': " << e.what() << std::endl;
86  return 3;
87  }
88 #endif
89  catch (const std::exception &e) {
90  std::cerr << "[Error] cannot read infile '" << infile_name << "'! " << e.what() << std::endl;
91  return 2;
92  }
93  if (cloud_xyz.size() == 0) {
94  std::cerr << "[Error] empty cloud in file '" << infile_name << "'" << std::endl
95  << "maybe you used the wrong delimiter" << std::endl;
96  return 2;
97  }
98 
99  // compute characteristic length dnn if needed
100  if (opt_params.needs_dnn()) {
101  double dnn = std::sqrt(first_quartile(cloud_xyz));
102  if (opt_verbose > 0) {
103  std::cout << "[Info] computed dnn: " << dnn << std::endl;
104  }
105  opt_params.set_dnn(dnn);
106  if (dnn == 0.0) {
107  std::cerr << "[Error] dnn computed as zero. "
108  << "Suggestion: remove doublets, e.g. with 'sort -u'" << std::endl;
109  return 3;
110  }
111  }
112 
113  // Step 1) smoothing by position averaging of neighboring points
114  PointCloud cloud_xyz_smooth;
115  smoothen_cloud(cloud_xyz, cloud_xyz_smooth, opt_params.get_r());
116 
117  if (opt_verbose > 1) {
118  bool rc;
119  rc = cloud_to_csv(cloud_xyz_smooth);
120  if (!rc)
121  std::cerr << "[Error] can't write debug_smoothed.csv" << std::endl;
122  rc = debug_gnuplot(cloud_xyz, cloud_xyz_smooth);
123  if (!rc)
124  std::cerr << "[Error] can't write debug_smoothed.gnuplot" << std::endl;
125  }
126 
127  // Step 2) finding triplets of approximately collinear points
128  std::vector<triplet> triplets;
129  generate_triplets(cloud_xyz_smooth, triplets, opt_params.get_k(), opt_params.get_n(), opt_params.get_a());
130 
131  // Step 3) single link hierarchical clustering of the triplets
132  cluster_group cl_group;
133  compute_hc(cloud_xyz_smooth, cl_group, triplets, opt_params.get_s(), opt_params.get_t(), opt_params.is_tauto(),
134  opt_params.get_dmax(), opt_params.is_dmax(), opt_params.get_linkage(), opt_verbose);
135 
136  // Step 4) pruning by removal of small clusters ...
137  cleanup_cluster_group(cl_group, opt_params.get_m(), opt_verbose);
138  cluster_triplets_to_points(triplets, cl_group);
139 
140  // .. and (optionally) by splitting up clusters at gaps > dmax
141  if (opt_params.is_dmax()) {
142  cluster_group cleaned_up_cluster_group;
143  for (cluster_group::iterator cl = cl_group.begin(); cl != cl_group.end(); ++cl) {
144  max_step(cleaned_up_cluster_group, *cl, cloud_xyz, opt_params.get_dmax(), opt_params.get_m() + 2);
145  }
146  cl_group = cleaned_up_cluster_group;
147  }
148 
149  // std::cout<<" Cloud size : "<<cloud_xyz.size()<<" Clusters size : "<<cl_group.size()<<"\n";
150 
151  // store cluster labels in points
152  add_clusters(cloud_xyz, cl_group, opt_params.is_gnuplot());
153 
154  if (outfile_prefix) {
155  // redirect cout to outfile if requested
156  std::streambuf *backup = std::cout.rdbuf();
157  std::ofstream of;
158  of.open((std::string(outfile_prefix) + ".csv").c_str());
159  // replace the stream buffer from cout with the stream buffer from the
160  // opened file, so that everythin printed to cout is printed to the file.
161  std::cout.rdbuf(of.rdbuf());
162  clusters_to_csv(cloud_xyz);
163  of.close();
164  if (opt_params.is_gnuplot()) {
165  of.open((std::string(outfile_prefix) + ".gnuplot").c_str());
166  clusters_to_gnuplot(cloud_xyz, cl_group);
167  of.close();
168  }
169  // restore cout's default stream buffer
170  std::cout.rdbuf(backup);
171  } else if (opt_params.is_gnuplot()) {
172  clusters_to_gnuplot(cloud_xyz, cl_group);
173  } else {
174  clusters_to_csv(cloud_xyz);
175  }
176 
177  return 0;
178 }
Opt::get_skip
size_t get_skip()
Definition: option.cxx:284
Opt::is_dmax
bool is_dmax()
Definition: option.cxx:324
Opt::get_t
double get_t()
Definition: option.cxx:320
dnn.h
Opt::needs_dnn
bool needs_dnn()
Definition: option.cxx:276
Opt::set_dnn
void set_dnn(double dnn)
Definition: option.cxx:245
Opt::get_k
size_t get_k()
Definition: option.cxx:300
Opt::is_gnuplot
bool is_gnuplot()
Definition: option.cxx:280
Opt::get_ifname
const char * get_ifname()
Definition: option.cxx:268
usage
const char * usage
Definition: main.cxx:27
Opt::get_ofprefix
const char * get_ofprefix()
Definition: option.cxx:272
msd::first_quartile
float first_quartile(pcl::PointCloud< pcl::PointXYZ >::Ptr cloud)
Definition: msd.cxx:65
Opt::get_m
size_t get_m()
Definition: option.cxx:336
pointcloud.h
Opt::parse_args
int parse_args(int argc, char **argv)
Definition: option.cxx:74
Opt::get_n
size_t get_n()
Definition: option.cxx:304
triplet.h
Opt::is_tauto
bool is_tauto()
Definition: option.cxx:316
Opt::get_verbosity
int get_verbosity()
Definition: option.cxx:292
Opt::get_delimiter
char get_delimiter()
Definition: option.cxx:288
max_step
void max_step(std::vector< std::vector< size_t >> &new_clusters, const std::vector< size_t > &cluster, const PointCloud &cloud, double dmax, size_t min_size)
Definition: graph.cxx:125
clusters_to_csv
void clusters_to_csv(const PointCloud &cloud)
Definition: output.cxx:270
generate_triplets
void generate_triplets(const PointCloud &cloud, std::vector< triplet > &triplets, size_t k, size_t n, double a)
Definition: triplet.cxx:27
PointCloud
Definition: pointcloud.h:60
Opt::get_dmax
double get_dmax()
Definition: option.cxx:328
debug_gnuplot
bool debug_gnuplot(const PointCloud &cloud, const PointCloud &cloud_smooth, const char *fname)
Definition: output.cxx:75
graph.h
hc::compute_hc
cluster_group compute_hc(pcl::PointCloud< pcl::PointXYZI >::ConstPtr cloud, std::vector< triplet > const &triplets, ScaleTripletMetric triplet_metric, float t, int opt_verbose)
Definition: hc.cxx:139
load_csv_file
void load_csv_file(const char *fname, PointCloud &cloud, const char delimiter, size_t skip)
Definition: pointcloud.cxx:183
smoothen_cloud
void smoothen_cloud(const PointCloud &cloud, PointCloud &result_cloud, double r)
Definition: pointcloud.cxx:254
cleanup_cluster_group
void cleanup_cluster_group(cluster_group &cl_group, size_t m, int opt_verbose)
Definition: cluster.cxx:165
cluster_triplets_to_points
void cluster_triplets_to_points(const std::vector< triplet > &triplets, cluster_group &cl_group)
Definition: cluster.cxx:185
option.h
Opt::get_r
double get_r()
Definition: option.cxx:296
cloud_to_csv
bool cloud_to_csv(const PointCloud &cloud, const char *fname)
Definition: output.cxx:141
Opt::get_linkage
Linkage get_linkage()
Definition: option.cxx:332
clusters_to_gnuplot
void clusters_to_gnuplot(const PointCloud &cloud, const std::vector< cluster_t > &clusters)
Definition: output.cxx:165
add_clusters
void add_clusters(PointCloud &cloud, cluster_group &cl_group, bool gnuplot)
Definition: cluster.cxx:212
main
int main(int argc, char **argv)
Definition: main.cxx:56
Opt::get_a
double get_a()
Definition: option.cxx:308
Opt
Definition: option.h:18
cluster_group
std::vector< cluster_t > cluster_group
Definition: cluster.h:25
cluster.h
output.h
Opt::get_s
double get_s()
Definition: option.cxx:312