19#include <fmt/format.h>
26#include <taskflow/taskflow/taskflow.hpp>
27#include <taskflow/taskflow/algorithm/for_each.hpp>
31bool isInList(
const std::vector<size_t> *list,
size_t i) {
39void stats(
const std::vector<double> &x,
double &mean,
double &std) {
47 s += (y - mu) * (y - mu);
54void lattice(
double L,
size_t Nx,
size_t Ny,
size_t Nz,
double dL,
int seed,
55 std::vector<util::Point> &x,
int dim = 3) {
63 x.resize(Nx * Ny * Nz);
65 std::cerr <<
"Dimension = " << dim <<
" not supprted.\n";
70 for (
size_t i = 0; i < Nx; i++) {
71 for (
size_t j = 0; j < Ny; j++) {
74 y.d_x = i * L + dist(gen);
75 y.d_y = j * L + dist(gen);
80 }
else if (dim == 3) {
81 for (
size_t k = 0; k < Nz; k++) {
83 y.d_x = i * L + dist(gen);
84 y.d_y = j * L + dist(gen);
85 y.d_z = k * L + dist(gen);
98 std::vector<size_t> &xTags) {
102 for (
size_t i=0; i<x.size(); i++)
103 xTags[i] = dist(gen);
106template <
class NSearch>
108 const std::unique_ptr<NSearch> &
nsearch,
110 std::vector<std::vector<size_t>> &neigh,
111 std::vector<std::vector<float>> &neigh_sq_dist) {
112 neigh.resize(x.size());
113 neigh_sq_dist.resize(x.size());
114 auto t1 = steady_clock::now();
117 tf::Taskflow taskflow;
119 taskflow.for_each_index((std::size_t) 0, x.size(), (std::size_t) 1, [&x, &neigh, &neigh_sq_dist, &
nsearch, r](std::size_t i) {
120 std::vector<int> neighs;
121 std::vector<float> sqr_dist;
123 if (nsearch->radiusSearch(x[i], r, neighs, sqr_dist) >
125 for (std::size_t j = 0; j < neighs.size(); ++j)
126 if (size_t(neighs[j]) != i) {
127 neigh[i].push_back(size_t(neighs[j]));
128 neigh_sq_dist[i].push_back(sqr_dist[j]);
134 executor.run(taskflow).get();
136 auto t2 = steady_clock::now();
140template <
class NSearch>
142 const std::unique_ptr<NSearch> &
nsearch,
144 std::vector<std::vector<size_t>> &neigh,
145 std::vector<std::vector<float>> &neigh_sq_dist) {
146 neigh.resize(x.size());
147 neigh_sq_dist.resize(x.size());
148 auto t1 = steady_clock::now();
151 tf::Taskflow taskflow;
153 taskflow.for_each_index((std::size_t) 0, x.size(), (std::size_t) 1, [&x, &neigh, &neigh_sq_dist, &
nsearch, r](std::size_t i) {
154 std::vector<size_t> neighs;
155 std::vector<double> sqr_dist;
157 if (nsearch->radiusSearch(x[i], r, neighs, sqr_dist) >
159 for (std::size_t j = 0; j < neighs.size(); ++j)
160 if (size_t(neighs[j]) != i) {
161 neigh[i].push_back(size_t(neighs[j]));
162 neigh_sq_dist[i].push_back(sqr_dist[j]);
168 executor.run(taskflow).get();
170 auto t2 = steady_clock::now();
174template <
class NSearch>
176 const std::vector<size_t> &xTags,
177 const std::unique_ptr<NSearch> &
nsearch,
179 std::vector<std::vector<size_t>> &neigh,
180 std::vector<std::vector<float>> &neigh_sq_dist,
181 int selection_criteria) {
186 neigh.resize(x.size());
187 neigh_sq_dist.resize(x.size());
188 auto t1 = steady_clock::now();
191 tf::Taskflow taskflow;
193 taskflow.for_each_index((std::size_t) 0,
202 selection_criteria](std::size_t i) {
204 std::vector<size_t> neighs;
205 std::vector<double> sqr_dist;
208 if (selection_criteria == 1)
209 n = nsearch->radiusSearchExcludeTag(x[i], r,
214 else if (selection_criteria == 2)
215 n = nsearch->radiusSearchIncludeTag(x[i], r,
221 for (std::size_t j = 0; j < neighs.size(); ++j)
222 if (size_t(neighs[j]) != i) {
223 neigh[i].push_back(size_t(neighs[j]));
224 neigh_sq_dist[i].push_back(sqr_dist[j]);
230 executor.run(taskflow).get();
232 auto t2 = steady_clock::now();
237 std::vector<std::vector<size_t>> &neigh,
238 std::vector<std::vector<float>> &neigh_sq_dist) {
240 neigh.resize(x.size());
241 neigh_sq_dist.resize(x.size());
243 auto t1 = steady_clock::now();
246 tf::Taskflow taskflow;
248 taskflow.for_each_index((std::size_t) 0,
255 auto searchPoint = x[i];
257 for (size_t j = 0; j < x.size(); j++) {
258 auto dx = searchPoint - x[j];
259 auto l = dx.length();
260 if (util::isLess(l, r) and j != i) {
261 neigh[i].push_back(j);
262 neigh_sq_dist[i].push_back(l);
268 executor.run(taskflow).get();
270 auto t2 = steady_clock::now();
276 const std::vector<size_t> &xTags,
278 std::vector<std::vector<size_t>> &neigh,
279 std::vector<std::vector<float>> &neigh_sq_dist,
280 int selection_criteria) {
285 neigh.resize(x.size());
286 neigh_sq_dist.resize(x.size());
288 auto t1 = steady_clock::now();
291 tf::Taskflow taskflow;
293 taskflow.for_each_index((std::size_t) 0,
301 selection_criteria](std::size_t i) {
303 auto searchPoint = x[i];
304 auto searchPointTag = xTags[i];
306 for (size_t j = 0; j < x.size(); j++) {
307 auto dx = searchPoint - x[j];
308 auto l = dx.length();
309 if (util::isLess(l, r) and j != i) {
311 if (selection_criteria == 1) {
312 if (xTags[j] != searchPointTag) {
313 neigh[i].push_back(j);
314 neigh_sq_dist[i].push_back(l);
317 else if (selection_criteria == 2) {
318 if (xTags[j] == searchPointTag) {
319 neigh[i].push_back(j);
320 neigh_sq_dist[i].push_back(l);
328 executor.run(taskflow).get();
330 auto t2 = steady_clock::now();
335template <
class NSearch>
337 const std::unique_ptr<NSearch> &
nsearch,
341 std::vector<util::Point> &search_points,
342 std::vector<size_t> &err_points,
343 std::vector<double> &err_dist) {
345 search_points.resize(x.size());
346 err_points.resize(x.size());
347 err_dist.resize(x.size());
350 double dx_perturb = dL/100;
356 for (
size_t i=0; i<x.size(); i++) {
357 const auto &xi = x[i];
360 auto xi_perturb = xi;
361 for (
size_t k=0; k<3; k++)
362 xi_perturb[k] += dist(gen);
364 search_points[i] = xi_perturb;
367 auto t1 = steady_clock::now();
370 tf::Taskflow taskflow;
372 taskflow.for_each_index((std::size_t) 0, x.size(), (std::size_t) 1, [&x,
374 &err_points, &err_dist, &
nsearch](std::size_t i) {
376 const auto &xi = x[i];
379 const auto &xi_perturb = search_points[i];
382 size_t true_neigh = i;
383 double true_dist = (xi - xi_perturb).length();
386 double found_dist = 0.;
389 nsearch->closestPoint(xi_perturb, found_neigh, found_dist);
391 if (true_neigh != found_neigh) {
392 err_points[i] = found_neigh;
393 err_dist[i] = true_dist - found_dist;
402 executor.run(taskflow).get();
404 auto t2 = steady_clock::now();
409 const std::vector<std::vector<size_t>> &neigh2,
410 std::vector<std::string> tags,
411 int check_nodes_num = -1,
412 bool only_err_count =
false) {
413 size_t error_size = 0;
414 size_t error_nodes = 0;
415 size_t error_neighs = 0;
416 std::ostringstream composs;
417 for (
size_t i = 0; i < neigh1.size(); i++) {
419 if (check_nodes_num > 0 and i > check_nodes_num)
422 size_t err_neighs = 0;
423 auto &n1 = neigh1[i];
424 auto &n2 = neigh2[i];
426 bool header_done =
false;
427 if (n1.size() != n2.size()) {
428 composs <<
" Node = " << i <<
" \n";
429 composs << fmt::format(
" size ({}) {} != {} ({}) not matching\n",
430 tags[0], n1.size(), n2.size(), tags[1]);
438 composs <<
" Node = " << i <<
" \n";
440 composs << fmt::format(
" neigh = {} in {} search not found in {} "
441 "search neighs list\n",
442 j, tags[1], tags[0]);
448 error_neighs += err_neighs;
452 return fmt::format(
" error_size = {}, error_neighs = {}\n", error_size,
455 return fmt::format(
" error_size = {}, error_neighs = {}\n", error_size,
461 const std::vector<util::Point> &x,
462 const std::vector<util::Point> &search_points,
463 const std::vector<size_t> &err_points,
464 const std::vector<double> &err_dist,
465 bool only_err_count =
false) {
467 size_t error_size = 0;
468 std::ostringstream composs;
470 for (
size_t i = 0; i < err_points.size(); i++) {
472 if (err_points[i] != -1) {
473 composs << fmt::format(
" Node = {} at location = {}, "
474 "Search point = {}, closest point id = {} at"
475 " location = {}. True dist = {}, found "
477 i, x[i].printStr(), search_points[i]
478 .printStr(), err_points[i], x[err_points[i]]
479 .printStr(), (x[i] - search_points[i])
480 .length(), err_dist[i]);
486 return fmt::format(
" error_size = {}\n", error_size);
488 return fmt::format(
" error_size = {}\n", error_size) +
496 if (dim < 2 or dim > 3) {
497 return "testNanoflann: only dim = 2, 3 are accepted.\n";
503 size_t N_tot = Nx * Ny;
508 lattice(L, Nx, Ny, Nz, dL, seed, x, dim);
509 std::cout <<
"Total points = " << x.size() <<
"\n";
513 std::vector<std::vector<size_t>> neigh_nflann(N_tot, std::vector<size_t>());
514 std::vector<std::vector<float>> neigh_nflann_sq_dist(N_tot,
515 std::vector<float>());
517 std::vector<std::vector<size_t>> neigh_nflann_3d(N_tot, std::vector<size_t>());
518 std::vector<std::vector<float>> neigh_nflann_3d_sq_dist(N_tot,
519 std::vector<float>());
521 std::vector<std::vector<size_t>> neigh_brute(N_tot, std::vector<size_t>());
522 std::vector<std::vector<float>> neigh_brute_sq_dist(N_tot,
523 std::vector<float>());
526 double search_r = 1.5 * L;
527 auto brute_force_search_time =
531 std::unique_ptr<nsearch::NFlannSearchKd<3>> nflann_nsearch_3d
532 = std::make_unique<nsearch::NFlannSearchKd<3>>(x, 0);
534 std::unique_ptr<nsearch::NFlannSearchKd<dim>> nflann_nsearch
535 = std::make_unique<nsearch::NFlannSearchKd<dim>>(x, 0);
537 auto nflann_tree_set_time_3d = nflann_nsearch_3d->setInputCloud();
538 auto nflann_tree_search_time_3d =
541 auto nflann_tree_set_time = nflann_nsearch->setInputCloud();
542 auto nflann_tree_search_time =
547 neigh_nflann, neigh_brute, {
"nflann_tree",
"brute_force"}, -1,
true);
550 neigh_nflann_3d, neigh_brute, {
"nflann_tree-3d",
"brute_force"}, -1,
true);
552 std::ostringstream msg;
553 msg << fmt::format(
" Setup times (microseconds): \n"
554 " nflann_tree_set_time = {} \n "
555 " nflann_tree_set_time_3d = {}\n",
556 nflann_tree_set_time, nflann_tree_set_time_3d);
558 msg << fmt::format(
" Search times (microseconds): \n"
559 " brute_force_search_time = {}\n"
560 " nflann_tree_search_time = {}\n"
561 " nflann_tree_search_time_3d = {}\n",
562 brute_force_search_time,
563 nflann_tree_search_time,
564 nflann_tree_search_time_3d);
566 msg << fmt::format(
" Comparison results: \n"
567 " nflann_brute_compare: \n{}\n",
568 nflann_brute_compare);
570 msg << fmt::format(
" Comparison results: \n"
571 " nflann_brute_compare_3d: \n{}\n",
572 nflann_brute_compare_3d);
577 std::vector<std::vector<size_t>> neigh_nflann(N_tot, std::vector<size_t>());
578 std::vector<std::vector<float>> neigh_nflann_sq_dist(N_tot,
579 std::vector<float>());
581 std::vector<std::vector<size_t>> neigh_brute(N_tot, std::vector<size_t>());
582 std::vector<std::vector<float>> neigh_brute_sq_dist(N_tot,
583 std::vector<float>());
586 double search_r = 1.5 * L;
587 auto brute_force_search_time =
591 std::unique_ptr<nsearch::NFlannSearchKd<dim>> nflann_nsearch
592 = std::make_unique<nsearch::NFlannSearchKd<dim>>(x, 0);
594 auto nflann_tree_set_time = nflann_nsearch->setInputCloud();
595 auto nflann_tree_search_time =
600 neigh_nflann, neigh_brute, {
"nflann_tree",
"brute_force"}, -1,
true);
602 std::ostringstream msg;
603 msg << fmt::format(
" Setup times (microseconds): \n"
604 " nflann_tree_set_time = {}\n",
605 nflann_tree_set_time);
607 msg << fmt::format(
" Search times (microseconds): \n"
608 " brute_force_search_time = {}\n"
609 " nflann_tree_search_time = {}\n",
610 brute_force_search_time,
611 nflann_tree_search_time);
613 msg << fmt::format(
" Comparison results: \n"
614 " nflann_brute_compare: \n{}\n",
615 nflann_brute_compare);
628 if (dim < 2 or dim > 3) {
629 return "testNanoflannExcludeInclude: only dim = 2, 3 are accepted.\n";
635 size_t N_tot = Nx * Ny;
640 std::vector<size_t> xTags(N_tot, 0);
641 lattice(L, Nx, Ny, Nz, dL, seed, x, dim);
644 std::cout <<
"Total points = " << x.size() <<
"\n";
646 std::vector<std::vector<size_t>> neigh_default_nflann(N_tot, std::vector<size_t>());
647 std::vector<std::vector<float>> neigh_default_nflann_sq_dist(N_tot,
648 std::vector<float>());
650 std::vector<std::vector<size_t>> neigh_exclude_nflann(N_tot, std::vector<size_t>());
651 std::vector<std::vector<float>> neigh_exclude_nflann_sq_dist(N_tot,
652 std::vector<float>());
654 std::vector<std::vector<size_t>> neigh_include_nflann(N_tot, std::vector<size_t>());
655 std::vector<std::vector<float>> neigh_include_nflann_sq_dist(N_tot,
656 std::vector<float>());
659 std::vector<std::vector<size_t>> neigh_default_brute(N_tot, std::vector<size_t>());
660 std::vector<std::vector<float>> neigh_default_brute_sq_dist(N_tot,
661 std::vector<float>());
663 std::vector<std::vector<size_t>> neigh_exclude_brute(N_tot, std::vector<size_t>());
664 std::vector<std::vector<float>> neigh_exclude_brute_sq_dist(N_tot,
665 std::vector<float>());
667 std::vector<std::vector<size_t>> neigh_include_brute(N_tot, std::vector<size_t>());
668 std::vector<std::vector<float>> neigh_include_brute_sq_dist(N_tot,
669 std::vector<float>());
672 double search_r = 3. * L;
678 neigh_default_brute_sq_dist);
683 neigh_exclude_brute_sq_dist,
689 neigh_include_brute_sq_dist,
693 std::unique_ptr<nsearch::NFlannSearchKd<dim>> nflann_nsearch
694 = std::make_unique<nsearch::NFlannSearchKd<dim>>(x, 0,
702 search_r, neigh_default_nflann,
703 neigh_default_nflann_sq_dist);
708 search_r, neigh_exclude_nflann,
709 neigh_exclude_nflann_sq_dist,
715 search_r, neigh_include_nflann,
716 neigh_include_nflann_sq_dist,
721 neigh_default_nflann, neigh_default_brute,
722 {
"nflann_tree_default",
"brute_force_default"}, -1,
true);
725 neigh_exclude_nflann, neigh_exclude_brute,
726 {
"nflann_tree_exclude",
"brute_force_exclude"}, -1,
true);
729 neigh_include_nflann, neigh_include_brute,
730 {
"nflann_tree_include",
"brute_force_include"}, -1,
true);
732 std::ostringstream msg;
733 msg << fmt::format(
" Setup times (microseconds): \n"
734 " nflann_tree_set_time = {}\n",
737 msg << fmt::format(
" Default search times (microseconds): \n"
738 " brute_force_search_time = {}\n"
739 " nflann_tree_search_time = {}\n",
743 msg << fmt::format(
" Exclude comparison results: \n"
744 " nflann_brute_compare: \n{}\n",
745 nflann_brute_compare_default);
747 msg << fmt::format(
" Exclude search times (microseconds): \n"
748 " brute_force_search_time = {}\n"
749 " nflann_tree_search_time = {}\n",
753 msg << fmt::format(
" Exclude comparison results: \n"
754 " nflann_brute_compare: \n{}\n",
755 nflann_brute_compare_exclude);
757 msg << fmt::format(
" Include search times (microseconds): \n"
758 " brute_force_search_time = {}\n"
759 " nflann_tree_search_time = {}\n",
763 msg << fmt::format(
" Include comparison results: \n"
764 " nflann_brute_compare: \n{}\n",
765 nflann_brute_compare_include);
768 msg << fmt::format(
" Nflann all search times (microseconds): \n"
786 size_t N_tot = Nx * Ny * Nz;
789 lattice(L, Nx, Ny, Nz, dL, seed, x, 3);
790 std::cout <<
"Total points = " << x.size() <<
"\n";
794 = std::make_unique<nsearch::NFlannSearchKd<3>>(x, 0);
796 auto nflann_tree_set_time = nflann_nsearch->setInputCloud();
798 std::vector<size_t> err_points;
799 std::vector<util::Point> search_points;
800 std::vector<double> err_dist;
802 x, nflann_nsearch, seed, L, dL, search_points, err_points, err_dist);
810 std::ostringstream msg;
811 msg << fmt::format(
" Setup times (microseconds): \n"
812 " nflann_tree_set_time = {}\n",
813 nflann_tree_set_time);
815 msg << fmt::format(
" Comparison results: \n"
816 " nflann_compare: \n{}\n",
826template std::string test::testNanoflann<2>(
size_t N,
double L,
double dL,
int seed);
827template std::string test::testNanoflann<3>(
size_t N,
double L,
double dL,
int seed);
829template std::string test::testNanoflannExcludeInclude<2>(
size_t N,
double L,
830 double dL,
int seed, testNSearchData &data);
831template std::string test::testNanoflannExcludeInclude<3>(
size_t N,
double L,
832 double dL,
int seed, testNSearchData &data);
double neighSearchTreeClosestPointSizet(const std::vector< util::Point > &x, const std::unique_ptr< NSearch > &nsearch, const int &seed, const double &L, const double &dL, std::vector< util::Point > &search_points, std::vector< size_t > &err_points, std::vector< double > &err_dist)
double neighSearchTreeSizet(const std::vector< util::Point > &x, const std::unique_ptr< NSearch > &nsearch, const double &r, std::vector< std::vector< size_t > > &neigh, std::vector< std::vector< float > > &neigh_sq_dist)
double neighSearchTree(const std::vector< util::Point > &x, const std::unique_ptr< NSearch > &nsearch, const double &r, std::vector< std::vector< size_t > > &neigh, std::vector< std::vector< float > > &neigh_sq_dist)
std::string compare_closest_point_results(const std::vector< util::Point > &x, const std::vector< util::Point > &search_points, const std::vector< size_t > &err_points, const std::vector< double > &err_dist, bool only_err_count=false)
void assignRandomTags(std::vector< util::Point > &x, int numTags, int seed, std::vector< size_t > &xTags)
void lattice(double L, size_t Nx, size_t Ny, size_t Nz, double dL, int seed, std::vector< util::Point > &x, int dim=3)
void stats(const std::vector< double > &x, double &mean, double &std)
bool isInList(const std::vector< size_t > *list, size_t i)
double neighSearchBruteExcludeInclude(const std::vector< util::Point > &x, const std::vector< size_t > &xTags, const double &r, std::vector< std::vector< size_t > > &neigh, std::vector< std::vector< float > > &neigh_sq_dist, int selection_criteria)
std::string compare_results(const std::vector< std::vector< size_t > > &neigh1, const std::vector< std::vector< size_t > > &neigh2, std::vector< std::string > tags, int check_nodes_num=-1, bool only_err_count=false)
double neighSearchBrute(const std::vector< util::Point > &x, const double &r, std::vector< std::vector< size_t > > &neigh, std::vector< std::vector< float > > &neigh_sq_dist)
double neighSearchTreeSizetExcludeInclude(const std::vector< util::Point > &x, const std::vector< size_t > &xTags, const std::unique_ptr< NSearch > &nsearch, const double &r, std::vector< std::vector< size_t > > &neigh, std::vector< std::vector< float > > &neigh_sq_dist, int selection_criteria)
Methods for performing efficient search of neighboring points.
std::string testNanoflannExcludeInclude(size_t N, double L, double dL, int seed, testNSearchData &data)
Perform test on nsearch.
std::string testNanoflannClosestPoint(size_t N, double L, double dL, int seed)
Perform test on nsearch.
std::string testNanoflann(size_t N, double L, double dL, int seed)
Perform test on nsearch.
float timeDiff(std::chrono::steady_clock::time_point begin, std::chrono::steady_clock::time_point end, std::string unit="microseconds")
Returns difference between two times.
unsigned int getNThreads()
Get number of threads to be used by taskflow.
RandGenerator get_rd_gen(int seed=-1)
Return random number generator.
std::uniform_real_distribution UniformDistribution
std::mt19937 RandGenerator
std::uniform_int_distribution UniformIntDistribution
double d_defaultBruteSearchTime
double d_includeNFlannSearchTime
double d_excludeNFlannSearchTime
double d_includeBruteSearchTime
double d_defaultNFlannSearchTime
double d_excludeBruteSearchTime
A structure to represent 3d vectors.