mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2026-08-06 20:32:25 +02:00
added docs
This commit is contained in:
@@ -29,6 +29,7 @@ AARE
|
||||
python/cluster/index
|
||||
python/file/index
|
||||
python/histogram/index
|
||||
python/pedestal/index
|
||||
pyFit
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
Pedestal
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:caption: Pedestal
|
||||
:maxdepth: 1
|
||||
|
||||
pyFastPedestal
|
||||
pyPedestal
|
||||
@@ -0,0 +1,83 @@
|
||||
FastPedestal
|
||||
============
|
||||
|
||||
``FastPedestal`` calculates a running mean, variance and standard deviation for each pixel in a
|
||||
series of frames. The python binding only exposes ``uint16`` input but the underlying
|
||||
C++ class is templated. Initialize it with ``n_samples`` frames using
|
||||
``push_init()``. Once ``ready`` is true, use ``push()`` for steady-state
|
||||
updates.
|
||||
|
||||
.. warning::
|
||||
|
||||
FastPedestal is not usable until you have pushed ``n_samples`` initial frames with ``push_init(raw)``.
|
||||
You can check the state with ``ready``.
|
||||
|
||||
The public factory selects the bound C++ specialization from ``dtype``:
|
||||
|
||||
* ``numpy.float64`` creates ``FastPedestal_d``
|
||||
* ``numpy.float32`` creates ``FastPedestal_f``
|
||||
* ``numpy.int16`` creates ``FastPedestal_i16``
|
||||
|
||||
The internal calculations are done with double, but the cached mean and on demand var and std are returned in the specified type.
|
||||
|
||||
Factory
|
||||
-------
|
||||
|
||||
.. py:currentmodule:: aare
|
||||
|
||||
.. autofunction:: FastPedestal
|
||||
|
||||
Loading from a file
|
||||
-------------------
|
||||
|
||||
``FastPedestal.from_file()`` initializes the pedestal from ``n_samples``
|
||||
frames after ``skip_first``, then applies steady-state updates for any frames
|
||||
remaining in the file. The input frames must contain ``uint16`` data; ``dtype``
|
||||
selects the output type of the pedestal statistics.
|
||||
|
||||
.. autofunction:: aare.FastPedestal.from_file
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
pedestal = FastPedestal.from_file(
|
||||
"frames.npy", n_samples=100, skip_first=10, dtype=np.float32
|
||||
)
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import numpy as np
|
||||
from aare import FastPedestal
|
||||
|
||||
pedestal = FastPedestal(512, 1024, n_samples=100, dtype=np.float32)
|
||||
|
||||
# Initialize with n_samples frames
|
||||
for frame in initialization_frames:
|
||||
pedestal.push_init(frame)
|
||||
|
||||
# Now we can push a frame for pedestal update
|
||||
if pedestal.ready:
|
||||
pedestal.push(next_frame)
|
||||
|
||||
# Mean and std are also ready
|
||||
mean = pedestal.mean()
|
||||
noise = pedestal.std()
|
||||
|
||||
# Direct pedestal subtraction is also supported
|
||||
for frame in raw_data:
|
||||
image = frame - pedestal
|
||||
|
||||
Complete API
|
||||
------------
|
||||
|
||||
The API below is for the ``float64`` specialization. All dtype variants share
|
||||
the same API.
|
||||
|
||||
.. autoclass:: aare._aare.FastPedestal_d
|
||||
:special-members: __init__
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
@@ -0,0 +1,42 @@
|
||||
Pedestal
|
||||
========
|
||||
|
||||
``Pedestal`` calculates a running mean and variance for each pixel in a series
|
||||
of ``uint16`` frames. ``push()`` updates the cached mean immediately. For
|
||||
faster batch initialization, use ``push_no_update()`` for each frame and call
|
||||
``update_mean()`` after the batch.
|
||||
|
||||
Three specializations are available from :mod:`aare`:
|
||||
|
||||
* ``Pedestal_d`` uses ``float64`` storage
|
||||
* ``Pedestal_f`` uses ``float32`` storage
|
||||
* ``Pedestal_i16`` uses ``int16`` storage
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from aare import Pedestal_d
|
||||
|
||||
pedestal = Pedestal_d(512, 1024, 100)
|
||||
|
||||
for frame in initialization_frames:
|
||||
pedestal.push_no_update(frame)
|
||||
|
||||
pedestal.update_mean()
|
||||
mean = pedestal.mean()
|
||||
noise = pedestal.std()
|
||||
|
||||
Complete API
|
||||
------------
|
||||
|
||||
The API below is for the ``float64`` specialization. All dtype variants share
|
||||
the same API.
|
||||
|
||||
.. autoclass:: aare._aare.Pedestal_d
|
||||
:special-members: __init__
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
@@ -39,7 +39,9 @@ set(PYTHON_FILES
|
||||
aare/ClusterFinder.py
|
||||
aare/ClusterVector.py
|
||||
aare/Cluster.py
|
||||
aare/FastPedestal.py
|
||||
aare/calibration.py
|
||||
aare/factory.py
|
||||
aare/func.py
|
||||
aare/RawFile.py
|
||||
aare/transform.py
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from . import _aare
|
||||
import numpy as np
|
||||
from .ClusterFinder import _type_to_char
|
||||
from .factory import _type_to_char
|
||||
|
||||
|
||||
def Cluster(x : int, y : int, data, cluster_size=(3,3), dtype = np.int32):
|
||||
@@ -21,4 +21,4 @@ def Cluster(x : int, y : int, data, cluster_size=(3,3), dtype = np.int32):
|
||||
except AttributeError:
|
||||
raise ValueError(f"Unsupported combination of type and cluster size: {dtype}/{cluster_size} when requesting {class_name}")
|
||||
|
||||
return cls(x, y, data)
|
||||
return cls(x, y, data)
|
||||
|
||||
@@ -1,21 +1,10 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
from . import _aare
|
||||
import numpy as np
|
||||
from .factory import _type_to_char
|
||||
|
||||
_supported_cluster_sizes = [(2,2), (3,3), (5,5), (7,7), (9,9),]
|
||||
|
||||
def _type_to_char(dtype):
|
||||
if dtype == np.int32:
|
||||
return 'i'
|
||||
elif dtype == np.float32:
|
||||
return 'f'
|
||||
elif dtype == np.float64:
|
||||
return 'd'
|
||||
elif dtype == np.int16:
|
||||
return 'i16'
|
||||
else:
|
||||
raise ValueError(f"Unsupported dtype: {dtype}. Only np.int32, np.float32, and np.float64 are supported.")
|
||||
|
||||
def _get_class(name, cluster_size, dtype):
|
||||
"""
|
||||
Helper function to get the class based on the name, cluster size, and dtype.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .factory import _get_typed_class
|
||||
|
||||
|
||||
def _get_fast_pedestal_class(dtype):
|
||||
return _get_typed_class("FastPedestal", dtype)
|
||||
|
||||
|
||||
def FastPedestal(rows, cols, n_samples=1000, dtype=np.float64):
|
||||
"""Create a FastPedestal with the requested output dtype.
|
||||
|
||||
This factory hides the dtype suffix used by the templated C++ bindings.
|
||||
Supported dtypes are ``np.float64``, ``np.float32``, and ``np.int16``.
|
||||
"""
|
||||
cls = _get_fast_pedestal_class(dtype)
|
||||
return cls(rows, cols, n_samples)
|
||||
|
||||
|
||||
def from_file(filename, n_samples=1000, skip_first=0, dtype=np.float64):
|
||||
"""Create a FastPedestal from frames in a file.
|
||||
|
||||
The input frames must contain uint16 data. ``dtype`` selects the output
|
||||
type of the pedestal mean, variance, and standard deviation.
|
||||
"""
|
||||
cls = _get_fast_pedestal_class(dtype)
|
||||
return cls.from_file(
|
||||
filename, n_samples=n_samples, skip_first=skip_first
|
||||
)
|
||||
|
||||
|
||||
FastPedestal.from_file = from_file
|
||||
@@ -23,6 +23,7 @@ from ._aare import corner
|
||||
# from ._aare import ClusterFinderMT, ClusterCollector, ClusterFileSink, ClusterVector_i
|
||||
|
||||
from ._version import __version__
|
||||
from .FastPedestal import FastPedestal
|
||||
from .ClusterFinder import ClusterFinder, ClusterCollector, ClusterFinderMT, ClusterFileSink, ClusterFile
|
||||
from .ClusterVector import ClusterVector
|
||||
from .Cluster import Cluster
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
import numpy as np
|
||||
|
||||
from . import _aare
|
||||
|
||||
|
||||
_TYPE_TO_CHAR = {
|
||||
np.dtype(np.int32): "i",
|
||||
np.dtype(np.float32): "f",
|
||||
np.dtype(np.float64): "d",
|
||||
np.dtype(np.int16): "i16",
|
||||
}
|
||||
|
||||
|
||||
def _type_to_char(dtype):
|
||||
"""Return the suffix used by bindings instantiated for ``dtype``."""
|
||||
try:
|
||||
return _TYPE_TO_CHAR[np.dtype(dtype)]
|
||||
except (KeyError, TypeError):
|
||||
supported = ", ".join(str(dtype) for dtype in _TYPE_TO_CHAR)
|
||||
raise ValueError(
|
||||
f"Unsupported dtype: {dtype}. Supported dtypes are {supported}."
|
||||
) from None
|
||||
|
||||
|
||||
def _get_typed_class(name, dtype):
|
||||
"""Return a bound class named ``<name>_<dtype suffix>``."""
|
||||
class_name = f"{name}_{_type_to_char(dtype)}"
|
||||
try:
|
||||
return getattr(_aare, class_name)
|
||||
except AttributeError:
|
||||
raise ValueError(
|
||||
f"Unsupported dtype for {name}: {dtype} "
|
||||
f"(binding {class_name} is not available)."
|
||||
) from None
|
||||
@@ -14,8 +14,9 @@ template <typename SUM_TYPE>
|
||||
void define_fast_pedestal_bindings(py::module &m, const std::string &name) {
|
||||
|
||||
py::class_<FastPedestal<SUM_TYPE>>(m, name.c_str(), py::buffer_protocol())
|
||||
.def(py::init<uint32_t, uint32_t, uint32_t>())
|
||||
.def(py::init<uint32_t, uint32_t>())
|
||||
.def(py::init<uint32_t, uint32_t, uint32_t>(), py::arg("rows"),
|
||||
py::arg("cols"), py::arg("n_samples"))
|
||||
.def(py::init<uint32_t, uint32_t>(), py::arg("rows"), py::arg("cols"))
|
||||
|
||||
.def(
|
||||
"mean",
|
||||
@@ -24,7 +25,7 @@ void define_fast_pedestal_bindings(py::module &m, const std::string &name) {
|
||||
*mean = self.mean();
|
||||
return return_image_data(mean);
|
||||
},
|
||||
"Return a copy of the mean of the pedestal as a NumPy array")
|
||||
"Return a copy of the cached mean as a NumPy array")
|
||||
.def(
|
||||
"var",
|
||||
[](FastPedestal<SUM_TYPE> &self) {
|
||||
@@ -32,7 +33,7 @@ void define_fast_pedestal_bindings(py::module &m, const std::string &name) {
|
||||
*variance = self.variance();
|
||||
return return_image_data(variance);
|
||||
},
|
||||
"Return a copy of the variance of the pedestal as a NumPy array")
|
||||
"Calculate the variance and return it as a NumPy array")
|
||||
.def(
|
||||
"std",
|
||||
[](FastPedestal<SUM_TYPE> &self) {
|
||||
@@ -40,14 +41,15 @@ void define_fast_pedestal_bindings(py::module &m, const std::string &name) {
|
||||
*standard_deviation = self.std();
|
||||
return return_image_data(standard_deviation);
|
||||
},
|
||||
"Return a copy of the standard deviation of the pedestal as a "
|
||||
"Calculate the standard deviation and return it as a "
|
||||
"NumPy array")
|
||||
.def(
|
||||
"view",
|
||||
[](py::object self_py) {
|
||||
return py::module_::import("numpy").attr("asarray")(self_py);
|
||||
},
|
||||
"Return non-owning, non-writable view of the pedestal as a NumPy "
|
||||
"Return non-owning, non-writable view of the pedestal mean as a "
|
||||
"NumPy "
|
||||
"array")
|
||||
|
||||
// We need to buffer protocol to allow for numpy operations using the
|
||||
@@ -95,7 +97,8 @@ void define_fast_pedestal_bindings(py::module &m, const std::string &name) {
|
||||
"pushed at least n_samples samples)")
|
||||
.def_property_readonly(
|
||||
"n_samples", &FastPedestal<SUM_TYPE>::n_samples,
|
||||
"Return the number of samples to push to the pedestal to be ready")
|
||||
"Return the number of samples to push to the pedestal to be ready. "
|
||||
"This value also affect how fast it updates in the steady state.")
|
||||
.def("clone",
|
||||
[](FastPedestal<SUM_TYPE> &pedestal) {
|
||||
return FastPedestal<SUM_TYPE>(pedestal);
|
||||
|
||||
@@ -1,7 +1,88 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from aare import FastPedestal_d, FastPedestal_f
|
||||
from aare import (
|
||||
FastPedestal,
|
||||
FastPedestal_d,
|
||||
FastPedestal_f,
|
||||
FastPedestal_i16,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("dtype", "pedestal_type"),
|
||||
[
|
||||
(np.float64, FastPedestal_d),
|
||||
(np.float32, FastPedestal_f),
|
||||
(np.int16, FastPedestal_i16),
|
||||
],
|
||||
)
|
||||
def test_fast_pedestal_factory(dtype, pedestal_type):
|
||||
pedestal = FastPedestal(2, 3, n_samples=4, dtype=dtype)
|
||||
|
||||
assert isinstance(pedestal, pedestal_type)
|
||||
assert pedestal.rows == 2
|
||||
assert pedestal.cols == 3
|
||||
assert pedestal.n_samples == 4
|
||||
|
||||
|
||||
def test_fast_pedestal_factory_defaults_to_double():
|
||||
assert isinstance(FastPedestal(2, 3), FastPedestal_d)
|
||||
|
||||
|
||||
def test_fast_pedestal_factory_rejects_unbound_dtype():
|
||||
with pytest.raises(ValueError, match="Unsupported dtype for FastPedestal"):
|
||||
FastPedestal(2, 3, dtype=np.int32)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("kwargs", "expected_n_samples"),
|
||||
[
|
||||
({"rows": 2, "cols": 3}, 1000),
|
||||
({"rows": 2, "cols": 3, "n_samples": 4}, 4),
|
||||
],
|
||||
)
|
||||
def test_fast_pedestal_binding_accepts_constructor_keywords(
|
||||
kwargs, expected_n_samples
|
||||
):
|
||||
pedestal = FastPedestal_d(**kwargs)
|
||||
|
||||
assert pedestal.rows == 2
|
||||
assert pedestal.cols == 3
|
||||
assert pedestal.n_samples == expected_n_samples
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("dtype", "pedestal_type", "expected_dtype"),
|
||||
[
|
||||
(np.float64, FastPedestal_d, np.float64),
|
||||
(np.float32, FastPedestal_f, np.float32),
|
||||
(np.int16, FastPedestal_i16, np.int16),
|
||||
],
|
||||
)
|
||||
def test_fast_pedestal_factory_from_file(
|
||||
tmp_path, dtype, pedestal_type, expected_dtype
|
||||
):
|
||||
frames = np.array(
|
||||
[[[100, 100]], [[2, 4]], [[4, 6]], [[5, 7]]], dtype=np.uint16
|
||||
)
|
||||
filename = tmp_path / "frames.npy"
|
||||
np.save(filename, frames)
|
||||
|
||||
pedestal = FastPedestal.from_file(
|
||||
filename, n_samples=2, skip_first=1, dtype=dtype
|
||||
)
|
||||
|
||||
assert isinstance(pedestal, pedestal_type)
|
||||
assert pedestal.ready
|
||||
assert pedestal.cur_samples == 2
|
||||
assert pedestal.mean().dtype == expected_dtype
|
||||
np.testing.assert_array_equal(pedestal.mean(), [[4, 6]])
|
||||
|
||||
|
||||
def test_fast_pedestal_factory_from_file_rejects_unbound_dtype():
|
||||
with pytest.raises(ValueError, match="Unsupported dtype for FastPedestal"):
|
||||
FastPedestal.from_file("unused.npy", dtype=np.int32)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
||||
Reference in New Issue
Block a user