frame nr and checks on mask
Build on RHEL9 / build (push) Successful in 2m55s
Build on RHEL8 / build (push) Successful in 3m21s
Run tests using data on local RHEL8 / build (push) Successful in 4m0s

This commit is contained in:
Erik Fröjdh
2026-09-01 11:29:54 +02:00
parent def1f172f9
commit 93eb41e170
5 changed files with 66 additions and 8 deletions
+3 -2
View File
@@ -19,6 +19,9 @@
### Bugfixes:
- Fixed ``ClusterVector`` move operations to transfer storage instead of
copying every cluster.
- Validate that ``ClusterVector`` masks are one-dimensional, C-contiguous
Boolean arrays.
- Preserve ``ClusterVector`` frame numbers when reducing cluster dimensions.
- Fixed broken reading of old (pre reordering) Moench03
## 2026.7.2
@@ -168,5 +171,3 @@ dhanya.thattil@psi.ch
+4 -2
View File
@@ -194,7 +194,8 @@ template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
ClusterVector<Cluster<T, 2, 2, CoordType>> reduce_to_2x2(
const ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>>
&cv) {
ClusterVector<Cluster<T, 2, 2, CoordType>> result;
ClusterVector<Cluster<T, 2, 2, CoordType>> result(cv.size(),
cv.frame_number());
for (const auto &c : cv) {
result.push_back(reduce_to_2x2(c));
}
@@ -211,7 +212,8 @@ template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
ClusterVector<Cluster<T, 3, 3, CoordType>> reduce_to_3x3(
const ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>>
&cv) {
ClusterVector<Cluster<T, 3, 3, CoordType>> result;
ClusterVector<Cluster<T, 3, 3, CoordType>> result(cv.size(),
cv.frame_number());
for (const auto &c : cv) {
result.push_back(reduce_to_3x3(c));
}
+6 -2
View File
@@ -37,10 +37,14 @@ void define_ClusterVector(py::module &m, const std::string &typestr) {
.def(
"__call__",
[](ClusterVector<ClusterType> &self, py::array_t<bool> mask) {
[](ClusterVector<ClusterType> &self,
py::array_t<bool, py::array::c_style> mask) {
if (mask.ndim() != 1) {
throw py::value_error("Mask must be one-dimensional");
}
return self(make_view_1d(mask));
},
py::arg("mask"), R"(
py::arg("mask").noconvert(), R"(
Create a copy of the clustervector and apply a boolean mask to the ClusterVector.
Parameters
+31 -2
View File
@@ -83,12 +83,15 @@ def test_make_a_hitmap_from_cluster_vector():
def test_2x2_reduction():
cv = ClusterVector((3,3))
cv.frame_number = 135
cv.push_back(_aare.Cluster3x3i(5, 5, np.array([1, 1, 1, 2, 3, 1, 2, 2, 1], dtype=np.int32)))
cv.push_back(_aare.Cluster3x3i(5, 5, np.array([2, 2, 1, 2, 3, 1, 1, 1, 1], dtype=np.int32)))
reduced_cv = np.array(_aare.reduce_to_2x2(cv), copy=False)
reduced = _aare.reduce_to_2x2(cv)
reduced_cv = np.array(reduced, copy=False)
assert reduced.frame_number == cv.frame_number
assert reduced_cv.size == 2
assert reduced_cv[0]["x"] == 5
assert reduced_cv[0]["y"] == 5
@@ -100,14 +103,17 @@ def test_2x2_reduction():
def test_3x3_reduction():
cv = _aare.ClusterVector_Cluster5x5d()
cv.frame_number = 246
cv.push_back(_aare.Cluster5x5d(5,5,np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0,
1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], dtype=np.double)))
cv.push_back(_aare.Cluster5x5d(5,5,np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0,
1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], dtype=np.double)))
reduced_cv = np.array(_aare.reduce_to_3x3(cv), copy=False)
reduced = _aare.reduce_to_3x3(cv)
reduced_cv = np.array(reduced, copy=False)
assert reduced.frame_number == cv.frame_number
assert reduced_cv.size == 2
assert reduced_cv[0]["x"] == 5
assert reduced_cv[0]["y"] == 5
@@ -130,3 +136,26 @@ def test_masking():
assert cv_masked_array[0]["x"] == 1
assert cv_masked_array[0]["y"] == 2
assert (cv_masked_array[0]["data"] == np.ones((3,3),dtype=np.int32)).all()
def test_masking_requires_c_contiguous_array():
cv = _aare.ClusterVector_Cluster3x3i()
cv.push_back(_aare.Cluster3x3i(1, 2, np.ones(9, dtype=np.int32)))
cv.push_back(_aare.Cluster3x3i(3, 4, np.ones(9, dtype=np.int32)))
mask = np.array([True, False, True, False], dtype=bool)[::2]
assert not mask.flags.c_contiguous
with pytest.raises(TypeError):
cv(mask)
def test_masking_requires_one_dimension():
cv = _aare.ClusterVector_Cluster3x3i()
cv.push_back(_aare.Cluster3x3i(1, 2, np.ones(9, dtype=np.int32)))
cv.push_back(_aare.Cluster3x3i(3, 4, np.ones(9, dtype=np.int32)))
mask = np.array([[True, False]], dtype=bool)
with pytest.raises(ValueError, match="one-dimensional"):
cv(mask)
+22
View File
@@ -271,6 +271,28 @@ TEST_CASE("Concatenate two cluster vectors where we need to allocate") {
REQUIRE(ptr[3].y == 17);
}
TEST_CASE("Reducing a ClusterVector preserves its frame number") {
SECTION("Reduce to 2x2") {
ClusterVector<Cluster<int32_t, 3, 3>> source(1, 135);
source.push_back(Cluster<int32_t, 3, 3>{});
auto reduced = aare::reduce_to_2x2(source);
CHECK(reduced.size() == source.size());
CHECK(reduced.frame_number() == source.frame_number());
}
SECTION("Reduce to 3x3") {
ClusterVector<Cluster<int32_t, 5, 5>> source(1, 246);
source.push_back(Cluster<int32_t, 5, 5>{});
auto reduced = aare::reduce_to_3x3(source);
CHECK(reduced.size() == source.size());
CHECK(reduced.frame_number() == source.frame_number());
}
}
struct ClusterTestData {
uint8_t ClusterSizeX;
uint8_t ClusterSizeY;