12 fret_efficiency: float,
13 n_samples: int = 10000,
23 Second rank order parameter S2 of the donor dye. This can correspond
24 to the fraction of trapped donor dye.
26 Second rank order parameter S2 of the acceptor dye. This can correspond
27 to the fraction of trapped acceptor dye.
28 fret_efficiency : float
31 The number of bins in the kappa2 distribution that is
34 Upper kappa2 bound in the generated histogram
36 Lower kappa2 bound in the generate histogram
38 The number random vector pairs that are drawn (default: 10000)
45 k2_step = (k2_max - k2_min) / (n_bins - 1)
46 k2_scale = np.arange(k2_min, k2_max + 1e-14, k2_step, dtype=np.float64)
49 donor_vec = np.random.randn(n_samples, 3)
50 acceptor_vec = np.random.randn(n_samples, 3)
53 x = 1 / fret_efficiency - 1
55 k2s = np.zeros(n_samples, dtype=np.float64)
56 for i
in range(n_samples):
58 acceptor = acceptor_vec[i]
61 delta = np.arccos(np.dot(donor, acceptor)
62 / (np.linalg.norm(donor) * np.linalg.norm(acceptor)))
63 beta1 = np.arccos(donor[0] / np.linalg.norm(donor))
64 beta2 = np.arccos(acceptor[0] / np.linalg.norm(acceptor))
66 k2_trapped_free = kappasq(
73 k2_free_trapped = kappasq(
80 k2_trapped_trapped = kappasq(
88 Ek2 = ((1 - sD2) * (1 - sA2) / (1 + x)
89 + sD2 * sA2 / (1 + 2 / 3. / k2_trapped_trapped * x)
90 + sD2 * (1 - sA2) / (1 + 2 / 3. / k2_trapped_free * x)
91 + (1 - sD2) * sA2 / (1 + 2 / 3. / k2_free_trapped * x))
92 k2 = 2 / 3. * x / (1 / Ek2 - 1)
96 k2hist, bins = np.histogram(k2s, k2_scale)
97 return k2_scale, k2hist, k2s
100 def kappasq_all_delta_new(
108 ) -> typing.Tuple[np.ndarray, np.ndarray, np.ndarray]:
111 for beta1
in np.arange(0, np.pi/2, step=step / 180. * np.pi):
112 weight_beta1 = np.sin(beta1)
113 for beta2
in np.arange(
114 start=abs(delta - beta1),
115 stop=min(delta + beta1, np.pi / 2.),
116 step=step / 180. * np.pi
118 weight_beta2 = np.sin(beta1)
120 weight_beta1 * weight_beta2
134 k2_step = (k2_max - k2_min) / (n_bins - 1)
135 k2scale = np.arange(k2_min, k2_max + 1e-14, k2_step, dtype=np.float64)
137 k2hist, x = np.histogram(ks, bins=k2scale, weights=weights)
138 return k2scale, k2hist, ks
141 @nb.jit(nopython=
True)
142 def kappasq_all_delta(
150 ) -> typing.Tuple[np.ndarray, np.ndarray, np.ndarray]:
151 """Computes a orientation factor distribution for a wobbling in
152 a cone model using parameters that can be estimated by experimental
155 The function used second rank order parameter of the donor and acceptor
156 and the angle delta between the symmetry axes of the dyes as input. These
157 parameters can be estimated by the residual anisotropy the the dyes. The
158 second rank order parameter of the donor and acceptor are estimated by the
159 dye's residual anisotropies. The angle between the symmetry axes is
160 estimated by the residual anisotropy of the FRET sensitized emission
161 (see: `chisurf.fluorescence.anisotropy.kappa2.s2delta`).
163 This function computes a orientation factor distribution,
164 :math:`p(/kappa^2)`, for a wobbling in a cone model (WIC) for second rank
165 structure factors of the donor and acceptor, and an angle :math:`delta`.
166 The angle :math:`delta` is the angle between the symmetry axes of the
167 dyes and can be estimated using experimental residual anisotropies [1]_.
172 The angle delta (in rad) for which the WIC orientation factor
173 distribution is calculated.
175 Second rank order parameter S2 of the donor dye. This can correspond
176 to the fraction of trapped donor dye.
178 Second rank order parameter S2 of the acceptor dye. This can correspond
179 to the fraction of trapped acceptor dye.
181 The step size in degrees that is used to sample the
184 The number of bins in the kappa2 distribution that is
187 Upper kappa2 bound in the generated histogram
189 Lower kappa2 bound in the generate histogram
193 k2scale : numpy-array
194 A linear scale in the range of [0, 4] with *n_bins* elements
196 The histogram of kappa2 values
198 A numpy-array containing all computed kappa2 values. The histogram
199 corresponds to a histogram over all returned kappa2 values.
203 >>> from scikit_fluorescence.modeling.kappa2 import kappasq_all_delta
204 >>> k2s, k2h, k2v = kappasq_all_delta(
211 >>> np.allclose(k2h, np.array(
212 ... [ 0. , 0. , 0. , 0. ,
213 ... 3205.72877776, 1001.19048825, 611.44917432, 252.97166906,
214 ... 0. , 0. , 0. , 0. ,
215 ... 0. , 0. , 0. , 0. ,
216 ... 0. , 0. , 0. , 0. ,
217 ... 0. , 0. , 0. , 0. ,
218 ... 0. , 0. , 0. , 0. ,
219 ... 0. , 0. ]), rtol=0.3, atol=2.0)
224 The angle :math:`/beta_1` is varied in the range (0,pi/2)
225 The angle :math:`/phi` is varied in the range (0, 2 pi)
229 .. [1] Simon Sindbert, Stanislav Kalinin, Hien Nguyen, Andrea Kienzler,
230 Lilia Clima, Willi Bannwarth, Bettina Appel, Sabine Mueller, Claus A. M.
231 Seidel, "Accurate Distance Determination of Nucleic Acids via Foerster
232 Resonance Energy Transfer: Implications of Dye Linker Length and Rigidity"
233 vol. 133, pp. 2463-2480, J. Am. Chem. Soc., 2011
237 beta1 = np.arange(0.001, np.pi / 2.0, step * np.pi / 180.0,
239 phi = np.arange(0.001, 2.0 * np.pi, step * np.pi / 180.0, dtype=np.float64)
242 rda_vec = np.array([1, 0, 0], dtype=np.float64)
245 k2 = np.zeros((n, m), dtype=np.float64)
246 k2hist = np.zeros(n_bins - 1, dtype=np.float64)
249 k2_step = (k2_max - k2_min) / (n_bins - 1)
250 k2scale = np.arange(k2_min, k2_max + 1e-14, k2_step, dtype=np.float64)
252 d1 = np.array([np.cos(beta1[i]), 0, np.sin(beta1[i])])
253 n1 = np.array([-np.sin(beta1[i]), 0, np.cos(beta1[i])])
254 n2 = np.array([0, 1, 0])
256 d2 = ((n1 * np.cos(phi[j]) + n2 * np.sin(phi[j]))
257 * np.sin(delta) + d1 * np.cos(delta))
258 beta2 = np.arccos(np.abs(d2.dot(rda_vec)))
266 y, x = np.histogram(k2[i, :], bins=k2scale)
267 k2hist += y*np.sin(beta1[i])
268 return k2scale, k2hist, k2
271 @nb.jit(nopython=
True)
278 n_samples: int = 10000
279 ) -> typing.Tuple[np.array, np.array, np.array]:
280 """Computes a orientation factor distribution for a wobbling in a
281 cone model using specific second rank structure factors of the donor
284 This function computes a orientation factor distribution,
285 :math:`p(/kappa^2)`, for a wobbling in a cone model (WIC) for second rank
286 structure factors of the donor and acceptor estimated using experimental
287 residual anisotropies [1]_.
292 Second rank order parameter S2 of the donor dye
294 Second rank order parameter S2 of the acceptor dye
296 The number of bins in the kappa2 histogram that is
299 Upper kappa2 bound in the generated histogram
301 Lower kappa2 bound in the generate histogram
303 The number random vector pairs that are drawn (default: 10000)
307 k2scale : numpy-array
308 A linear scale in the range of [0, 4] with *n_bins* elements
310 The histogram of kappa2 values
312 A numpy-array containing all computed kappa2 values. The histogram
313 corresponds to a histogram over all returned kappa2 values.
317 >>> from scikit_fluorescence.modeling.kappa2 import kappasq_all_delta
318 >>> k2_scale, k2_hist, k2 = kappasq_all(
325 array([0. , 0.13333333, 0.26666667, 0.4 , 0.53333333,
326 0.66666667, 0.8 , 0.93333333, 1.06666667, 1.2 ,
327 1.33333333, 1.46666667, 1.6 , 1.73333333, 1.86666667,
328 2. , 2.13333333, 2.26666667, 2.4 , 2.53333333,
329 2.66666667, 2.8 , 2.93333333, 3.06666667, 3.2 ,
330 3.33333333, 3.46666667, 3.6 , 3.73333333, 3.86666667,
332 >>> reference = np.array(
333 ... [0.0000e+00, 0.0000e+00, 0.0000e+00, 3.1920e+04, 4.3248e+04,
334 ... 1.4842e+04, 5.8930e+03, 2.5190e+03, 1.0840e+03, 3.9700e+02,
335 ... 9.4000e+01, 3.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,
336 ... 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,
337 ... 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,
338 ... 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00])
339 >>> np.allclose(reference, k2_hist, rtol=0.3, atol=2.0)
344 .. [1] Simon Sindbert, Stanislav Kalinin, Hien Nguyen, Andrea Kienzler,
345 Lilia Clima, Willi Bannwarth, Bettina Appel, Sabine Mueller, Claus A. M.
346 Seidel, "Accurate Distance Determination of Nucleic Acids via Foerster
347 Resonance Energy Transfer: Implications of Dye Linker Length and Rigidity"
348 vol. 133, pp. 2463-2480, J. Am. Chem. Soc., 2011
351 k2 = np.zeros(n_samples, dtype=np.float64)
352 step = (k2_max - k2_min) / (n_bins - 1)
353 k2scale = np.arange(k2_min, k2_max + 1e-14, step, dtype=np.float64)
354 k2hist = np.zeros(k2scale.shape[0] - 1, dtype=np.float64)
355 for i
in range(n_samples):
356 d1 = np.random.random(3)
357 d2 = np.random.random(3)
358 n1 = np.linalg.norm(d1)
359 n2 = np.linalg.norm(d2)
362 delta = np.arccos(np.dot(d1, d2) / (n1 * n2))
363 beta1 = np.arccos(d1[0] / n1)
364 beta2 = np.arccos(d2[0] / n2)
372 y, x = np.histogram(k2, bins=k2scale)
374 return k2scale, k2hist, k2
377 @nb.jit(nopython=
True)
383 ) -> typing.Tuple[float, float]:
384 r"""Calculates the distance between the center of two dipoles and the
385 orientation-factor kappa of the dipoles
387 Calculates for the vectors d1 and d2 pointing to the donors and the vectors
388 a1 and a2 pointing to the ends of the acceptor dipole the orientation
394 Vector pointing to the first point of the dipole D
396 Vector pointing to the second point of the dipole D
398 Vector pointing to the first point of the dipole A
400 Vector pointing to the second point of the dipole A
405 distance between the center of the dipoles and the orientation factor
406 for the two dipoles kappa
410 The four vectors defining the dipole of the donor :math:`\vec{r}_{D1}` and
411 :math:`\vec{r}_{D2}` specified by the parameters `d1` and `d2` and
412 :math:`\vec{r}_{A1}` and :math:`\vec{r}_{A2}` specified by the parameters
413 `a1` and `a1` are used to compute orientation factor :math:`kappa^2`
414 and the distance between the center of the two dipoles :math:`R_{DA}`.
416 The distance :math:`R_{DA}` between the dipole centers and :math:`kappa`
417 is calculated as follows:
421 R_{D,21}=|\vec{r}_{D2} - \vec{r}_{D1}| \
422 R_{A,21}=|\vec{r}_{A2} - \vec{r}_{A1}| \
423 \hat{\mu}_{D}=1/R_{D,21} \cdot (\vec{r}_{D2}-\vec{r}_{D1}) \
424 \hat{\mu}_{A}=1/R_{A,21} \cdot (\vec{r}_{A2}-\vec{r}_{A1}) \
425 \vec{m}_{D}=\vec{r}_{D1}+1/2 \cdot \hat{\mu}_{D} \
426 \vec{m}_{A}=\vec{r}_{A1}+1/2 \cdot \hat{\mu}_{A} \
427 \vec{r}_{DA}=\vec{m}_{D}-\vec{m}_{A} \
428 R_{DA}=|\vec{m}_{D}-\vec{m}_{A}| \
429 \hat{\mu}_{DA}=\vec{r}_{DA} / R_{DA} \
430 \kappa=\langle\mu_A,\mu_D\rangle-3\cdot\langle\mu_D,\mu_{DA}\rangle \cdot \langle\mu_A,\mu_{DA}\rangle
434 >>> import scikit_fluorescence.modeling.kappa2
435 >>> donor_dipole = np.array(
439 ... ], dtype=np.float64
441 >>> acceptor_dipole = np.array(
445 ... ], dtype=np.float64
447 >>> scikit_fluorescence.modeling.kappa2.kappa(
451 (0.8660254037844386, 1.0000000000000002)
465 (d11 - d21) * (d11 - d21) +
466 (d12 - d22) * (d12 - d22) +
467 (d13 - d23) * (d13 - d23)
471 muD1 = (d21 - d11) / dD21
472 muD2 = (d22 - d12) / dD21
473 muD3 = (d23 - d13) / dD21
476 dM1 = d11 + dD21 * muD1 / 2.0
477 dM2 = d12 + dD21 * muD2 / 2.0
478 dM3 = d13 + dD21 * muD3 / 2.0
492 (a11 - a21) * (a11 - a21) +
493 (a12 - a22) * (a12 - a22) +
494 (a13 - a23) * (a13 - a23)
498 muA1 = (a21 - a11) / dA21
499 muA2 = (a22 - a12) / dA21
500 muA3 = (a23 - a13) / dA21
503 aM1 = a11 + dA21 * muA1 / 2.0
504 aM2 = a12 + dA21 * muA2 / 2.0
505 aM3 = a13 + dA21 * muA3 / 2.0
513 dRDA = np.sqrt(RDA1 * RDA1 + RDA2 * RDA2 + RDA3 * RDA3)
521 kappa = (muA1 * muD1 + muA2 * muD2 + muA3 * muD3
522 - 3.0 * (muD1 * nRDA1 + muD2 * nRDA2 + muD3 * nRDA3)
523 * (muA1 * nRDA1 + muA2 * nRDA2 + muA3 * nRDA3))
528 donor_dipole: np.ndarray,
529 acceptor_dipole: np.ndarray
530 ) -> typing.Tuple[float, float]:
531 """Calculates the orientation-factor kappa
533 :param donor_dipole: 2x3 vector of the donor-dipole
534 :param acceptor_dipole: 2x3 vector of the acceptor-dipole
535 :return: distance, kappa
540 >>> import numpy as np
541 >>> donor_dipole = np.array([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]],
542 ... dtype=np.float64)
543 >>> acceptor_dipole = np.array([[0.0, 0.5, 0.0], [0.0, 0.5, 1.0]],
544 ... dtype=np.float64)
545 >>> kappa(donor_dipole, acceptor_dipole)
546 (0.8660254037844386, 1.0000000000000002)
548 return kappa_distance(
549 donor_dipole[0], donor_dipole[1],
550 acceptor_dipole[0], acceptor_dipole[1]
559 ) -> typing.Tuple[float, float]:
560 """Calculate s2delta from the residual anisotropies of the donor
566 Fundamental anisotropy, the anisotropy of the dyes at time zero (
569 The second rank oder parameter of the donor dye. The second rank oder
570 parameter can be computed using the dye's residual anisotropy (see
573 The second rank oder parameter of the direct excited acceptor dye.
575 The residual anisotropy on the acceptor excited by the donor dye.
580 A second rank order parameter of the angle [1]_ eq. 10
582 The angle between the two symmetry axes of the dipols in units of rad.
586 >>> from scikit_fluorescence.modeling.kappa2 import s2delta
593 ... s2_donor=s2donor,
594 ... s2_acceptor=s2acceptor,
595 ... r_inf_AD=r_inf_AD
597 (0.4385964912280701, 0.6583029208008411)
601 The parameters `s2_donor` and `s2_acceptor`, which correspond to
602 :math:`S^{(2)}_D` and :math:`S^{(2)}_A` are calculated using the dye's
603 residual anisotropy [1]_
607 S^{(2)}_D = - /sqrt{/frac{r_{D,inf}}{r_{0,D}}} \
608 S^{(2)}_D = /sqrt{/frac{r_{A,inf}}{r_{0,A}}} \
613 .. [1] Simon Sindbert, Stanislav Kalinin, Hien Nguyen, Andrea Kienzler,
614 Lilia Clima, Willi Bannwarth, Bettina Appel, Sabine Mueller, Claus A. M.
615 Seidel, "Accurate Distance Determination of Nucleic Acids via Foerster
616 Resonance Energy Transfer: Implications of Dye Linker Length and Rigidity"
617 vol. 133, pp. 2463-2480, J. Am. Chem. Soc., 2011
620 s2_delta = r_inf_AD/(r_0 * s2_donor * s2_acceptor)
621 delta = np.arccos(np.sqrt((2.0 * s2_delta + 1.0) / 3.0))
622 return s2_delta, delta
625 def calculate_kappa_distance(
631 ) -> typing.Tuple[np.ndarray, np.ndarray]:
632 """Calculates the orientation factor kappa2 and the distance of a
633 trajectory given the atom-indices of the donor and the acceptor.
635 :param xyz: numpy-array (frame, atom, xyz)
636 :param aid1: int, atom-index of d-dipole 1
637 :param aid2: int, atom-index of d-dipole 2
638 :param aia1: int, atom-index of a-dipole 1
639 :param aia2: int, atom-index of a-dipole 2
641 :return: distances, kappa2
643 n_frames = xyz.shape[0]
644 ks = np.empty(n_frames, dtype=np.float32)
645 ds = np.empty(n_frames, dtype=np.float32)
647 for i_frame
in range(n_frames):
649 d, k = kappa_distance(
650 xyz[i_frame, aid1], xyz[i_frame, aid2],
651 xyz[i_frame, aia1], xyz[i_frame, aia2]
656 print(
"Frame ", i_frame,
"skipped, calculation error")
661 @nb.jit(nopython=
True)
669 """Calculates kappa2 given a set of oder parameters and angles
674 The angle between the symmetry axis of rotation of the dyes in units
677 The second rank oder parameter of the donor
679 The second rank oder parameter of the acceptor
681 The angle between the symmetry axes of the rotation of the dye and
682 the distance vector RDA between the two dipoles
684 The angle between the symmetry axes of the rotation of the dye and
685 the distance vector RDA between the two dipoles
690 The orientation factor that corresponds to the provided angles.
695 This function corresponds to eq. 9 in [1]_.
699 .. [1] Simon Sindbert, Stanislav Kalinin, Hien Nguyen, Andrea Kienzler,
700 Lilia Clima, Willi Bannwarth, Bettina Appel, Sabine Mueller, Claus A. M.
701 Seidel, "Accurate Distance Determination of Nucleic Acids via Foerster
702 Resonance Energy Transfer: Implications of Dye Linker Length and Rigidity"
703 vol. 133, pp. 2463-2480, J. Am. Chem. Soc., 2011
706 s2delta = (3.0 * np.cos(delta) * np.cos(delta) - 1.0) / 2.0
707 s2beta1 = (3.0 * np.cos(beta1) * np.cos(beta1) - 1.0) / 2.0
708 s2beta2 = (3.0 * np.cos(beta2) * np.cos(beta2) - 1.0) / 2.0
715 6 * s2beta1 * s2beta2 +
719 9 * np.cos(beta1) * np.cos(beta2) * np.cos(delta)
725 def p_isotropic_orientation_factor(
727 normalize: bool =
True
729 """Calculates an the probability of a given kappa2 according to
730 an isotropic orientation factor distribution
735 An array containing kappa squared values.
737 If this parameter is set to True (default) the returned distribution is
743 The probability distribution of kappa2 for isotropic oriented dipoles
748 >>> from scikit_fluorescence.modeling import kappa2
749 >>> k2 = np.linspace(0.1, 4, 32)
750 >>> p_k2 = kappa2.p_isotropic_orientation_factor(k2=k2)
752 array([0.17922824, 0.11927194, 0.09558154, 0.08202693, 0.07297372,
753 0.06637936, 0.06130055, 0.05723353, 0.04075886, 0.03302977,
754 0.0276794 , 0.02359627, 0.02032998, 0.01763876, 0.01537433,
755 0.01343829, 0.01176177, 0.01029467, 0.00899941, 0.00784718,
756 0.00681541, 0.00588615, 0.00504489, 0.0042798 , 0.0035811 ,
757 0.00294063, 0.00235153, 0.001808 , 0.00130506, 0.00083845,
762 http://www.fretresearch.org/kappasquaredchapter.pdf
767 r = np.zeros_like(k2)
768 for i, k
in enumerate(ks):
770 r[i] = 0.5 / (s3 * k) * np.log(2 + s3)
772 r[i] = 0.5 / (s3 * k) * np.log((2 + s3)
773 / (k + np.sqrt(k**2 - 1.0)))
775 r /= max(1.0, r.sum())