Skip to content

Commit 1964e24

Browse files
DJDuquenjacazio
authored andcommitted
fix: Handle cell duplication with an error (acts-project#4745)
This makes clusterization (both 1D and 2D) throw an exception when duplicate cells are given as input. Additionally, the `Connect2d::operator()` is a bit smarter in returning `ConnectResult::eNoConnStop` as quickly as possible (it previously waited unnecessarily until going past a full column). This could provide some performance improvement in cases where your cells are heavily "column-like". Fixes acts-project#4736
1 parent b69bf0b commit 1964e24

4 files changed

Lines changed: 77 additions & 20 deletions

File tree

Core/include/Acts/Clusterization/Clusterization.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ concept CanReserve = requires(Cluster cluster, std::size_t n) {
109109
enum class ConnectResult {
110110
eNoConn, // No connections, keep looking
111111
eNoConnStop, // No connections, stop looking
112-
eConn // Found connection
112+
eConn, // Found connection
113+
eDuplicate // Found duplicate cell, throw an exception
113114
};
114115

115116
// Default connection type for 2-D grids: 4- or 8-cell connectivity
@@ -160,6 +161,7 @@ struct DefaultConnect<Cell, 2> : public Connect2D<Cell> {
160161
/// @param [in] data collection of quantities for clusterization
161162
/// @param [in] cells the cell collection to be labeled
162163
/// @param [in] connect the connection type (see DefaultConnect)
164+
/// @throws std::invalid_argument if the input contains duplicate cells.
163165
template <typename CellCollection, std::size_t GridDim = 2,
164166
typename Connect =
165167
DefaultConnect<typename CellCollection::value_type, GridDim>>
@@ -191,6 +193,8 @@ ClusterCollection createClusters(CellCollection& cells,
191193
/// @brief createClusters
192194
/// Alternative convenience function which runs both labelClusters and
193195
/// createClusters.
196+
///
197+
/// @throws std::invalid_argument if the input contains duplicate cells.
194198
template <typename CellCollection, typename ClusterCollection,
195199
std::size_t GridDim = 2,
196200
typename Connect =

Core/include/Acts/Clusterization/Clusterization.ipp

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ Connections<GridDim> getConnections(std::size_t idx, std::vector<Cell>& cells,
8989
std::size_t idx2 = idx - i - 1;
9090
ConnectResult cr = connect(cells[idx], cells[idx2]);
9191

92+
if (cr == ConnectResult::eDuplicate) {
93+
throw std::invalid_argument(
94+
"Clusterization: input contains duplicate cells");
95+
}
9296
if (cr == ConnectResult::eNoConnStop) {
9397
break;
9498
}
@@ -153,31 +157,47 @@ template <typename Cell>
153157
Acts::Ccl::HasRetrievableRowInfo<Cell>)
154158
ConnectResult Connect2D<Cell>::operator()(const Cell& ref,
155159
const Cell& iter) const {
156-
int deltaRow = std::abs(getCellRow(ref) - getCellRow(iter));
157-
int deltaCol = std::abs(getCellColumn(ref) - getCellColumn(iter));
158-
// Iteration is column-wise, so if too far in column, can
159-
// safely stop
160-
if (deltaCol > 1) {
161-
return ConnectResult::eNoConnStop;
162-
}
163-
// For same reason, if too far in row we know the pixel is not
164-
// connected, but need to keep iterating
165-
if (deltaRow > 1) {
166-
return ConnectResult::eNoConn;
167-
}
168-
// Decide whether or not cluster is connected based on 4- or
169-
// 8-connectivity
170-
if ((deltaRow + deltaCol) <= (conn8 ? 2 : 1)) {
171-
return ConnectResult::eConn;
160+
int deltaRow = getCellRow(iter) - getCellRow(ref);
161+
int deltaCol = getCellColumn(iter) - getCellColumn(ref);
162+
assert((deltaCol < 0 || (deltaCol == 0 && deltaRow <= 0)) &&
163+
"Not iterating backwards");
164+
165+
switch (deltaCol) {
166+
case 0:
167+
if (deltaRow == 0) {
168+
return ConnectResult::eDuplicate;
169+
} else if (deltaRow == -1) {
170+
return ConnectResult::eConn;
171+
} else {
172+
return ConnectResult::eNoConn;
173+
}
174+
case -1:
175+
if (deltaRow > static_cast<int>(conn8)) {
176+
return ConnectResult::eNoConn;
177+
} else if (deltaRow < -static_cast<int>(conn8)) {
178+
return ConnectResult::eNoConnStop;
179+
} else {
180+
return ConnectResult::eConn;
181+
}
182+
default:
183+
return ConnectResult::eNoConnStop;
172184
}
173-
return ConnectResult::eNoConn;
174185
}
175186

176187
template <Acts::Ccl::HasRetrievableColumnInfo Cell>
177188
ConnectResult Connect1D<Cell>::operator()(const Cell& ref,
178189
const Cell& iter) const {
179-
int deltaCol = std::abs(getCellColumn(ref) - getCellColumn(iter));
180-
return deltaCol == 1 ? ConnectResult::eConn : ConnectResult::eNoConnStop;
190+
int deltaCol = getCellColumn(iter) - getCellColumn(ref);
191+
assert((deltaCol <= 0) && "Not iterating backwards");
192+
193+
switch (deltaCol) {
194+
case 0:
195+
return ConnectResult::eDuplicate;
196+
case -1:
197+
return ConnectResult::eConn;
198+
default:
199+
return ConnectResult::eNoConnStop;
200+
}
181201
}
182202

183203
template <std::size_t GridDim>

Tests/UnitTests/Core/Clusterization/ClusterizationTests1D.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,22 @@ BOOST_AUTO_TEST_CASE(Grid_1D_rand) {
129129
}
130130
}
131131

132+
BOOST_AUTO_TEST_CASE(Grid_1D_duplicate_cells) {
133+
using Cell = Cell1D;
134+
using CellC = std::vector<Cell>;
135+
using Cluster = Cluster1D;
136+
using ClusterC = std::vector<Cluster>;
137+
138+
CellC cells = {Cell(42), Cell(42)};
139+
ClusterC clusters;
140+
141+
Ccl::ClusteringData data;
142+
143+
BOOST_CHECK_THROW(
144+
(Ccl::createClusters<CellC, ClusterC, 1>(data, cells, clusters)),
145+
std::invalid_argument);
146+
}
147+
132148
BOOST_AUTO_TEST_SUITE_END()
133149

134150
} // namespace ActsTests

Tests/UnitTests/Core/Clusterization/ClusterizationTests2D.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,23 @@ BOOST_AUTO_TEST_CASE(Grid_2D_rand) {
248248
}
249249
}
250250
}
251+
252+
BOOST_AUTO_TEST_CASE(Grid_2D_duplicate_cells) {
253+
using Cell = Cell2D;
254+
using CellC = std::vector<Cell>;
255+
using Cluster = Cluster2D;
256+
using ClusterC = std::vector<Cluster>;
257+
258+
CellC cells = {Cell(10, 20), Cell(10, 20)};
259+
ClusterC clusters;
260+
261+
Ccl::ClusteringData data;
262+
263+
BOOST_CHECK_THROW(
264+
(Ccl::createClusters<CellC, ClusterC>(data, cells, clusters)),
265+
std::invalid_argument);
266+
}
267+
251268
BOOST_AUTO_TEST_SUITE_END()
252269

253270
} // namespace ActsTests

0 commit comments

Comments
 (0)