IMP logo
IMP Reference Guide  develop.d97d4ead1f,2024/11/21
The Integrative Modeling Platform
lib/IMP/bff/spectroscopy/decay.py
1 import typing
2 import numpy as np
3 
4 import IMP.bff
5 
6 from typing import NamedTuple
7 
8 MAX_FLOAT = np.finfo(np.float64).max
9 MIN_FLOAT = np.finfo(np.float64).min
10 
11 
12 class DataSettings(NamedTuple):
13  data: np.ndarray = None
14  data_noise: np.ndarray = None
15  time_axis: np.array = None
16  irf_histogram: np.array = None
17  acquisition_time: float = MAX_FLOAT
18 
19 
20 class LifetimeSettings(NamedTuple):
21  lifetime_spectrum: np.array = np.array([], dtype=np.float64)
22  use_amplitude_threshold: bool = False
23  abs_lifetime_spectrum: bool = True
24  amplitude_threshold: float = MIN_FLOAT
25 
26 
27 class ConvolutionSettings(NamedTuple):
28  convolution_method: int = IMP.bff.DecayConvolution.FAST
29  excitation_period: float = 100.0
30  irf_shift_channels: float = 0.0
31  irf_background_counts: float = 0.0
32  start: int = 0
33  stop: int = -1
34  active: bool = True
35 
36 
37 class PatternSettings(NamedTuple):
38  constant_offset: float = 0.0
39  pattern: IMP.bff.DecayCurve = None
40  pattern_fraction: float = 0.0
41  start: int = 0
42  stop: int = -1
43  active: bool = True
44 
45 
46 class PileupSettings(NamedTuple):
47  pile_up_model: str = "coates"
48  repetition_rate: float = 10.0
49  instrument_dead_time: float = 120.0
50  start: int = 0
51  stop: int = -1
52  active: bool = True
53 
54 
55 class ScalingSettings(NamedTuple):
56  constant_offset: float = 0.0
57  start: int = 0
58  stop: int = -1
59  active: bool = True
60 
61 
62 class LinearizationSettings(NamedTuple):
63  linearization_table: IMP.bff.DecayCurve = None
64  start: int = 0
65  stop: int = -1
66  active: bool = True
67 
68 
69 class ScoreSettings(NamedTuple):
70  score_type: str = "default"
71  start: int = 0
72  stop: int = -1
73 
74 
75 class Decay(object):
76 
77  # These attributes are skipped when saving to JSON
78  _ignore_attributes = [
79  'irf_histogram',
80  # 'tttr_data',
81  # 'tttr_irf',
82  'linearization_table',
83  'corrected_irf',
84  'x',
85  'y',
86  'data_weights',
87  'number_of_photons'
88  ]
89 
90  _attributes = {
91  #VERSION
92  #####################
93  # TODO
94  # 'version': ("", "get_version"),
95  # Data
96  ############################
97  'data': ("_data", "y"),
98  'data_noise': ("_data", "ey"),
99  'model': ("_model", "y"),
100  'y': ("_model", "y"),
101  'x': ("_model", "x"),
102  'acquisition_time': ("_data", "acquisition_time"),
103  'time_axis': ("_data", "x"),
104  'irf_histogram': ("_irf", "y"),
105  'irf': ("_irf", "y"),
106  # 'tttr_data': ("_data", None, "set_tttr"),
107  # 'tttr_irf': ("_irf", None, "set_tttr"),
108  # LIFETIME SPECTRUM
109  ############################
110  'lifetime_spectrum': ("lifetime_handler", "get_lifetime_spectrum", "set_lifetime_spectrum"),
111  'use_amplitude_threshold': ("lifetime_handler", "use_amplitude_threshold"),
112  'abs_lifetime_spectrum': ("lifetime_handler", "abs_lifetime_spectrum"),
113  'amplitude_threshold': ("lifetime_handler", "amplitude_threshold"),
114  # CONVOLUTION
115  ############################
116  'corrected_irf': ("decay_convolution.corrected_irf", "y"),
117  'convolution_range': ("decay_convolution", "get_range", "set_range"),
118  'convolution_method': ("decay_convolution", "convolution_method"),
119  'excitation_period': ("decay_convolution", "excitation_period"),
120  'irf_shift_channels': ("decay_convolution", "irf_shift_channels"),
121  'irf_background_counts': ("decay_convolution", "irf_background_counts"),
122  # Scatter
123  ############################
124  'scatter_fraction': ("decay_scatter", "pattern_fraction"),
125  # BACKGROUND
126  ############################
127  'constant_offset': ("", "constant_background"),
128  'pattern_fraction': ("decay_background", "pattern_fraction"),
129  # PILE-UP
130  #############################
131  'pile_up_model': ("decay_pileup", "pile_up_model"),
132  'instrument_dead_time': ("decay_pileup", "instrument_dead_time"),
133  'use_pile_up_correction': ("decay_pileup", "active"),
134  # SCALE
135  ############################
136  'scale_model_to_data': ("decay_scale", "active"),
137  'number_of_photons': ("decay_scale", "number_of_photons"),
138  # LINEARIZATION
139  ############################
140  'linearization_table': ("decay_linearization.data", "y"),
141  'linearization': ("decay_linearization.data", "y"),
142  'use_linearization': ("decay_linearization", "active"),
143  # SCORE
144  ###########################
145  'score_type': ("decay_score", "score_type"),
146  'score_range': ('', 'get_score_range', 'set_score_range'),
147  'score': ("decay_score", "score"),
148  'weighted_residuals': ("decay_score", "weighted_residuals")
149  }
150 
151  _methods = {
152  'get_mean_lifetime': ("decay_convolution", "get_mean_lifetime"),
153  'get_score': ("decay_score", "get_score")
154  }
155 
156  @staticmethod
157  def make_decay_curves(
158  data: np.ndarray = None,
159  data_noise: np.ndarray = None,
160  time_axis: np.array = None,
161  irf_histogram: np.array = None,
162  # tttr_data: tttrlib.TTTR = None,
163  # tttr_irf: tttrlib.TTTR = None,
164  # tttr_micro_time_coarsening: int = 1,
165  acquisition_time: float = MAX_FLOAT,
166  ) -> typing.Tuple[IMP.bff.DecayCurve, IMP.bff.DecayCurve]:
167  # Data
168  if time_axis is None:
169  time_axis = np.array([], np.float64)
170  if data is None:
171  data = np.array([], np.float64)
172  # IRF
173  if irf_histogram is None:
174  irf_histogram = np.zeros_like(data)
175  if len(irf_histogram) > 0:
176  irf_histogram[0] = 1.0
177  decay = IMP.bff.DecayCurve(x=time_axis, y=data, acquisition_time=acquisition_time)
178  irf = IMP.bff.DecayCurve(x=time_axis, y=irf_histogram)
179  if data_noise is not None:
180  decay.set_ey(data_noise)
181  return decay, irf
182 
183  def __init__(
184  self,
185  data_settings=None, # type: DataSettings
186  lifetime_settings=None, # type: LifetimeSettings
187  convolution_settings=None, # type: ConvolutionSettings
188  scatter_settings=None, # type: PatternSettings
189  background_settings=None, # type: PatternSettings
190  pileup_settings=None, # type: PileupSettings
191  scaling_settings=None, # type: ScalingSettings
192  linearization_settings=None, # type: LinearizationSettings
193  score_settings=None # type: ScoreSettings
194  ):
195  super().__init__()
196  if data_settings is None:
197  data_settings = DataSettings()
198  if lifetime_settings is None:
199  lifetime_settings = LifetimeSettings()
200  if convolution_settings is None:
201  convolution_settings = ConvolutionSettings()
202  if background_settings is None:
203  background_settings = PatternSettings()
204  if scatter_settings is None:
205  scatter_settings = PatternSettings()
206  if pileup_settings is None:
207  pileup_settings = PileupSettings()
208  if linearization_settings is None:
209  linearization_settings = LinearizationSettings()
210  if scaling_settings is None:
211  scaling_settings = ScalingSettings()
212  if score_settings is None:
213  score_settings = ScoreSettings()
214 
215  # init decay curves
216  data, irf = self.make_decay_curves(*data_settings)
217  model = IMP.bff.DecayCurve(data.x)
218 
219  lifetime_handler = IMP.bff.DecayLifetimeHandler(*lifetime_settings)
220  decay_convolution = IMP.bff.DecayConvolution(lifetime_handler, irf, *convolution_settings)
221  decay_scatter = IMP.bff.DecayPattern(*scatter_settings)
222  decay_scatter.data = irf
223  decay_background = IMP.bff.DecayPattern(*background_settings)
224  decay_pileup = IMP.bff.DecayPileup(data, *pileup_settings)
225  decay_linearization = IMP.bff.DecayLinearization(*linearization_settings)
226  decay_scale = IMP.bff.DecayScale(data, *scaling_settings)
227  decay_score = IMP.bff.DecayScore(model, data, *score_settings)
228 
229  self._data, self._irf, self._model = data, irf, model
230  self.lifetime_handler = lifetime_handler
231  self.decay_convolution = decay_convolution
232  self.decay_scatter = decay_scatter
233  self.decay_pileup = decay_pileup
234  self.decay_linearization = decay_linearization
235  self.decay_scale = decay_scale
236  self.decay_background = decay_background
237  self.decay_score = decay_score
238 
239  self._decay_modifier = [
240  self.decay_convolution,
241  self.decay_scatter,
242  # self.decay_pileup, # TODO: seems cn
243  self.decay_linearization,
244  self.decay_scale,
245  self.decay_background,
246  ]
247 
248  def load(self, *args, **kwargs):
249  super().load(*args, **kwargs)
250  self._model.x = self._data.x
251  self._irf.x = self._data.x
252 
253  def update(self):
254  dc = self
255  for dm in self._decay_modifier:
256  dm.add(dc._model)
257 
258  @property
259  def score(self, *args, **kwargs):
260  self.update()
261  return self.decay_score.get_score(*args, **kwargs)
262 
263  @property
264  def mean_lifetime(self):
265  return self.decay_convolution.get_mean_lifetime(self._data)
266 
267  @property
268  def constant_background(self):
269  return self.decay_scale.constant_background
270 
271  @constant_background.setter
272  def constant_background(self, v):
273  self.decay_scale.constant_background = v
274  self.decay_background.constant_offset = v
275 
276  def get_score_range(self):
277  return self.decay_score.get_range(self._data)
278 
279  def set_score_range(self, start_stop):
280  for dm in self._decay_modifier:
281  dm.set_range(start_stop)
282  self.decay_score.set_range(start_stop)
283 
A decorator that adds pile-up effects to a DecayCurve object.
Definition: DecayPileup.h:34
Compute convolved decay.
A decay modifier to apply linearization to a DecayCurve.
A class for scaling a DecayCurve by a constant factor and subtracting a constant background value...
Definition: DecayScale.h:34
Class for scoring model fluorescence decay.
Definition: DecayScore.h:34
Class for fluorescence decay curves.
Definition: DecayCurve.h:38
The DecayPattern class represents a decay pattern with a constant offset and a background pattern...
Definition: DecayPattern.h:26
Bayesian Fluorescence Framework.
Store and handle lifetime spectra.