7#ifndef RLDeconvolutor_H
8#define RLDeconvolutor_H
17#include "FairLogger.h"
22 RLDeconvolutor(
const std::vector<float>& y,
const std::vector<float>& kernel_,
const float R2threshold_,
const int max_iterations_)
25 reversed_kernel(kernel_),
27 R2threshold(R2threshold_),
28 max_iterations(max_iterations_),
31 deconvolved.resize(y.size(), 1.0);
32 std::reverse(reversed_kernel.begin(), reversed_kernel.end());
40 auto next_step = convolution(deconvolved, kernel);
41 for (
int iter = 0; iter < max_iterations; ++iter) {
43 LOG(debug4) <<
"RLDeconvolutor : calculating error " << iter;
44 std::vector<float> error = constrainOperator(elementwiseDivision(blurred_signal, next_step));
45 LOG(debug4) <<
"RLDeconvolutor : recalculating deconvolved " << iter;
46 deconvolved = elementwiseMultiplication(deconvolved, convolution(error, reversed_kernel));
47 next_step = convolution(deconvolved, kernel);
49 R2.push_back(R2score(blurred_signal, next_step));
50 if (R2.back() > R2default)
51 R2.back() = R2default;
52 LOG(debug4) <<
"RLDeconvolutor : estimated error R2 " << R2.back();
55 if (R2.back() < R2threshold) {
56 LOG(debug4) <<
"RLDeconvolutor : coverged at iter " << iter;
63 LOG(debug4) <<
"RLDeconvolutor : did not converge.";
66 LOG(debug4) <<
"RLDeconvolutor : findCamelPoints";
67 camel_points = findCamelPoints();
70 LOG(debug4) <<
"RLDeconvolutor : extracting";
83 return signal_deconvolved;
88 return signal_decomposed;
92 return convolution(deconvolved, kernel);
95 const std::vector<float>&
getR2()
const {
100 std::vector<float> blurred_signal;
101 std::vector<float> deconvolved;
102 std::vector<float> kernel;
103 std::vector<float> reversed_kernel;
104 std::vector<float> R2;
106 inline static constexpr float R2default = 2.0;
110 std::vector<size_t> camel_points;
111 std::vector<std::pair<size_t, float>> signal_info;
112 std::vector<std::vector<float>> signal_deconvolved;
113 std::vector<std::vector<float>> signal_decomposed;
115 std::vector<float> convolution(
const std::vector<float>& signal,
const std::vector<float>& kern)
const {
118 size_t signal_size = signal.size();
119 size_t kernel_size = kern.size();
120 size_t padding = kernel_size / 2;
122 std::vector<float> padded_signal(signal_size + 2 * padding, 0.0);
123 std::copy(signal.begin(), signal.end(), padded_signal.begin() + padding);
125 std::vector<float> result(signal_size, 0.0);
127 for (
size_t i = 0;
i < signal_size; ++
i)
128 for (
size_t j = 0; j < kernel_size; ++j)
129 result.at(
i) += padded_signal.at(
i + kernel_size - 1 - j) * kern.at(j);
134 std::vector<float> constrainOperator(
const std::vector<float>& data_array) {
135 std::vector<float> out_array(data_array.size(), 0.0);
138 auto condition = [](
float number) {
143 for (
size_t i = 0;
i < data_array.size(); ++
i) {
144 if (condition(data_array.at(
i)))
145 out_array.at(
i) = data_array.at(
i);
147 out_array.at(
i) = 0.0;
152 std::vector<float> elementwiseMultiplication(
const std::vector<float>& vec1,
const std::vector<float>& vec2)
const {
153 std::vector<float>
result(vec1.size());
154 assert(vec1.size() == vec2.size());
156 for (
size_t i = 0;
i < vec1.size(); ++
i)
162 std::vector<float> elementwiseDivision(
const std::vector<float>& vec1,
const std::vector<float>& vec2)
const {
163 std::vector<float>
result(vec1.size());
164 assert(vec1.size() == vec2.size());
166 for (
size_t i = 0;
i < vec1.size(); ++
i)
167 result.at(
i) = vec1.at(
i) / (vec2.at(
i) + std::numeric_limits<float>::min());
172 float R2score(
const std::vector<float>& true_values,
const std::vector<float>& predicted_values)
const {
173 assert(true_values.size() == predicted_values.size());
174 if (true_values.empty())
return R2default;
176 float mean_true = std::accumulate(true_values.begin(), true_values.end(), 0.0) / true_values.size();
177 float ss_total = 0.0;
178 float ss_residual = 0.0;
180 for (
size_t i = 0;
i < true_values.size(); ++
i) {
181 ss_total += std::pow(true_values.at(
i) - mean_true, 2);
182 ss_residual += std::pow(true_values.at(
i) - predicted_values.at(
i), 2);
185 return ss_residual / (ss_total + std::numeric_limits<float>::min());
188 std::vector<size_t> findMaximaIndices(
const std::vector<float>& vec)
const {
189 std::vector<size_t> maxima_indices;
190 if (vec.empty())
return maxima_indices;
192 for (
size_t i = 1;
i < vec.size() - 1; ++
i) {
193 if (vec.at(
i) > vec.at(
i - 1) && vec.at(
i) > vec.at(
i + 1)) {
194 maxima_indices.push_back(
i);
198 return maxima_indices;
201 std::vector<size_t> findCamelPoints()
const {
202 std::vector<size_t> maxima_indices = findMaximaIndices(deconvolved);
203 std::vector<size_t> c_points;
205 LOG(debug4) <<
"RLDeconvolutor : findCamelPoints between total maxima " << maxima_indices.size();
206 if (!maxima_indices.empty()) {
207 for (
size_t i = 0;
i < maxima_indices.size() - 1; ++
i) {
209 auto camel_area = getSubvector(deconvolved, maxima_indices.at(
i), maxima_indices.at(
i + 1));
210 if (!camel_area.empty()) {
211 size_t camel_point = maxima_indices.at(
i) + std::distance(camel_area.begin(), std::min_element(camel_area.begin(), camel_area.end()));
212 c_points.push_back(camel_point);
216 c_points.insert(c_points.begin(), 0);
217 c_points.push_back(deconvolved.size() - 1);
218 for(
auto it : c_points)
219 LOG(debug4) <<
"RLDeconvolutor : found CamelPoints " << it;
224 std::vector<float> getSubvector(
const std::vector<float>& vec,
size_t start,
size_t end)
const {
225 return std::vector<float>(vec.begin() + start, vec.begin() + end);
228 void extractSignalInfo() {
230 if (camel_points.empty())
return;
233 for (
size_t i = 0;
i < camel_points.size() - 1; ++
i) {
234 int start_index = camel_points.at(
i);
235 int end_index = camel_points.at(
i + 1);
238 std::vector<float> subvector = getSubvector(deconvolved, start_index, end_index);
239 std::vector<float> thisVector(deconvolved.size(), 0.0);
240 std::copy(subvector.begin(), subvector.end(), thisVector.begin() + start_index);
241 signal_deconvolved.push_back(thisVector);
244 std::vector<float> reconstructed_signal = convolution(thisVector, kernel);
245 signal_decomposed.push_back(reconstructed_signal);
248 auto max_amplitude_iter = std::max_element(reconstructed_signal.begin(), reconstructed_signal.end());
249 float max_amplitude = *max_amplitude_iter;
250 int max_amplitude_position = std::distance(reconstructed_signal.begin(), max_amplitude_iter);
253 signal_info.push_back(std::make_pair(max_amplitude_position, max_amplitude));
friend F32vec4 max(const F32vec4 &a, const F32vec4 &b)
Class to apply Richardson-Lucy deconvolution.
const std::vector< float > & getR2() const
RLDeconvolutor(const std::vector< float > &y, const std::vector< float > &kernel_, const float R2threshold_, const int max_iterations_)
std::vector< float > getWfmApproximation() const
const std::vector< std::vector< float > > & getSignalDeconvolution() const
const std::vector< std::pair< size_t, float > > & getSignalInfo() const
const std::vector< std::vector< float > > & getSignalDecomposition() const
void setMaxIterations(int max)
void setR2threshold(float thr)