updated docs and gain map
Build on RHEL9 / build (push) Successful in 2m40s
Build on RHEL8 / build (push) Successful in 3m7s
Run tests using data on local RHEL8 / build (push) Successful in 3m58s

This commit is contained in:
Erik Frojdh
2026-08-29 09:02:02 +02:00
parent c158eec000
commit ae4324714c
9 changed files with 386 additions and 157 deletions
+36 -8
View File
@@ -69,19 +69,47 @@ def ClusterFileSink(clusterfindermt, cluster_file, dtype=np.int32):
def ClusterFile(fname, cluster_size=(3,3), dtype=np.int32, chunk_size = 1000, mode = "r"):
"""
Factory function to create a ClusterFile object. Provides a cleaner syntax for
the templated ClusterFile in C++.
"""Create a reader or writer for a legacy binary cluster file.
Parameters
----------
fname : path-like
Cluster file to open.
cluster_size : tuple[int, int], default=(3, 3)
Cluster dimensions stored in the file.
dtype : numpy dtype, default=numpy.int32
Data type of the cluster values stored in the file.
chunk_size : int, default=1000
Maximum number of selected clusters returned by each iterator step.
mode : {"r", "w", "a"}, default="r"
Open for reading, truncate and write, or append, respectively.
Returns
-------
ClusterFile
The compiled ClusterFile specialization matching ``cluster_size`` and
``dtype``.
Notes
-----
The file format contains no cluster shape or data-type metadata. Supplying
values that do not match the file causes its bytes to be interpreted
incorrectly. Iterator chunks may combine frames, so their frame number is
not reliable per-cluster metadata.
Examples
--------
.. code-block:: python
from aare import ClusterFile
with ClusterFile("clusters.clust", cluster_size=(3,3), dtype=np.int32) as cf:
# cf is now a ClusterFile_Cluster3x3i object but you don't need to know that.
with ClusterFile(
"clusters.clust", cluster_size=(3, 3), dtype=np.int32
) as cf:
for clusters in cf:
# Loop over clusters in chunks of 1000
# The type of clusters will be a ClusterVector_Cluster3x3i in this case
# Process clusters in chunks of at most 1000.
...
"""
+45 -19
View File
@@ -28,10 +28,16 @@ void define_ClusterFile(py::module &m, const std::string &typestr) {
auto class_name = fmt::format("ClusterFile_{}", typestr);
py::class_<ClusterFile<ClusterType>>(m, class_name.c_str())
py::class_<ClusterFile<ClusterType>>(
m, class_name.c_str(),
"Read and write legacy binary cluster files. The format contains no "
"cluster type or shape metadata, so this class must match the file.")
.def(py::init<const std::filesystem::path &, size_t,
const std::string &>(),
py::arg(), py::arg("chunk_size") = 1000, py::arg("mode") = "r")
py::arg("fname"), py::arg("chunk_size") = 1000,
py::arg("mode") = "r",
"Open a cluster file. Mode must be 'r' to read, 'w' to truncate "
"and write, or 'a' to append.")
.def(
"read_clusters",
[](ClusterFile<ClusterType> &self, size_t n_clusters) {
@@ -39,32 +45,52 @@ void define_ClusterFile(py::module &m, const std::string &typestr) {
self.read_clusters(n_clusters));
return v;
},
py::return_value_policy::take_ownership, py::arg("n_clusters"))
.def("read_frame",
[](ClusterFile<ClusterType> &self) {
auto v = new ClusterVector<ClusterType>(self.read_frame());
return v;
})
.def("set_roi", &ClusterFile<ClusterType>::set_roi, py::arg("roi"))
.def("tell", &ClusterFile<ClusterType>::tell)
py::return_value_policy::take_ownership, py::arg("n_clusters"),
"Read up to n_clusters without preserving frame boundaries. The "
"result may combine frames, so its frame number is not reliable "
"per-cluster metadata.")
.def(
"read_frame",
[](ClusterFile<ClusterType> &self) {
auto v = new ClusterVector<ClusterType>(self.read_frame());
return v;
},
"Read and return the next complete frame with its frame number.")
.def("set_roi", &ClusterFile<ClusterType>::set_roi, py::arg("roi"),
"Select clusters whose centers lie within the half-open ROI.")
.def("tell", &ClusterFile<ClusterType>::tell,
"Return the current byte position in the file.")
.def("estimate_n_clusters",
&ClusterFile<ClusterType>::estimate_n_clusters)
&ClusterFile<ClusterType>::estimate_n_clusters,
"Estimate the number of clusters from the file size. Frame "
"headers can make this larger than the actual count.")
.def(
"set_noise_map",
[](ClusterFile<ClusterType> &self, py::array_t<int32_t> noise_map) {
auto view = make_view_2d(noise_map);
self.set_noise_map(view);
},
py::arg("noise_map"))
py::arg("noise_map"),
"Set a two-dimensional, C-contiguous int32 noise map indexed as "
"[y, x]. The map must cover every cluster center coordinate.")
.def("set_gain_map",
[](ClusterFile<ClusterType> &self, py::array_t<double> gain_map) {
auto view = make_view_2d(gain_map);
self.set_gain_map(view);
})
.def(
"set_gain_map",
[](ClusterFile<ClusterType> &self, py::array_t<double> gain_map) {
auto view = make_view_2d(gain_map);
self.set_gain_map(view);
},
py::arg("gain_map"),
"Set a two-dimensional, C-contiguous float64 gain map in "
"ADU/energy, indexed as [y, x]. Clusters whose complete footprint "
"extends beyond the map are retained with all data values set to "
"zero.")
.def("close", &ClusterFile<ClusterType>::close)
.def("write_frame", &ClusterFile<ClusterType>::write_frame)
.def("close", &ClusterFile<ClusterType>::close,
"Close the file. Calling close more than once is safe.")
.def("write_frame", &ClusterFile<ClusterType>::write_frame,
py::arg("clusters"),
"Write one ClusterVector, including its frame number.")
.def("__enter__", [](ClusterFile<ClusterType> &self) { return &self; })
.def("__exit__",
[](ClusterFile<ClusterType> &self,