1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Module for the manipulation of angular information."""
24
25
26 from math import acos, pi, sin
27 from numpy import dot
28 from warnings import warn
29
30
31 from generic_fns import pipes
32 from generic_fns.interatomic import interatomic_loop
33 from generic_fns.mol_res_spin import exists_mol_res_spin_data, generate_spin_id, spin_loop
34 from relax_errors import RelaxError, RelaxNoPdbError, RelaxNoSequenceError, RelaxNoTensorError
35 from relax_warnings import RelaxWarning
36
37
67
68
70 """Calculate the spherical angles of the bond vector in the ellipsoid frame."""
71
72
73 Dx, Dy, Dz = diffusion_tensor.unit_axes()
74
75
76 for spin, mol_name, res_num, res_name in spin_loop(full_info=True):
77
78 if not hasattr(spin, 'xh_vect'):
79
80 spin_id = generate_spin_id(mol_name=mol_name, res_num=res_num, res_name=res_name, spin_num=spin.num, spin_name=spin.name)
81
82
83 warn(RelaxWarning("No angles could be calculated for the spin " + repr(spin_id) + "."))
84
85
86 continue
87
88
89 dz = dot(Dz, spin.xh_vect)
90 dx = dot(Dx, spin.xh_vect)
91
92
93 spin.theta = acos(dz)
94
95
96 spin.phi = acos(dx / sin(spin.theta))
97
98
99 -def fold_spherical_angles(theta, phi, theta_lower=0, theta_upper=2*pi, theta_window=2*pi, phi_lower=0, phi_upper=2*pi, phi_window=2*pi):
100 """Fold the spherical angles taking symmetry into account.
101
102 The angles will be folded between::
103
104 0 <= theta <= pi,
105 0 <= phi <= 2*pi,
106
107 @param theta: The azimuthal angle.
108 @type theta: float
109 @param phi: The polar angle.
110 @type phi: float
111 @param theta_lower: The theta angle lower bound (defaults to 0).
112 @type theta_lower: float
113 @param theta_upper: The theta angle upper bound (defaults to 2*pi).
114 @type theta_upper: float
115 @param theta_window: The size of the theta angle window where symmetry exists (defaults to 2*pi).
116 @type theta_window: float
117 @param phi_lower: The phi angle lower bound (defaults to 0).
118 @type phi_lower: float
119 @param phi_upper: The phi angle upper bound (defaults to 2*pi).
120 @type phi_upper: float
121 @param phi_window: The size of the phi angle window where symmetry exists (defaults to 2*pi).
122 @type phi_window: float
123 @return: The folded angles, theta and phi.
124 @rtype: float
125 """
126
127
128 if theta_window - (theta_upper - theta_lower) > 1e-7:
129 raise RelaxError("The theta angle lower and upper bounds [%s, %s] do not match the window size of %s." % (theta_lower, theta_upper, theta_window))
130 if phi_window - (phi_upper - phi_lower) > 1e-7:
131 raise RelaxError("The phi angle lower and upper bounds [%s, %s] do not match the window size of %s." % (phi_lower, phi_upper, phi_window))
132
133
134 theta = wrap_angles(theta, theta_lower, theta_upper, theta_window)
135 phi = wrap_angles(phi, phi_lower, phi_upper, phi_window)
136
137
138 if phi >= phi_upper - phi_window/2.0:
139 theta = pi - theta
140 phi = phi - pi
141
142
143 theta = wrap_angles(theta, theta_lower, theta_upper, theta_window)
144 phi = wrap_angles(phi, phi_lower, phi_upper, phi_window)
145
146
147 return theta, phi
148
149
151 """Function for calculating the angle alpha of the XH vector within the spheroid frame."""
152
153
154 for interatom in interatomic_loop():
155
156 if not hasattr(interatom, 'vector'):
157
158 warn(RelaxWarning("No angles could be calculated for the spin pair '%s' and '%s'." % (interatom.spin_id1, interatom.spin_id2)))
159
160
161 continue
162
163
164 interatom.alpha = acos(dot(cdp.diff_tensor.Dpar_unit, interatom.vector))
165
166
168 """Convert the given angle to be between the lower and upper values.
169
170 @param angle: The starting angle.
171 @type angle: float
172 @param lower: The lower bound.
173 @type lower: float
174 @param upper: The upper bound.
175 @type upper: float
176 @param window: The size of the window where symmetry exists (defaults to 2pi).
177 @type window: float
178 @return: The wrapped angle.
179 @rtype: float
180 """
181
182
183 if window - (upper - lower) > 1e-7:
184 raise RelaxError("The lower and upper bounds [%s, %s] do not match the window size of %s." % (lower, upper, window))
185
186
187 while True:
188
189 if angle > upper:
190 angle = angle - window
191
192
193 elif angle < lower:
194 angle = angle + window
195
196
197 else:
198 break
199
200
201 return angle
202