Antonino Ingargiola -- tritemio AT gmail.com
ORCID 0000-0002-9348-1397
twitter @tritemio_sc
Last updated: Oct. 2016
In this notebook I derive correction formulas (and their inverse) for $E$ and $S$ in μs-ALEX measurements. I also define the A-direct excitation as a function of different observable, derive their expression as a function of physical parameters and discuss their interpretation. The expressions here derived (direct excitation, E correction formula) are valid for any smFRET measurements (freely diffusing or immobilized). The main reference is (Lee, BJ 2005, PDF, SI). Beyond what reported in (Lee, BJ 2005), here I derive a more complete set of expressions together with their physical interpretation that was incomplete in the original publication. The algebraic part is performed through Computer-assisted symbolic computation using Sympy for proof of correctness.
We start defining the signal (e.g. the corrected counts in each channel):
$$n_d = I_{D_{ex}} \, \sigma_{D_{ex}}^D \, \phi_D \, \eta_{D_{det}}^{D_{em}} \, (1-E)$$$$n_a = I_{D_{ex}} \, \sigma_{D_{ex}}^D \, \phi_A \, \eta_{A_{det}}^{A_{em}} \, E$$$$ n_{aa} = I_{A_{ex}} \, \sigma_{A_{ex}}^A \, \phi_A \, \eta_{A_{det}}^{A_{em}}$$$$n_a^* = n_a + Lk + Dir$$where
$$Lk = I_{D_{ex}} \, \sigma_{D_{ex}}^D \, \phi_D \, \eta_{A_{det}}^{D_{em}} \, (1-E)$$$$Dir = I_{D_{ex}} \, \sigma_{D_{ex}}^A \, \phi_A \, \eta_{A_{det}}^{A_{em}}$$$$\gamma = \frac{\phi_A\,\eta_{A_{det}}^{A_{em}}}{\phi_D\,\eta_{D_{det}}^{D_{em}}}$$$$ \beta = \frac{I_{A_{ex}}\sigma_{A_{ex}}^A}{I_{D_{ex}}\sigma_{D_{ex}}^D}$$The last quantity, $\beta$, is obtained when fitting the gamma factor from the $S_R$ of a series of static samples (Lee, BJ 2005).
Let define the FRET efficiency $E$ and the proximity ratios $E_{PR}$ and $E_R$:
$$ E = \frac{n_a}{n_a + \gamma \, n_d} \qquad E_R = \frac{n^*_a}{n^*_a + n_d} \qquad E_{PR} = \frac{n_a}{n_a + n_d}$$where $n_d$, $n_a$ are the donor and acceptor detected counts after all the corrections, while $n^*_a$ is the acceptor counts with only background correction (no leakage and direct excitation corrections).
Similarly, the definitions of uncorrected stoichiometry ($S_R$ and $S_{PR}$) and corrected stoichiometry ($S$) are:
$$ S_{R} = \frac{n_d + n^*_a}{n_d + n^*_a + n_{aa}} \qquad S_{PR} = \frac{n_d + n_a}{n_d + n_a + n_{aa}} \qquad S = \frac{\gamma n_d + n_a}{\gamma n_d + n_a + n_{aa}}$$The relation between $n_a$ and $n^*_a$ is:
$$n^*_a = n_a + Lk + Dir$$The term $Dir$ can be equivalently expressed as:
a function of $n_{aa}$:
$$ Dir = d_{AA} \cdot n_{aa}$$a function of the "corrected total signal" $(n_a + \gamma\,n_d)$:
$$ Dir = d_{T} \cdot (n_a + \gamma\,n_d) $$a function of the "corrected total signal divided by $\gamma$" $(n_a/\gamma + n_d)$:
$$ Dir = d_{T'} \cdot (n_a/\gamma + n_d) $$a function of $n_d$:
$$ Dir = d_{D} \cdot n_d $$a function of $n_a$:
$$ Dir = d_{A} \cdot n_a $$The coefficient $d_{AA}$ can be computed from an acceptor-only population in ALEX measurement as:
$$ d_{AA} = \frac{Dir}{n_{aa}} $$$$Dir = I_{D_{ex}} \, \sigma_{D_{ex}}^A \, \phi_A \, \eta_{A_{det}}^{A_{em}}$$In terms of physical parameters it is:
$$ d_{AA} = \frac{I_{D_{ex}}}{I_{A_{ex}}} \frac{\sigma_{D_{ex}}^A}{\sigma_{A_{ex}}^A} $$NOTE: This coefficient is $d$ in Lee, BJ 2005.
From the definition, it follows that:
$$ d_{T} = \frac{Dir}{n_a + \gamma\, n_d} $$$$n_a = I_{D_{ex}} \, \sigma_{D_{ex}}^D \, \phi_A \, \eta_{A_{det}}^{A_{em}} \, E$$To derive the expression of $d_{T}$ as a function of physical parameters, consider the case of 100% FRET molecule. In this case $n_d = 0$ and we obtain:
$$ d_{T} = \frac{\sigma_{D_{ex}}^A}{\sigma_{D_{ex}}^D} $$Now note that for $E < 1$, if $\gamma$ is fixed, the "corrected total signal" (i.e. the corrected burst size in freely-diffusing measurements) $n_a + \gamma\, n_d$ will not change for any $E < 1$. Therefore the previous expression is valid for any $E$.
Note that we can express $d_{T}$ as the product of $\beta$ and $d_{AA}$ (def. 1):
$$ d_{T} = \beta \, d_{AA}$$This relation follows from the definition of $\beta$ reported in the previous section and originally defined in (Lee, BJ 2005).
The coefficient $d_{T'}$ can be obtained from the $d_{T}$ expression noting that we simply divide the "corrected total signal" by $\gamma$:
$$ d_{T'} = \frac{\sigma_{D_{ex}}^A}{\sigma_{D_{ex}}^A} \gamma$$NOTE: The coefficient $d_{T'}$ is $d'$ in Lee, BJ 2005 paper (p. 2943) and SI.
In fact, the definition of $d'$ given in eq. (27) of Lee, BJ 2005 involves a $E=0$ population, for which $n_d + n_a/\gamma = n_d$.
The coefficient $d_{D}$ is a function of $E$ as well as the physical parameters. Taking the ratio of the physical definitions of $Dir$ and $n_d$ we obtain:
$$ d_{D} = \frac{\sigma_{D_{ex}}^A}{\sigma_{D_{ex}}^A} \frac{\gamma}{1 - E} = d_{T} \frac{\gamma}{1 - E} $$The coefficient $d_{A}$ is a function of $E$ as well as the physical parameters. Taking the ratio of the physical definitions of $Dir$ and $n_a$ we obtain:
$$ d_{A} = \frac{\sigma_{D_{ex}}^A}{\sigma_{D_{ex}}^D} \frac{1}{E} $$Definitions 4 and 5 are inconvenient because the coefficient depends on $E$. "Def. 3" does not depend on $E$ but depends on $\gamma$, while "Def. 2" depends only on the ratio of two absorption cross sections and is therefore the most general form. "Def. 1" can only be used in an ALEX measurement but it is easy to fit from the $S$ value of the A-only population.
So, for non-ALEX measurement, "Def. 2" ($d_{T}$) gives the simplest and most general coefficient. It can be computed from datasheet values or from $d_{AA}$ estimated from an ALEX measurement using the same dyes pair and D-excitation wavelength ($d_{T} = \beta\, d_{AA}$).
As physical interpretation, definitions 2 and 3 are similar. In "Def. 2", when $E=1$, the "corrected total signal" is $n_a$. When $E < 1$, the "corrected total signal" do not change (at the same excitation intensity, and fixed $\gamma$): they are the sum of acceptor and $\gamma$-corrected donor counts. Similar considerations hold for "Def. 3" (starting from $E=0$).
import sympy
from sympy import init_printing, symbols, solve, Eq
init_printing() # beautiful maths
E, Er, Epr = symbols('E, E_R, E_PR')
S, Sr, Spr = symbols('S, S_R, S_PR')
nd, na, ns_a, n_dir, naa, nt = symbols('n_d n_a n^*_a n_dir n_aa n_t')
gamma, Lk = symbols('gamma L_k')
d_exAA, d_exT, d_exD = symbols("d_dirAA d_dirT, d_dirD")
def PR(nd, na):
return na/(na + nd)
PR(nd, na)
def FRET(nd, na, gamma):
return na / (na + gamma*nd)
FRET(nd, na, gamma)
As a first step we write $n^*_a$ as a function of $n_a$ and save the symbolic expression:
ns_a_as_func_na = na + Lk*nd + n_dir
ns_a_as_func_na
Here we write the PR substituting $n^*_a$ with $n_a + L_k\, n_d + Dir$ and $Dir$ with the "Def. 2" expression:
Er_sym = sympy.factor(PR(nd, ns_a).subs(ns_a, ns_a_as_func_na).subs(n_dir, d_exT*(nd*gamma + na)))
Er_sym
The previous expression is the proximity ratio $E_R$. We "solve" it to obtain $n_d$ as a function of $E_R$. Then we replace the obtained expression in the FRET formula:
E_func_Er = sympy.factor(FRET(nd, na, gamma).subs(nd, solve(Er_sym - Er, nd)[0])).collect(Er)
E_func_Er
print(sympy.printing.latex(E_func_Er))
\frac{E_{R} \left(L_{k} + d_{dirT} \gamma + 1\right) - L_{k} - d_{dirT} \gamma}{E_{R} \left(L_{k} - \gamma + 1\right) - L_{k} + \gamma}
E_func_Er
The previous expression is $E$ as a function of $E_R$, including gamma, leakage and direct excitation coefficients. It is the same of equation S9 when we replace $d_{exT}\gamma$ with $d'$.
From this symbolic expression we can define the python function:
print(E_func_Er)
(E_R*(L_k + d_dirT*gamma + 1) - L_k - d_dirT*gamma)/(E_R*(L_k - gamma + 1) - L_k + gamma)
def correct_E_gamma_leak_dir(E_R, gamma, L_k=0, d_dirT=0):
E_R = np.asarray(E_R)
return ((E_R*(L_k + d_dirT*gamma + 1) - L_k - d_dirT*gamma) /
(E_R*(L_k - gamma + 1) - L_k + gamma))
In case we want to compute $E$ using the coefficient $d_{AA}$ for direct excitation (as obtained from ALEX measurements) we simply replace the relation:
$$ d_{T} = \beta\, d_{AA}$$in the previous expression.
Now we can derive the simpler expression in the case we want to correct only one parameter.
For only gamma correction we obtain:
E_func_Er.subs(Lk, 0).subs(d_exT, 0)
For the only leakage correction we obtain:
sympy.collect(E_func_Er.subs(gamma, 1).subs(d_exT, 0), Er)
For the only direct excitation correction we obtain:
sympy.collect(E_func_Er.subs(gamma, 1).subs(Lk, 0), Er)
NOTE: The latter 3 formulas for correcting only one coefficient cannot be chained. In other words, applying them in sequence do not yield the same result as applying the complete formula.
Conversely, to compute $E_R$ as a function of $E$ we invert the previous expression:
Er_func_E = solve(E - E_func_Er, Er)[0]
sympy.collect(Er_func_E, E)
And we define the python function:
print(sympy.collect(Er_func_E, E))
(E*(-L_k + gamma) + L_k + d_dirT*gamma)/(E*(-L_k + gamma - 1) + L_k + d_dirT*gamma + 1)
def uncorrect_E_gamma_leak_dir(E, gamma, L_k=0, d_dirT=0):
E = np.asarray(E)
return ((E*(-L_k + gamma) + L_k + d_dirT*gamma) /
(E*(-L_k + gamma - 1) + L_k + d_dirT*gamma + 1))
And the inverse for only a single correction are (in the order gamma, leakage, direct excitation)
Er_func_E.subs(Lk, 0).subs(d_exT, 0)
sympy.collect(Er_func_E.subs(gamma, 1).subs(d_exT, 0), Er)
sympy.collect(Er_func_E.subs(gamma, 1).subs(Lk, 0), Er)
def StoichRaw(nd, na, naa):
return (na + nd)/(na + nd + naa)
StoichRaw(nd, na, naa)
def Stoich(nd, na, naa, gamma):
return (na + gamma*nd)/(na + gamma*nd + naa)
Stoich(nd, na, naa, gamma)
As a first step we write $n^*_a$ as a function of $n_a$ and save the symbolic expression:
ns_a_as_func_na = na + Lk*nd + n_dir
ns_a_as_func_na
Here we write $S_R$ substituting $n^*_a$ with $n_a + L_k n_d + Dir$ and $Dir$ with $d_{T}(n_a + \gamma\,n_d)$ (Definition 2):
Sr_sym = sympy.factor(
StoichRaw(nd, ns_a, naa).subs(ns_a, ns_a_as_func_na).subs(n_dir, d_exT*(na + gamma*nd))
)
Sr_sym
The previous expression is $S_R$. We can use it to express $n_a$ as a function of $S_R$ and $n_d$:
S_sym = Stoich(nd, na, naa, gamma)
S_sym
S_func_Sr_nx = S_sym.subs(na, solve(Sr_sym - Sr, na)[0]).factor()
S_func_Sr_nx
The previous expression if $S$ as a function of $S_R$, $n_d$, $n_a$, $n_{aa}$ and correction coefficients.
Now we use the expression of $E$ to try to eliminate $n_d$, $n_a$ and $n_{aa}$ from the previous expression:
E_sym = FRET(nd, na, gamma)
E_sym
na_func_Sr = solve(Sr_sym - Sr, na)[0]
na_func_Sr
E_func_Sr = E_sym.subs(na, na_func_Sr).factor()
E_func_Sr
nd_func_E_Sr = solve(E_func_Sr - E, nd)[0]
nd_func_E_Sr
S_func_E_Sr = S_func_Sr_nx.replace(nd, nd_func_E_Sr).factor()
S_func_E_Sr
Note that in the previous expression there is no more dependency on $n_{aa}$ (we have not eliminated the variable, it simply simplifies).
The previous expression is $S$ as a function of $S_{R}$, $E$ (gamma corrected) and all correction coefficients.
Let's replace $E$ with $E_{R}$:
ns_a_as_func_na
Er_sym = PR(nd, ns_a).subs(ns_a, ns_a_as_func_na).subs(n_dir, d_exT*(nd*gamma + na))
Er_sym
E_func_Er = FRET(nd, na, gamma).subs(nd, solve(Er_sym - Er, nd)[0]).factor()
E_func_Er
S_func_Er_Sr = S_func_E_Sr.replace(E, E_func_Er).factor()
S_func_Er_Sr
print(sympy.printing.latex(S_func_Er_Sr))
\frac{S_{R} \left(E_{R} L_{k} - E_{R} \gamma + E_{R} - L_{k} + \gamma\right)}{E_{R} L_{k} S_{R} - E_{R} S_{R} \gamma + E_{R} S_{R} - L_{k} S_{R} - S_{R} d_{dirT} + S_{R} \gamma - S_{R} + d_{dirT} + 1}
The previous expression is $S$ as a function of $S_{R}$, $E_{R}$ and all correction coefficients.
Let's make a python function out of it:
print(S_func_Er_Sr)
S_R*(E_R*L_k - E_R*gamma + E_R - L_k + gamma)/(E_R*L_k*S_R - E_R*S_R*gamma + E_R*S_R - L_k*S_R - S_R*d_dirT + S_R*gamma - S_R + d_dirT + 1)
def correct_S(E_R, S_R, gamma, L_k, d_dirT):
return (S_R*(E_R*L_k - E_R*gamma + E_R - L_k + gamma) /
(E_R*L_k*S_R - E_R*S_R*gamma + E_R*S_R - L_k*S_R - S_R*d_dirT +
S_R*gamma - S_R + d_dirT + 1))
If we want to express $S$ as a function of $S_{PR}$ (i.e. the stoichiometry with leakage and direct excitation correction), we just set $L_k = 0$ and $d_{T} = 0 $ in the previous expression.
S_func_E_Spr = (S_func_E_Sr.replace(Lk, 0).replace(d_exT, 0)
.replace(Sr, Spr).replace(Er, Epr))
S_func_E_Spr
S_func_Epr_Spr = (S_func_Er_Sr.replace(Lk, 0).replace(d_exT, 0)
.replace(Sr, Spr).replace(Er, Epr))
S_func_Epr_Spr
S_func_Er_Sr
Sr_func_Er_S = solve(S_func_Er_Sr - S, Sr)[0]
Sr_func_Er_S
print(Sr_func_Er_S)
S*(d_dirT + 1)/(-E_R*L_k*S + E_R*L_k + E_R*S*gamma - E_R*S - E_R*gamma + E_R + L_k*S - L_k + S*d_dirT - S*gamma + S + gamma)
def uncorrect_S(E_R, S, gamma, L_k, d_dirT):
return (S*(d_dirT + 1) /
(-E_R*L_k*S + E_R*L_k + E_R*S*gamma - E_R*S - E_R*gamma +
E_R + L_k*S - L_k + S*d_dirT - S*gamma + S + gamma))
Test consistency between apply and un-apply of numerical corrections for $E$.
import numpy as np
Ex = np.arange(-0.2, 1.2, 0.1)
gamma_ = 0.75
leakage_ = 0.04
dir_ex_t_ = 0.08
Ex_roundtrip = uncorrect_E_gamma_leak_dir(correct_E_gamma_leak_dir(Ex, gamma_), gamma_)
np.allclose(Ex, Ex_roundtrip)
True
Ex_roundtrip = uncorrect_E_gamma_leak_dir(correct_E_gamma_leak_dir(Ex, gamma_, leakage_, dir_ex_t_),
gamma_, leakage_, dir_ex_t_)
np.allclose(Ex, Ex_roundtrip)
True
Ex_roundtrip = correct_E_gamma_leak_dir(uncorrect_E_gamma_leak_dir(Ex, gamma_, leakage_, dir_ex_t_),
gamma_, leakage_, dir_ex_t_)
np.allclose(Ex, Ex_roundtrip)
True
Test that $S$ correction functions:
Ex = np.arange(-0.2, 1.2, 0.01)
Sx = np.arange(-0.2, 1.2, 0.01)
np.random.shuffle(Ex)
np.random.shuffle(Sx)
Let's do a consistency check:
gamma_ = 1
leakage_ = 0
dir_ex_t_ = 0
S_corr = correct_S(Ex, Sx, gamma_, leakage_, dir_ex_t_)
S_uncorr = uncorrect_S(Ex, S_corr, gamma_, leakage_, dir_ex_t_)
np.allclose(S_corr, Sx)
True
np.allclose(S_uncorr, Sx)
True
gamma_ = 0.7
leakage_ = 0.05
dir_ex_t_ = 0.1
S_corr = correct_S(Ex, Sx, gamma_, leakage_, dir_ex_t_)
S_uncorr = uncorrect_S(Ex, S_corr, gamma_, leakage_, dir_ex_t_)
np.allclose(S_uncorr, Sx)
True
%matplotlib inline
import matplotlib.pyplot as plt
idx = Sx.argsort()
plt.plot(S_corr[idx], 'o')
[<matplotlib.lines.Line2D at 0x10fcb7b70>]