Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-07 07:48:41

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Clusterization/Clusterization.hpp"
0012 #include "Acts/Utilities/HashCombine.hpp"
0013 #include "Acts/Utilities/Helpers.hpp"
0014 
0015 #include <algorithm>
0016 #include <array>
0017 #include <cstdlib>
0018 #include <iostream>
0019 #include <iterator>
0020 #include <memory>
0021 #include <random>
0022 #include <stdexcept>
0023 #include <utility>
0024 #include <vector>
0025 
0026 using namespace Acts;
0027 
0028 using Rectangle = std::array<int, 4>;
0029 
0030 std::vector<Rectangle> concat(std::vector<std::vector<Rectangle>> vecs) {
0031   std::vector<Rectangle> flat;
0032   for (std::vector<Rectangle>& v : vecs) {
0033     if (flat.empty()) {
0034       flat = std::move(v);
0035     } else {
0036       flat.reserve(flat.size() + v.size());
0037       std::move(v.begin(), v.end(), std::back_inserter(flat));
0038       v.clear();
0039     }
0040   }
0041   return flat;
0042 }
0043 
0044 template <typename RNG>
0045 std::vector<Rectangle> segment(int x0, int y0, int x1, int y1, RNG& rng) {
0046   // Leave enough space for one-cell buffer around clusters
0047   int xmin = x0 + 3;
0048   int xmax = x1 - 3;
0049   int ymin = y0 + 3;
0050   int ymax = y1 - 3;
0051 
0052   // terminal case 1
0053   if (xmax < xmin || ymax < ymin) {
0054     return {{x0, y0, x1, y1}};
0055   }
0056 
0057   std::bernoulli_distribution cointoss;
0058   bool splitx = cointoss(rng);
0059   bool splity = cointoss(rng);
0060 
0061   // terminal case 2
0062   if (!(splitx || splity)) {
0063     return {{x0, y0, x1, y1}};
0064   }
0065 
0066   int x_ = std::uniform_int_distribution<std::int32_t>(xmin, xmax)(rng);
0067   int y_ = std::uniform_int_distribution<std::int32_t>(ymin, ymax)(rng);
0068 
0069   if (splitx && !splity) {
0070     return concat({segment(x0, y0, x_, y1, rng), segment(x_, y0, x1, y1, rng)});
0071   } else if (!splitx && splity) {
0072     return concat({segment(x0, y0, x1, y_, rng), segment(x0, y_, x1, y1, rng)});
0073   } else if (splitx && splity) {
0074     return concat({segment(x0, y0, x_, y_, rng), segment(x_, y0, x1, y_, rng),
0075                    segment(x0, y_, x_, y1, rng), segment(x_, y_, x1, y1, rng)});
0076   }
0077   throw std::runtime_error("unreachable");
0078 }
0079 
0080 struct Cell2D {
0081   Cell2D(int rowv, int colv) : row(rowv), col(colv) {}
0082   int row, col;
0083   Ccl::Label label{Ccl::NO_LABEL};
0084 };
0085 
0086 int getCellRow(const Cell2D& cell) {
0087   return cell.row;
0088 }
0089 
0090 int getCellColumn(const Cell2D& cell) {
0091   return cell.col;
0092 }
0093 
0094 bool operator==(const Cell2D& left, const Cell2D& right) {
0095   return left.row == right.row && left.col == right.col;
0096 }
0097 
0098 bool cellComp(const Cell2D& left, const Cell2D& right) {
0099   return (left.row == right.row) ? left.col < right.col : left.row < right.row;
0100 }
0101 
0102 struct Cluster2D {
0103   std::vector<Cell2D> cells;
0104   std::size_t hash{0};
0105 };
0106 
0107 void clusterAddCell(Cluster2D& cl, const Cell2D& cell) {
0108   cl.cells.push_back(cell);
0109 }
0110 
0111 void hash(Cluster2D& cl) {
0112   std::ranges::sort(cl.cells, cellComp);
0113   cl.hash = 0;
0114   for (const Cell2D& c : cl.cells) {
0115     cl.hash = Acts::hashMixAndCombine(cl.hash, c.col);
0116   }
0117 }
0118 
0119 bool clHashComp(const Cluster2D& left, const Cluster2D& right) {
0120   return left.hash < right.hash;
0121 }
0122 
0123 template <typename RNG>
0124 void genclusterw(int x, int y, int x0, int y0, int x1, int y1,
0125                  std::vector<Cell2D>& cells, RNG& rng, double startp = 0.5,
0126                  double decayp = 0.9) {
0127   std::vector<Cell2D> add;
0128 
0129   auto maybe_add = [&](int x_, int y_) {
0130     Cell2D c(x_, y_);
0131     if (std::uniform_real_distribution<double>()(rng) < startp &&
0132         !rangeContainsValue(cells, c)) {
0133       cells.push_back(c);
0134       add.push_back(c);
0135     }
0136   };
0137 
0138   // NORTH
0139   if (y < y1) {
0140     maybe_add(x, y + 1);
0141   }
0142   // NORTHEAST
0143   if (x < x1 && y < y1) {
0144     maybe_add(x + 1, y + 1);
0145   }
0146   // EAST
0147   if (x < x1) {
0148     maybe_add(x + 1, y);
0149   }
0150   // SOUTHEAST
0151   if (x < x1 && y > y0) {
0152     maybe_add(x + 1, y - 1);
0153   }
0154   // SOUTH
0155   if (y > y0) {
0156     maybe_add(x, y - 1);
0157   }
0158   // SOUTHWEST
0159   if (x > x0 && y > y0) {
0160     maybe_add(x - 1, y - 1);
0161   }
0162   // WEST
0163   if (x > x0) {
0164     maybe_add(x - 1, y);
0165   }
0166   // NORTHWEST
0167   if (x > x0 && y < y1) {
0168     maybe_add(x - 1, y + 1);
0169   }
0170 
0171   for (Cell2D& c : add) {
0172     genclusterw(c.row, c.col, x0, y0, x1, y1, cells, rng, startp * decayp,
0173                 decayp);
0174   }
0175 }
0176 
0177 template <typename RNG>
0178 Cluster2D gencluster(int x0, int y0, int x1, int y1, RNG& rng,
0179                      double startp = 0.5, double decayp = 0.9) {
0180   int x0_ = x0 + 1;
0181   int x1_ = x1 - 1;
0182   int y0_ = y0 + 1;
0183   int y1_ = y1 - 1;
0184 
0185   int x = std::uniform_int_distribution<std::int32_t>(x0_, x1_)(rng);
0186   int y = std::uniform_int_distribution<std::int32_t>(y0_, y1_)(rng);
0187 
0188   std::vector<Cell2D> cells = {Cell2D(x, y)};
0189   genclusterw(x, y, x0_, y0_, x1_, y1_, cells, rng, startp, decayp);
0190 
0191   Cluster2D cl;
0192   cl.cells = std::move(cells);
0193 
0194   return cl;
0195 }
0196 
0197 namespace ActsTests {
0198 
0199 BOOST_AUTO_TEST_SUITE(ClusterizationSuite)
0200 
0201 BOOST_AUTO_TEST_CASE(Grid_2D_rand) {
0202   using Cell = Cell2D;
0203   using CellC = std::vector<Cell>;
0204   using Cluster = Cluster2D;
0205   using ClusterC = std::vector<Cluster>;
0206 
0207   std::size_t sizeX = 1000;
0208   std::size_t sizeY = 1000;
0209   std::size_t startSeed = 71902647;
0210   std::size_t ntries = 100;
0211 
0212   std::cout << "Grid_2D_rand test with parameters: " << std::endl;
0213   std::cout << " sizeX = " << sizeX << std::endl;
0214   std::cout << " sizeY = " << sizeY << std::endl;
0215   std::cout << " startSeed = " << startSeed << std::endl;
0216   std::cout << " ntries = " << ntries << std::endl;
0217 
0218   while (ntries-- > 0) {
0219     std::mt19937_64 rnd(startSeed++);
0220 
0221     std::vector<Cluster> cls;
0222     std::vector<Cell> cells;
0223     for (Rectangle& rect : segment(0, 0, sizeX, sizeY, rnd)) {
0224       auto& [x0, y0, x1, y1] = rect;
0225       Cluster cl = gencluster(x0, y0, x1, y1, rnd);
0226       hash(cl);
0227       cells.insert(cells.end(), cl.cells.begin(), cl.cells.end());
0228       cls.push_back(cl);
0229     }
0230 
0231     std::shuffle(cells.begin(), cells.end(), rnd);
0232 
0233     Ccl::ClusteringData data;
0234     ClusterC newCls;
0235     Ccl::createClusters<CellC, ClusterC>(data, cells, newCls);
0236 
0237     for (Cluster& cl : newCls) {
0238       hash(cl);
0239     }
0240 
0241     std::ranges::sort(cls, clHashComp);
0242     std::ranges::sort(newCls, clHashComp);
0243 
0244     BOOST_CHECK_EQUAL(cls.size(), newCls.size());
0245     for (std::size_t i = 0; i < cls.size(); i++) {
0246       BOOST_CHECK_EQUAL(cls.at(i).hash, newCls.at(i).hash);
0247     }
0248   }
0249 }
0250 
0251 BOOST_AUTO_TEST_CASE(Grid_2D_duplicate_cells) {
0252   using Cell = Cell2D;
0253   using CellC = std::vector<Cell>;
0254   using Cluster = Cluster2D;
0255   using ClusterC = std::vector<Cluster>;
0256 
0257   CellC cells = {Cell(10, 20), Cell(10, 20)};
0258   ClusterC clusters;
0259 
0260   Ccl::ClusteringData data;
0261 
0262   BOOST_CHECK_THROW(
0263       (Ccl::createClusters<CellC, ClusterC>(data, cells, clusters)),
0264       std::invalid_argument);
0265 }
0266 
0267 BOOST_AUTO_TEST_SUITE_END()
0268 
0269 }  // namespace ActsTests