mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2026-11-06 15:13:31 +01:00
Merge 'origin/main' into feature/cuda_clusterfinder
This commit is contained in:
commit
156667efde
64 files changed
+4365
-542
No files matched your search
@@ -29,7 +29,7 @@ pybind11_add_module(_aare NO_EXTRAS src/module.cpp)
|
||||
target_link_libraries(_aare PRIVATE aare_core aare_compiler_flags)
|
||||
target_include_directories(
|
||||
_aare SYSTEM
|
||||
PRIVATE $<TARGET_PROPERTY:Minuit2::Minuit2,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
PRIVATE $<TARGET_PROPERTY:aare::Minuit2,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
|
||||
set_target_properties(
|
||||
_aare PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/aare
|
||||
@@ -63,6 +63,7 @@ endif()
|
||||
# List of python files to be copied to the build directory
|
||||
set(PYTHON_FILES
|
||||
aare/__init__.py
|
||||
aare/_version.py
|
||||
aare/CtbRawFile.py
|
||||
aare/ClusterFinder.py
|
||||
aare/ClusterVector.py
|
||||
@@ -90,6 +91,8 @@ foreach(FILE ${PYTHON_EXAMPLES})
|
||||
message(STATUS "Copying ${FILE} to ${CMAKE_BINARY_DIR}/${FILE}")
|
||||
endforeach(FILE ${PYTHON_EXAMPLES})
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../VERSION
|
||||
${CMAKE_BINARY_DIR}/aare/VERSION)
|
||||
if(AARE_INSTALL_PYTHONEXT)
|
||||
set(AARE_PY_INSTALL_TARGETS _aare)
|
||||
if(AARE_CUDA)
|
||||
@@ -105,4 +108,8 @@ if(AARE_INSTALL_PYTHONEXT)
|
||||
FILES ${PYTHON_FILES}
|
||||
DESTINATION aare
|
||||
COMPONENT python)
|
||||
install(
|
||||
FILES ../VERSION
|
||||
DESTINATION aare
|
||||
COMPONENT python)
|
||||
endif()
|
||||
+15
-2
@@ -30,12 +30,13 @@ from ._aare import corner
|
||||
|
||||
# from ._aare import ClusterFinderMT, ClusterCollector, ClusterFileSink, ClusterVector_i
|
||||
|
||||
from ._version import __version__
|
||||
from .ClusterFinder import ClusterFinder, ClusterCollector, ClusterFinderMT, ClusterFileSink, ClusterFile
|
||||
from .ClusterFinder import ClusterFinderCUDA, _cuda_available
|
||||
from .ClusterVector import ClusterVector
|
||||
from .Cluster import Cluster
|
||||
|
||||
from ._aare import Gaussian, RisingScurve, FallingScurve, Pol1, Pol2
|
||||
from ._aare import Gaussian, RisingScurve, FallingScurve, Pol1, Pol2, GaussianErfcPlateau, GaussianChargeSharing, GaussianChargeSharingKb
|
||||
from ._aare import fit
|
||||
from ._aare import fit_gaus, fit_pol1, fit_scurve, fit_scurve2
|
||||
from ._aare import Interpolator
|
||||
@@ -44,11 +45,13 @@ from ._aare import reduce_to_2x2, reduce_to_3x3
|
||||
|
||||
from ._aare import apply_custom_weights
|
||||
|
||||
from ._aare import Etai, Etad, Etaf
|
||||
|
||||
from .CtbRawFile import CtbRawFile
|
||||
from .RawFile import RawFile
|
||||
from .ScanParameters import ScanParameters
|
||||
|
||||
from .utils import random_pixels, random_pixel, flat_list, add_colorbar
|
||||
from .utils import random_pixels, random_pixel, flat_list, add_colorbar, Timer
|
||||
|
||||
|
||||
#make functions available in the top level API
|
||||
@@ -59,3 +62,13 @@ from ._aare import apply_calibration, count_switching_pixels
|
||||
from ._aare import calculate_pedestal, calculate_pedestal_float, calculate_pedestal_g0, calculate_pedestal_g0_float
|
||||
|
||||
from ._aare import VarClusterFinder
|
||||
from ._aare import (
|
||||
PedestalTrackingPixelHistogram,
|
||||
PixelHistogram,
|
||||
PixelHistogram_d,
|
||||
PixelHistogram_f,
|
||||
PixelHistogram_u8,
|
||||
PixelHistogram_u16,
|
||||
PixelHistogram_u32,
|
||||
PixelHistogram_u64,
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
# This file is used to get the version of the package from the VERSION file
|
||||
from importlib.metadata import PackageNotFoundError, version
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
__version__ = version('aare')
|
||||
except PackageNotFoundError:
|
||||
__version__ = Path(__file__).parent.joinpath('VERSION').read_text().strip()
|
||||
@@ -17,6 +17,15 @@ class AdcSar05060708Transform64to16:
|
||||
return _aare.adc_sar_05_06_07_08decode64to16(data)
|
||||
|
||||
class Moench05Transform:
|
||||
"""
|
||||
Transforms Moench05 chip data from a buffer of bytes (uint8_t)
|
||||
to a numpy array of uint16. Assumes data taken with analog samples and assumes adc 1, 9, 13 are enabled.
|
||||
(e.g. for 10g mode adc 0,1,2,3 and 8,9,10,11 and 12,13,14,15 are enabled but only adc 1,9,13 contain relevant data)
|
||||
|
||||
.. note::
|
||||
A moench05 chip has 160 rows and 50 cols per adc and has dynamic range 16 bit. Each adc sample is encoded in 16 bits.
|
||||
The transformation thus requires 160*50*16/16 = 8000 analog samples per adc.
|
||||
"""
|
||||
#Could be moved to C++ without changing the interface
|
||||
def __init__(self):
|
||||
self.pixel_map = _aare.GenerateMoench05PixelMap()
|
||||
@@ -81,6 +90,10 @@ class Matterhorn10Transform:
|
||||
A matterhorn chip has 256 columns and 256 rows.
|
||||
A matterhornchip with dynamic range 16 and 2 counters thus requires
|
||||
256*256*16*2/(2*64) = 1024 transceiver samples. (Per default 2 channels are enabled per transceiver sample, each channel storing 64 bits)
|
||||
|
||||
.. note::
|
||||
Due to an artefact in the chip, the transformation only fully supports 2 or 4 counters. Also if you enable 2 counters you can only select counter 1 and 2 or 0, 3 to get reasonable results.
|
||||
Otherwise only the first half of the image is correct.
|
||||
"""
|
||||
def __init__(self, dynamic_range : int, num_counters : int):
|
||||
self.pixel_map = _aare.GenerateMatterhorn10PixelMap(dynamic_range, num_counters)
|
||||
@@ -105,7 +118,7 @@ class Matterhorn10Transform:
|
||||
checks if data is compatible for transformation
|
||||
|
||||
:param data: data to be transformed, expected to be a 1D numpy array of uint8
|
||||
:type data: np.ndarray
|
||||
:type data: np.ndarray(n_counters, n_rows, n_cols)
|
||||
:raises ValueError: if not compatible
|
||||
"""
|
||||
expected_size = (Matterhorn10.nRows*Matterhorn10.nCols*self.num_counters*self.dynamic_range)//8 # read_frame returns data in uint8_t
|
||||
@@ -118,11 +131,11 @@ class Matterhorn10Transform:
|
||||
def __call__(self, data):
|
||||
self.data_compatibility(data)
|
||||
if self.dynamic_range == 16:
|
||||
return np.take(data.view(np.uint16), self.pixel_map)
|
||||
return np.take(data.view(np.uint16), self.pixel_map).reshape(self.num_counters, Matterhorn10.nRows, Matterhorn10.nCols)
|
||||
elif self.dynamic_range == 8:
|
||||
return np.take(data.view(np.uint8), self.pixel_map)
|
||||
return np.take(data.view(np.uint8), self.pixel_map).reshape(self.num_counters, Matterhorn10.nRows, Matterhorn10.nCols)
|
||||
else: #dynamic range 4
|
||||
return np.take(_aare.expand4to8bit(data.view(np.uint8)), self.pixel_map)
|
||||
return np.take(_aare.expand4to8bit(data.view(np.uint8)), self.pixel_map).reshape(self.num_counters, Matterhorn10.nRows, Matterhorn10.nCols)
|
||||
|
||||
class Mythen302Transform:
|
||||
"""
|
||||
|
||||
+16
-1
@@ -2,6 +2,7 @@
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
||||
import time
|
||||
|
||||
def random_pixels(n_pixels, xmin=0, xmax=512, ymin=0, ymax=1024):
|
||||
"""Return a list of random pixels.
|
||||
@@ -34,4 +35,18 @@ def add_colorbar(ax, im, size="5%", pad=0.05):
|
||||
divider = make_axes_locatable(ax)
|
||||
cax = divider.append_axes("right", size=size, pad=pad)
|
||||
plt.colorbar(im, cax=cax)
|
||||
return ax, im, cax
|
||||
return ax, im, cax
|
||||
|
||||
|
||||
class Timer:
|
||||
def __init__(self, label="Elapsed time:", verbose=True):
|
||||
self.label = label
|
||||
self.verbose = verbose
|
||||
def __enter__(self):
|
||||
self.start = time.perf_counter()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc, tb):
|
||||
self.elapsed = time.perf_counter() - self.start
|
||||
if self.verbose:
|
||||
print(f"{self.label} {self.elapsed:.3f}s")
|
||||
@@ -22,4 +22,9 @@ void define_defs_bindings(py::module &m) {
|
||||
moench04.attr("nPixelsPerSuperColumn") = Moench04::nPixelsPerSuperColumn;
|
||||
moench04.attr("superColumnWidth") = Moench04::superColumnWidth;
|
||||
moench04.attr("adcNumbers") = Moench04::adcNumbers;
|
||||
|
||||
auto moench05 = py::class_<Moench05>(m, "Moench05");
|
||||
moench05.attr("nRows") = Moench05::nRows;
|
||||
moench05.attr("nCols") = Moench05::nCols;
|
||||
moench05.attr("adcNumbers") = Moench05::adcNumbers;
|
||||
}
|
||||
@@ -13,12 +13,12 @@ void define_eta(py::module &m, const std::string &typestr) {
|
||||
|
||||
py::class_<Eta2<T>>(m, class_name.c_str())
|
||||
.def(py::init<>())
|
||||
.def_readonly("x", &Eta2<T>::x, "eta x value")
|
||||
.def_readonly("y", &Eta2<T>::y, "eta y value")
|
||||
.def_readonly("c", &Eta2<T>::c,
|
||||
"eta corner value cTopLeft, cTopRight, "
|
||||
"cBottomLeft, cBottomRight")
|
||||
.def_readonly("sum", &Eta2<T>::sum, "photon energy of cluster");
|
||||
.def_readwrite("x", &Eta2<T>::x, "eta x value")
|
||||
.def_readwrite("y", &Eta2<T>::y, "eta y value")
|
||||
.def_readwrite("c", &Eta2<T>::c,
|
||||
"eta corner value cTopLeft, cTopRight, "
|
||||
"cBottomLeft, cBottomRight")
|
||||
.def_readwrite("sum", &Eta2<T>::sum, "photon energy of cluster");
|
||||
}
|
||||
|
||||
void define_corner_enum(py::module &m) {
|
||||
|
||||
@@ -11,17 +11,20 @@
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
// clang-format off
|
||||
#define REGISTER_INTERPOLATOR_ETA2(T, N, M, U) \
|
||||
register_interpolate<T, N, M, U, aare::calculate_full_eta2<T, N, M, U>>( \
|
||||
interpolator, "_full_eta2", "full eta2"); \
|
||||
register_interpolate<T, N, M, U, aare::calculate_eta2<T, N, M, U>>( \
|
||||
interpolator, "", "eta2");
|
||||
interpolator, "", "eta2"); \
|
||||
register_interpolate_custom_eta<T, N, M, U>(interpolator);
|
||||
|
||||
#define REGISTER_INTERPOLATOR_ETA3(T, N, M, U) \
|
||||
register_interpolate<T, N, M, U, aare::calculate_eta3<T, N, M, U>>( \
|
||||
interpolator, "_eta3", "full eta3"); \
|
||||
register_interpolate<T, N, M, U, aare::calculate_cross_eta3<T, N, M, U>>( \
|
||||
interpolator, "_cross_eta3", "cross eta3");
|
||||
// clang-format on
|
||||
|
||||
template <typename Type, uint8_t CoordSizeX, uint8_t CoordSizeY,
|
||||
typename CoordType = uint16_t, auto EtaFunction>
|
||||
@@ -48,6 +51,34 @@ void register_interpolate(py::class_<aare::Interpolator> &interpolator,
|
||||
docstring.c_str(), py::arg("cluster_vector"));
|
||||
}
|
||||
|
||||
template <typename Type, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
|
||||
typename CoordType = uint16_t>
|
||||
void register_interpolate_custom_eta(
|
||||
py::class_<aare::Interpolator> &interpolator) {
|
||||
|
||||
using ClusterType = Cluster<Type, ClusterSizeX, ClusterSizeY, CoordType>;
|
||||
|
||||
interpolator.def(
|
||||
"interpolate",
|
||||
[](aare::Interpolator &self, const ClusterVector<ClusterType> &clusters,
|
||||
const std::vector<Eta2<Type>> &etas) {
|
||||
auto photons = self.interpolate<Type, ClusterSizeX, ClusterSizeY, CoordType>(clusters, etas);
|
||||
auto *ptr = new std::vector<Photon>{std::move(photons)};
|
||||
return return_vector(ptr);
|
||||
},
|
||||
R"(
|
||||
Interpolation based on custom eta values provided by the user.
|
||||
|
||||
Args:
|
||||
cluster_vector: vector of clusters to interpolate
|
||||
etas: vector of eta values for each cluster (must be in the same order as the clusters)
|
||||
|
||||
Returns:
|
||||
interpolated photons
|
||||
)",
|
||||
py::arg("cluster_vector"), py::arg("etas"));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void register_transform_eta_values(
|
||||
py::class_<aare::Interpolator> &interpolator) {
|
||||
@@ -65,6 +96,8 @@ void define_interpolation_bindings(py::module &m) {
|
||||
|
||||
PYBIND11_NUMPY_DTYPE(aare::Photon, x, y, energy);
|
||||
|
||||
PYBIND11_NUMPY_DTYPE(aare::Coordinate2D, x, y);
|
||||
|
||||
auto interpolator =
|
||||
py::class_<aare::Interpolator>(m, "Interpolator")
|
||||
.def(py::init(
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
#include "aare/hist/PedestalTrackingPixelHistogram.hpp"
|
||||
#include "np_helper.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <pybind11/numpy.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
namespace py = pybind11;
|
||||
using namespace ::aare;
|
||||
|
||||
void define_pedestal_tracking_pixel_histogram_bindings(py::module &m) {
|
||||
py::class_<PedestalTrackingPixelHistogram>(
|
||||
m, "PedestalTrackingPixelHistogram",
|
||||
"A pixel-wise histogram of frame - pedestal residuals, with a "
|
||||
"per-pixel running pedestal estimate sharded across worker threads")
|
||||
.def(
|
||||
py::init<int, int, int, double, double, int, std::size_t, double>(),
|
||||
R"(
|
||||
Initialize a PedestalTrackingPixelHistogram.
|
||||
|
||||
Args:
|
||||
rows: Number of rows in the detector
|
||||
cols: Number of columns in the detector
|
||||
n_bins: Number of histogram bins along the residual axis
|
||||
xmin: Minimum residual value (inclusive)
|
||||
xmax: Maximum residual value (exclusive)
|
||||
n_threads: Number of worker threads (default: 1). Each
|
||||
worker owns a disjoint row slice of both the
|
||||
pedestal and the histogram, so the partition
|
||||
determines per-thread memory usage.
|
||||
max_pending: Maximum number of frames that can be
|
||||
queued for asynchronous filling before
|
||||
fill_async() applies backpressure
|
||||
on the caller (default: 16).
|
||||
n_sigma: Sigma multiplier used as the gate for the
|
||||
pedestal-update side effect of
|
||||
fill_async(): a pixel sample is
|
||||
pushed back into the pedestal estimate iff
|
||||
``abs(residual) < n_sigma * cached_std``. Set to
|
||||
``0.0`` to disable the pedestal update and get
|
||||
histogram-only async behaviour (default: 1.0).
|
||||
Also exposed live via the ``n_sigma`` property.
|
||||
)",
|
||||
py::kw_only(), py::arg("rows"), py::arg("cols"), py::arg("n_bins"),
|
||||
py::arg("xmin"), py::arg("xmax"), py::arg("n_threads") = 1,
|
||||
py::arg("max_pending") = std::size_t{16}, py::arg("n_sigma") = 1.0)
|
||||
|
||||
.def(
|
||||
"push_pedestal_no_update",
|
||||
[](PedestalTrackingPixelHistogram &self,
|
||||
py::array_t<PedestalTrackingPixelHistogram::FrameType, 0>
|
||||
frame) {
|
||||
auto view = make_view_2d(frame);
|
||||
self.push_pedestal_no_update(view);
|
||||
},
|
||||
R"(
|
||||
Accumulate `frame` into the per-pixel running pedestal
|
||||
estimate without refreshing the cached mean.
|
||||
|
||||
Use repeatedly while bootstrapping the pedestal, then call
|
||||
update_mean() once before starting to fill the histogram.
|
||||
|
||||
Args:
|
||||
frame: A 2D numpy array of raw pixel values (dtype: uint16)
|
||||
)",
|
||||
py::arg("frame").noconvert())
|
||||
|
||||
.def("update_mean", &PedestalTrackingPixelHistogram::update_mean,
|
||||
R"(
|
||||
Refresh each partial pedestal's cached per-pixel mean from
|
||||
its running sums. Drains pending async fills first, then
|
||||
dispatches the update to the worker pool so the writes to
|
||||
each shard happen on the same thread that reads them in
|
||||
fill_async().
|
||||
)",
|
||||
py::call_guard<py::gil_scoped_release>())
|
||||
|
||||
.def(
|
||||
"pedestal_mean",
|
||||
[](const PedestalTrackingPixelHistogram &self) {
|
||||
// pedestal_mean() flushes + locks + memcpys; do all of
|
||||
// that without the GIL, only reacquire to wrap into a
|
||||
// numpy array.
|
||||
NDArray<PedestalTrackingPixelHistogram::AxisType, 2> *ptr =
|
||||
nullptr;
|
||||
{
|
||||
py::gil_scoped_release release;
|
||||
ptr = new NDArray<PedestalTrackingPixelHistogram::AxisType,
|
||||
2>(self.pedestal_mean());
|
||||
}
|
||||
return return_image_data(ptr);
|
||||
},
|
||||
R"(
|
||||
Snapshot the per-pixel pedestal mean stitched together
|
||||
from all shards.
|
||||
|
||||
Returns:
|
||||
A 2D numpy array (rows x cols, dtype: float64)
|
||||
containing the current cached pedestal mean.
|
||||
)")
|
||||
|
||||
.def(
|
||||
"fill_async",
|
||||
[](PedestalTrackingPixelHistogram &self,
|
||||
py::array_t<PedestalTrackingPixelHistogram::FrameType, 0>
|
||||
image) {
|
||||
// Copy the numpy buffer into an owned NDArray while we
|
||||
// still hold the GIL so we don't depend on the array's
|
||||
// backing storage outliving this call.
|
||||
auto view = make_view_2d(image);
|
||||
NDArray<PedestalTrackingPixelHistogram::FrameType, 2> owned(
|
||||
view);
|
||||
// Release the GIL while enqueueing -
|
||||
// fill_async can block on backpressure
|
||||
// when the queue is full.
|
||||
py::gil_scoped_release release;
|
||||
self.fill_async(std::move(owned));
|
||||
},
|
||||
R"(
|
||||
Submit an image for asynchronous filling with sigma-clipped
|
||||
pedestal tracking.
|
||||
|
||||
For each pixel the worker pool:
|
||||
* histograms the pedestal-subtracted residual when it
|
||||
falls in ``[xmin, xmax)``, and
|
||||
* additionally pushes the raw pixel value back into the
|
||||
per-thread pedestal estimate when
|
||||
``abs(residual) < n_sigma * cached_std`` (the
|
||||
sigma-clipped pedestal-update gate).
|
||||
|
||||
The cached std is populated by ``update_mean()``, so
|
||||
``push_pedestal_no_update()`` + ``update_mean()`` must have
|
||||
run at least once for the pedestal-update side effect to
|
||||
fire. Setting ``n_sigma = 0`` disables the side effect and
|
||||
recovers plain histogram-only async filling.
|
||||
|
||||
The image is copied into an internal buffer before this call
|
||||
returns, so the caller may mutate or free the numpy array
|
||||
immediately. If the internal queue is full this call blocks
|
||||
(with the GIL released) until a slot becomes available.
|
||||
|
||||
Args:
|
||||
image: A 2D numpy array of raw pixel values (dtype: uint16)
|
||||
)",
|
||||
py::arg("image").noconvert())
|
||||
|
||||
.def("fill_from_file", &PedestalTrackingPixelHistogram::fill_from_file,
|
||||
R"(
|
||||
Fill the histogram from a file.
|
||||
|
||||
Args:
|
||||
file_path: Path to the file to fill from
|
||||
max_frames: Maximum number of frames to fill from the file (default: -1)
|
||||
)",
|
||||
py::call_guard<py::gil_scoped_release>(), py::arg("fname"),
|
||||
py::arg("max_frames") = -1, py::arg("verbose") = false)
|
||||
.def("process_pedestal_file",
|
||||
&PedestalTrackingPixelHistogram::process_pedestal_file,
|
||||
R"(
|
||||
Process a pedestal file.
|
||||
|
||||
Args:
|
||||
file_path: Path to the file to process
|
||||
max_frames: Maximum number of frames to process from the file (default: -1)
|
||||
)",
|
||||
py::call_guard<py::gil_scoped_release>(), py::arg("fname"),
|
||||
py::arg("max_frames") = -1, py::arg("verbose") = false)
|
||||
.def_property("n_sigma", &PedestalTrackingPixelHistogram::n_sigma,
|
||||
&PedestalTrackingPixelHistogram::set_n_sigma,
|
||||
R"(
|
||||
Sigma multiplier used as the pedestal-update gate in
|
||||
fill_async(). Atomic; safe to read or write
|
||||
from any thread. Setting it to 0.0 disables the pedestal
|
||||
update entirely. The new value takes effect on subsequent
|
||||
per-pixel evaluations inside the worker pool.
|
||||
)")
|
||||
|
||||
.def("flush", &PedestalTrackingPixelHistogram::flush,
|
||||
R"(
|
||||
Block until all images submitted via
|
||||
fill_async() have been merged into the
|
||||
accumulators. Cheap when nothing is pending.
|
||||
)",
|
||||
py::call_guard<py::gil_scoped_release>())
|
||||
|
||||
.def(
|
||||
"values",
|
||||
[](const PedestalTrackingPixelHistogram &self) {
|
||||
// values() implicitly flushes - release the GIL while it
|
||||
// does so. Allocation/copy into the NDArray runs without
|
||||
// the GIL too; only the numpy wrapping needs it.
|
||||
NDArray<PedestalTrackingPixelHistogram::StorageType, 3> *ptr =
|
||||
nullptr;
|
||||
{
|
||||
py::gil_scoped_release release;
|
||||
ptr =
|
||||
new NDArray<PedestalTrackingPixelHistogram::StorageType,
|
||||
3>(self.values());
|
||||
}
|
||||
return return_image_data(ptr);
|
||||
},
|
||||
R"(
|
||||
Get the histogram data as a numpy array.
|
||||
|
||||
Implicitly flushes any pending asynchronous fills before
|
||||
returning, so the snapshot is consistent with everything
|
||||
submitted up to this call.
|
||||
|
||||
Returns:
|
||||
A 3D numpy array (rows x cols x n_bins, dtype: uint16)
|
||||
containing the histogram bins for each pixel.
|
||||
)")
|
||||
|
||||
.def(
|
||||
"bin_centers",
|
||||
[](const PedestalTrackingPixelHistogram &self) {
|
||||
auto ptr =
|
||||
new NDArray<PedestalTrackingPixelHistogram::AxisType, 1>(
|
||||
self.bin_centers());
|
||||
return return_image_data(ptr);
|
||||
},
|
||||
R"(
|
||||
Get the bin centers along the residual axis.
|
||||
|
||||
Returns:
|
||||
A 1D numpy array (dtype: float32) of bin center values.
|
||||
)")
|
||||
|
||||
.def(
|
||||
"bin_edges",
|
||||
[](const PedestalTrackingPixelHistogram &self) {
|
||||
auto ptr =
|
||||
new NDArray<PedestalTrackingPixelHistogram::AxisType, 1>(
|
||||
self.bin_edges());
|
||||
return return_image_data(ptr);
|
||||
},
|
||||
R"(
|
||||
Get the bin edges along the residual axis.
|
||||
|
||||
Returns:
|
||||
A 1D numpy array (dtype: float32) of bin edge values.
|
||||
)");
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
#include "aare/hist/PixelHistogram.hpp"
|
||||
#include "np_helper.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <pybind11/numpy.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <string>
|
||||
|
||||
namespace py = pybind11;
|
||||
using namespace ::aare;
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename StorageType>
|
||||
void define_pixel_histogram_binding(py::module &m, const char *class_name,
|
||||
const char *storage_dtype) {
|
||||
using Hist = PixelHistogram<StorageType, double>;
|
||||
|
||||
const std::string doc =
|
||||
std::string("A histogram for pixel-wise statistics with float64 input "
|
||||
"axis and ") +
|
||||
storage_dtype + " bin storage";
|
||||
|
||||
py::class_<Hist>(m, class_name, doc.c_str())
|
||||
.def(py::init<int, int, int, double, double, int, std::size_t>(),
|
||||
R"(
|
||||
Initialize a PixelHistogram.
|
||||
|
||||
Args:
|
||||
rows: Number of rows in the detector
|
||||
cols: Number of columns in the detector
|
||||
n_bins: Number of histogram bins
|
||||
xmin: Minimum value for histogram range
|
||||
xmax: Maximum value for histogram range
|
||||
n_threads: Number of threads for parallel filling (default: 1)
|
||||
max_pending: Maximum number of images that can be queued for
|
||||
asynchronous filling before fill_async() applies
|
||||
backpressure on the caller (default: 16)
|
||||
)",
|
||||
py::kw_only(), py::arg("rows"), py::arg("cols"), py::arg("n_bins"),
|
||||
py::arg("xmin"), py::arg("xmax"), py::arg("n_threads") = 1,
|
||||
py::arg("max_pending") = std::size_t{16})
|
||||
|
||||
.def(
|
||||
"fill_async",
|
||||
[](Hist &self, py::array_t<double, 0> image) {
|
||||
// Copy the numpy buffer into an owned NDArray while we
|
||||
// still hold the GIL so we don't depend on the array's
|
||||
// backing storage outliving this call.
|
||||
auto view = make_view_2d(image);
|
||||
NDArray<double, 2> owned(view);
|
||||
// Release the GIL while enqueueing - fill_async can block
|
||||
// on backpressure when the queue is full.
|
||||
py::gil_scoped_release release;
|
||||
self.fill_async(std::move(owned));
|
||||
},
|
||||
R"(
|
||||
Submit an image for asynchronous filling.
|
||||
|
||||
The image is copied into an internal buffer before this call
|
||||
returns, so the caller may mutate or free the numpy array
|
||||
immediately. The actual histogram update happens on a
|
||||
background thread. If the internal queue is full this call
|
||||
blocks (with the GIL released) until a slot becomes available.
|
||||
|
||||
Args:
|
||||
image: A 2D numpy array of pixel values (dtype: float64)
|
||||
)",
|
||||
py::arg("image").noconvert())
|
||||
|
||||
.def("flush", &Hist::flush,
|
||||
R"(
|
||||
Block until all images submitted via fill_async() have been
|
||||
merged into the accumulators. Cheap when nothing is pending.
|
||||
)",
|
||||
py::call_guard<py::gil_scoped_release>())
|
||||
|
||||
.def(
|
||||
"values",
|
||||
[](const Hist &self) {
|
||||
// values() implicitly flushes - release the GIL while it
|
||||
// does so. Allocation/copy into the NDArray runs without
|
||||
// the GIL too; only the numpy wrapping needs it.
|
||||
NDArray<StorageType, 3> *ptr = nullptr;
|
||||
{
|
||||
py::gil_scoped_release release;
|
||||
ptr = new NDArray<StorageType, 3>(self.values());
|
||||
}
|
||||
return return_image_data(ptr);
|
||||
},
|
||||
R"(
|
||||
Get the histogram data as a numpy array.
|
||||
|
||||
Implicitly flushes any pending asynchronous fills before
|
||||
returning, so the snapshot is consistent with everything
|
||||
submitted up to this call.
|
||||
|
||||
Returns:
|
||||
A 3D numpy array containing the histogram bins for each pixel
|
||||
)")
|
||||
|
||||
.def(
|
||||
"bin_centers",
|
||||
[](const Hist &self) {
|
||||
auto ptr = new NDArray<double, 1>(self.bin_centers());
|
||||
return return_image_data(ptr);
|
||||
},
|
||||
R"(
|
||||
Get the bin centers along the value axis.
|
||||
|
||||
Returns:
|
||||
A 1D numpy array containing the center values for each histogram bin
|
||||
)")
|
||||
.def(
|
||||
"bin_edges",
|
||||
[](const Hist &self) {
|
||||
auto ptr = new NDArray<double, 1>(self.bin_edges());
|
||||
return return_image_data(ptr);
|
||||
},
|
||||
R"(
|
||||
Get the bin edges along the value axis.
|
||||
|
||||
Returns:
|
||||
A 1D numpy array containing the edge values for the histogram bins
|
||||
)");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void define_pixel_histogram_bindings(py::module &m) {
|
||||
define_pixel_histogram_binding<double>(m, "PixelHistogram_d", "float64");
|
||||
define_pixel_histogram_binding<float>(m, "PixelHistogram_f", "float32");
|
||||
define_pixel_histogram_binding<std::uint64_t>(m, "PixelHistogram_u64",
|
||||
"uint64");
|
||||
define_pixel_histogram_binding<std::uint32_t>(m, "PixelHistogram_u32",
|
||||
"uint32");
|
||||
define_pixel_histogram_binding<std::uint16_t>(m, "PixelHistogram_u16",
|
||||
"uint16");
|
||||
define_pixel_histogram_binding<std::uint8_t>(m, "PixelHistogram_u8",
|
||||
"uint8");
|
||||
|
||||
// Backwards-compatible alias for the generic Python class name.
|
||||
m.attr("PixelHistogram") = m.attr("PixelHistogram_d");
|
||||
}
|
||||
@@ -280,6 +280,7 @@ void define_raw_file_io_bindings(py::module &m) {
|
||||
.def("tell", &RawFile::tell, R"(
|
||||
Return the current frame number.)")
|
||||
.def_property_readonly("total_frames", &RawFile::total_frames)
|
||||
.def("__len__", &RawFile::total_frames)
|
||||
.def("rows", static_cast<size_t (RawFile::*)() const>(&RawFile::rows))
|
||||
.def(
|
||||
"rows",
|
||||
|
||||
@@ -226,5 +226,7 @@ void define_ctb_raw_file_io_bindings(py::module &m) {
|
||||
.def_property_readonly("image_size_in_bytes",
|
||||
&CtbRawFile::image_size_in_bytes)
|
||||
|
||||
.def_property_readonly("frames_in_file", &CtbRawFile::frames_in_file);
|
||||
.def_property_readonly("frames_in_file", &CtbRawFile::frames_in_file)
|
||||
.def_property_readonly("total_frames", &CtbRawFile::total_frames)
|
||||
.def("__len__", &CtbRawFile::total_frames);
|
||||
}
|
||||
@@ -60,6 +60,7 @@ void define_file_io_bindings(py::module &m) {
|
||||
.def("seek", &File::seek)
|
||||
.def("tell", &File::tell)
|
||||
.def_property_readonly("total_frames", &File::total_frames)
|
||||
.def("__len__", &File::total_frames)
|
||||
.def_property_readonly("rows", &File::rows)
|
||||
.def_property_readonly("cols", &File::cols)
|
||||
.def_property_readonly("bitdepth", &File::bitdepth)
|
||||
|
||||
+52
-25
@@ -5,7 +5,6 @@
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/stl_bind.h>
|
||||
|
||||
#include "aare/Chi2.hpp"
|
||||
#include "aare/Fit.hpp"
|
||||
#include "aare/FitModel.hpp"
|
||||
#include "aare/Models.hpp"
|
||||
@@ -13,7 +12,7 @@
|
||||
namespace py = pybind11;
|
||||
using namespace pybind11::literals;
|
||||
|
||||
template <typename Model, typename FCN>
|
||||
template <typename Model>
|
||||
py::object
|
||||
fit_dispatch(const aare::FitModel<Model> &model,
|
||||
py::array_t<double, py::array::c_style | py::array::forcecast> x,
|
||||
@@ -22,7 +21,6 @@ fit_dispatch(const aare::FitModel<Model> &model,
|
||||
|
||||
template <typename Model> void bind_fit_model(py::module &m, const char *name) {
|
||||
using FM = aare::FitModel<Model>;
|
||||
using FCN = aare::func::Chi2Model1DGrad<Model>;
|
||||
py::class_<FM>(m, name)
|
||||
.def(py::init<unsigned int, unsigned int, double, bool>(),
|
||||
py::arg("strategy") = 0, py::arg("max_calls") = 100,
|
||||
@@ -85,8 +83,7 @@ template <typename Model> void bind_fit_model(py::module &m, const char *name) {
|
||||
py::array_t<double, py::array::c_style | py::array::forcecast> x,
|
||||
py::array_t<double, py::array::c_style | py::array::forcecast> y,
|
||||
py::object y_err_obj, int n_threads) -> py::object {
|
||||
return fit_dispatch<Model, FCN>(self, x, y, y_err_obj,
|
||||
n_threads);
|
||||
return fit_dispatch<Model>(self, x, y, y_err_obj, n_threads);
|
||||
},
|
||||
R"doc(
|
||||
Fit this model to 1D or 3D data using Minuit2.
|
||||
@@ -145,7 +142,7 @@ py::dict pack_1d_result_dict(const aare::NDArray<double, 1> &result,
|
||||
}
|
||||
|
||||
// Helper: typed dispatch for one Model, handles 1D/3D + y_err logic
|
||||
template <typename Model, typename FCN>
|
||||
template <typename Model>
|
||||
py::object
|
||||
fit_dispatch(const aare::FitModel<Model> &model,
|
||||
py::array_t<double, py::array::c_style | py::array::forcecast> x,
|
||||
@@ -175,9 +172,9 @@ fit_dispatch(const aare::FitModel<Model> &model,
|
||||
new NDArray<double, 3>({y.shape(0), y.shape(1), npar}, 0.0);
|
||||
auto y_view_err = make_view_3d(y_err);
|
||||
|
||||
aare::fit_3d<Model, FCN>(model, x_view, y_view, y_view_err,
|
||||
par_out->view(), err_out->view(),
|
||||
chi2_out->view(), n_threads);
|
||||
aare::fit_3d<Model>(model, x_view, y_view, y_view_err,
|
||||
par_out->view(), err_out->view(),
|
||||
chi2_out->view(), n_threads);
|
||||
|
||||
if (model.compute_errors()) {
|
||||
return py::dict("par"_a = return_image_data(par_out),
|
||||
@@ -193,9 +190,9 @@ fit_dispatch(const aare::FitModel<Model> &model,
|
||||
NDView<double, 3> dummy_err{};
|
||||
NDView<double, 3> dummy_err_out{};
|
||||
|
||||
aare::fit_3d<Model, FCN>(model, x_view, y_view, dummy_err,
|
||||
par_out->view(), dummy_err_out,
|
||||
chi2_out->view(), n_threads);
|
||||
aare::fit_3d<Model>(model, x_view, y_view, dummy_err,
|
||||
par_out->view(), dummy_err_out,
|
||||
chi2_out->view(), n_threads);
|
||||
|
||||
return py::dict("par"_a = return_image_data(par_out),
|
||||
"chi2"_a = return_image_data(chi2_out));
|
||||
@@ -217,10 +214,9 @@ fit_dispatch(const aare::FitModel<Model> &model,
|
||||
}
|
||||
|
||||
auto y_view_err = make_view_1d(y_err);
|
||||
result =
|
||||
aare::fit_pixel<Model, FCN>(model, x_view, y_view, y_view_err);
|
||||
result = aare::fit_pixel<Model>(model, x_view, y_view, y_view_err);
|
||||
} else {
|
||||
result = aare::fit_pixel<Model, FCN>(model, x_view, y_view);
|
||||
result = aare::fit_pixel<Model>(model, x_view, y_view);
|
||||
}
|
||||
|
||||
return pack_1d_result_dict<Model>(result, model.compute_errors());
|
||||
@@ -679,6 +675,11 @@ void define_fit_bindings(py::module &m) {
|
||||
|
||||
// ── Bind model classes ──────────────────────────────────────────
|
||||
bind_fit_model<aare::model::Gaussian>(m, "Gaussian");
|
||||
bind_fit_model<aare::model::GaussianErfcPlateau>(m, "GaussianErfcPlateau");
|
||||
bind_fit_model<aare::model::GaussianChargeSharing>(m,
|
||||
"GaussianChargeSharing");
|
||||
bind_fit_model<aare::model::GaussianChargeSharingKb>(
|
||||
m, "GaussianChargeSharingKb");
|
||||
bind_fit_model<aare::model::RisingScurve>(m, "RisingScurve");
|
||||
bind_fit_model<aare::model::FallingScurve>(m, "FallingScurve");
|
||||
bind_fit_model<aare::model::Pol1>(m, "Pol1");
|
||||
@@ -691,28 +692,54 @@ void define_fit_bindings(py::module &m) {
|
||||
py::array_t<double, py::array::c_style | py::array::forcecast> y,
|
||||
py::object y_err_obj, int n_threads) -> py::object {
|
||||
using namespace aare::model;
|
||||
using namespace aare::func;
|
||||
|
||||
// ── Polynomial of degree 1 ───────
|
||||
if (py::isinstance<aare::FitModel<Pol1>>(model_obj)) {
|
||||
const auto &mdl =
|
||||
model_obj.cast<const aare::FitModel<Pol1> &>();
|
||||
return fit_dispatch<Pol1, Chi2Pol1>(mdl, x, y, y_err_obj,
|
||||
n_threads);
|
||||
return fit_dispatch<Pol1>(mdl, x, y, y_err_obj, n_threads);
|
||||
}
|
||||
|
||||
// ── Polynomial of degree 2 ───────
|
||||
if (py::isinstance<aare::FitModel<Pol2>>(model_obj)) {
|
||||
const auto &mdl =
|
||||
model_obj.cast<const aare::FitModel<Pol2> &>();
|
||||
return fit_dispatch<Pol2, Chi2Pol2>(mdl, x, y, y_err_obj,
|
||||
n_threads);
|
||||
return fit_dispatch<Pol2>(mdl, x, y, y_err_obj, n_threads);
|
||||
}
|
||||
|
||||
// ── Gaussian ───────
|
||||
if (py::isinstance<aare::FitModel<Gaussian>>(model_obj)) {
|
||||
const auto &mdl =
|
||||
model_obj.cast<const aare::FitModel<Gaussian> &>();
|
||||
return fit_dispatch<Gaussian, Chi2Gaussian>(
|
||||
return fit_dispatch<Gaussian>(mdl, x, y, y_err_obj, n_threads);
|
||||
}
|
||||
|
||||
// ── GaussianErfcPlateau ───────
|
||||
if (py::isinstance<aare::FitModel<GaussianErfcPlateau>>(
|
||||
model_obj)) {
|
||||
const auto &mdl =
|
||||
model_obj
|
||||
.cast<const aare::FitModel<GaussianErfcPlateau> &>();
|
||||
return fit_dispatch<GaussianErfcPlateau>(mdl, x, y, y_err_obj,
|
||||
n_threads);
|
||||
}
|
||||
|
||||
// ── GaussianChargeSharing ───────
|
||||
if (py::isinstance<aare::FitModel<GaussianChargeSharing>>(
|
||||
model_obj)) {
|
||||
const auto &mdl =
|
||||
model_obj
|
||||
.cast<const aare::FitModel<GaussianChargeSharing> &>();
|
||||
return fit_dispatch<GaussianChargeSharing>(mdl, x, y, y_err_obj,
|
||||
n_threads);
|
||||
}
|
||||
|
||||
// ── GaussianChargeSharingKb ───────
|
||||
if (py::isinstance<aare::FitModel<GaussianChargeSharingKb>>(
|
||||
model_obj)) {
|
||||
const auto &mdl = model_obj.cast<
|
||||
const aare::FitModel<GaussianChargeSharingKb> &>();
|
||||
return fit_dispatch<GaussianChargeSharingKb>(
|
||||
mdl, x, y, y_err_obj, n_threads);
|
||||
}
|
||||
|
||||
@@ -720,16 +747,16 @@ void define_fit_bindings(py::module &m) {
|
||||
if (py::isinstance<aare::FitModel<RisingScurve>>(model_obj)) {
|
||||
const auto &mdl =
|
||||
model_obj.cast<const aare::FitModel<RisingScurve> &>();
|
||||
return fit_dispatch<RisingScurve, Chi2RisingScurve>(
|
||||
mdl, x, y, y_err_obj, n_threads);
|
||||
return fit_dispatch<RisingScurve>(mdl, x, y, y_err_obj,
|
||||
n_threads);
|
||||
}
|
||||
|
||||
// ── Falling Scurve ───────
|
||||
if (py::isinstance<aare::FitModel<FallingScurve>>(model_obj)) {
|
||||
const auto &mdl =
|
||||
model_obj.cast<const aare::FitModel<FallingScurve> &>();
|
||||
return fit_dispatch<FallingScurve, Chi2FallingScurve>(
|
||||
mdl, x, y, y_err_obj, n_threads);
|
||||
return fit_dispatch<FallingScurve>(mdl, x, y, y_err_obj,
|
||||
n_threads);
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
|
||||
@@ -72,6 +72,7 @@ void define_jungfrau_data_file_io_bindings(py::module &m) {
|
||||
.def_property_readonly("bitdepth", &JungfrauDataFile::bitdepth)
|
||||
.def_property_readonly("current_file", &JungfrauDataFile::current_file)
|
||||
.def_property_readonly("total_frames", &JungfrauDataFile::total_frames)
|
||||
.def("__len__", &JungfrauDataFile::total_frames)
|
||||
.def_property_readonly("n_files", &JungfrauDataFile::n_files)
|
||||
.def("read_frame", &read_dat_frame,
|
||||
R"(
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "bind_Defs.hpp"
|
||||
#include "bind_Eta.hpp"
|
||||
#include "bind_Interpolator.hpp"
|
||||
#include "bind_PedestalTrackingPixelHistogram.hpp"
|
||||
#include "bind_PixelHistogram.hpp"
|
||||
#include "bind_PixelMap.hpp"
|
||||
#include "bind_RawFile.hpp"
|
||||
#include "bind_calibration.hpp"
|
||||
@@ -64,6 +66,8 @@ PYBIND11_MODULE(_aare, m) {
|
||||
define_raw_master_file_bindings(m);
|
||||
define_var_cluster_finder_bindings(m);
|
||||
define_pixel_map_bindings(m);
|
||||
define_pixel_histogram_bindings(m);
|
||||
define_pedestal_tracking_pixel_histogram_bindings(m);
|
||||
define_pedestal_bindings<double>(m, "Pedestal_d");
|
||||
define_pedestal_bindings<float>(m, "Pedestal_f");
|
||||
define_fit_bindings(m);
|
||||
|
||||
+61
-3
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <pybind11/numpy.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
@@ -12,7 +13,8 @@ namespace py = pybind11;
|
||||
|
||||
template <typename SUM_TYPE>
|
||||
void define_pedestal_bindings(py::module &m, const std::string &name) {
|
||||
py::class_<Pedestal<SUM_TYPE>>(m, name.c_str())
|
||||
|
||||
py::class_<Pedestal<SUM_TYPE>>(m, name.c_str(), py::buffer_protocol())
|
||||
.def(py::init<int, int, int>())
|
||||
.def(py::init<int, int>())
|
||||
.def("mean",
|
||||
@@ -21,6 +23,23 @@ void define_pedestal_bindings(py::module &m, const std::string &name) {
|
||||
*mea = self.mean();
|
||||
return return_image_data(mea);
|
||||
})
|
||||
.def("view",
|
||||
[](py::object self_py) {
|
||||
auto &self = self_py.cast<Pedestal<SUM_TYPE> &>();
|
||||
auto v = self.view();
|
||||
std::array<py::ssize_t, 2> shape{
|
||||
static_cast<py::ssize_t>(v.shape(0)),
|
||||
static_cast<py::ssize_t>(v.shape(1))};
|
||||
std::array<py::ssize_t, 2> byte_strides{
|
||||
static_cast<py::ssize_t>(v.strides()[0]) *
|
||||
static_cast<py::ssize_t>(sizeof(SUM_TYPE)),
|
||||
static_cast<py::ssize_t>(v.strides()[1]) *
|
||||
static_cast<py::ssize_t>(sizeof(SUM_TYPE))};
|
||||
auto arr = py::array_t<SUM_TYPE>(shape, byte_strides, v.data(),
|
||||
self_py);
|
||||
arr.attr("setflags")(py::arg("write") = false);
|
||||
return arr;
|
||||
})
|
||||
.def("variance",
|
||||
[](Pedestal<SUM_TYPE> &self) {
|
||||
auto var = new NDArray<SUM_TYPE, 2>{};
|
||||
@@ -33,6 +52,23 @@ void define_pedestal_bindings(py::module &m, const std::string &name) {
|
||||
*std = self.std();
|
||||
return return_image_data(std);
|
||||
})
|
||||
.def(
|
||||
"__array_ufunc__",
|
||||
[](py::object self, py::object ufunc, const std::string &method,
|
||||
py::args inputs, py::kwargs kwargs) -> py::object {
|
||||
if (method != "__call__" || inputs.size() != 2 ||
|
||||
inputs[1].ptr() != self.ptr() ||
|
||||
py::cast<std::string>(ufunc.attr("__name__")) !=
|
||||
"subtract") {
|
||||
return py::reinterpret_borrow<py::object>(
|
||||
Py_NotImplemented);
|
||||
}
|
||||
|
||||
auto mean =
|
||||
py::module_::import("builtins").attr("memoryview")(self);
|
||||
return ufunc(inputs[0], mean, **kwargs);
|
||||
},
|
||||
"Support subtracting a Pedestal from a NumPy array.")
|
||||
.def("clear", py::overload_cast<>(&Pedestal<SUM_TYPE>::clear))
|
||||
.def_property_readonly("rows", &Pedestal<SUM_TYPE>::rows)
|
||||
.def_property_readonly("cols", &Pedestal<SUM_TYPE>::cols)
|
||||
@@ -49,6 +85,16 @@ void define_pedestal_bindings(py::module &m, const std::string &name) {
|
||||
auto v = make_view_2d(f);
|
||||
pedestal.push(v);
|
||||
})
|
||||
.def(
|
||||
"push_with_threshold",
|
||||
[](Pedestal<SUM_TYPE> &pedestal,
|
||||
py::array_t<uint16_t, py::array::c_style> &f,
|
||||
py::array_t<SUM_TYPE, py::array::c_style> &threshold) {
|
||||
auto frame_view = make_view_2d(f);
|
||||
auto threshold_view = make_view_2d(threshold);
|
||||
pedestal.push_with_threshold(frame_view, threshold_view);
|
||||
},
|
||||
py::arg("frame").noconvert(), py::arg("threshold").noconvert())
|
||||
.def(
|
||||
"push_no_update",
|
||||
[](Pedestal<SUM_TYPE> &pedestal,
|
||||
@@ -57,5 +103,17 @@ void define_pedestal_bindings(py::module &m, const std::string &name) {
|
||||
pedestal.push_no_update(v);
|
||||
},
|
||||
py::arg().noconvert())
|
||||
.def("update_mean", &Pedestal<SUM_TYPE>::update_mean);
|
||||
}
|
||||
.def("update_mean", &Pedestal<SUM_TYPE>::update_mean)
|
||||
.def_buffer([](Pedestal<SUM_TYPE> &self) {
|
||||
auto mean = self.view();
|
||||
return py::buffer_info(
|
||||
const_cast<SUM_TYPE *>(mean.data()), sizeof(SUM_TYPE),
|
||||
py::format_descriptor<SUM_TYPE>::format(), 2,
|
||||
{static_cast<py::ssize_t>(mean.shape(0)),
|
||||
static_cast<py::ssize_t>(mean.shape(1))},
|
||||
{static_cast<py::ssize_t>(mean.strides()[0] * sizeof(SUM_TYPE)),
|
||||
static_cast<py::ssize_t>(mean.strides()[1] *
|
||||
sizeof(SUM_TYPE))},
|
||||
true);
|
||||
});
|
||||
}
|
||||
@@ -34,6 +34,10 @@ void define_var_cluster_finder_bindings(py::module &m) {
|
||||
auto noise_map_span = make_view_2d(noise_map);
|
||||
self.set_noiseMap(noise_map_span);
|
||||
})
|
||||
.def("set_numberOfNeighbours",
|
||||
&VarClusterFinder<double>::set_numberOfNeighbours)
|
||||
.def("set_empty_surroundingPixels",
|
||||
&VarClusterFinder<double>::set_empty_surroundingPixels)
|
||||
.def("set_peripheralThresholdFactor",
|
||||
&VarClusterFinder<double>::set_peripheralThresholdFactor)
|
||||
.def("find_clusters",
|
||||
|
||||
@@ -0,0 +1,357 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fbdc2fb9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Test `GaussianErfcPlateau` Python bindings\n",
|
||||
"\n",
|
||||
"Minimal check for the Aare Minuit2 object API against a SciPy `curve_fit` reference.\n",
|
||||
"\n",
|
||||
"Model:\n",
|
||||
"\n",
|
||||
"\\[\n",
|
||||
"f(x) =\n",
|
||||
"A \\exp\\left[-\\frac{1}{2}\\left(\\frac{x-\\mu}{\\sigma}\\right)^2\\right]\n",
|
||||
"+\n",
|
||||
"\\frac{S}{2}\\left[\n",
|
||||
"1 - \\operatorname{erf}\\left(\n",
|
||||
"\\frac{x-\\mu}{\\sqrt{2}\\sigma}\n",
|
||||
"\\right)\n",
|
||||
"\\right]\n",
|
||||
"\\]\n",
|
||||
"\n",
|
||||
"Parameter order:\n",
|
||||
"\n",
|
||||
"```text\n",
|
||||
"[A, S, mu, sigma]\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "2835b05b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import time\n",
|
||||
"import numpy as np\n",
|
||||
"np.set_printoptions(suppress=True, precision=6)\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"from scipy.special import erf\n",
|
||||
"from scipy.optimize import curve_fit\n",
|
||||
"from pprint import pprint\n",
|
||||
"\n",
|
||||
"import sys\n",
|
||||
"sys.path.insert(0, \"/home/ferjao_k/aare/build\")\n",
|
||||
"from aare import GaussianErfcPlateau"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "feb3872d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def gaussian_erfc_plateau(x, p):\n",
|
||||
" A, S, mu, sigma = p\n",
|
||||
" z = (x - mu) / (np.sqrt(2.0) * sigma)\n",
|
||||
" return A * np.exp(-0.5 * ((x - mu) / sigma)**2) + 0.5 * S * (1.0 - erf(z))\n",
|
||||
"\n",
|
||||
"def gaussian_erfc_plateau_curve_fit(x, A, S, mu, sigma):\n",
|
||||
" return gaussian_erfc_plateau(x, np.array([A, S, mu, sigma], dtype=float))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "4e10fc29",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png":
|
||||
"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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 800x400 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Synthetic data\n",
|
||||
"rng = np.random.default_rng(42)\n",
|
||||
"\n",
|
||||
"x = np.linspace(-4.0, 6.0, 251)\n",
|
||||
"\n",
|
||||
"p_true = np.array([\n",
|
||||
" 1.20, # A: Gaussian amplitude\n",
|
||||
" 1.00, # S: left plateau height\n",
|
||||
" 1.00, # mu: shared center / step position\n",
|
||||
" 0.65, # sigma: shared width\n",
|
||||
"])\n",
|
||||
"\n",
|
||||
"noise_sigma = 0.035\n",
|
||||
"\n",
|
||||
"y_true = gaussian_erfc_plateau(x, p_true)\n",
|
||||
"y = y_true + rng.normal(0.0, noise_sigma, size=x.shape)\n",
|
||||
"y_err = np.full_like(x, noise_sigma)\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(8, 4))\n",
|
||||
"plt.plot(x, y_true, label=\"true\")\n",
|
||||
"plt.scatter(x, y, s=10, label=\"noisy data\")\n",
|
||||
"plt.xlabel(\"x\")\n",
|
||||
"plt.ylabel(\"y\")\n",
|
||||
"plt.title(\"Synthetic Gaussian + erfc plateau data\")\n",
|
||||
"plt.legend()\n",
|
||||
"plt.grid(True, alpha=0.3)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "20571047",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"True params : [1.2 1. 1. 0.65]\n",
|
||||
"SciPy params: [1.19916 1.000479 1.005638 0.64249 ]\n",
|
||||
"SciPy abs error: [0.00084 0.000479 0.005638 0.00751 ]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# SciPy reference fit\n",
|
||||
"p0_ref = np.array([1.0, 0.8, 0.5, 0.8])\n",
|
||||
"\n",
|
||||
"bounds_ref = (\n",
|
||||
" [-np.inf, -np.inf, -np.inf, 1e-12],\n",
|
||||
" [ np.inf, np.inf, np.inf, np.inf],\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"p_scipy, cov_scipy = curve_fit(\n",
|
||||
" gaussian_erfc_plateau_curve_fit,\n",
|
||||
" x,\n",
|
||||
" y,\n",
|
||||
" p0=p0_ref,\n",
|
||||
" sigma=y_err,\n",
|
||||
" absolute_sigma=True,\n",
|
||||
" bounds=bounds_ref,\n",
|
||||
" maxfev=20_000,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"True params : \", p_true)\n",
|
||||
"print(\"SciPy params: \", p_scipy)\n",
|
||||
"print(\"SciPy abs error:\", np.abs(p_scipy - p_true))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "60ae684f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Parameter list:\n",
|
||||
"['A', 'S', 'mu', 'sigma']\n",
|
||||
"n_par: 4\n",
|
||||
"\n",
|
||||
"== Tuned fit settings ==\n",
|
||||
"max_calls : 1000\n",
|
||||
"tolerance : 0.01\n",
|
||||
"compute_errors : True\n",
|
||||
"\n",
|
||||
"== Aare / Minuit2 result ==\n",
|
||||
"{'par': array([1.199158, 1.000478, 1.00564 , 0.642494]),\n",
|
||||
" 'par_err': array([0.008525, 0.003768, 0.005623, 0.005163]),\n",
|
||||
" 'chi2': array([218.22232])}\n",
|
||||
"\n",
|
||||
"True params : [1.2 1. 1. 0.65]\n",
|
||||
"SciPy params : [1.19916 1.000479 1.005638 0.64249 ]\n",
|
||||
"Aare params : [1.199158 1.000478 1.00564 0.642494]\n",
|
||||
"SciPy abs error : [0.00084 0.000479 0.005638 0.00751 ]\n",
|
||||
"Aare abs error : [0.000842 0.000478 0.00564 0.007506]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Aare / Minuit2 object API fit\n",
|
||||
"model = GaussianErfcPlateau()\n",
|
||||
"\n",
|
||||
"print(\"Parameter list:\")\n",
|
||||
"print(model.par_names)\n",
|
||||
"print(\"n_par:\", model.n_par)\n",
|
||||
"print()\n",
|
||||
"\n",
|
||||
"# Optional: provide explicit starts close enough to avoid relying only on estimate_par().\n",
|
||||
"model.SetParameter(\"A\", 1.0)\n",
|
||||
"model.SetParameter(\"S\", 0.8)\n",
|
||||
"model.SetParameter(\"mu\", 0.5)\n",
|
||||
"model.SetParameter(\"sigma\", 0.8)\n",
|
||||
"\n",
|
||||
"# Optional fit settings\n",
|
||||
"model.compute_errors = True\n",
|
||||
"model.max_calls = 1000\n",
|
||||
"model.tolerance = 0.01\n",
|
||||
"\n",
|
||||
"print(\"== Tuned fit settings ==\")\n",
|
||||
"print(f\"max_calls : {model.max_calls}\")\n",
|
||||
"print(f\"tolerance : {model.tolerance}\")\n",
|
||||
"print(f\"compute_errors : {model.compute_errors}\")\n",
|
||||
"print()\n",
|
||||
"\n",
|
||||
"res_aare = model.fit(x, y, y_err)\n",
|
||||
"\n",
|
||||
"print(\"== Aare / Minuit2 result ==\")\n",
|
||||
"pprint(res_aare, sort_dicts=False)\n",
|
||||
"\n",
|
||||
"p_aare = np.array(res_aare[\"par\"], dtype=float)\n",
|
||||
"\n",
|
||||
"print()\n",
|
||||
"print(\"True params : \", p_true)\n",
|
||||
"print(\"SciPy params : \", p_scipy)\n",
|
||||
"print(\"Aare params : \", p_aare)\n",
|
||||
"print(\"SciPy abs error : \", np.abs(p_scipy - p_true))\n",
|
||||
"print(\"Aare abs error : \", np.abs(p_aare - p_true))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "3f1f13e0",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png":
|
||||
"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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 800x400 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"plt.figure(figsize=(8, 4))\n",
|
||||
"\n",
|
||||
"# plt.plot(x, y_true, label=\"true\")\n",
|
||||
"plt.scatter(x, y, s=10, label=\"data\", color=\"tab:blue\")\n",
|
||||
"plt.plot(x, gaussian_erfc_plateau(x, p_scipy), linewidth=4.0, label=\"SciPy curve_fit\", color=\"tab:red\")\n",
|
||||
"plt.plot(x, model(x, p_aare), linewidth=1.0, label=\"Aare Minuit2\", color=\"tab:cyan\")\n",
|
||||
"\n",
|
||||
"plt.xlabel(\"x\")\n",
|
||||
"plt.ylabel(\"y\")\n",
|
||||
"plt.title(\"Gaussian + erfc plateau fit comparison\")\n",
|
||||
"plt.legend()\n",
|
||||
"plt.grid(True, alpha=0.3)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "1359c6b6",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"SciPy curve_fit : 1.273 ms\n",
|
||||
"Aare Minuit2 : 0.159 ms\n",
|
||||
"\n",
|
||||
"SciPy bench params: [1.19916 1.000479 1.005638 0.64249 ]\n",
|
||||
"Aare bench params : [1.199158 1.000478 1.00564 0.642494]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def bench(fn, n_repeats=200):\n",
|
||||
" for _ in range(3):\n",
|
||||
" fn()\n",
|
||||
"\n",
|
||||
" t0 = time.perf_counter()\n",
|
||||
" for _ in range(n_repeats):\n",
|
||||
" res = fn()\n",
|
||||
" t1 = time.perf_counter()\n",
|
||||
"\n",
|
||||
" return res, (t1 - t0) / n_repeats\n",
|
||||
"\n",
|
||||
"def fit_scipy_once():\n",
|
||||
" return curve_fit(\n",
|
||||
" gaussian_erfc_plateau_curve_fit,\n",
|
||||
" x,\n",
|
||||
" y,\n",
|
||||
" p0=p0_ref,\n",
|
||||
" sigma=y_err,\n",
|
||||
" absolute_sigma=True,\n",
|
||||
" bounds=bounds_ref,\n",
|
||||
" maxfev=20_000,\n",
|
||||
" )[0]\n",
|
||||
"\n",
|
||||
"def fit_aare_once():\n",
|
||||
" m = GaussianErfcPlateau()\n",
|
||||
" m.SetParameter(\"A\", 1.0)\n",
|
||||
" m.SetParameter(\"S\", 0.8)\n",
|
||||
" m.SetParameter(\"mu\", 0.5)\n",
|
||||
" m.SetParameter(\"sigma\", 0.8)\n",
|
||||
" m.max_calls = 1000\n",
|
||||
" m.tolerance = 0.01\n",
|
||||
" return m.fit(x, y, y_err)[\"par\"]\n",
|
||||
"\n",
|
||||
"p_scipy_bench, t_scipy = bench(fit_scipy_once, n_repeats=200)\n",
|
||||
"p_aare_bench, t_aare = bench(fit_aare_once, n_repeats=200)\n",
|
||||
"\n",
|
||||
"print(f\"SciPy curve_fit : {1e3*t_scipy:.3f} ms\")\n",
|
||||
"print(f\"Aare Minuit2 : {1e3*t_aare:.3f} ms\")\n",
|
||||
"print()\n",
|
||||
"print(\"SciPy bench params:\", p_scipy_bench)\n",
|
||||
"print(\"Aare bench params :\", p_aare_bench)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f6c02fe0-c642-470b-965a-f6931ac74726",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,404 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "bb29ae9f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Test `GaussianChargeSharingKb` Python bindings\n",
|
||||
"\n",
|
||||
"This notebook tests and benchmarks the Aare Minuit2 object API for the 8-parameter Kα/Kβ charge-sharing model.\n",
|
||||
"\n",
|
||||
"\\[\n",
|
||||
"f(x)=p_0-p_1x+N\\left[\n",
|
||||
"G_\\alpha(x)+qG_\\beta(x)+C H_\\alpha(x)+qC H_\\beta(x)\n",
|
||||
"\\right]\n",
|
||||
"\\]\n",
|
||||
"\n",
|
||||
"with\n",
|
||||
"\n",
|
||||
"\\[\n",
|
||||
"\\mu_\\beta = r\\mu_\\alpha\n",
|
||||
"\\]\n",
|
||||
"\n",
|
||||
"Parameter order:\n",
|
||||
"\n",
|
||||
"```text\n",
|
||||
"[p0, p1, mu, sigma, N, C, kb_mean, kb_frac]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"where:\n",
|
||||
"\n",
|
||||
"```text\n",
|
||||
"kb_mean = r\n",
|
||||
"kb_frac = q\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "e6de205a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import time\n",
|
||||
"import numpy as np\n",
|
||||
"np.set_printoptions(suppress=True, precision=6)\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"from scipy.special import erf\n",
|
||||
"from scipy.optimize import curve_fit\n",
|
||||
"from pprint import pprint\n",
|
||||
"\n",
|
||||
"import sys\n",
|
||||
"sys.path.insert(0, \"/home/ferjao_k/sw/aare/build\")\n",
|
||||
"\n",
|
||||
"from aare import GaussianChargeSharingKb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "4ad6bc4a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def gaussian_charge_sharing_kb(x, p):\n",
|
||||
" p0, p1, mu, sigma, N, C, kb_mean, kb_frac = p\n",
|
||||
"\n",
|
||||
" mu_b = kb_mean * mu\n",
|
||||
"\n",
|
||||
" u = (x - mu) / sigma\n",
|
||||
" ub = (x - mu_b) / sigma\n",
|
||||
"\n",
|
||||
" G = np.exp(-0.5 * u**2)\n",
|
||||
" Gb = np.exp(-0.5 * ub**2)\n",
|
||||
"\n",
|
||||
" H = 0.5 * (1.0 - erf(u / np.sqrt(2.0)))\n",
|
||||
" Hb = 0.5 * (1.0 - erf(ub / np.sqrt(2.0)))\n",
|
||||
"\n",
|
||||
" return p0 - p1 * x + N * (G + kb_frac * Gb + C * H + kb_frac * C * Hb)\n",
|
||||
"\n",
|
||||
"def gaussian_charge_sharing_kb_curve_fit(x, p0, p1, mu, sigma, N, C, kb_mean, kb_frac):\n",
|
||||
" return gaussian_charge_sharing_kb(\n",
|
||||
" x,\n",
|
||||
" np.array([p0, p1, mu, sigma, N, C, kb_mean, kb_frac], dtype=float),\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "93e4550c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png":
|
||||
"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3DhcvXoVH330EdauXau7SOrYsaPuGIcOHcKLL76IGTNmIDo6Gv/+978xduxY3HzzzbjzzjsB1CUEt9xyC1QqFd544w20bt0au3btwltvvYVz585h+fLliI2NxY8//oh77rkHY8eO1bXfXO/AsmXL8PTTTyM1NRVLly5FVFQUTp06haNHj5qN56ZNmxAbG4tevXo1EvkbLl26hBYtWmDevHmIjIzE1atX8emnn6JPnz7IyMhAu3btLD4WUDdmfdCgQUhKSsI//vEPREdHIycnB1u3btVdEO3atQsPP/wwHn74YcyePRu+vr44f/58o8OarG3rq6++ittuuw3//ve/UVRUhOnTp2P48OE4ceIEvLy8sG/fPly9ehVPP/20Vd8Q/+Mf/0D79u3x4YcfAqgb+nLvvfciMzMTISEhAOqSmnbt2uGRRx5BeHg4srOz8fHHH6N37944fvw4IiIi9I751FNPYejQofjss89QWloKHx8fvPbaa5g7dy6eeeYZjBo1ChcuXMC4ceNQXV2Ntm3b6h5bVlaG1NRUXLx4Ea+++iq6du2KY8eO4Y033sCRI0ewefNmSJKEXr16wcfHB88//zzeeOMN3HXXXY0OWxs3bhyGDh2KVatW4cKFC3j55Zfx5z//We+1On36NO69915MnToVAQEB+O233zB//nzs2bPH4DWtqqrCfffdh/Hjx2PGjBm65NmUxj7LQF0CPWrUKNx5551Ys2YNampq8N577+Hy5ctGj1ldXY3HH38ca9aswaJFizBlyhST51+8eDESExPx4YcfQpZlLFiwAGlpaUhPT0ffvn1NPu7y5ctITU2Fj48PlixZgujoaHz++eeYPHmyQd0zZ86gb9++GDduHEJCQnDu3DksXLgQt99+O44cOQIfH59Gf2dZ8xoQuSVBRC4tPz9f3H777QKAACB8fHxEv379xNy5c0VxcbFe3dTUVNG9e3e9smeffVYEBwfr1QUgoqOjRVFRka4sJydHqFQqMXfuXF3Zu+++KwCIzMxMg3YlJiYKX19fcf78eV1ZeXm5CA8PF+PHj9eVjR8/XgQGBurVE0KI9957TwAQx44dE0IIkZeXJwCIWbNmGZxr+fLleu0oLi4WwcHB4vbbbxeyLJuInHG+vr7i1ltvNSivra0V1dXVup/a2lqTx6ipqRFVVVWiTZs24oUXXjDZTq2tW7cKAGLr1q1CCCH27dsnAIj169ebPIc2PteuXTNZJzMzUwAQy5cvt7qt2jbde++9evX/7//+TwAQu3btEkIIsXr1agFALF261OQ5jLWpS5cuoqamRle+Z88eAUD897//NdvWkpISERAQIBYtWqQr18b1ySef1Kt/9epVodFoxMMPP6xXvmvXLgFApKam6srmzp0rVCqV2Lt3r17dL7/8UgAQP/zwg65s2bJlIjAwUPeZi42NFU8++aTYvn273mO17Zo4caJe+YIFCwQAkZ2dbfR5yrIsqqurRXp6ugAgDh06pLtv9OjRAoD45JNPDB43evRokZiYqFdm6We5d+/eIj4+XlRWVurKiouLRYsWLUTDS4XExETdc3/11VeNPgchbrzWcXFxory8XFdeVFQkwsPDxd13323ysUIIMX36dCFJkjh48KBe+aBBg/Q+Lw1p43f+/HkBQHz99de6+8z9zjJ2DGOvAZG74vAhIhfXokUL7NixA3v37sW8efNw//3349SpU5g5cya6dOmi133+/PPP4+DBg/jf//4HoG64xGeffYbRo0cjMDBQ77gDBgxAUFCQ7nZ0dDSioqIMhm6Y0717dyQkJOhu+/r6om3btnrH+O677zBgwADExcWhpqZG95OWlgYAequ5WGrnzp0oKirCxIkTbTa+edSoUfDx8dH91P9mtKamBu+88w46duwItVoNb29vqNVqnD59GidOnLD6XDfffDPCwsIwffp0LF26FMePHzeo07t3bwDAQw89hP/7v//DH3/8YdGxrW3rfffdp3e7a9euAGDV+8CYoUOHwsvLy+xxS0pKMH36dNx8883w9vaGt7c3AgMDUVpaarStDzzwgN7t3bt3o7KyEg899JBe+a233mowzOa7775D586d0b17d7334ZAhQwyGdj311FO4ePEiVq1ahSlTpiA+Ph4rV65Eamoq3n33XYN2WRLDs2fP4rHHHkNMTAy8vLzg4+OD1NRUALDouZrT2Ge5tLQU+/btw4gRI6BWq3X1AgMDMXz4cKPH1H62Fy9ebDDsq6FRo0bpTTwOCgrC8OHDsX37dtTW1pp83NatW9GpUye9oXoA8NhjjxnUzc3NxYQJExAfHw9vb2/4+PggMTERgPH4GWPta0DkbpgUELmJXr16Yfr06fjiiy9w6dIlvPDCCzh37pzeZOP7778frVq10g0VWrFiBUpLSzFp0iSD47Vo0cKgTKPRoLy83OI2WXKMy5cv49tvv9W74Pbx8dHNcaif1FgqLy8PANCyZUurH5uQkGD0gvf999/H3r17sXfvXoP7pk2bhtdffx0jRozAt99+i19//RV79+5Ft27drIqXVkhICNLT09G9e3e8+uqr6NSpE+Line truncated
|
||||
"text/plain": [
|
||||
"<Figure size 900x500 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"rng = np.random.default_rng(123)\n",
|
||||
"\n",
|
||||
"x = np.linspace(0.0, 140.0, 281)\n",
|
||||
"\n",
|
||||
"p_true = np.array([\n",
|
||||
" 14.0, # p0\n",
|
||||
" 0.010, # p1, model uses p0 - p1*x\n",
|
||||
" 62.0, # mu: K-alpha position\n",
|
||||
" 2.0, # sigma\n",
|
||||
" 180.0, # N\n",
|
||||
" 0.10, # C: charge-sharing plateau\n",
|
||||
" 1.105, # kb_mean: K-beta mean ratio\n",
|
||||
" 0.3, # kb_frac: K-beta fraction\n",
|
||||
"])\n",
|
||||
"\n",
|
||||
"noise_sigma = 1.5\n",
|
||||
"y_true = gaussian_charge_sharing_kb(x, p_true)\n",
|
||||
"y = y_true + rng.normal(0.0, noise_sigma, size=x.shape)\n",
|
||||
"y_err = np.full_like(x, noise_sigma)\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(9, 5))\n",
|
||||
"plt.plot(x, y_true, label=\"true\")\n",
|
||||
"plt.scatter(x, y, s=10, label=\"noisy data\")\n",
|
||||
"plt.xlabel(\"x\")\n",
|
||||
"plt.ylabel(\"y\")\n",
|
||||
"plt.title(\"Synthetic GaussianChargeSharingKb data\")\n",
|
||||
"plt.legend()\n",
|
||||
"plt.grid(True, alpha=0.3)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "2133a34c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"True params : [ 14. 0.01 62. 2. 180. 0.1 1.105 0.3 ]\n",
|
||||
"SciPy params : [ 14.534234 0.015155 62.003314 1.998024 180.396284 0.098433\n",
|
||||
" 1.104748 0.302732]\n",
|
||||
"SciPy abs error : [0.534234 0.005155 0.003314 0.001976 0.396284 0.001567 0.000252 0.002732]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# SciPy reference fit\n",
|
||||
"p0_ref = np.array([12.0, 0.0, 60.0, 6.0, 150.0, 0.20, 1.10, 0.10])\n",
|
||||
"\n",
|
||||
"bounds_ref = (\n",
|
||||
" [-np.inf, -np.inf, 0.0, 1e-12, 0.0, -np.inf, 1.02, 0.0],\n",
|
||||
" [ np.inf, np.inf, 140.0, 50.0, np.inf, np.inf, 1.40, 1.00],\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"p_scipy, cov_scipy = curve_fit(\n",
|
||||
" gaussian_charge_sharing_kb_curve_fit,\n",
|
||||
" x,\n",
|
||||
" y,\n",
|
||||
" p0=p0_ref,\n",
|
||||
" sigma=y_err,\n",
|
||||
" absolute_sigma=True,\n",
|
||||
" bounds=bounds_ref,\n",
|
||||
" maxfev=50_000,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"True params :\", p_true)\n",
|
||||
"print(\"SciPy params :\", p_scipy)\n",
|
||||
"print(\"SciPy abs error :\", np.abs(p_scipy - p_true))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "2a563865",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Parameter list:\n",
|
||||
"['p0', 'p1', 'mu', 'sigma', 'N', 'C', 'kb_mean', 'kb_frac']\n",
|
||||
"n_par: 8\n",
|
||||
"\n",
|
||||
"{'par': array([ 14.534164, 0.015155, 62.003317, 1.99802 , 180.396621,\n",
|
||||
" 0.098433, 1.104748, 0.302733]),\n",
|
||||
" 'par_err': array([0.564971, 0.005172, 0.009856, 0.008685, 0.698493, 0.00188 ,\n",
|
||||
" 0.000509, 0.003632]),\n",
|
||||
" 'chi2': array([262.404385])}\n",
|
||||
"\n",
|
||||
"True params : [ 14. 0.01 62. 2. 180. 0.1 1.105 0.3 ]\n",
|
||||
"SciPy params : [ 14.534234 0.015155 62.003314 1.998024 180.396284 0.098433\n",
|
||||
" 1.104748 0.302732]\n",
|
||||
"Aare params : [ 14.534164 0.015155 62.003317 1.99802 180.396621 0.098433\n",
|
||||
" 1.104748 0.302733]\n",
|
||||
"SciPy abs error : [0.534234 0.005155 0.003314 0.001976 0.396284 0.001567 0.000252 0.002732]\n",
|
||||
"Aare abs error : [0.534164 0.005155 0.003317 0.00198 0.396621 0.001567 0.000252 0.002733]\n",
|
||||
"Aare - SciPy : [-0.00007 -0. 0.000003 -0.000004 0.000337 -0. -0.\n",
|
||||
" 0.000001]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Aare / Minuit2 object API fit\n",
|
||||
"model = GaussianChargeSharingKb()\n",
|
||||
"\n",
|
||||
"print(\"Parameter list:\")\n",
|
||||
"print(model.par_names)\n",
|
||||
"print(\"n_par:\", model.n_par)\n",
|
||||
"print()\n",
|
||||
"\n",
|
||||
"model.SetParameter(\"p0\", 12.0)\n",
|
||||
"model.SetParameter(\"p1\", 0.0)\n",
|
||||
"model.SetParameter(\"mu\", 58.0)\n",
|
||||
"model.SetParameter(\"sigma\", 4.0)\n",
|
||||
"model.SetParameter(\"N\", 150.0)\n",
|
||||
"model.SetParameter(\"C\", 0.10)\n",
|
||||
"model.SetParameter(\"kb_mean\", 1.20)\n",
|
||||
"model.SetParameter(\"kb_frac\", 0.40)\n",
|
||||
"\n",
|
||||
"model.SetParLimits(\"kb_mean\", 1.02, 1.40)\n",
|
||||
"model.SetParLimits(\"kb_frac\", 0.0, 1.00)\n",
|
||||
"\n",
|
||||
"model.compute_errors = True\n",
|
||||
"model.max_calls = 4000\n",
|
||||
"model.tolerance = 0.01\n",
|
||||
"\n",
|
||||
"res_aare = model.fit(x, y, y_err)\n",
|
||||
"pprint(res_aare, sort_dicts=False)\n",
|
||||
"\n",
|
||||
"p_aare = np.array(res_aare[\"par\"], dtype=float)\n",
|
||||
"\n",
|
||||
"print()\n",
|
||||
"print(\"True params :\", p_true)\n",
|
||||
"print(\"SciPy params :\", p_scipy)\n",
|
||||
"print(\"Aare params :\", p_aare)\n",
|
||||
"print(\"SciPy abs error :\", np.abs(p_scipy - p_true))\n",
|
||||
"print(\"Aare abs error :\", np.abs(p_aare - p_true))\n",
|
||||
"print(\"Aare - SciPy :\", p_aare - p_scipy)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "fc217c0e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png":
|
||||
"iVBORw0KGgoAAAANSUhEUgAAA1IAAAHUCAYAAAAwUBnrAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAACieklEQVR4nOzdd3xUVd7H8c+UZNJ7hwChq6BSLKBSFAt2wIquYMW1PLqsDV1X0F3x0bWt7ur6qIAF26ro2hEFdEFFBJEqJRCQhEBIL5NM5j5/TDJk0sskc4Hv+/XKS+bOLb87Z8bML+ec37EYhmEgIiIiIiIirWYNdAAiIiIiIiIHGyVSIiIiIiIibaRESkREREREpI2USImIiIiIiLSREikREREREZE2UiIlIiIiIiLSRkqkRERERERE2kiJlIiIiIiISBspkRIREREREWkjJVIi0iXWrFnDtddeS58+fQgNDSU0NJR+/foxbdo0fvzxx0CH1yqLFy/GYrGwePHiTr+W2+3m1VdfZdy4cSQkJBAUFERSUhLnnnsu//nPf3C73T4x/fvf/+70mDpLXl4eM2bM4MgjjyQ8PJzo6GgGDhzI7373O9asWePdb+bMmVgsFvbt29clcY0ZM4YxY8Z0+nUsFgu33HJLg+0PPPAAFouF3//+97jdbr+09aJFixg+fDjh4eFYLBYWLFjA3LlzsVgsbN++3bvf/Pnzeeqpp9p9ncNJ7ftSRA4/9kAHICKHvn/961/ccsstDBgwgNtuu42jjjoKi8XChg0beOONNzjuuOPYsmULffr0CXSozRo6dCjLly/nyCOP7NTrVFRUcOGFF/LFF19w2WWX8dxzz5GSksLevXv57LPPuPjii3nrrbe44IILOjWOrlBSUsKJJ55ISUkJd955J8cccwzl5eX8+uuvvPfee6xevZqjjz46ILH985//DMh1DcPgtttu45lnnuGee+5h9uzZfjvvJZdcQv/+/fnwww8JDw9nwIABuFwuli9fTmpqqnff+fPns3btWm6//Xa/XPtQdt1113HWWWcFOgwRCQAlUiLSqf773/9y0003cc455/Dvf/+b4OBg73OnnnoqN998M++88w6hoaEBjLJ1oqKiOPHEEzv9OtOnT+fzzz9n3rx5XHXVVT7PTZw4kTvvvJPy8vJOj6OusrIywsLC/H7ed955hy1btvDVV18xduxYn+emT5/u7XnrSrX32tkJc2NcLhfXXHMNr776Ko899hh33HGH3869e/du9u/fz4QJEzjttNN8nktMTPTbdQ4Xte+T7t27071790CHIyIBoKF9ItKpHn74YWw2G//61798kqi6Lr74YtLS0ryPf/zxRy677DJ69epFaGgovXr14vLLL2fHjh0+xzU1pKaxoUpfffUVY8aMIT4+ntDQUHr06MGkSZMoKyvz7vPcc89xzDHHEBERQWRkJAMHDuTee+/1Pt/Y0L7Wxlob09dff83vf/97EhISiI+PZ+LEiezevdu7X05ODi+++CJnnnlmgySqVr9+/Rr00lRVVXHfffeRlpZGVFQU48aNY9OmTT77LFy4kAsuuIDu3bsTEhJC3759mTZtWoOhcrWv608//cRFF11EbGyst7fQ6XTyxz/+kZSUFMLCwhg1ahQrV66kV69eTJ061ec8OTk5TJs2je7duxMcHExGRgazZs3C5XJ598nLywPw6Q2py2pt+Gtqz549XH755URHR5OcnMw111xDYWGhzz7/+Mc/GDVqFElJSYSHhzN48GAeffRRqqqqfPYbM2YMgwYNYunSpYwcOZKwsDCuueYa73N1h/Zt374di8XC3/72N5544gkyMjKIiIhgxIgRfPfddw3i/L//+z/69++Pw+HgyCOPZP78+UydOpVevXo1eq8VFRVMmjSJ+fPn8+KLLzaZRFVUVDB9+nRSUlIIDQ1l9OjRrFq1qtF9a82cOdP7Zf/uu+/GYrF446j/eRkzZgwff/wxO3bswGKxeH9aMn/+fEaMGEFERAQREREce+yxvPTSSz77vPzyyxxzzDGEhIQQFxfHhAkT2LBhg88+U6dOJSIigo0bN3LmmWcSHh5OamoqjzzyCADfffcdJ598MuHh4fTv35958+b5HF97PwsXLuTqq68mLi6O8PBwzjvvPLZt2+azrz8+E439f6g1/7/Zv38/N910E926dSM4OJjevXtz33334XQ6fc5VO/Tz1Vdf5YgjjiAsLIxjjjmGjz76qMU2EZHOpR4pEek01dXVfP311wwfPrzJL8qN2b59OwMGDOCyyy4jLi6O7OxsnnvuOY477jjWr19PQkJCm+LYvn0755xzDqeccgovv/wyMTEx/Pbbb3z22WdUVlYSFhbGm2++yU033cStt97K3/72N6xWK1u2bGH9+vV+jfW6667jnHPOYf78+ezcuZM777yTK6+8kq+++gqAr7/+mqqqKi688MI23eO9997LSSedxIsvvkhRURF333035513Hhs2bMBmswGwdetWRowYwXXXXUd0dDTbt2/niSee4OSTT+aXX34hKCjI55wTJ07ksssu48Ybb6S0tBSAq6++mrfeeou77rqLU089lfXr1zNhwgSKiop8js3JyeH444/HarXy5z//mT59+rB8+XL+8pe/sH37dubMmQPAiBEjALjqqqu49957OeWUU4iPj2/2XidNmsSll17Ktddeyy+//MKMGTMAz5f0Wlu3bmXy5MlkZGQQHBzMzz//zF//+lc2btzosx9AdnY2V155JXfddRcPP/xwo8lbXf/4xz8YOHCgdw7R/fffz9lnn01mZibR0dEAvPDCC0ybNo1Jkybx5JNPUlhYyKxZsxp8Sa5VXFzM+PHjWbZsGW+99RaTJk1q8vr33nsvQ4cO5cUXX6SwsJCZM2cyZswYVq1aRe/evRs95rrrruOYY45h4sSJ3HrrrUyePBmHw9Hovv/85z+54YYb2Lp1K++//36zr0WtP//5zzz00ENMnDiRP/7xj0RHR7N27VqfPyjMnj2be++9l8svv5zZs2eTl5fHzJkzGTFiBCtWrKBfv37efauqqpg4cSI33ngjd955J/Pnz2fGjBkUFRXx7rvvcvfdd9O9e3eeeeYZpk6dyqBBgxg2bJhPTNdeey2nn36697P2pz/9iTFjxrBmzRpiYmIA/3wm6mvN/28qKioYO3YsW7duZdasWRx99NF88803zJ49m9WrV/Pxxx/7nPPjjz9mxYoVPPjgg0RERPDoo48yYcIENm3a1GSbi0gXMEREOklOTo4BGJdddlmD51wul1FVVeX9cbvdTZ7H5XIZJSUlRnh4uPH00097tz/wwANGY/8bmzNnjgEYmZmZhmEYxr///W8DMFavXt3kNW655RYjJiam2fv5+uuvDcD4+uuv2xxrbUw33XSTz/6PPvqoARjZ2dmGYRjGI488YgDGZ5991mws9WM6++yzfba//fbbBmAsX7680ePcbrdRVVVl7NixwwCMDz74wPtc7ev65z//2eeYdevWGYBx9913+2x/4403DMCYMmWKd9u0adOMiIgIY8eOHT77/u1vfzMAY926dd5tDz74oBEcHGwABmBkZGQYN954o/Hzzz/7HFsb16OPPuqz/aabbjJCQkKafA9VV1cbVVVVxiuvvGLYbDZj//793udGjx5tAMaiRYsaHDd69Ghj9OjR3seZmZkGYAwePNhwuVze7T/88IMBGG+88Yb3eikpKcYJJ5zgc74dO3YYQUFBRs+ePX221943YLzwwguN3oNhHGjroUOH+tzr9u3bjaCgIOO6665r8ti68T/22GM+2+t/XgzDMM4555wGcTZl27Zths1mM6644oom98nPzzdCQ0MbvE+zsrIMh8NhTJ482bttypQpBmC8++673m1VVVVGYmKiARg//fSTd3teXp5hs9mM6dOnN7ifCRMm+Fzrv//9rwEYf/nLXxqNsT2fibrP1WrN/2+ef/55AzDefvttn+3/+7//awDGF1984d0GGMnJyUZRUZF3W05OjmG1Wo3Zs2c3eQ0R6Xwa2iciATFs2DCCgoK8P48//rj3uZKSEu6++2769u2L3W7HbrcTERFBaWlpg2FArXHssccSHBzMDTfcwLx58xoM7wE4/vjjKSgo4PLLL+eDDz5odWW4tsZ6/vnn+zyuHaJXfyhgW7XmvLm5udx4442kp6djt9sJCgqiZ8+eAI3GWr9XZMmSJQBccsklPtsvuugi7HbfAQ4fffQRY8eOJS0tDZfL5f0ZP368z7nA06OTlZXFyy+/zLRp04iIiOD5559n2LBhvPHGG62614qKCnJzc73bVq1axfnnn098fDw2m42goCCuuuoqqqur+fXXX32Oj42N5dRTT21wnaacc8453l6+2uvDgdd606ZN5OTkNHidevTowUknndToOU855RRiYmKYNWsWW7Zsafb6kydP9hlK1rNnT0aOHMnXX3/d6nvwp4ULF1JdXc3NN9/c5D7Lly+nvLy8wfDP9PR0Tj31VBYtWuSz3WKxcPbZZ3sf2+12+vbtS2pqKkOGDPFuj4uLIykpqdHPzxVXXOHzeOTIkfTs2dPnderoZ6Ixrfn/zVdffUV4eDgXXXSRz/ba16f+6zF27FgiIyO9j5OTk5u8bxHpOkqkRKTTJCQkEBoa2ugv+/nz57NixQo+/PDDBs9NnjyZZ599luuuu47PP/+cH374gRUrVpCYmNiuIgt9+vThyy+/JCkpiZtvvpk+ffrQp08fnn76ae8+v/vd73j55ZfZsWMHkyZNIikpiRNOOIGFCxc2e+62xlp/2Frt8KrafXv06AFAZmZmm+6xpfO63W7OOOMM3nvvPe666y4WLVrEDz/84J3b01is9Ydj1s5nSk5O9tlut9sbXH/Pnj385z//8UmWg4KCOOqoowAaJKrJyclcffXVPP/886xZs4YlS5YQHBzMbbfd1uZ7zcrK4pRTTuG3337j6aef5pLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1000x500 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"plt.figure(figsize=(10, 5))\n",
|
||||
"# plt.plot(x, y_true, label=\"true\")\n",
|
||||
"plt.scatter(x, y, s=10, label=\"data\")\n",
|
||||
"plt.plot(x, gaussian_charge_sharing_kb(x, p_scipy), linewidth=3.0, label=\"SciPy curve_fit\", color=\"tab:orange\")\n",
|
||||
"plt.plot(x, model(x, p_aare), linewidth=1.5, label=\"Aare Minuit2\", color=\"tab:cyan\")\n",
|
||||
"plt.xlabel(\"x\")\n",
|
||||
"plt.ylabel(\"y\")\n",
|
||||
"plt.title(\"GaussianChargeSharingKb fit comparison\")\n",
|
||||
"plt.legend()\n",
|
||||
"plt.grid(True, alpha=0.3)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "a4a6aec0",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"SciPy curve_fit : 17.591 ms\n",
|
||||
"Aare Minuit2 : 1.888 ms\n",
|
||||
"\n",
|
||||
"SciPy bench params: [ 14.534234 0.015155 62.003314 1.998024 180.396284 0.098433\n",
|
||||
" 1.104748 0.302732]\n",
|
||||
"Aare bench params : [ 32.421516 0.162626 62.154113 2.413067 169.643047 0.05319\n",
|
||||
" 1.271962 0. ]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def bench(fn, n_repeats=200):\n",
|
||||
" for _ in range(3):\n",
|
||||
" fn()\n",
|
||||
"\n",
|
||||
" t0 = time.perf_counter()\n",
|
||||
" for _ in range(n_repeats):\n",
|
||||
" res = fn()\n",
|
||||
" t1 = time.perf_counter()\n",
|
||||
"\n",
|
||||
" return res, (t1 - t0) / n_repeats\n",
|
||||
"\n",
|
||||
"def fit_scipy_once():\n",
|
||||
" return curve_fit(\n",
|
||||
" gaussian_charge_sharing_kb_curve_fit,\n",
|
||||
" x,\n",
|
||||
" y,\n",
|
||||
" p0=p0_ref,\n",
|
||||
" sigma=y_err,\n",
|
||||
" absolute_sigma=True,\n",
|
||||
" bounds=bounds_ref,\n",
|
||||
" maxfev=50_000,\n",
|
||||
" )[0]\n",
|
||||
"\n",
|
||||
"def fit_aare_once():\n",
|
||||
" m = GaussianChargeSharingKb()\n",
|
||||
" m.SetParameter(\"p0\", 10.0)\n",
|
||||
" m.SetParameter(\"p1\", 0.0)\n",
|
||||
" m.SetParameter(\"mu\", 50.0)\n",
|
||||
" m.SetParameter(\"sigma\", 5.0)\n",
|
||||
" m.SetParameter(\"N\", 150.0)\n",
|
||||
" m.SetParameter(\"C\", 0.10)\n",
|
||||
" m.SetParameter(\"kb_mean\", 1.20)\n",
|
||||
" m.SetParameter(\"kb_frac\", 0.40)\n",
|
||||
" \n",
|
||||
" m.SetParLimits(\"kb_mean\", 1.02, 1.40)\n",
|
||||
" m.SetParLimits(\"kb_frac\", 0.0, 1.00)\n",
|
||||
" m.max_calls = 4000\n",
|
||||
" m.tolerance = 0.01\n",
|
||||
" return np.array(m.fit(x, y, y_err)[\"par\"], dtype=float)\n",
|
||||
"\n",
|
||||
"p_scipy_bench, t_scipy = bench(fit_scipy_once, n_repeats=200)\n",
|
||||
"p_aare_bench, t_aare = bench(fit_aare_once, n_repeats=200)\n",
|
||||
"\n",
|
||||
"print(f\"SciPy curve_fit : {1e3*t_scipy:.3f} ms\")\n",
|
||||
"print(f\"Aare Minuit2 : {1e3*t_aare:.3f} ms\")\n",
|
||||
"print()\n",
|
||||
"print(\"SciPy bench params:\", p_scipy_bench)\n",
|
||||
"print(\"Aare bench params :\", p_aare_bench)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "77a15aea",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## No-Kβ sanity check\n",
|
||||
"\n",
|
||||
"For no-Kβ data, prefer `GaussianChargeSharing`.\n",
|
||||
"\n",
|
||||
"You can also use this 8-parameter model and fix:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"model.FixParameter(\"kb_frac\", 0.0)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"but the 6-parameter model is cleaner and usually better conditioned."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4abba19d-f4ca-4a41-adf8-1d0f4946086a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import pytest
|
||||
|
||||
from aare import Interpolator, ClusterVector, Etai, Cluster
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def test_interpolation_api():
|
||||
eta_distribution = np.zeros((10, 10, 1)) # dummy eta distribution
|
||||
etax_bins = np.linspace(0, 1.0, 11)
|
||||
etay_bins = np.linspace(0, 1.0, 11)
|
||||
e_bins = np.array([0., 10.]) # dummy energy bins
|
||||
interpolator = Interpolator(eta_distribution, etax_bins, etay_bins, e_bins)
|
||||
|
||||
cluster_vector = ClusterVector()
|
||||
cluster_vector.push_back(Cluster(10, 5, np.ones(shape=9, dtype=np.int32)))
|
||||
cluster_vector.push_back(Cluster(20, 10, np.ones(shape=9, dtype=np.int32)))
|
||||
|
||||
eta1 = Etai()
|
||||
eta1.x = 0.1
|
||||
eta1.y = 0.1
|
||||
eta1.sum = 5
|
||||
eta2 = Etai()
|
||||
eta2.x = 0.1
|
||||
eta2.y = 0.9
|
||||
eta2.sum = 6
|
||||
etas = np.array([eta1, eta2]) # dummy etas for the clusters
|
||||
|
||||
photons = interpolator.interpolate(cluster_vector, etas)
|
||||
|
||||
assert photons.size == cluster_vector.size # should return one photon per cluster
|
||||
@@ -3,7 +3,7 @@
|
||||
[
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"execution_count": 2,
|
||||
"id": "efef8e20-6571-4561-8f0b-6048b57907de",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -14,14 +14,14 @@
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"from matplotlib.gridspec import GridSpec\n",
|
||||
"import sys\n",
|
||||
"sys.path.insert(0, '/home/ferjao_k/sw/aare/build')\n",
|
||||
"sys.path.insert(0, '/home/ferjao_k/aare/build')\n",
|
||||
"from aare import fit_gaus # lmfit\n",
|
||||
"from aare import Gaussian, fit # minuit2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": 3,
|
||||
"id": "35772e2c-37c6-4986-a9c0-7dca4a034827",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -48,7 +48,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": 4,
|
||||
"id": "06c8fddb-56d9-4f84-8b21-4ffd8b7bd26f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -95,7 +95,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": 5,
|
||||
"id": "dc0b52b6-9fc3-453d-b6eb-e325a2b8342e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -128,7 +128,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"execution_count": 6,
|
||||
"id": "9cc999b9-e0d8-4deb-ae29-e8bd0141534b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -190,14 +190,14 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": 7,
|
||||
"id": "a98a41f3-fd2e-4bfc-9ec6-0d23dd38e896",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png":
|
||||
"iVBORw0KGgoAAAANSUhEUgAAA9oAAAKoCAYAAACIioc5AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdeXhU1fnA8e+dJZN9XyYJIYR9CTuKbAKyuKFVVGrVKtatorQo1tbaVlx+4C4tWK2WCkqRaivuyg6KgIR9XxPIQnayL7Pe3x+TGQlrQia5k+T9PM88D7lz5t73DjNz553znnMUVVVVhBBCCCGEEEII4RU6rQMQQgghhBBCCCHaEkm0hRBCCCGEEEIIL5JEWwghhBBCCCGE8CJJtIUQQgghhBBCCC+SRFsIIYQQQgghhPAiSbSFEEIIIYQQQggvkkRbCCGEEEIIIYTwIkm0hRBCCCGEEEIIL5JEWwghhBBCCCGE8CJJtNu43bt3c99999GlSxcCAgIICAigW7duPPTQQ2zdulXr8Bpk3bp1KIrCunXrWvzYs2bNQlGUc97mz59/zti+/vprZs2a1eBjLFmyhLlz53o99vMZM2YMY8aMuaTHzp49m08//dSr8UDTYmqqqVOn0qlTp2bbf0Nfv6e/1oKDg8+6f/v27YwfP57g4GDCw8OZPHky6enpTYqtoKCAqVOnEh0dTWBgIMOGDWP16tVntRswYIAntkmTJjXpmEII75NrfdPItb4+udY3nq9e67Ozs5kxYwajR48mPDwcRVFYuHDhOdvKtd77DFoHIJrPP/7xDx599FF69OjBb3/7W/r06YOiKBw4cIAPP/yQyy67jKNHj9KlSxetQ72gQYMGsWnTJnr37q1ZDN9++y1hYWH1tqWkpBAQEHBWbF9//TVvvvlmgy/AS5YsYe/evcyYMcOLETeP2bNnc+utt3LTTTd5db9///vfvbq/xvjzn//Mb3/7W82Of6ZNmzah1+vrbTt48CBjxoxhwIABfPTRR9TW1vKXv/yFUaNGsXPnTmJiYhp9HIvFwrhx4ygtLeWvf/0rsbGxvPnmm1xzzTWsWrWK0aNHe9p+8MEHVFVVcfPNNzf5/IQQ3iXXeu+Ra72LXOubX0td648ePcq///1vBgwYwHXXXceHH3543rZyrfc+SbTbqB9++IFp06Zx/fXX89///hc/Pz/PfVdddRWPPPIIH3/8MQEBARpG2TChoaFcccUVmsYwePBgoqOjz3mf1rG1BVp+sfK1L5/nej395S9/wWQy8eWXXxIaGgq4XpPdunXj1Vdf5aWXXmr0cRYsWMDevXvZuHEjw4YNA2Ds2LH079+fJ598kh9//NHTtm/fvgCYTKZLOSUhRDORa713ybW+ecm1/ictda2/8sorKSwsBGDr1q0XTLTlWu99UjreRs2ePRu9Xs8//vGPehfe0912220kJCR4/t66dSu33347nTp1IiAggE6dOvGLX/yCEydO1Hucu+zlTAsXLkRRFI4fP+7ZtmbNGsaMGUNUVBQBAQF07NiRW265herqak+bt956i/79+xMcHExISAg9e/bkj3/8o+f+c5XjNDRWd0xr167l4YcfJjo6mqioKCZPnszJkycb9FxeyJmxTZ06lTfffBOgXunZ6c/J6caMGcNXX33FiRMn6rV3O3XqFNOmTSMxMRE/Pz86d+7M008/jcViuWhsqqry8ssvk5ycjL+/P4MGDeKbb745q11tbS0zZ85kwIABhIWFERkZybBhw/jss8/qtVMUhaqqKhYtWuSJ010CVlhYyLRp0+jduzfBwcHExsZy1VVX8f333zfgWTy7nOz48eMoisKrr77K66+/TkpKCsHBwQwbNozNmzdfdH/u//eVK1dy7733EhkZSVBQEDfccMNZJVhnlpMtXbrUUy54umeeeQa9Xs/KlSs927Zu3cqNN95IZGQk/v7+DBw4kI8++qhB59xQdrudL7/8kltuucVz4QVITk5m7NixLFu27JL2u2zZMnr06OFJsgEMBgN33XUXW7ZsIScnp8mxCyGal1zr68ck13q51su1vj6dTlI9LUmPdhvkcDhYu3YtQ4YMIT4+vsGPO378OD169OD2228nMjKS3Nxc3nrrLS677DL2799/3l95L7S/66+/nlGjRvGvf/2L8PBwcnJy+Pbbb7FarQQGBrJ06VKmTZvG9OnTefXVV9HpdBw9epT9+/d7Ndb777+f66+/niVLlpCVlcXvfvc77rrrLtasWdOgc3E4HNjtds/fiqKcVfIDrtKkqqoq/vvf/7Jp0ybP9vP9P/z973/nwQcf5NixY2d9iNbW1jJ27FiOHTvGs88+S79+/fj++++ZM2cOO3fu5KuvvrpgzM8++yzPPvss9913H7feeitZWVk88MADOBwOevTo4WlnsVg4deoUTzzxBImJiVitVlatWsXkyZN57733uPvuuwFXmdNVV13F2LFj+fOf/wzguRicOnUKcF2gzGYzlZWVLFu2jDFjxrB69epLHpP15ptv0rNnT8+4tj//+c9cd911ZGRknFXedy733XcfEyZM8Py//+lPf2LMmDHs3r2b8PDwcz7m9ttvZ/369cycOZMrrriCIUOGsGbNGl544QX++Mc/MmHCBADWrl3LNddcw9ChQ3n77bcJCwtj6dKl/PznP6e6upqpU6de0jmf6dixY9TU1NCvX7+z7uvXrx8rV66ktrYWf3//Ru137969jBo16pz7BNi3bx+JiYmXFrQQotnJtV6u9SDXepBrvfBhqmhz8vLyVEC9/fbbz7rPbrerNpvNc3M6nefdj91uVysrK9WgoCD1r3/9q2f7M888o57rpfPee++pgJqRkaGqqqr+97//VQF1586d5z3Go48+qoaHh1/wfNauXasC6tq1axsdqzumadOm1Wv/8ssvq4Cam5t7wWO7z/XMW2Ji4nlje+SRR875/JzP9ddfryYnJ5+1/e2331YB9aOPPqq3/aWXXlIBdcWKFefdZ0lJierv76/efPPN9bb/8MMPKqCOHj36vI91v0buu+8+deDAgfXuCwoKUu+5556LnpN7H+PGjTsrhnMZPXp0vZgyMjJUQO3bt69qt9s927ds2aIC6ocffnjB/bn/3893/i+88IJn2z333HPW819bW6sOHDhQTUlJUffv36/GxcWpo0ePrhdLz5491YEDB6o2m63eYydNmqTGx8erDodDVdWGvX5V9fzvK3fM5zrn2bNnq4B68uTJC+77XIxGo/rQQw+dtX3jxo0qoC5ZsuSs+5KTk9Xrr7++0ccSQnifXOvlWi/XernWN0ZaWpoKqO+9994F28m13nuknqCdGTx4MEaj0XN77bXXPPdVVlby+9//nq5du2IwGDAYDAQHB1NVVcWBAwcafawBAwbg5+fHgw8+yKJFi845a+Lll19OaWkpv/jFL/jss88oKipq0L4bG+uNN95Y72/3L4Znlp+dz6pVq0hLS/Pcvv766wY9rinWrFlDUFAQt956a73t7l9PzzU7tNumTZuora3lzjvvrLd9+PDhJCcnn9X+448/ZsSIEQQHB2MwGDAajSxYsKBR/+9vv/02gwYNwt/f37OP1atXX9Jrx+3666+v15vQ2P+3853/2rVrL/g4k8nERx99RHFxMYMGDUJVVT788ENPLEePHuXgwYOe/dvtds/tuuuuIzc3l0OHDjX4PBviXCWcDbmvpfcphNCeXOtd5Fpfn1zr62sv13qhHUm026Do6GgCAgLO+QG1ZMkS0tLS+Pzzz8+674477mD+/Pncf//9LF++nC1btpCWlkZMTAw1NTWNjqNLly6sWrWK2NhYHnnkEbp06UKXLl3461//6mnzy1/+kn/961+cOHGCW265hdjYWIYOHVpvbMy5NDbWqKioen+7J3po6Hn179+fIUOGeG7nKu3xtuLiYsxm81kfrLGxsRgMBoqLiy/4WACz2XzWfWdu++STT5gyZQqJiYksXryYTZs2kZaWxq9+9Stqa2sbFOvrr7/Oww8/zNChQ/nf//7H5s2bSUtL45prrrmk145bU//fznf+F3ru3Lp27cqoUaM8X2JOLwnMz88H4Iknnqj3ZdZoNDJt2jSABn+RvBj3c3CumE+dOoWiKOctjbvYfs+3T4DIyMhG71MI0XLkWi/XernWu8i1XvgqGaPdBun1eq666ipWrFhBbm5uvQ8N94yPZ07YUVZWxpdffskzzzzDH/7wB89295ie07nHh1gslnozE57rw2bUqFGMGjUKh8PB1q1bmTdvHjNmzCAuLo7bb78dgHvvvZd7772XqqoqvvvuO5555hkmTZrE4cOHz/mLbGNibc2ioqL48ccfUVW13gW4oKAAu91+wXF07g/svLy8s+7Ly8urNyHI4sWLSUlJ4T//+U+94zRkEpbT9zFmzBjeeuutetsrKioavI/mcL7z79q160Uf+89//pOvvvqKyy+/nPnz5/Pzn/+coUOHAnie+6eeeorJkyef8/Gnj41rCve6uHv27Dnrvj179tC1a9dLGrPVt2/f8+4TIDU1tfHBCiFajFzr2wa51jedXOuFr5Ie7TbqqaeewuFw8Otf/xqbzXbR9oqioKrqWVP6//Of/8ThcNTb5v7g3r17d73tX3zxxXn3r9frGTp0qGeWzu3bt5/VJigoiGuvvZann34aq9XKvn37mhyrFhr7S6zJZDpn23HjxlFZWcmnn35ab/v777/vuf98rrjiCvz9/fn3v/9db/vGjRvP6v1QFAU/P796F968vLyzZiK9UKyKopz1/7F79+56k8Ro4Xznf7EJW/bs2cNvfvMb7r77br7//nv69evHz3/+c0pKSgDXhbVbt27s2rWrXu/H6beQkBCvnIPBYOCGG27gk08+qfdlJjMzk7Vr15734n8xN998MwcPHqy3jJfdbmfx4sUMHTq03izFQgjfJNd67ci13kWu9b59rRfakh7tNmrEiBLine truncated
|
||||
"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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1200x800 with 4 Axes>"
|
||||
]
|
||||
@@ -228,7 +228,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"execution_count": 8,
|
||||
"id": "1f6bc651-80c1-41dd-8a05-7f15aba006aa",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -275,7 +275,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"execution_count": 9,
|
||||
"id": "5a417145-ce42-4c3a-a7bf-05ff97ba0450",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -285,8 +285,8 @@
|
||||
"text": [
|
||||
"Method time (ms) med|dA| med|dMu| med|dSig|\n",
|
||||
"--------------------------------------------------------------------------------\n",
|
||||
"[lmfit (LM) ] 189.58 ms 6.272 0.0940 0.0949\n",
|
||||
"[Minuit2 (obj API) ] 124.59 ms 6.272 0.0940 0.0949 chi2/ndf=880.9946\n"
|
||||
"[lmfit (LM) ] 90.30 ms 6.272 0.0940 0.0949\n",
|
||||
"[Minuit2 (obj API) ] 59.60 ms 6.272 0.0940 0.0949 chi2/ndf=880.9946\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -336,39 +336,12 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"execution_count": null,
|
||||
"id": "55ecc77c-0823-408d-a811-8e4f4900f332",
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" Minuit2 (obj API) n_threads= 1 456.26 ± 10.76 ms (45.6262 ± 1.0762 μs/pixel)\n",
|
||||
" lmfit (LM) n_threads= 1 752.77 ± 108.16 ms (75.2771 ± 10.8165 μs/pixel)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" Minuit2 (obj API) n_threads= 2 238.34 ± 26.57 ms (23.8345 ± 2.6566 μs/pixel)\n",
|
||||
" lmfit (LM) n_threads= 2 410.95 ± 84.96 ms (41.0945 ± 8.4959 μs/pixel)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" lmfit (LM) n_threads= 4 205.44 ± 35.26 ms (20.5445 ± 3.5259 μs/pixel)\n",
|
||||
" Minuit2 (obj API) n_threads= 4 139.22 ± 14.06 ms (13.9224 ± 1.4060 μs/pixel)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" Minuit2 (obj API) n_threads= 8 130.12 ± 3.27 ms (13.0118 ± 0.3269 μs/pixel)\n",
|
||||
" lmfit (LM) n_threads= 8 199.97 ± 6.88 ms (19.9968 ± 0.6877 μs/pixel)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" Minuit2 (obj API) n_threads=16 134.81 ± 10.13 ms (13.4807 ± 1.0130 μs/pixel)\n",
|
||||
" lmfit (LM) n_threads=16 188.32 ± 9.86 ms (18.8322 ± 0.9860 μs/pixel)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# ===============\n",
|
||||
"# THREAD SCALING\n",
|
||||
@@ -402,33 +375,10 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": null,
|
||||
"id": "d5f3152d-be84-420e-8045-9c42ac5c24cb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png":
|
||||
"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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1500x500 with 3 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png":
|
||||
"iVBORw0KGgoAAAANSUhEUgAABW0AAAHqCAYAAAB/bWzAAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAADM5ElEQVR4nOzdd3RU1d7G8WcmPaSRRggQOoFQQ0sgkSJIrwqCiCIoolyvIveq2CiKYhevHQtFBbEAFxHs9N57J4CUGCCQQvrMef/gzVzGJBAgySTk+1kra+Xss885z5yZzEx+s2cfk2EYhgAAAAAAAAAApYLZ0QEAAAAAAAAAAP9D0RYAAAAAAAAAShGKtgAAAAAAAABQilC0BQAAAAAAAIBShKItAAAAAAAAAJQiFG0BAAAAAAAAoBShaAsAAAAAAAAApQhFWwAAAAAAAAAoRSjaAgAAAAAAAEApQtEWKOPWr1+v/v37KywsTG5ubqpUqZLatGmjf/3rX3b9OnTooA4dOhR7HpPJpIkTJxb7ca7HjBkzZDKZdPToUVvbfffdpxo1ajgs0+7duzV69Gi1adNGFSpUkMlk0rJlywrs//XXX6tZs2Zyd3dXaGioxowZo9TU1Dz9UlNTNWbMGIWGhsrd3V3NmjXT119/XWS5V61apQceeEAtWrSQm5tbnvP6d++++67q168vNzc31axZU5MmTVJ2dnaefgkJCbrvvvsUGBgoT09PtWnTRr///nuR5S4pzz33nEwmkxo1alSo/rNnz9bUqVPztB89elQmk0lvvPFGEScsHo7+ewIAwNFMJlOhfpYtW6Zly5bJZDLpu+++c3TsQimp/yeuVX65SvP/JABQWM6ODgDg+v3444/q06ePOnTooNdee02VK1fW6dOntWnTJn399dd68803bX0/+OADByZFQTZt2qQFCxYoMjJSnTp10g8//FBg36+++kpDhw7VAw88oLffflsHDhzQU089pT179uiXX36x63v77bdr48aNeuWVV1SvXj3Nnj1bd911l6xWq4YMGXLDuX///Xf99ttvioyMlI+PzxULzS+99JKef/55jRs3Tl26dNHGjRv13HPP6eTJk5o2bZqtX2Zmpjp16qQLFy7onXfeUXBwsN5//31169ZNv/32m9q3b3/DuUvCtm3b9MYbb6hSpUqF3mb27NnatWuXxowZU3zBAABAsVu7dq3d8osvvqilS5fqjz/+sGuPiIjQli1bSjJaubJ27VpVrVrV0TEA4IZQtAXKsNdee001a9bUzz//LGfn//05Dx48WK+99ppd34iIiJKOh0K45557NGzYMEnSd999V2DR1mKx6IknnlCXLl30ySefSJI6duwob29v3X333VqyZIm6d+8uSVq8eLF+/fVXW6E2t++xY8f0xBNPaNCgQXJycrLte9WqVapZs6aqVKmS57iZmZn66aef1LdvX7v2559/XhMmTJAkvfHGGwUWbc+dO6fJkydr5MiRevnllyVdGg2RnZ2t5557TmPGjLE9Nj/77DPt2rVLa9asUZs2bWy5mzZtqieffFLr16+/+gl1sJycHA0fPlyjRo3S9u3bdfbsWYfmSUtLk6enp0MzAABQnkRHR9stBwUFyWw252kvCrzOF6w4zjcAlDSmRwDKsHPnzikwMNCuYJvLbLb/8/7714Yu/9r1W2+9pZo1a8rLy0tt2rTRunXr8uzvk08+Ub169eTm5qaIiAjNnj270F+Fjo+P16hRo1S1alW5urravh6fk5NTqNs5e/ZstWnTRl5eXvLy8lKzZs302Wef2db/+uuv6tu3r6pWrSp3d3fVqVNHo0aNcnjBrDD+fj8VZN26dTp9+rSGDx9u1z5w4EB5eXlp/vz5trb58+fLy8tLAwcOtOs7fPhwnTp1yq74abVa9cgjj6hdu3Y6duyYXf+0tDT16tVL9957r+Lj468r908//aSMjIw8uYcPHy7DMLRgwQK73OHh4baCrSQ5Oztr6NCh2rBhg06ePHnFY3Xo0EGNGjXSypUrFR0dLQ8PD1WpUkXPP/+8LBaLrd8rr7wis9mcp0B+3333ydPTUzt37izUbcvPK6+8osTERL300kuF3qZDhw768ccfdezYMbuvTf7d1f5O77vvPnl5eWnnzp3q0qWLvL291alTJ0lSVlaWJk+ebJuiIigoSMOHD9eZM2fs9jF37lx16dJFlStXloeHhxo0aKBx48bp4sWLefLMmDFD4eHhcnNzU4MGDTRr1qx8b9+HH36opk2bysvLS97e3qpfv76eeeaZQp8fAABudtnZ2Xr22WcVGhoqHx8fde7cWfv377frk/s+Z8WKFWrbtq08PT01YsQISVJycrL+/e9/q2bNmnJ1dVWVKlU0ZsyYPK/f77//vtq1a6fg4GBV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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1400x500 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# =============================\n",
|
||||
"# FIGURE 1: Residual histograms\n",
|
||||
@@ -549,7 +499,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.5"
|
||||
"version": "3.11.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"from matplotlib.gridspec import GridSpec\n",
|
||||
"import sys\n",
|
||||
"# sys.path.insert(0, '/home/ferjao_k/sw/aare/build')\n",
|
||||
"sys.path.insert(0, '/home/kferjaoui/sw/aare/build')\n",
|
||||
"sys.path.insert(0, '/home/ferjao_k/aare/build')\n",
|
||||
"\n",
|
||||
"from aare import fit_scurve2\n",
|
||||
"from aare import FallingScurve, fit"
|
||||
@@ -30,7 +29,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'/home/kferjaoui/sw/aare/build/aare/__init__.py'"
|
||||
"'/home/ferjao_k/aare/build/aare/__init__.py'"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
@@ -45,7 +44,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"execution_count": 3,
|
||||
"id": "35772e2c-37c6-4986-a9c0-7dca4a034827",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -72,7 +71,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": 4,
|
||||
"id": "06c8fddb-56d9-4f84-8b21-4ffd8b7bd26f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -128,7 +127,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"execution_count": 5,
|
||||
"id": "dc0b52b6-9fc3-453d-b6eb-e325a2b8342e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -155,7 +154,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"execution_count": 6,
|
||||
"id": "13bcd5a6-8f95-4300-a002-04023d0f9bab",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -187,7 +186,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"execution_count": 7,
|
||||
"id": "1f6bc651-80c1-41dd-8a05-7f15aba006aa",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -217,7 +216,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"execution_count": 8,
|
||||
"id": "5a417145-ce42-4c3a-a7bf-05ff97ba0450",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -227,8 +226,8 @@
|
||||
"text": [
|
||||
"Method time (ms) med|dp0| med|dp1| med|dp2| med|dp3| med|dp4| med|dp5|\n",
|
||||
"--------------------------------------------------------------------------------------------------------------\n",
|
||||
"[lmfit (LM) ] 1030.91 ms 22.1470 0.2336 0.2184 0.3132 14.3955 0.3997\n",
|
||||
"[Minuit2 (analytic) ] 435.57 ms 17.1099 0.2147 0.2293 0.2664 11.9425 0.3518 chi2/ndf=596.8385\n"
|
||||
"[lmfit (LM) ] 359.31 ms 18.6946 0.2249 0.2177 0.2663 11.9347 0.3635\n",
|
||||
"[Minuit2 (analytic) ] 257.18 ms 17.1035 0.2147 0.2293 0.2668 11.9449 0.3518 chi2/ndf=596.8385\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -289,7 +288,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"execution_count": 9,
|
||||
"id": "55ecc77c-0823-408d-a811-8e4f4900f332",
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
@@ -299,20 +298,20 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" Minuit2 (analytic) n_threads= 1 1616.61 ± 22.09 ms (161.6606 ± 2.2089 µs/pixel)\n",
|
||||
" lmfit (LM) n_threads= 1 2927.48 ± 36.18 ms (292.7479 ± 3.6182 µs/pixel)\n",
|
||||
" lmfit (LM) n_threads= 1 1404.39 ± 11.48 ms (140.4392 ± 1.1478 µs/pixel)\n",
|
||||
" Minuit2 (analytic) n_threads= 1 1022.42 ± 1.69 ms (102.2417 ± 0.1690 µs/pixel)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" lmfit (LM) n_threads= 2 1471.15 ± 23.35 ms (147.1150 ± 2.3353 µs/pixel)\n",
|
||||
" Minuit2 (analytic) n_threads= 2 825.64 ± 68.98 ms (82.5642 ± 6.8976 µs/pixel)\n",
|
||||
" lmfit (LM) n_threads= 2 708.78 ± 6.14 ms (70.8775 ± 0.6142 µs/pixel)\n",
|
||||
" Minuit2 (analytic) n_threads= 2 521.15 ± 0.96 ms (52.1151 ± 0.0962 µs/pixel)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" Minuit2 (analytic) n_threads= 4 507.67 ± 93.00 ms (50.7666 ± 9.2997 µs/pixel)\n",
|
||||
" lmfit (LM) n_threads= 4 965.44 ± 137.53 ms (96.5436 ± 13.7534 µs/pixel)\n",
|
||||
" Minuit2 (analytic) n_threads= 4 256.73 ± 2.40 ms (25.6728 ± 0.2399 µs/pixel)\n",
|
||||
" lmfit (LM) n_threads= 4 352.83 ± 0.77 ms (35.2833 ± 0.0767 µs/pixel)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" Minuit2 (analytic) n_threads= 8 352.28 ± 41.26 ms (35.2275 ± 4.1260 µs/pixel)\n",
|
||||
" lmfit (LM) n_threads= 8 555.64 ± 25.59 ms (55.5636 ± 2.5588 µs/pixel)\n",
|
||||
" lmfit (LM) n_threads= 8 226.62 ± 1.48 ms (22.6616 ± 0.1479 µs/pixel)\n",
|
||||
" Minuit2 (analytic) n_threads= 8 164.39 ± 0.51 ms (16.4386 ± 0.0509 µs/pixel)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
@@ -356,14 +355,14 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"execution_count": 10,
|
||||
"id": "d5f3152d-be84-420e-8045-9c42ac5c24cb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png":
|
||||
"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 truncated
|
||||
"iVBORw0KGgoAAAANSUhEUgAABjUAAAN2CAYAAACxdwtsAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3Qd0VNXWwPGdQioBQkjo3RCQoogIogKKFBXQh4oVbE95gigKYsGCigqIgB9gQyyAgKgPlfcUxQYqVREVxYCCCNIC0tOT+dY+vDvMnUxCyiRT8v+tdTOZO3fu3DYzZ84+Z58Qh8PhEAAAAAAAAAAAAD8X6usNAAAAAAAAAAAAKA6CGgAAAAAAAAAAICAQ1AAAAAAAAAAAAAGBoAYAAAAAAAAAAAgIBDUAAAAAAAAAAEBAIKgBAAAAAAAAAAACAkENAAAAAAAAAAAQEAhqAAAAAAAAAACAgEBQAwAAAAAAAAAABASCGgAAACjUjTfeKCEhIWbq3r17sY+ULms9T9fhC19++aVzG3T6448/fLIdQGFef/112zXqC66vr9sDBNr3DQAAqHwIagAA4KfcK2Rdp6pVq8qpp54qw4cPly1btvh6UwOCv1bcFXaew8LCpEaNGnLGGWfIfffdJ7t37/b1psLHli5dKnfddZd06dJFYmJiShSwWbhwofTs2VMSEhIkMjJSmjRpIrfccots3ry50Ofs2rXLvF5ycrJER0dLfHy8nHvuufLyyy9LXl5eOeyhyMyZM+Xmm2+Wtm3bSnh4uHP/dHuLkpmZKRMnTpQOHTpItWrVJDY2Vtq0aSMPPfSQHDp0qNDnffvtt3L11VdLvXr1zHGpXbu29O/fXz799NNy2Dt4cvDgQZkwYYJceeWV5jy7XtcnC4iW9hotzfsBgcn1mho7dqyvNwcAAHhJuLdWBAAAKs6xY8dk48aNZnr11Vfl/ffflwsvvJBTEETy8/NNZez3339vptmzZ8uaNWukYcOGFbodWuGrlcOqol8bdjNmzDDv9ZJwOBxy0003yRtvvGGbv23bNvPZMW/ePHn33Xfl4osvLlDZ37t3b/n7779tgYNvvvnGTP/+97/lvffek6ioKK+epnvvvbfIIIQn+/fvNxXU+j5x9fPPP5vpzTfflM8//1yaNm1qe/yVV16RIUOGmPeaZe/evbJ48WIzPfLII/LYY49JeerYsaM888wzUplpQO7+++8v8fNKc42W9v2AisH3DQAAKC6CGgAABIirrrpKzjzzTMnOzpaVK1fKf/7zHzM/PT1dBg0aZCqGtMWpt+Xm5kpOTo5pBYuS0Qo27XFRpUqVEp/nw4cPmwq5n376yczXnhpTpkyRyZMnV+hp6NOnj5nge9rSuEGDBub60FboWvFenECIawWuVhpqL68FCxbIL7/8Yq7Ra6+91vyvvRWsoOkVV1zhrCzWYJZWBOs1OGvWLPPaH3/8sTz88MMFKuR1ff/85z9lzJgx0qpVK4/bpM9r3769DBgwoMBj+n7R5+k+6rW/fv36k+6jBiasgIZ+Tul9rcjWXh8a8NDPxmuuuUZWrFghoaHHO6rrem+//XZnQKNz587St29fUxn+0UcfmXmPP/64nHXWWXLJJZdIeWndurWZKjs9X+3atTPnff78+XLgwIEily/tNVqa9wMqDt83AACg2BwAAMAvffHFFw79qram1157zfb4ddddZ3v8s88+M/OXLl3quOmmmxynn366o3bt2o6IiAhHdHS045RTTjHzf/zxxwKvdcMNNzjX061bN8fvv//uGDhwoCMhIcEREhJitkW9+OKLjiuuuMKRkpJiHgsPD3fExcWZ17rvvvscaWlpBdbduHFj57offfRRx4cffujo3Lmz2ab69es7xowZ48jOzjbLvvDCC45WrVo5IiMjHU2bNnU8+eSTjvz8/ALrzM3Ndbz++uuOHj16OGrVqmW2IzEx0dG/f3/H559/bltW98f1OLlPun2udu7cafalbdu2jqpVq5ptSU5Odtx9992OXbt2FdgW1/XrcVy3bp3joosuctSoUcPM27p1a6nP88GDB835sx7r3bt3oeu48sorHQ0aNDDLV6tWzXHuuec6XnnlFUdeXl6B5ZcvX+647LLLHPXq1XNUqVLFERsba45Dnz59zDnS1y3s2nD373//29GxY0dHVFSUIykpyXHzzTc79uzZU+C4FLa/7sensGOh6xw1apTj/PPPdzRq1MicG912fc2ePXs65syZU+BaKeq1jh496njssccc7du3N+uyrqHTTjvN8c9//tPx0UcfOfxNenq68389NkUdR+t9oufYWubaa691PrZ//37z3rUe02ve8vzzzzvn6/v/119/dT724IMPOh/Tc/7333/bXvOqq64yj9WpU8eRmppaYJse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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1600x900 with 6 Axes>"
|
||||
]
|
||||
@@ -383,7 +382,7 @@
|
||||
{
|
||||
"data": {
|
||||
"image/png":
|
||||
"iVBORw0KGgoAAAANSUhEUgAABW0AAAHqCAYAAAB/bWzAAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAA5gFJREFUeJzs3XlYVNX/B/D3nWHfdwHZVwVUVBRZVExzya3ct1JTs6xfmq1WbmVaVmZ9W63UrNzSsrS00tTEFfddUQFFQPZN1pl7f3+MTI4DiAhcwPfreXhqzj333s9ch2F4c+45giRJEoiIiIiIiIiIiIioUVDIXQARERERERERERER/YehLREREREREREREVEjwtCWiIiIiIiIiIiIqBFhaEtERERERERERETUiDC0JSIiIiIiIiIiImpEGNoSERERERERERERNSIMbYmIiIiIiIiIiIgaEYa2RERERERERERERI0IQ1siIiIiIiIiIiKiRoShLVEzdvDgQTz22GPw8PCAsbExWrRogYiICLz44os6/WJiYhATE1Pv9QiCgHnz5tX7eWpj5cqVEAQBiYmJ2rYJEybAy8tLtprOnDmDadOmISIiAubm5hAEAbt27aqy/9q1axEaGgoTExO4urpixowZKCws1OtXWFiIGTNmwNXVFSYmJggNDcXatWvrrO7Y2FhMnjwZHTt2hLGxsd51vdP//vc/tGrVCsbGxvD29sb8+fNRXl6u1y89PR0TJkyAg4MDzMzMEBERgR07dtRZ3Q3lzTffhCAICAkJqVH/1atXY+nSpXrtiYmJEAQBH3zwQR1XWD/k/n4iIiJqCIIg1Ohr165d2LVrFwRBwIYNG+Quu0Ya6neGe1VZXY359w4iopoykLsAIqofv//+OwYNGoSYmBgsXrwYLi4uSE1NxeHDh7F27Vp8+OGH2r6ff/65jJVSVQ4fPoxNmzahffv26NmzJzZv3lxl3x9//BHjxo3D5MmT8dFHH+HixYt49dVXcfbsWfz11186fYcMGYK4uDi8++67CAgIwOrVqzF69GiIoogxY8bcd907duzA9u3b0b59e1hZWVUbNL/zzjuYPXs2XnvtNfTu3RtxcXF48803cf36dSxbtkzbr7S0FD179kRubi4+/vhjODk54bPPPkPfvn2xfft2dO/e/b7rbgjHjx/HBx98gBYtWtR4n9WrV+P0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 truncated
|
||||
"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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1400x500 with 2 Axes>"
|
||||
]
|
||||
@@ -503,7 +502,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.13.5"
|
||||
"version": "3.11.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from aare import Pedestal_d, Pedestal_f
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("pedestal_type", "expected_dtype"),
|
||||
[(Pedestal_d, np.float64), (Pedestal_f, np.float32)],
|
||||
)
|
||||
def test_numpy_array_minus_pedestal(pedestal_type, expected_dtype):
|
||||
pedestal = pedestal_type(2, 3)
|
||||
pedestal.push(np.array([[2, 4, 6], [8, 10, 12]], dtype=np.uint16))
|
||||
array = np.array([[12, 14, 16], [18, 20, 22]], dtype=np.uint16)
|
||||
|
||||
result = array - pedestal
|
||||
|
||||
np.testing.assert_array_equal(
|
||||
result, np.array([[10, 10, 10], [10, 10, 10]], dtype=expected_dtype)
|
||||
)
|
||||
assert result.dtype == expected_dtype
|
||||
|
||||
|
||||
def test_numpy_array_minus_pedestal_rejects_incompatible_shape():
|
||||
pedestal = Pedestal_d(2, 3)
|
||||
array = np.zeros((2, 2), dtype=np.float64)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
array - pedestal
|
||||
|
||||
|
||||
def test_pedestal_exposes_mean_as_read_only_buffer():
|
||||
pedestal = Pedestal_d(2, 3)
|
||||
pedestal.push(np.array([[2, 4, 6], [8, 10, 12]], dtype=np.uint16))
|
||||
|
||||
mean = np.asarray(pedestal)
|
||||
|
||||
np.testing.assert_array_equal(mean, pedestal.view())
|
||||
assert np.shares_memory(mean, pedestal.view())
|
||||
assert not mean.flags.writeable
|
||||
@@ -8,10 +8,10 @@ def test_matterhorn10_16bit(test_data_path):
|
||||
with CtbRawFile(test_data_path / "raw/Matterhorn10/16bit_master_0.json", transform = transform.Matterhorn10Transform(dynamic_range=16, num_counters=1)) as f:
|
||||
headers, frames = f.read_frame()
|
||||
|
||||
assert frames.shape == (256, 256)
|
||||
assert frames.shape == (1, 256, 256)
|
||||
assert frames.dtype == np.uint16
|
||||
|
||||
expected_data = np.tile(np.arange(255, -1, -1,dtype=np.uint16), (256, 1)) # TODO: endianess issue ?
|
||||
expected_data = np.tile(np.arange(255, -1, -1,dtype=np.uint16), (1, 256, 1)) # TODO: endianess issue ?
|
||||
|
||||
assert np.all(frames == expected_data)
|
||||
|
||||
@@ -22,24 +22,23 @@ def test_matterhorn10_8bit(test_data_path):
|
||||
with CtbRawFile(test_data_path / "raw/Matterhorn10/8bit_master_1.json", transform = transform.Matterhorn10Transform(dynamic_range=8, num_counters=1)) as f:
|
||||
headers, frames = f.read_frame()
|
||||
|
||||
assert frames.shape == (256, 256)
|
||||
assert frames.shape == (1, 256, 256)
|
||||
assert frames.dtype == np.uint8
|
||||
|
||||
expected_data = np.tile(np.arange(255, -1, -1,dtype=np.uint8), (256, 1)) # TODO: endianess issue ?
|
||||
expected_data = np.tile(np.arange(255, -1, -1,dtype=np.uint8), (1, 256, 1)) # TODO: endianess issue ?
|
||||
|
||||
assert np.all(frames == expected_data)
|
||||
|
||||
|
||||
@pytest.mark.withdata
|
||||
def test_matterhorn10_4bit(test_data_path):
|
||||
""" Matterhorn10Transform 1 counter 4 bit dynamic range """
|
||||
with CtbRawFile(test_data_path / "raw/Matterhorn10/newnewrun_4bit_1counter_master_0.json", transform = transform.Matterhorn10Transform(dynamic_range=4, num_counters=1)) as f:
|
||||
headers, frames = f.read_frame()
|
||||
|
||||
assert frames.shape == (256, 256)
|
||||
assert frames.shape == (1, 256, 256)
|
||||
assert frames.dtype == np.uint8
|
||||
|
||||
expected_data = np.tile(np.tile(np.arange(15, -1, -1, dtype=np.uint8), 16), (256, 1)) # TODO: endianess issue ?
|
||||
expected_data = np.tile(np.tile(np.arange(15, -1, -1, dtype=np.uint8), 16), (1, 256, 1)) # TODO: endianess issue ?
|
||||
|
||||
assert np.all(frames == expected_data)
|
||||
|
||||
@@ -50,9 +49,9 @@ def test_matterhorn10_16bit_4counters(test_data_path):
|
||||
with CtbRawFile(test_data_path / "raw/Matterhorn10/4counter_16bit_master_4.json", transform = transform.Matterhorn10Transform(dynamic_range=16, num_counters=4)) as f:
|
||||
headers, frames = f.read_frame()
|
||||
|
||||
assert frames.shape == (4*256, 256)
|
||||
assert frames.shape == (4, 256, 256)
|
||||
assert frames.dtype == np.uint16
|
||||
|
||||
expected_data = np.tile(np.arange(255, -1, -1,dtype=np.uint16), (4*256, 1)) # TODO: endianess issue ?
|
||||
expected_data = np.tile(np.arange(255, -1, -1,dtype=np.uint16), (4, 256, 1)) # TODO: endianess issue ?
|
||||
|
||||
assert np.all(frames == expected_data)
|
||||
Reference in new issue
Block a user