Source code for bio_rtd.pdf

"""Wrapping classes for probability distribution functions

This module contains subclasses of `bio_rtd.core.PDF`.

The integral of a probability distribution function (PDF) over time has
a value of 1.

Examples
--------
>>> t = _np.linspace(0, 100, 1001)
>>> dt = t[1]
>>> pdf = GaussianFixedDispersion(t, 0.2)
>>> pdf.update_pdf(rt_mean=40)
>>> p = pdf.get_p()
>>> print(round(p.sum() * dt, 8))
1.0
>>> t[p.argmax()]
40.0

"""

__version__ = '0.7'
__author__ = 'Jure Sencar'

import numpy as _np

import bio_rtd.peak_shapes as _peak_shapes

from bio_rtd.core import PDF as _PDF


[docs]class GaussianFixedDispersion(_PDF): """Gaussian PDF with fixed dispersion Parameters ---------- dispersion_index : float Dispersion index, defined as `sigma * sigma / rt_mean`. Where `rt_mean` is a mean residence time and `sigma` is a standard deviation. cutoff : float Cutoff limit for trimming front and end tailing. Cutoff limit is relative to the peak max value. See Also -------- The documentation of superclass (`rtd_lib.core.PDF`). Examples ------- >>> t = _np.linspace(0, 100, 1001) >>> dt = t[1] >>> pdf = GaussianFixedDispersion(t, dispersion_index=0.2) >>> pdf.update_pdf(rt_mean=40) >>> p = pdf.get_p() >>> print(round(p.sum() * dt, 8)) 1.0 >>> t[p.argmax()] 40.0 """ # info about what key-value argument combinations could be passed into `update_pdf()` _possible_key_groups = [['f', 'v_void'], ['rt_mean']] _optional_keys = [] def __init__(self, t: _np.ndarray, dispersion_index: float, cutoff=0.0001, pdf_id: str = "GaussianFixedDispersion"): super().__init__(t, pdf_id) self.dispersion_index = dispersion_index self.cutoff_relative_to_max = cutoff def _calc_pdf(self, kw_pars: dict) -> _np.ndarray: # Get rt_mean from parameters. rt_mean = kw_pars['rt_mean'] \ if 'rt_mean' in kw_pars.keys() \ else kw_pars['v_void'] / kw_pars['f'] sigma = (rt_mean * self.dispersion_index) ** 0.5 # Calc probability distribution `p`. if self.trim_and_normalize: t_max = rt_mean + sigma * \ _np.sqrt(-2 * _np.log(self.cutoff_relative_to_max)) i_max = min(_np.ceil(t_max / self._dt) + 1, self._t_steps_max) else: i_max = self._t_steps_max * self._dt t = _np.arange(i_max) * self._dt p = _peak_shapes.gaussian(t, rt_mean, sigma) return p
[docs]class GaussianFixedRelativeWidth(_PDF): """ Gaussian PDF with fixed relative peak width relative_sigma = sigma / rt_mean """ # info about what key-value argument combinations could be passed into `update_pdf()` _possible_key_groups = [['f', 'v_void'], ['rt_mean']] _optional_keys = [] # dispersion index def __init__(self, t: _np.array, relative_sigma: float, cutoff=0.0001, pdf_id: str = ""): super().__init__(t, pdf_id) self.relative_sigma = relative_sigma self.cutoff_relative_to_max = cutoff def _calc_pdf(self, kw_pars: dict) -> _np.ndarray: # get rt_mean from parameters rt_mean = kw_pars['rt_mean'] if 'rt_mean' in kw_pars.keys() else kw_pars['v_void'] / kw_pars['f'] # calc sigma sigma = rt_mean * self.relative_sigma # calc pdf t_max = sigma * _np.sqrt(-2 * _np.log(self.cutoff_relative_to_max)) + rt_mean t_max = min(_np.ceil(t_max / self._dt), self._t_steps_max) * self._dt p = _peak_shapes.gaussian(_np.arange(0, t_max, self._dt), rt_mean, sigma) return p
[docs]class ExpModGaussianFixedDispersion(_PDF): """ Exponentially Modified Gaussian PDF with fixed dispersion `dispersion_index = sigma**2 / rt_mean` `pdf(rt_mean) = calc_emg(t, rt_mean, sigma, skew)` Methods ------- set_pdf_pars(dispersion_index: float, skew: float) Sets the dispersion index and skew factor Abstract Methods ---------------- update_pdf(**kwargs) Calculate new pdf for a given set of parameters. `pdf_update_keys` contains groups of possible parameter combinations. _possible_key_groups : Sequence[Sequence[str]] List of keys for key-value argument combinations that could be specified to `update_pdf(**kwarg)` function """ # info about what key-value argument combinations could be passed into `update_pdf()` _possible_key_groups = [['f', 'v_void'], ['rt_mean']] _optional_keys = ['skew'] def __init__(self, t: _np.array, dispersion_index: float, skew: float, pdf_id: str = ""): super().__init__(t, pdf_id) self.dispersion_index = dispersion_index self.skew = skew def _calc_pdf(self, kw_pars: dict) -> _np.ndarray: # get rt_mean from parameters rt_mean = kw_pars['rt_mean'] if 'rt_mean' in kw_pars.keys() else kw_pars['v_void'] / kw_pars['f'] # get skew from parameters if provided skew = kw_pars['skew'] if 'skew' in kw_pars.keys() else self.skew # calc sigma sigma = (rt_mean * self.dispersion_index) ** 0.5 # calc pdf t = _np.arange(0, self._t_steps_max * self._dt, self._dt) p = _peak_shapes.emg(t, rt_mean, sigma, skew) return p
[docs]class ExpModGaussianFixedRelativeWidth(_PDF): """ Exponentially Modified Gaussian PDF with fixed relative peak width """ # info about what key-value argument combinations could be passed into `update_pdf()` _possible_key_groups = [['rt_mean'], ['f', 'v_void']] _optional_keys = ['skew'] def __init__(self, t: _np.array, sigma_relative: float, skew: float, pdf_id: str = ""): super().__init__(t, pdf_id) self.sigma_relative = sigma_relative self.skew = skew def _calc_pdf(self, kw_pars: dict) -> _np.ndarray: # get rt_mean from parameters rt_mean = kw_pars['rt_mean'] if 'rt_mean' in kw_pars.keys() else kw_pars['v_void'] / kw_pars['f'] # get skew from parameters if provided skew = kw_pars['skew'] if 'skew' in kw_pars.keys() else self.skew # calc sigma sigma = rt_mean * self.sigma_relative # calc pdf t = _np.arange(0, self._t_steps_max * self._dt, self._dt) p = _peak_shapes.emg(t, rt_mean, sigma, skew) return p
[docs]class TanksInSeries(_PDF): """ Tanks in series PDF `rt_mean` means flow-through time through entire unit operation (all tanks) Methods ------- set_pdf_pars(n_tanks: float) Sets number of tanks Abstract Methods ---------------- update_pdf(**kwargs) Calculate new pdf for a given set of parameters. `pdf_update_keys` contains groups of possible parameter combinations. _possible_key_groups : Sequence[Sequence[str]] List of keys for key-value argument combinations that could be specified to `update_pdf(**kwarg)` function """ _possible_key_groups = [['rt_mean'], ['f', 'v_void']] _optional_keys = ['n_tanks'] def __init__(self, t: _np.array, n_tanks: float, pdf_id: str = ""): super().__init__(t, pdf_id) self.n_tanks = n_tanks def _calc_pdf(self, kw_pars: dict) -> _np.ndarray: # get rt_mean from parameters rt_mean = kw_pars['rt_mean'] if 'rt_mean' in kw_pars.keys() else kw_pars['v_void'] / kw_pars['f'] # get skew n_tanks parameters if provided n_tanks = kw_pars['n_tanks'] if 'n_tanks' in kw_pars.keys() else self.n_tanks # calc pdf t = _np.arange(0, self._t_steps_max * self._dt, self._dt) p = _peak_shapes.tanks_in_series(t, rt_mean, n_tanks) return p