1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 """The Miloushev and Palmer (2005) 2-site exchange R1rho U{MP05<http://wiki.nmr-relax.com/MP05>} model.
27
28 Description
29 ===========
30
31 This module is for the function, gradient and Hessian of the U{MP05<http://wiki.nmr-relax.com/MP05>} model.
32
33
34 References
35 ==========
36
37 The model is named after the reference:
38
39 - Miloushev V. Z. and Palmer A. (2005). R1rho relaxation for two-site chemical exchange: General approximations and some exact solutions. J. Magn. Reson., 177, 221-227. (U{DOI: 10.1016/j.jmr.2005.07.023<http://dx.doi.org/10.1016/j.jmr.2005.07.023>}).
40
41
42 Code origin
43 ===========
44
45 The code was copied from the U{TP02<http://wiki.nmr-relax.com/TP02>} model, hence it originates as the funTrottPalmer.m Matlab file from the sim_all.tar file attached to task #7712 (U{https://web.archive.org/web/https://gna.org/task/?7712}). This is code from Nikolai Skrynnikov and Martin Tollinger.
46
47 Links to the copyright licensing agreements from all authors are:
48
49 - Nikolai Skrynnikov, U{http://article.gmane.org/gmane.science.nmr.relax.devel/4279},
50 - Martin Tollinger, U{http://article.gmane.org/gmane.science.nmr.relax.devel/4276}.
51
52
53 Links
54 =====
55
56 More information on the MP05 model can be found in the:
57
58 - U{relax wiki<http://wiki.nmr-relax.com/MP05>},
59 - U{relax manual<http://www.nmr-relax.com/manual/The_MP05_2_site_exchange_R1_rho_model.html>},
60 - U{relaxation dispersion page of the relax website<http://www.nmr-relax.com/analyses/relaxation_dispersion.html#MP05>}.
61 """
62
63
64 from numpy import arctan2, isfinite, min, sin, sum
65 from numpy.ma import fix_invalid, masked_where
66
67
68 -def r1rho_MP05(r1rho_prime=None, omega=None, offset=None, pA=None, dw=None, kex=None, R1=0.0, spin_lock_fields=None, spin_lock_fields2=None, back_calc=None):
69 """Calculate the R1rho' values for the TP02 model.
70
71 See the module docstring for details. This is the Miloushev and Palmer (2005) equation according to Korzhnev (J. Biomol. NMR (2003), 26, 39-48).
72
73
74 @keyword r1rho_prime: The R1rho_prime parameter value (R1rho with no exchange).
75 @type r1rho_prime: numpy float array of rank [NE][NS][NM][NO][ND]
76 @keyword omega: The chemical shift for the spin in rad/s.
77 @type omega: numpy float array of rank [NE][NS][NM][NO][ND]
78 @keyword offset: The spin-lock offsets for the data.
79 @type offset: numpy float array of rank [NE][NS][NM][NO][ND]
80 @keyword pA: The population of state A.
81 @type pA: float
82 @keyword dw: The chemical exchange difference between states A and B in rad/s.
83 @type dw: numpy float array of rank [NE][NS][NM][NO][ND]
84 @keyword kex: The kex parameter value (the exchange rate in rad/s).
85 @type kex: float
86 @keyword R1: The R1 relaxation rate.
87 @type R1: numpy float array of rank [NE][NS][NM][NO][ND]
88 @keyword spin_lock_fields: The R1rho spin-lock field strengths (in rad.s^-1).
89 @type spin_lock_fields: numpy float array of rank [NE][NS][NM][NO][ND]
90 @keyword spin_lock_fields2: The R1rho spin-lock field strengths squared (in rad^2.s^-2). This is for speed.
91 @type spin_lock_fields2: numpy float array of rank [NE][NS][NM][NO][ND]
92 @keyword back_calc: The array for holding the back calculated R1rho values. Each element corresponds to the combination of offset and spin lock field.
93 @type back_calc: numpy float array of rank [NE][NS][NM][NO][ND]
94 """
95
96
97 t_numer_zero = False
98
99
100 pB = 1.0 - pA
101
102
103 kex2 = kex**2
104
105
106 Wa = omega
107 Wb = omega + dw
108
109
110 phi_ex = pA * pB * dw**2
111 numer = phi_ex * kex
112
113
114
115 W = pA*Wa + pB*Wb
116
117
118 da = Wa - offset
119
120
121 db = Wb - offset
122
123
124 d = W - offset
125
126
127 waeff2 = spin_lock_fields2 + da**2
128
129
130 wbeff2 = spin_lock_fields2 + db**2
131
132
133 weff2 = spin_lock_fields2 + d**2
134
135
136 theta = arctan2(spin_lock_fields, d)
137
138
139 sin_theta2 = sin(theta)**2
140 R1_cos_theta2 = R1 * (1.0 - sin_theta2)
141 R1rho_prime_sin_theta2 = r1rho_prime * sin_theta2
142
143
144
145 if min(numer) == 0.0:
146 t_numer_zero = True
147 mask_numer_zero = masked_where(numer == 0.0, numer)
148
149
150 waeff2_wbeff2 = waeff2*wbeff2
151 fact_denom = waeff2_wbeff2 + weff2*kex2
152
153 fact = 1.0 + 2.0*kex2*(pA*waeff2 + pB*wbeff2) / fact_denom
154 denom = waeff2_wbeff2/weff2 + kex2 - sin_theta2*phi_ex*(fact)
155
156
157 back_calc[:] = R1_cos_theta2 + R1rho_prime_sin_theta2 + sin_theta2 * numer / denom
158
159
160
161 if t_numer_zero:
162 replace = R1_cos_theta2 + R1rho_prime_sin_theta2
163 back_calc[mask_numer_zero.mask] = replace[mask_numer_zero.mask]
164
165
166
167 if not isfinite(sum(back_calc)):
168
169 fix_invalid(back_calc, copy=False, fill_value=1e100)
170