IMP logo
IMP Reference Guide  develop.d97d4ead1f,2024/11/21
The Integrative Modeling Platform
DecayConvolution.h
Go to the documentation of this file.
1 /**
2  * \file IMP/bff/DecayConvolution.h
3  * \brief Compute convolved decay
4  *
5  * \authors Thomas-Otavio Peulen
6  * Copyright 2007-2022 IMP Inventors. All rights reserved.
7  *
8  */
9 
10 #ifndef IMPBFF_DECAYCONVOLUTION_H
11 #define IMPBFF_DECAYCONVOLUTION_H
12 
13 #include <IMP/bff/bff_config.h>
14 
15 #include <memory>
16 #include <cmath> /* std::fmod */
17 #include <iostream>
18 #include <algorithm> /* std::fill */
19 
20 #include <IMP/bff/DecayRoutines.h>
21 
22 #include <IMP/bff/DecayCurve.h>
23 #include <IMP/bff/DecayModifier.h>
25 
26 IMPBFF_BEGIN_NAMESPACE
27 
28 
29 
30 //! Compute convolved decay
32 
33 public:
34 
35  typedef enum {
36  FAST_PERIODIC_TIME,
37  FAST_TIME,
38  FAST_PERIODIC,
39  FAST,
40  FAST_AVX,
41  FAST_PERIODIC_AVX
42  } ConvolutionType;
43 
44  static void compute_corrected_irf(
45  DecayCurve *irf,
46  DecayCurve *corrected_irf,
47  double irf_shift_channels,
48  double irf_background_counts
49  ) {
50 #if IMPBFF_VERBOSE
51  std::clog << "DecayConvolution::compute_corrected_irf:" << std::endl;
52  std::clog << "-- irf_shift_channels:" << irf_shift_channels << std::endl;
53  std::clog << "-- irf_background_counts:" << irf_background_counts << std::endl;
54  std::clog << "-- irf->ptr():" << irf << std::endl;
55  std::clog << "-- irf->size():" << irf->size() << std::endl;
56  std::clog << "-- corrected_irf->ptr():" << corrected_irf << std::endl;
57  std::clog << "-- corrected_irf->size():" << corrected_irf->size() << std::endl;
58 #endif
59  corrected_irf->resize(irf->size());
60  for (size_t i = 0; i < irf->size(); i++)
61  corrected_irf->_y[i] = std::max(irf->_y[i] - irf_background_counts, 0.0);
62  corrected_irf->set_shift(irf_shift_channels);
63  }
64 
65  //***********************************************//
66  //* STATIC METHODS *//
67  //***********************************************//
68  /*!
69  * Compute a mean lifetime by the moments of the decay and the instrument
70  * response function.
71  *
72  * The computed lifetime is the first lifetime determined by the method of
73  * moments (Irvin Isenberg, 1973, Biophysical journal).
74  *
75  * @param irf_histogram
76  * @param decay_histogram
77  * @param micro_time_resolution
78  * @return
79  */
80  static double compute_mean_lifetime(
81  std::vector<double> irf_histogram,
82  std::vector<double> decay_histogram,
83  double micro_time_resolution
84  ){
85 #if IMPBFF_VERBOSE
86  std::clog << "DecayConvolution::compute_mean_lifetime" << std::endl;
87  std::clog << "-- micro_time_resolution:" << micro_time_resolution << std::endl;
88  std::clog << "-- irf_histogram.size():" << irf_histogram.size() << std::endl;
89  std::clog << "-- decay_histogram.size():" << decay_histogram.size() << std::endl;
90 #endif
91  double m0_irf = std::accumulate(irf_histogram.begin(), irf_histogram.end(),0.0);
92  double m0_data = std::accumulate(decay_histogram.begin(), decay_histogram.end(), 0.0);
93 #if IMPBFF_VERBOSE
94  std::clog << "-- m0_irf:" << m0_irf << std::endl;
95  std::clog << "-- m0_data:" << m0_data << std::endl;
96 #endif
97  double m1_irf = 0.0;
98  double m1_data = 0.0;
99  for(size_t i = 0; i<irf_histogram.size(); i++)
100  m1_irf += (double) i * irf_histogram[i];
101  for(size_t i = 0; i<decay_histogram.size(); i++)
102  m1_data += (double) i * decay_histogram[i];
103 #if IMPBFF_VERBOSE
104  std::clog << "-- m1_irf:" << m1_irf << std::endl;
105  std::clog << "-- m1_data:" << m1_data << std::endl;
106 #endif
107  double g1 = m0_data / m0_irf;
108  double g2 = (m1_data - g1 * m1_irf) / m0_irf;
109  double tau1 = g2 / g1 * micro_time_resolution;
110  return tau1;
111  }
112 
113 private:
114 
115  /// Input lifetime spectrum
116  Pointer<DecayLifetimeHandler> lifetime_handler;
117 
118  /// Background and shift corrected irf
119  DecayCurve *corrected_irf = nullptr;
120 
121  /// The time shift of the irf
122  double irf_shift_channels = 0.0;
123 
124  /// Background counts of irf
125  double irf_background_counts = 0.0;
126 
127  /// The method used for convolution
128  int convolution_method = 0;
129 
130  /// The excitation repetition period (usually in nano seconds)
131  double excitation_period = std::numeric_limits<double>::max();
132 
133  /// Tracks if the computed corrected irf matched the input
134  bool corrected_irf_valid = false;
135 
136  void convolve_lifetimes(DecayCurve* decay, bool zero_fill = true){
137  // Get lifetime spectrum
138  auto lh = lifetime_handler->get_lifetime_spectrum();
139  auto lt = lh.data(); int ln = lh.size();
140 
141  // corrected irf
142  auto irfc = &get_corrected_irf();
143 
144  // convolution range
145  auto start = get_start(irfc);
146  int stop = get_stop(irfc);
147  double dt = decay->get_average_dx();
148 
149  // excitation period
150  double ex_per = get_excitation_period();
151 
152  // convolution method
153  int cm = get_convolution_method();
154 
155  // Data
156  double* my = decay->get_y().data();
157  int nm = (int) decay->get_y().size();
158  double* mx = decay->get_x().data();
159 
160  // IRF
161  double* iy = irfc->get_y().data();
162  int ni = (int) irfc->get_y().size();
163 
164  if(nm > 1) {
165  if(zero_fill){
166  std::fill(my, my + nm, 0.0);
167  }
168  if (cm == FAST_PERIODIC_TIME) {
170  my, nm,
171  mx, nm,
172  iy, ni,
173  lt, ln,
174  start, stop,
175  ex_per);
176  } else if (cm == FAST_TIME) {
178  my, nm,
179  mx, nm,
180  iy, ni,
181  lt, ln,
182  start, stop);
183  } else if (cm == FAST_PERIODIC) {
184  decay_fconv_per(my, lt, iy, ln / 2, start, stop, nm, ex_per, dt);
185  } else if (cm == FAST) {
186  decay_fconv(my, lt, iy, ln / 2, start, stop, dt);
187  } else if (cm == FAST_AVX) {
188  decay_fconv_avx(my, lt, iy, ln / 2, start, stop, dt);
189  } else if (cm == FAST_PERIODIC_AVX) {
190  decay_fconv_per_avx(my, lt, iy, ln / 2, start, stop, nm, ex_per, dt);
191  }
192  }
193 #if IMPBFF_VERBOSE
194  std::clog << "DecayConvolution::convolve_lifetimes" << std::endl;
195  std::clog << "-- convolution_method: " << cm << std::endl;
196  std::clog << "-- convolution start, stop: " << start << ", " << stop << std::endl;
197  std::clog << "-- histogram spacing (dt): " << dt << std::endl;
198  std::clog << "-- excitation_period: " << ex_per << std::endl;
199  std::clog << "-- lifetime spectrum: "; for(auto &v: l) std::clog << v << ", "; std::clog << "\n";
200  // std::clog << "-- irfc: "; for(auto &v: *(irfc->get_y())) std::clog << v << ", "; std::clog << "\n";
201  std::clog << std::endl;
202 #endif
203  }
204 
205  void set_data(DecayCurve* v) override {
206  DecayModifier::set_data(v);
207  auto irf = get_data();
208  if(v != nullptr) {
209  corrected_irf->set_x(irf->x);
210  corrected_irf->set_y(irf->y);
211  }
212  }
213 
214  void update_irf(){
215  if(!corrected_irf_valid) {
216  compute_corrected_irf(
217  get_irf(), corrected_irf,
218  get_irf_shift_channels(),
219  get_irf_background_counts());
220  }
221  corrected_irf_valid = true;
222  }
223 
224 public:
225 
226  /*================*/
227  /* IRF */
228  /*================*/
229  void set_irf(DecayCurve *v) {
230  set_data(v);
231  }
232 
233  DecayCurve *get_irf() {
234  return get_data();
235  }
236 
237  /*================*/
238  /* Corrected IRF */
239  /*================*/
240  void set_irf_shift_channels(double v) {
241  double n_channels = std::max(1., (double) get_irf()->size());
242  irf_shift_channels = std::fmod(v, n_channels);
243  corrected_irf_valid = false;
244  }
245 
246  double get_irf_shift_channels() const {
247  return irf_shift_channels;
248  }
249 
250  void set_irf_background_counts(double v) {
251  irf_background_counts = v;
252  corrected_irf_valid = false;
253  }
254 
255  double get_irf_background_counts() const {
256  return irf_background_counts;
257  }
258 
259  DecayCurve& get_corrected_irf() {
260  update_irf();
261  return *corrected_irf;
262  }
263 
264  /*================*/
265  /* Convolution */
266  /*================*/
267 
268  /// The method used for convolution
269  /*!
270  * 0 - fconv_per_cs_time_axis
271  * 1 - fconv_cs_time_axis
272  * 2 - fconv_per
273  * 3 - fconv
274  * 4 - fconv with AVX optimization
275  * 5 - fconv_per with AVX optimization
276  */
278  convolution_method = std::max(0, std::min(5, v));
279  }
280 
281  int get_convolution_method() const {
282  return convolution_method;
283  }
284 
285  void set_excitation_period(double v) {
286  excitation_period = v;
287  }
288 
289  double get_excitation_period() const {
290  return excitation_period;
291  }
292 
293  double get_mean_lifetime(DecayCurve* decay){
294  auto irf = get_corrected_irf().y;
295  auto data = decay->y;
296  auto dt = decay->get_average_dx();
297  return compute_mean_lifetime(irf, data, dt);
298  }
299 
300  void set(
301  int convolution_method = FAST_PERIODIC_TIME,
302  double excitation_period = 100,
303  double irf_shift_channels = 0.0,
304  double irf_background_counts = 0
305  ) {
306  set_irf_background_counts(irf_background_counts);
307  set_convolution_method(convolution_method);
308  set_excitation_period(excitation_period);
309  set_irf_shift_channels(irf_shift_channels);
310  }
311 
312  DecayConvolution(
313  DecayLifetimeHandler *lifetime_handler= nullptr,
314  DecayCurve *instrument_response_function = nullptr,
315  int convolution_method = FAST,
316  double excitation_period = 100,
317  double irf_shift_channels = 0.0,
318  double irf_background_counts = 0,
319  int start = 0, int stop = -1,
320  bool active = true
321  ) : DecayModifier(instrument_response_function, start, stop, active){
322 #if IMPBFF_VERBOSE
323  std::clog << "DecayConvolution::DecayConvolution" << std::endl;
324 #endif
325  corrected_irf = new DecayCurve();
326  corrected_irf->resize(1);
327  default_data->resize(1);
328  default_data->y[0] = 1.0;
329  this->lifetime_handler = lifetime_handler;
330  set(
331  convolution_method,
332  excitation_period,
333  irf_shift_channels,
334  irf_background_counts
335  );
336  }
337 
338  ~DecayConvolution() override {
339  delete corrected_irf;
340  }
341 
342  void add(DecayCurve* out) override{
343  if ((out != nullptr) && is_active()) {
344  // resize output to IRF
345  out->resize(get_data()->size(), 0.0);
346  convolve_lifetimes(out);
347  }
348  }
349 
350 };
351 
353 
354 IMPBFF_END_NAMESPACE
355 
356 
357 #endif //IMPBFF_DECAYCONVOLUTION_H
void set_shift(double v)
Sets the time shift of the decay curve.
Simple Accessible Volume decorator.
void resize(size_t n, double v=0.0, double dx=1.0)
Resize the curve.
void decay_fconv_avx(double *fit, double *x, double *lamp, int numexp, int start, int stop, double dt=0.05)
Convolve lifetime spectrum with instrument response (fast convolution, AVX optimized for large lifeti...
void set_convolution_method(int v)
The method used for convolution.
void decay_fconv_cs_time_axis(double *inplace_output, int n_output, double *time_axis, int n_time_axis, double *irf, int n_irf, double *lifetime_spectrum, int n_lifetime_spectrum, int convolution_start=0, int convolution_stop=-1)
Decay routines (e.g. convolution, scaling, and lamp shift routines)
Compute convolved decay.
size_t size() const
Get the size of the curve.
A decorator that modifies a DecayCurve within a specified range.
Definition: DecayModifier.h:29
A more IMP-like version of the std::vector.
Definition: Vector.h:50
void decay_fconv(double *fit, double *x, double *lamp, int numexp, int start, int stop, double dt=0.05)
Convolve lifetime spectrum with instrument response (fast convolution, low repetition rate) ...
void decay_fconv_per(double *fit, double *x, double *lamp, int numexp, int start, int stop, int n_points, double period, double dt=0.05)
Convolve lifetime spectrum with instrument response (fast convolution, high repetition rate) ...
A smart pointer to a reference counted object.
Definition: Pointer.h:87
double get_average_dx()
Get the average x-value difference.
#define IMP_VALUES(Name, PluralName)
Define the type for storing sets of values.
Definition: value_macros.h:23
std::vector< double > & get_x()
Get the x-values of the curve.
void add(DecayCurve *out) override
Class for fluorescence decay curves.
static double compute_mean_lifetime(std::vector< double > irf_histogram, std::vector< double > decay_histogram, double micro_time_resolution)
void decay_fconv_per_cs_time_axis(double *model, int n_model, double *time_axis, int n_time_axis, double *irf, int n_irf, double *lifetime_spectrum, int n_lifetime_spectrum, int convolution_start=0, int convolution_stop=-1, double period=100.0)
Store and handle lifetime spectra.
Class for fluorescence decay curves.
Definition: DecayCurve.h:38
void decay_fconv_per_avx(double *fit, double *x, double *lamp, int numexp, int start, int stop, int n_points, double period, double dt=0.05)
Convolve lifetime spectrum with instrument response (fast convolution, high repetition rate)...
void set_y(std::vector< double > &v)
Sets the y values of the decay curve.
std::vector< double > & get_y()
Returns the y values of the decay curve.