Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ClusterizationTests2D.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ClusterizationTests2D.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2022 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <boost/test/data/test_case.hpp>
10 #include <boost/test/unit_test.hpp>
11 
13 
14 #include <algorithm>
15 #include <array>
16 #include <cstdlib>
17 #include <iostream>
18 #include <iterator>
19 #include <memory>
20 #include <random>
21 #include <stdexcept>
22 #include <utility>
23 #include <vector>
24 
25 #include <boost/functional/hash.hpp>
26 
27 namespace Acts {
28 namespace Test {
29 
30 using Rectangle = std::array<int, 4>;
31 
32 std::vector<Rectangle> concat(std::vector<std::vector<Rectangle>> vecs) {
33  std::vector<Rectangle> flat;
34  for (std::vector<Rectangle>& v : vecs) {
35  if (flat.empty()) {
36  flat = std::move(v);
37  } else {
38  flat.reserve(flat.size() + v.size());
39  std::move(v.begin(), v.end(), std::back_inserter(flat));
40  v.clear();
41  }
42  }
43  return flat;
44 }
45 
46 template <typename RNG>
47 std::vector<Rectangle> segment(int x0, int y0, int x1, int y1, RNG& rng) {
48  // Leave enough space for one-cell buffer around clusters
49  int xmin = x0 + 3;
50  int xmax = x1 - 3;
51  int ymin = y0 + 3;
52  int ymax = y1 - 3;
53 
54  // terminal case 1
55  if (xmax < xmin or ymax < ymin) {
56  return {{x0, y0, x1, y1}};
57  }
58 
59  std::bernoulli_distribution cointoss;
60  bool splitx = cointoss(rng);
61  bool splity = cointoss(rng);
62 
63  // terminal case 2
64  if (not(splitx or splity)) {
65  return {{x0, y0, x1, y1}};
66  }
67 
68  int x_ = std::uniform_int_distribution(xmin, xmax)(rng);
69  int y_ = std::uniform_int_distribution(ymin, ymax)(rng);
70 
71  if (splitx and not splity) {
72  return concat({segment(x0, y0, x_, y1, rng), segment(x_, y0, x1, y1, rng)});
73  } else if (not splitx and splity) {
74  return concat({segment(x0, y0, x1, y_, rng), segment(x0, y_, x1, y1, rng)});
75  } else if (splitx and splity) {
76  return concat({segment(x0, y0, x_, y_, rng), segment(x_, y0, x1, y_, rng),
77  segment(x0, y_, x_, y1, rng), segment(x_, y_, x1, y1, rng)});
78  }
79  throw std::runtime_error("unreachable");
80 }
81 
82 struct Cell2D {
83  Cell2D(int rowv, int colv) : row(rowv), col(colv) {}
84  int row, col;
86 };
87 
88 int getCellRow(const Cell2D& cell) {
89  return cell.row;
90 }
91 
92 int getCellColumn(const Cell2D& cell) {
93  return cell.col;
94 }
95 
97  return cell.label;
98 }
99 
100 bool operator==(const Cell2D& left, const Cell2D& right) {
101  return left.row == right.row and left.col == right.col;
102 }
103 
104 bool cellComp(const Cell2D& left, const Cell2D& right) {
105  return (left.row == right.row) ? left.col < right.col : left.row < right.row;
106 }
107 
108 struct Cluster2D {
109  std::vector<Cell2D> cells;
110  size_t hash{0};
111 };
112 
113 void clusterAddCell(Cluster2D& cl, const Cell2D& cell) {
114  cl.cells.push_back(cell);
115 }
116 
117 void hash(Cluster2D& cl) {
118  std::sort(cl.cells.begin(), cl.cells.end(), cellComp);
119  cl.hash = 0;
120  for (const Cell2D& c : cl.cells) {
121  boost::hash_combine(cl.hash, c.col);
122  }
123 }
124 
125 bool clHashComp(const Cluster2D& left, const Cluster2D& right) {
126  return left.hash < right.hash;
127 }
128 
129 template <typename RNG>
130 void genclusterw(int x, int y, int x0, int y0, int x1, int y1,
131  std::vector<Cell2D>& cells, RNG& rng, double startp = 0.5,
132  double decayp = 0.9) {
133  std::vector<Cell2D> add;
134 
135  auto maybe_add = [&](int x_, int y_) {
136  Cell2D c(x_, y_);
137  if (std::uniform_real_distribution<double>()(rng) < startp and
138  std::find(cells.begin(), cells.end(), c) == cells.end()) {
139  cells.push_back(c);
140  add.push_back(c);
141  }
142  };
143 
144  // NORTH
145  if (y < y1) {
146  maybe_add(x, y + 1);
147  }
148  // NORTHEAST
149  if (x < x1 and y < y1) {
150  maybe_add(x + 1, y + 1);
151  }
152  // EAST
153  if (x < x1) {
154  maybe_add(x + 1, y);
155  }
156  // SOUTHEAST
157  if (x < x1 and y > y0) {
158  maybe_add(x + 1, y - 1);
159  }
160  // SOUTH
161  if (y > y0) {
162  maybe_add(x, y - 1);
163  }
164  // SOUTHWEST
165  if (x > x0 and y > y0) {
166  maybe_add(x - 1, y - 1);
167  }
168  // WEST
169  if (x > x0) {
170  maybe_add(x - 1, y);
171  }
172  // NORTHWEST
173  if (x > x0 and y < y1) {
174  maybe_add(x - 1, y + 1);
175  }
176 
177  for (Cell2D& c : add) {
178  genclusterw(c.row, c.col, x0, y0, x1, y1, cells, rng, startp * decayp,
179  decayp);
180  }
181 }
182 
183 template <typename RNG>
184 Cluster2D gencluster(int x0, int y0, int x1, int y1, RNG& rng,
185  double startp = 0.5, double decayp = 0.9) {
186  int x0_ = x0 + 1;
187  int x1_ = x1 - 1;
188  int y0_ = y0 + 1;
189  int y1_ = y1 - 1;
190 
191  int x = std::uniform_int_distribution(x0_, x1_)(rng);
192  int y = std::uniform_int_distribution(y0_, y1_)(rng);
193 
194  std::vector<Cell2D> cells = {Cell2D(x, y)};
195  genclusterw(x, y, x0_, y0_, x1_, y1_, cells, rng, startp, decayp);
196 
197  Cluster2D cl;
198  cl.cells = std::move(cells);
199 
200  return cl;
201 }
202 
203 BOOST_AUTO_TEST_CASE(Grid_2D_rand) {
204  using Cell = Cell2D;
205  using CellC = std::vector<Cell>;
206  using Cluster = Cluster2D;
207  using ClusterC = std::vector<Cluster>;
208 
209  size_t sizeX = 1000;
210  size_t sizeY = 1000;
211  size_t startSeed = 71902647;
212  size_t ntries = 100;
213 
214  std::cout << "Grid_2D_rand test with parameters: " << std::endl;
215  std::cout << " sizeX = " << sizeX << std::endl;
216  std::cout << " sizeY = " << sizeY << std::endl;
217  std::cout << " startSeed = " << startSeed << std::endl;
218  std::cout << " ntries = " << ntries << std::endl;
219 
220  while (ntries-- > 0) {
221  std::mt19937_64 rnd(startSeed++);
222 
223  std::vector<Cluster> cls;
224  std::vector<Cell> cells;
225  for (Rectangle& rect : segment(0, 0, sizeX, sizeY, rnd)) {
226  auto& [x0, y0, x1, y1] = rect;
227  Cluster cl = gencluster(x0, y0, x1, y1, rnd);
228  hash(cl);
229  cells.insert(cells.end(), cl.cells.begin(), cl.cells.end());
230  cls.push_back(cl);
231  }
232 
233  std::shuffle(cells.begin(), cells.end(), rnd);
234 
235  ClusterC newCls = Ccl::createClusters<CellC, ClusterC>(cells);
236 
237  for (Cluster& cl : newCls) {
238  hash(cl);
239  }
240 
241  std::sort(cls.begin(), cls.end(), clHashComp);
242  std::sort(newCls.begin(), newCls.end(), clHashComp);
243 
244  BOOST_CHECK_EQUAL(cls.size(), newCls.size());
245  for (size_t i = 0; i < cls.size(); i++) {
246  BOOST_CHECK_EQUAL(cls.at(i).hash, newCls.at(i).hash);
247  }
248  }
249 }
250 
251 } // namespace Test
252 } // namespace Acts