1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Module containing the target functions of the Frame Order theories."""
24
25
26 from copy import deepcopy
27 from math import acos, cos, pi, sin, sqrt
28 from numpy import add, array, dot, float32, float64, ones, outer, subtract, transpose, uint8, zeros
29
30
31 from extern.sobol.sobol_lib import i4_sobol_generate
32 from lib.alignment.alignment_tensor import to_5D, to_tensor
33 from lib.alignment.pcs import pcs_tensor
34 from lib.alignment.rdc import rdc_tensor
35 from lib.compat import norm
36 from lib.errors import RelaxError
37 from lib.float import isNaN
38 from lib.frame_order.conversions import create_rotor_axis_alpha
39 from lib.frame_order.double_rotor import compile_2nd_matrix_double_rotor, pcs_numeric_qr_int_double_rotor, pcs_numeric_quad_int_double_rotor
40 from lib.frame_order.free_rotor import compile_2nd_matrix_free_rotor
41 from lib.frame_order.iso_cone import compile_2nd_matrix_iso_cone, pcs_numeric_quad_int_iso_cone, pcs_numeric_qr_int_iso_cone
42 from lib.frame_order.iso_cone_free_rotor import compile_2nd_matrix_iso_cone_free_rotor
43 from lib.frame_order.iso_cone_torsionless import compile_2nd_matrix_iso_cone_torsionless, pcs_numeric_quad_int_iso_cone_torsionless, pcs_numeric_qr_int_iso_cone_torsionless
44 from lib.frame_order.matrix_ops import reduce_alignment_tensor
45 from lib.frame_order.pseudo_ellipse import compile_2nd_matrix_pseudo_ellipse, pcs_numeric_quad_int_pseudo_ellipse, pcs_numeric_qr_int_pseudo_ellipse
46 from lib.frame_order.pseudo_ellipse_free_rotor import compile_2nd_matrix_pseudo_ellipse_free_rotor
47 from lib.frame_order.pseudo_ellipse_torsionless import compile_2nd_matrix_pseudo_ellipse_torsionless, pcs_numeric_quad_int_pseudo_ellipse_torsionless, pcs_numeric_qr_int_pseudo_ellipse_torsionless
48 from lib.frame_order.rotor import compile_2nd_matrix_rotor, pcs_numeric_quad_int_rotor, pcs_numeric_qr_int_rotor
49 from lib.frame_order.variables import MODEL_DOUBLE_ROTOR, MODEL_FREE_ROTOR, MODEL_ISO_CONE, MODEL_ISO_CONE_FREE_ROTOR, MODEL_ISO_CONE_TORSIONLESS, MODEL_PSEUDO_ELLIPSE, MODEL_PSEUDO_ELLIPSE_FREE_ROTOR, MODEL_PSEUDO_ELLIPSE_TORSIONLESS, MODEL_RIGID, MODEL_ROTOR
50 from lib.geometry.coord_transform import spherical_to_cartesian
51 from lib.geometry.rotations import euler_to_R_zyz, tilt_torsion_to_R, two_vect_to_R
52 from lib.linear_algebra.kronecker_product import kron_prod
53 from lib.physical_constants import pcs_constant
54 from target_functions.chi2 import chi2
55
56
58 """Class containing the target function of the optimisation of Frame Order matrix components."""
59
60 - def __init__(self, model=None, init_params=None, full_tensors=None, full_in_ref_frame=None, rdcs=None, rdc_errors=None, rdc_weights=None, rdc_vect=None, dip_const=None, pcs=None, pcs_errors=None, pcs_weights=None, atomic_pos=None, temp=None, frq=None, paramag_centre=zeros(3), scaling_matrix=None, sobol_max_points=200, sobol_oversample=100, com=None, ave_pos_pivot=zeros(3), pivot=None, pivot_opt=False, quad_int=False):
61 """Set up the target functions for the Frame Order theories.
62
63 @keyword model: The name of the Frame Order model.
64 @type model: str
65 @keyword init_params: The initial parameter values.
66 @type init_params: numpy float64 array
67 @keyword full_tensors: An array of the {Axx, Ayy, Axy, Axz, Ayz} values for all full alignment tensors. The format is [Axx1, Ayy1, Axy1, Axz1, Ayz1, Axx2, Ayy2, Axy2, Axz2, Ayz2, ..., Axxn, Ayyn, Axyn, Axzn, Ayzn].
68 @type full_tensors: numpy nx5D, rank-1 float64 array
69 @keyword full_in_ref_frame: An array of flags specifying if the tensor in the reference frame is the full or reduced tensor.
70 @type full_in_ref_frame: numpy rank-1 array
71 @keyword rdcs: The RDC lists. The first index must correspond to the different alignment media i and the second index to the spin systems j.
72 @type rdcs: numpy rank-2 array
73 @keyword rdc_errors: The RDC error lists. The dimensions of this argument are the same as for 'rdcs'.
74 @type rdc_errors: numpy rank-2 array
75 @keyword rdc_weights: The RDC weight lists. The dimensions of this argument are the same as for 'rdcs'.
76 @type rdc_weights: numpy rank-2 array
77 @keyword rdc_vect: The unit XH vector lists corresponding to the RDC values. The first index must correspond to the spin systems and the second index to the x, y, z elements.
78 @type rdc_vect: numpy rank-2 array
79 @keyword dip_const: The dipolar constants for each RDC. The indices correspond to the spin systems j.
80 @type dip_const: numpy rank-1 array
81 @keyword pcs: The PCS lists. The first index must correspond to the different alignment media i and the second index to the spin systems j.
82 @type pcs: numpy rank-2 array
83 @keyword pcs_errors: The PCS error lists. The dimensions of this argument are the same as for 'pcs'.
84 @type pcs_errors: numpy rank-2 array
85 @keyword pcs_weights: The PCS weight lists. The dimensions of this argument are the same as for 'pcs'.
86 @type pcs_weights: numpy rank-2 array
87 @keyword atomic_pos: The atomic positions of all spins for the PCS and PRE data. The first index is the spin systems j and the second is the structure or state c.
88 @type atomic_pos: numpy rank-3 array
89 @keyword temp: The temperature of each PCS data set.
90 @type temp: numpy rank-1 array
91 @keyword frq: The frequency of each PCS data set.
92 @type frq: numpy rank-1 array
93 @keyword paramag_centre: The paramagnetic centre position (or positions).
94 @type paramag_centre: numpy rank-1, 3D array or rank-2, Nx3 array
95 @keyword scaling_matrix: The square and diagonal scaling matrix.
96 @type scaling_matrix: numpy rank-2 array
97 @keyword sobol_max_points: The maximum number of Sobol' points to use for the numerical PCS integration technique.
98 @type sobol_max_points: int
99 @keyword sobol_oversample: The oversampling factor Ov used for the total number of points N * Ov * 10**M, where N is the maximum number of Sobol' points and M is the number of dimensions or torsion-tilt angles for the system.
100 @type sobol_oversample: int
101 @keyword com: The centre of mass of the system. This is used for defining the rotor model systems.
102 @type com: numpy 3D rank-1 array
103 @keyword ave_pos_pivot: The pivot point to rotate all atoms about to the average domain position. In most cases this will be the centre of mass of the moving domain. This pivot is shifted by the translation vector.
104 @type ave_pos_pivot: numpy 3D rank-1 array
105 @keyword pivot: The pivot point for the ball-and-socket joint motion. This is needed if PCS or PRE values are used.
106 @type pivot: numpy rank-1, 3D array or None
107 @keyword pivot_opt: A flag which if True will allow the pivot point of the motion to be optimised.
108 @type pivot_opt: bool
109 @keyword quad_int: A flag which if True will perform high precision numerical integration via the scipy.integrate quad(), dblquad() and tplquad() integration methods rather than the rough quasi-random numerical integration.
110 @type quad_int: bool
111 """
112
113
114 if not model:
115 raise RelaxError("The type of Frame Order model must be specified.")
116
117
118 self.params = deepcopy(init_params)
119
120
121 self.model = model
122 self.full_tensors = deepcopy(full_tensors)
123 self.full_in_ref_frame = deepcopy(full_in_ref_frame)
124 self.rdc = deepcopy(rdcs)
125 self.rdc_weights = deepcopy(rdc_weights)
126 self.rdc_vect = deepcopy(rdc_vect)
127 self.dip_const = deepcopy(dip_const)
128 self.pcs = deepcopy(pcs)
129 self.pcs_weights = deepcopy(pcs_weights)
130 self.atomic_pos = deepcopy(atomic_pos)
131 self.temp = deepcopy(temp)
132 self.frq = deepcopy(frq)
133 self.total_num_params = len(init_params)
134 self.sobol_max_points = sobol_max_points
135 self.sobol_oversample = sobol_oversample
136 self.com = deepcopy(com)
137 self.pivot_opt = pivot_opt
138 self.quad_int = quad_int
139
140
141 self._init_tensors()
142
143
144 self.scaling_matrix = scaling_matrix
145 if self.scaling_matrix is not None:
146 self.scaling_flag = True
147 else:
148 self.scaling_flag = False
149
150
151 self.num_align = 0
152 if rdcs is not None:
153 self.num_align = len(rdcs)
154 elif pcs is not None:
155 self.num_align = len(pcs)
156
157
158 rdc_flag = [True] * self.num_align
159 pcs_flag = [True] * self.num_align
160 for align_index in range(self.num_align):
161 if rdcs is None or len(rdcs[align_index]) == 0:
162 rdc_flag[align_index] = False
163 if pcs is None or len(pcs[align_index]) == 0:
164 pcs_flag[align_index] = False
165 self.rdc_flag = sum(rdc_flag)
166 self.pcs_flag = sum(pcs_flag)
167
168
169 self._translation_vector = zeros(3, float64)
170
171
172 if self.rdc_flag and (rdc_vect is None or not len(rdc_vect)):
173 raise RelaxError("The rdc_vect argument " + repr(rdc_vect) + " must be supplied.")
174 if self.pcs_flag and (atomic_pos is None or not len(atomic_pos)):
175 raise RelaxError("The atomic_pos argument " + repr(atomic_pos) + " must be supplied.")
176
177
178 self.num_spins = 0
179 if self.pcs_flag:
180 self.num_spins = len(pcs[0])
181
182
183 self.num_interatom = 0
184 if self.rdc_flag:
185 self.num_interatom = len(rdcs[0])
186
187
188 if self.pcs_flag:
189 self.spin_ones_struct = ones(self.num_spins, float64)
190 self.pivot = outer(self.spin_ones_struct, pivot)
191 self.paramag_centre = outer(self.spin_ones_struct, paramag_centre)
192 self.ave_pos_pivot = outer(self.spin_ones_struct, ave_pos_pivot)
193 else:
194 self.pivot = array([pivot])
195
196
197 for align_index in range(self.num_align):
198 to_tensor(self.A_3D[align_index], self.full_tensors[5*align_index:5*align_index+5])
199
200
201 if self.pcs_flag:
202 err = False
203 for i in range(len(pcs_errors)):
204 for j in range(len(pcs_errors[i])):
205 if not isNaN(pcs_errors[i, j]):
206 err = True
207 if err:
208 self.pcs_error = pcs_errors
209 else:
210
211 self.pcs_error = 0.1 * 1e-6 * ones((self.num_align, self.num_spins), float64)
212
213
214 if self.rdc_flag:
215 err = False
216 for i in range(len(rdc_errors)):
217 for j in range(len(rdc_errors[i])):
218 if not isNaN(rdc_errors[i, j]):
219 err = True
220 if err:
221 self.rdc_error = rdc_errors
222 else:
223
224 self.rdc_error = ones((self.num_align, self.num_interatom), float64)
225
226
227 if self.rdc_flag:
228 self.missing_rdc = zeros((self.num_align, self.num_interatom), uint8)
229
230
231 if self.pcs_flag:
232 self.missing_pcs = zeros((self.num_align, self.num_spins), uint8)
233
234
235 if self.rdc_flag or self.pcs_flag:
236 for align_index in range(self.num_align):
237
238 if self.rdc_flag:
239 for j in range(self.num_interatom):
240 if isNaN(self.rdc[align_index, j]):
241
242 self.missing_rdc[align_index, j] = 1
243
244
245 self.rdc[align_index, j] = 0.0
246
247
248 self.rdc_error[align_index, j] = 1.0
249
250
251 rdc_weights[align_index, j] = 1.0
252
253
254 if self.rdc_flag:
255 self.rdc_error[align_index, j] = self.rdc_error[align_index, j] / sqrt(rdc_weights[align_index, j])
256
257
258 if self.pcs_flag:
259 for j in range(self.num_spins):
260 if isNaN(self.pcs[align_index, j]):
261
262 self.missing_pcs[align_index, j] = 1
263
264
265 self.pcs[align_index, j] = 0.0
266
267
268 self.pcs_error[align_index, j] = 1.0
269
270
271 pcs_weights[align_index, j] = 1.0
272
273
274 if self.pcs_flag:
275 self.pcs_error[align_index, j] = self.pcs_error[align_index, j] / sqrt(pcs_weights[align_index, j])
276
277
278 if self.pcs_flag:
279
280 self.paramag_unit_vect = zeros(atomic_pos.shape, float64)
281 self.paramag_dist = zeros(self.num_spins, float64)
282 self.pcs_const = zeros((self.num_align, self.num_spins), float64)
283 self.r_pivot_atom = zeros((self.num_spins, 3), float32)
284 self.r_pivot_atom_rev = zeros((self.num_spins, 3), float32)
285 self.r_ln_pivot = self.pivot - self.paramag_centre
286
287
288 for align_index in range(self.num_align):
289 self.pcs_const[align_index] = pcs_constant(self.temp[align_index], self.frq[align_index], 1.0) * 1e30
290
291
292 self.pcs_theta = None
293 if self.pcs_flag:
294 self.pcs_theta = zeros((self.num_align, self.num_spins), float64)
295 self.pcs_theta_err = zeros((self.num_align, self.num_spins), float64)
296 self.dpcs_theta = zeros((self.total_num_params, self.num_align, self.num_spins), float64)
297 self.d2pcs_theta = zeros((self.total_num_params, self.total_num_params, self.num_align, self.num_spins), float64)
298
299
300 self.rdc_theta = None
301 if self.rdc_flag:
302 self.rdc_theta = zeros((self.num_align, self.num_interatom), float64)
303 self.drdc_theta = zeros((self.total_num_params, self.num_align, self.num_interatom), float64)
304 self.d2rdc_theta = zeros((self.total_num_params, self.total_num_params, self.num_align, self.num_interatom), float64)
305
306
307 ext = '_qr_int'
308 if self.quad_int:
309 ext = '_quad_int'
310
311
312 if model in [MODEL_RIGID]:
313 if model == MODEL_RIGID:
314 self.func = self.func_rigid
315
316
317 else:
318 if model == MODEL_PSEUDO_ELLIPSE:
319 self.create_sobol_data(dims=['theta', 'phi', 'sigma'])
320 self.func = getattr(self, 'func_pseudo_ellipse'+ext)
321 elif model == MODEL_PSEUDO_ELLIPSE_TORSIONLESS:
322 self.create_sobol_data(dims=['theta', 'phi'])
323 self.func = getattr(self, 'func_pseudo_ellipse_torsionless'+ext)
324 elif model == MODEL_PSEUDO_ELLIPSE_FREE_ROTOR:
325 self.create_sobol_data(dims=['theta', 'phi', 'sigma'])
326 self.func = getattr(self, 'func_pseudo_ellipse_free_rotor'+ext)
327 elif model == MODEL_ISO_CONE:
328 self.create_sobol_data(dims=['theta', 'phi', 'sigma'])
329 self.func = getattr(self, 'func_iso_cone'+ext)
330 elif model == MODEL_ISO_CONE_TORSIONLESS:
331 self.create_sobol_data(dims=['theta', 'phi'])
332 self.func = getattr(self, 'func_iso_cone_torsionless'+ext)
333 elif model == MODEL_ISO_CONE_FREE_ROTOR:
334 self.create_sobol_data(dims=['theta', 'phi', 'sigma'])
335 self.func = getattr(self, 'func_iso_cone_free_rotor'+ext)
336 elif model == MODEL_ROTOR:
337 self.create_sobol_data(dims=['sigma'])
338 self.func = getattr(self, 'func_rotor'+ext)
339 elif model == MODEL_FREE_ROTOR:
340 self.create_sobol_data(dims=['sigma'])
341 self.func = getattr(self, 'func_free_rotor'+ext)
342 elif model == MODEL_DOUBLE_ROTOR:
343 self.create_sobol_data(dims=['sigma', 'sigma2'])
344 self.func = getattr(self, 'func_double_rotor'+ext)
345
346
348 """Set up isotropic cone optimisation against the alignment tensor data."""
349
350
351 if self.full_tensors is None or not len(self.full_tensors):
352 raise RelaxError("The full_tensors argument " + repr(self.full_tensors) + " must be supplied.")
353 if self.full_in_ref_frame is None or not len(self.full_in_ref_frame):
354 raise RelaxError("The full_in_ref_frame argument " + repr(self.full_in_ref_frame) + " must be supplied.")
355
356
357 self.num_tensors = int(len(self.full_tensors) / 5)
358 self.A_3D = zeros((self.num_tensors, 3, 3), float64)
359 self.A_3D_bc = zeros((self.num_tensors, 3, 3), float64)
360 self.A_5D_bc = zeros(self.num_tensors*5, float64)
361
362
363 self.R_eigen = zeros((3, 3), float64)
364 self.R_eigen_2 = zeros((3, 3), float64)
365 self.R_ave = zeros((3, 3), float64)
366 self.Ri_prime = zeros((3, 3), float64)
367 self.Ri2_prime = zeros((3, 3), float64)
368 self.tensor_3D = zeros((3, 3), float64)
369
370
371 self.cone_axis = zeros(3, float64)
372 self.z_axis = array([0, 0, 1], float64)
373
374
375 self.rotor_axis = zeros(3, float64)
376 self.rotor_axis_2 = zeros(3, float64)
377
378
379 self.frame_order_2nd = zeros((9, 9), float64)
380
381
382 self.R = zeros((3, 3), float64)
383
384
386 """Quasi-random Sobol' integration target function for the double rotor model.
387
388 This function optimises the model parameters using the RDC and PCS base data. Quasi-random, Sobol' sequence based, numerical integration is used for the PCS.
389
390
391 @param params: The vector of parameter values. These can include {pivot_x, pivot_y, pivot_z, pivot_disp, ave_pos_x, ave_pos_y, ave_pos_z, ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_sigma_max, cone_sigma_max_2}.
392 @type params: list of float
393 @return: The chi-squared or SSE value.
394 @rtype: float
395 """
396
397
398 if self.scaling_flag:
399 params = dot(params, self.scaling_matrix)
400
401
402 if self.pivot_opt:
403 pivot2 = outer(self.spin_ones_struct, params[:3])
404 param_disp = params[3]
405 self._translation_vector = params[4:7]
406 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, sigma_max, sigma_max_2 = params[7:]
407 else:
408 pivot2 = self.pivot
409 param_disp = params[0]
410 self._translation_vector = params[1:4]
411 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, sigma_max, sigma_max_2 = params[4:]
412
413
414 euler_to_R_zyz(eigen_alpha, eigen_beta, eigen_gamma, self.R_eigen)
415
416
417 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
418
419
420 frame_order_2nd = compile_2nd_matrix_double_rotor(self.frame_order_2nd, Rx2_eigen, sigma_max, sigma_max_2)
421
422
423 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
424
425
426 RT_eigen = transpose(self.R_eigen)
427 RT_ave = transpose(self.R_ave)
428
429
430 if self.pcs_flag:
431
432 pivot = pivot2 + param_disp * self.R_eigen[:, 2]
433
434
435 self.calc_vectors(pivot=pivot, pivot2=pivot2, R_ave=self.R_ave, RT_ave=RT_ave)
436
437
438 chi2_sum = 0.0
439
440
441 if self.rdc_flag:
442
443 for align_index in range(self.num_align):
444
445 for j in range(self.num_interatom):
446
447 if not self.missing_rdc[align_index, j]:
448 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
449
450
451 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
452
453
454 if self.pcs_flag:
455
456 pcs_numeric_qr_int_double_rotor(points=sobol_data.sobol_angles, max_points=self.sobol_max_points, sigma_max=sigma_max, sigma_max_2=sigma_max_2, c=self.pcs_const, full_in_ref_frame=self.full_in_ref_frame, r_pivot_atom=self.r_pivot_atom, r_pivot_atom_rev=self.r_pivot_atom_rev, r_ln_pivot=self.r_ln_pivot, r_inter_pivot=self.r_inter_pivot, A=self.A_3D, R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=sobol_data.Ri_prime, Ri2_prime=sobol_data.Ri2_prime, pcs_theta=self.pcs_theta, pcs_theta_err=self.pcs_theta_err, missing_pcs=self.missing_pcs)
457
458
459 for align_index in range(self.num_align):
460 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
461
462
463 return chi2_sum
464
465
467 """SciPy quadratic integration target function for the double rotor model.
468
469 This function optimises the model parameters using the RDC and PCS base data. Quasi-random, Sobol' sequence based, numerical integration is used for the PCS.
470
471
472 @param params: The vector of parameter values. These can include {pivot_x, pivot_y, pivot_z, pivot_disp, ave_pos_x, ave_pos_y, ave_pos_z, ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_sigma_max, cone_sigma_max_2}.
473 @type params: list of float
474 @return: The chi-squared or SSE value.
475 @rtype: float
476 """
477
478
479 if self.scaling_flag:
480 params = dot(params, self.scaling_matrix)
481
482
483 if self.pivot_opt:
484 pivot2 = outer(self.spin_ones_struct, params[:3])
485 param_disp = params[3]
486 self._translation_vector = params[4:7]
487 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, sigma_max, sigma_max_2 = params[7:]
488 else:
489 pivot2 = self.pivot
490 param_disp = params[0]
491 self._translation_vector = params[1:4]
492 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, sigma_max, sigma_max_2 = params[4:]
493
494
495 euler_to_R_zyz(eigen_alpha, eigen_beta, eigen_gamma, self.R_eigen)
496
497
498 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
499
500
501 frame_order_2nd = compile_2nd_matrix_double_rotor(self.frame_order_2nd, Rx2_eigen, sigma_max, sigma_max_2)
502
503
504 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
505
506
507 RT_eigen = transpose(self.R_eigen)
508 RT_ave = transpose(self.R_ave)
509
510
511 if self.pcs_flag:
512
513 pivot = pivot2 + param_disp * self.R_eigen[:, 2]
514
515
516 self.calc_vectors(pivot=pivot, pivot2=pivot2, R_ave=self.R_ave, RT_ave=RT_ave)
517
518
519 chi2_sum = 0.0
520
521
522 if self.rdc_flag:
523
524 for align_index in range(self.num_align):
525
526 for j in range(self.num_interatom):
527
528 if not self.missing_rdc[align_index, j]:
529 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
530
531
532 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
533
534
535 if self.pcs_flag:
536
537 for align_index in range(self.num_align):
538
539 for j in range(self.num_spins):
540
541 if not self.missing_pcs[align_index, j]:
542
543 if self.full_in_ref_frame[align_index]:
544 r_pivot_atom = self.r_pivot_atom[j]
545 else:
546 r_pivot_atom = self.r_pivot_atom_rev[j]
547
548
549 self.pcs_theta[align_index, j] = pcs_numeric_quad_int_double_rotor(sigma_max=sigma_max, sigma_max_2=sigma_max_2, c=self.pcs_const[align_index, j], r_pivot_atom=r_pivot_atom, r_ln_pivot=self.r_ln_pivot[0], r_inter_pivot=self.r_inter_pivot[j], A=self.A_3D[align_index], R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=self.Ri_prime, Ri2_prime=self.Ri2_prime)
550
551
552 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
553
554
555 return chi2_sum
556
557
559 """Quasi-random Sobol' integration target function for the free rotor model.
560
561 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Simple numerical integration is used for the PCS.
562
563
564 @param params: The vector of parameter values. These are the tensor rotation angles {alpha, beta, gamma, theta, phi}.
565 @type params: list of float
566 @return: The chi-squared or SSE value.
567 @rtype: float
568 """
569
570
571 if self.scaling_flag:
572 params = dot(params, self.scaling_matrix)
573
574
575 if self.pivot_opt:
576 pivot = outer(self.spin_ones_struct, params[:3])
577 self._translation_vector = params[3:6]
578 ave_pos_beta, ave_pos_gamma, axis_alpha = params[6:]
579 else:
580 pivot = self.pivot
581 self._translation_vector = params[:3]
582 ave_pos_beta, ave_pos_gamma, axis_alpha = params[3:]
583
584
585 self.cone_axis = create_rotor_axis_alpha(alpha=axis_alpha, pivot=pivot[0], point=self.com)
586
587
588 two_vect_to_R(self.z_axis, self.cone_axis, self.R_eigen)
589
590
591 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
592
593
594 frame_order_2nd = compile_2nd_matrix_free_rotor(self.frame_order_2nd, Rx2_eigen)
595
596
597 self.reduce_and_rot(0.0, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
598
599
600 RT_eigen = transpose(self.R_eigen)
601 RT_ave = transpose(self.R_ave)
602
603
604 if self.pcs_flag:
605 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
606
607
608 chi2_sum = 0.0
609
610
611 if self.rdc_flag:
612
613 for align_index in range(self.num_align):
614
615 for j in range(self.num_interatom):
616
617 if not self.missing_rdc[align_index, j]:
618 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
619
620
621 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
622
623
624 if self.pcs_flag:
625
626 pcs_numeric_qr_int_rotor(points=sobol_data.sobol_angles, max_points=self.sobol_max_points, sigma_max=pi, c=self.pcs_const, full_in_ref_frame=self.full_in_ref_frame, r_pivot_atom=self.r_pivot_atom, r_pivot_atom_rev=self.r_pivot_atom_rev, r_ln_pivot=self.r_ln_pivot, A=self.A_3D, R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=sobol_data.Ri_prime, pcs_theta=self.pcs_theta, pcs_theta_err=self.pcs_theta_err, missing_pcs=self.missing_pcs)
627
628
629 for align_index in range(self.num_align):
630 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
631
632
633
634 return chi2_sum
635
636
638 """SciPy quadratic integration target function for the free rotor model.
639
640 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Scipy quadratic integration is used for the PCS.
641
642
643 @param params: The vector of parameter values. These are the tensor rotation angles {alpha, beta, gamma, theta, phi}.
644 @type params: list of float
645 @return: The chi-squared or SSE value.
646 @rtype: float
647 """
648
649
650 if self.scaling_flag:
651 params = dot(params, self.scaling_matrix)
652
653
654 if self.pivot_opt:
655 pivot = outer(self.spin_ones_struct, params[:3])
656 self._translation_vector = params[3:6]
657 ave_pos_beta, ave_pos_gamma, axis_alpha = params[6:]
658 else:
659 pivot = self.pivot
660 self._translation_vector = params[:3]
661 ave_pos_beta, ave_pos_gamma, axis_alpha = params[3:]
662
663
664 self.cone_axis = create_rotor_axis_alpha(alpha=axis_alpha, pivot=pivot[0], point=self.com)
665
666
667 two_vect_to_R(self.z_axis, self.cone_axis, self.R_eigen)
668
669
670 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
671
672
673 frame_order_2nd = compile_2nd_matrix_free_rotor(self.frame_order_2nd, Rx2_eigen)
674
675
676 self.reduce_and_rot(0.0, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
677
678
679 RT_eigen = transpose(self.R_eigen)
680 RT_ave = transpose(self.R_ave)
681
682
683 if self.pcs_flag:
684 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
685
686
687 chi2_sum = 0.0
688
689
690 if self.rdc_flag:
691
692 for align_index in range(self.num_align):
693
694 for j in range(self.num_interatom):
695
696 if not self.missing_rdc[align_index, j]:
697 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
698
699
700 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
701
702
703 if self.pcs_flag:
704
705 for align_index in range(self.num_align):
706
707 for j in range(self.num_spins):
708
709 if not self.missing_pcs[align_index, j]:
710
711 if self.full_in_ref_frame[align_index]:
712 r_pivot_atom = self.r_pivot_atom[j]
713 else:
714 r_pivot_atom = self.r_pivot_atom_rev[j]
715
716
717 self.pcs_theta[align_index, j] = pcs_numeric_quad_int_rotor(sigma_max=pi, c=self.pcs_const[align_index, j], r_pivot_atom=r_pivot_atom, r_ln_pivot=self.r_ln_pivot[0], A=self.A_3D[align_index], R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=self.Ri_prime)
718
719
720 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
721
722
723 return chi2_sum
724
725
727 """Quasi-random Sobol' integration target function for the isotropic cone model.
728
729 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Simple numerical integration is used for the PCS.
730
731
732 @param params: The vector of parameter values {alpha, beta, gamma, theta, phi, cone_theta, sigma_max} where the first 3 are the tensor rotation Euler angles, the next two are the polar and azimuthal angles of the cone axis, cone_theta is the cone opening half angle, and sigma_max is the torsion angle.
733 @type params: list of float
734 @return: The chi-squared or SSE value.
735 @rtype: float
736 """
737
738
739 if self.scaling_flag:
740 params = dot(params, self.scaling_matrix)
741
742
743 if self.pivot_opt:
744 pivot = outer(self.spin_ones_struct, params[:3])
745 self._translation_vector = params[3:6]
746 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, cone_theta, sigma_max = params[6:]
747 else:
748 pivot = self.pivot
749 self._translation_vector = params[:3]
750 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, cone_theta, sigma_max = params[3:]
751
752
753 spherical_to_cartesian([1.0, axis_theta, axis_phi], self.cone_axis)
754
755
756 two_vect_to_R(self.z_axis, self.cone_axis, self.R_eigen)
757
758
759 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
760
761
762 frame_order_2nd = compile_2nd_matrix_iso_cone(self.frame_order_2nd, Rx2_eigen, cone_theta, sigma_max)
763
764
765 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
766
767
768 RT_eigen = transpose(self.R_eigen)
769 RT_ave = transpose(self.R_ave)
770
771
772 if self.pcs_flag:
773 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
774
775
776 chi2_sum = 0.0
777
778
779 if self.rdc_flag:
780
781 for align_index in range(self.num_align):
782
783 for j in range(self.num_interatom):
784
785 if not self.missing_rdc[align_index, j]:
786 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
787
788
789 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
790
791
792 if self.pcs_flag:
793
794 pcs_numeric_qr_int_iso_cone(points=sobol_data.sobol_angles, max_points=self.sobol_max_points, theta_max=cone_theta, sigma_max=sigma_max, c=self.pcs_const, full_in_ref_frame=self.full_in_ref_frame, r_pivot_atom=self.r_pivot_atom, r_pivot_atom_rev=self.r_pivot_atom_rev, r_ln_pivot=self.r_ln_pivot, A=self.A_3D, R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=sobol_data.Ri_prime, pcs_theta=self.pcs_theta, pcs_theta_err=self.pcs_theta_err, missing_pcs=self.missing_pcs)
795
796
797 for align_index in range(self.num_align):
798 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
799
800
801 return chi2_sum
802
803
805 """SciPy quadratic integration target function for the isotropic cone model.
806
807 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Scipy quadratic integration is used for the PCS.
808
809
810 @param params: The vector of parameter values {beta, gamma, theta, phi, s1} where the first 2 are the tensor rotation Euler angles, the next two are the polar and azimuthal angles of the cone axis, and s1 is the isotropic cone order parameter.
811 @type params: list of float
812 @return: The chi-squared or SSE value.
813 @rtype: float
814 """
815
816
817 if self.scaling_flag:
818 params = dot(params, self.scaling_matrix)
819
820
821 if self.pivot_opt:
822 pivot = outer(self.spin_ones_struct, params[:3])
823 self._translation_vector = params[3:6]
824 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, cone_theta, sigma_max = params[6:]
825 else:
826 pivot = self.pivot
827 self._translation_vector = params[:3]
828 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, cone_theta, sigma_max = params[3:]
829
830
831 spherical_to_cartesian([1.0, axis_theta, axis_phi], self.cone_axis)
832
833
834 two_vect_to_R(self.z_axis, self.cone_axis, self.R_eigen)
835
836
837 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
838
839
840 frame_order_2nd = compile_2nd_matrix_iso_cone(self.frame_order_2nd, Rx2_eigen, cone_theta, sigma_max)
841
842
843 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
844
845
846 RT_eigen = transpose(self.R_eigen)
847 RT_ave = transpose(self.R_ave)
848
849
850 if self.pcs_flag:
851 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
852
853
854 chi2_sum = 0.0
855
856
857 if self.rdc_flag:
858
859 for align_index in range(self.num_align):
860
861 for j in range(self.num_interatom):
862
863 if not self.missing_rdc[align_index, j]:
864 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
865
866
867 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
868
869
870 if self.pcs_flag:
871
872 for align_index in range(self.num_align):
873
874 for j in range(self.num_spins):
875
876 if not self.missing_pcs[align_index, j]:
877
878 if self.full_in_ref_frame[align_index]:
879 r_pivot_atom = self.r_pivot_atom[j]
880 else:
881 r_pivot_atom = self.r_pivot_atom_rev[j]
882
883
884 self.pcs_theta[align_index, j] = pcs_numeric_quad_int_iso_cone(theta_max=cone_theta, sigma_max=sigma_max, c=self.pcs_const[align_index, j], r_pivot_atom=r_pivot_atom, r_ln_pivot=self.r_ln_pivot[0], A=self.A_3D[align_index], R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=self.Ri_prime)
885
886
887 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
888
889
890 return chi2_sum
891
892
894 """Quasi-random Sobol' integration target function for the free rotor isotropic cone model.
895
896 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Simple numerical integration is used for the PCS.
897
898
899 @param params: The vector of parameter values {beta, gamma, theta, phi, s1} where the first 2 are the tensor rotation Euler angles, the next two are the polar and azimuthal angles of the cone axis, and s1 is the isotropic cone order parameter.
900 @type params: list of float
901 @return: The chi-squared or SSE value.
902 @rtype: float
903 """
904
905
906 if self.scaling_flag:
907 params = dot(params, self.scaling_matrix)
908
909
910 if self.pivot_opt:
911 pivot = outer(self.spin_ones_struct, params[:3])
912 self._translation_vector = params[3:6]
913 ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, theta_max = params[6:]
914 else:
915 pivot = self.pivot
916 self._translation_vector = params[:3]
917 ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, theta_max = params[3:]
918
919
920 spherical_to_cartesian([1.0, axis_theta, axis_phi], self.cone_axis)
921
922
923 two_vect_to_R(self.z_axis, self.cone_axis, self.R_eigen)
924
925
926 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
927
928
929 frame_order_2nd = compile_2nd_matrix_iso_cone_free_rotor(self.frame_order_2nd, Rx2_eigen, theta_max)
930
931
932 self.reduce_and_rot(0.0, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
933
934
935 RT_eigen = transpose(self.R_eigen)
936 RT_ave = transpose(self.R_ave)
937
938
939 if self.pcs_flag:
940 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
941
942
943 chi2_sum = 0.0
944
945
946 if self.rdc_flag:
947
948 for align_index in range(self.num_align):
949
950 for j in range(self.num_interatom):
951
952 if not self.missing_rdc[align_index, j]:
953 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
954
955
956 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
957
958
959 if self.pcs_flag:
960
961 pcs_numeric_qr_int_iso_cone(points=sobol_data.sobol_angles, max_points=self.sobol_max_points, theta_max=theta_max, sigma_max=pi, c=self.pcs_const, full_in_ref_frame=self.full_in_ref_frame, r_pivot_atom=self.r_pivot_atom, r_pivot_atom_rev=self.r_pivot_atom_rev, r_ln_pivot=self.r_ln_pivot, A=self.A_3D, R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=sobol_data.Ri_prime, pcs_theta=self.pcs_theta, pcs_theta_err=self.pcs_theta_err, missing_pcs=self.missing_pcs)
962
963
964 for align_index in range(self.num_align):
965 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
966
967
968 return chi2_sum
969
970
972 """SciPy quadratic integration target function for the free rotor isotropic cone model.
973
974 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Scipy quadratic integration is used for the PCS.
975
976
977 @param params: The vector of parameter values {beta, gamma, theta, phi, s1} where the first 2 are the tensor rotation Euler angles, the next two are the polar and azimuthal angles of the cone axis, and s1 is the isotropic cone order parameter.
978 @type params: list of float
979 @return: The chi-squared or SSE value.
980 @rtype: float
981 """
982
983
984 if self.scaling_flag:
985 params = dot(params, self.scaling_matrix)
986
987
988 if self.pivot_opt:
989 pivot = outer(self.spin_ones_struct, params[:3])
990 self._translation_vector = params[3:6]
991 ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, theta_max = params[6:]
992 else:
993 pivot = self.pivot
994 self._translation_vector = params[:3]
995 ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, theta_max = params[3:]
996
997
998 spherical_to_cartesian([1.0, axis_theta, axis_phi], self.cone_axis)
999
1000
1001 two_vect_to_R(self.z_axis, self.cone_axis, self.R_eigen)
1002
1003
1004 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
1005
1006
1007 frame_order_2nd = compile_2nd_matrix_iso_cone_free_rotor(self.frame_order_2nd, Rx2_eigen, theta_max)
1008
1009
1010 self.reduce_and_rot(0.0, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
1011
1012
1013 RT_eigen = transpose(self.R_eigen)
1014 RT_ave = transpose(self.R_ave)
1015
1016
1017 if self.pcs_flag:
1018 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1019
1020
1021 chi2_sum = 0.0
1022
1023
1024 if self.rdc_flag:
1025
1026 for align_index in range(self.num_align):
1027
1028 for j in range(self.num_interatom):
1029
1030 if not self.missing_rdc[align_index, j]:
1031 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1032
1033
1034 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1035
1036
1037 if self.pcs_flag:
1038
1039 for align_index in range(self.num_align):
1040
1041 for j in range(self.num_spins):
1042
1043 if not self.missing_pcs[align_index, j]:
1044
1045 if self.full_in_ref_frame[align_index]:
1046 r_pivot_atom = self.r_pivot_atom[j]
1047 else:
1048 r_pivot_atom = self.r_pivot_atom_rev[j]
1049
1050
1051 self.pcs_theta[align_index, j] = pcs_numeric_quad_int_iso_cone(theta_max=theta_max, sigma_max=pi, c=self.pcs_const[align_index, j], r_pivot_atom=r_pivot_atom, r_ln_pivot=self.r_ln_pivot[0], A=self.A_3D[align_index], R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=self.Ri_prime)
1052
1053
1054 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1055
1056
1057 return chi2_sum
1058
1059
1061 """Quasi-random Sobol' integration target function for the torsionless isotropic cone model.
1062
1063 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Simple numerical integration is used for the PCS.
1064
1065
1066 @param params: The vector of parameter values {beta, gamma, theta, phi, cone_theta} where the first 2 are the tensor rotation Euler angles, the next two are the polar and azimuthal angles of the cone axis, and cone_theta is cone opening angle.
1067 @type params: list of float
1068 @return: The chi-squared or SSE value.
1069 @rtype: float
1070 """
1071
1072
1073 if self.scaling_flag:
1074 params = dot(params, self.scaling_matrix)
1075
1076
1077 if self.pivot_opt:
1078 pivot = outer(self.spin_ones_struct, params[:3])
1079 self._translation_vector = params[3:6]
1080 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, cone_theta = params[6:]
1081 else:
1082 pivot = self.pivot
1083 self._translation_vector = params[:3]
1084 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, cone_theta = params[3:]
1085
1086
1087 spherical_to_cartesian([1.0, axis_theta, axis_phi], self.cone_axis)
1088
1089
1090 two_vect_to_R(self.z_axis, self.cone_axis, self.R_eigen)
1091
1092
1093 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
1094
1095
1096 frame_order_2nd = compile_2nd_matrix_iso_cone_torsionless(self.frame_order_2nd, Rx2_eigen, cone_theta)
1097
1098
1099 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
1100
1101
1102 RT_eigen = transpose(self.R_eigen)
1103 RT_ave = transpose(self.R_ave)
1104
1105
1106 if self.pcs_flag:
1107 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1108
1109
1110 chi2_sum = 0.0
1111
1112
1113 if self.rdc_flag:
1114
1115 for align_index in range(self.num_align):
1116
1117 for j in range(self.num_interatom):
1118
1119 if not self.missing_rdc[align_index, j]:
1120 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1121
1122
1123 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1124
1125
1126 if self.pcs_flag:
1127
1128 pcs_numeric_qr_int_iso_cone_torsionless(points=sobol_data.sobol_angles, max_points=self.sobol_max_points, theta_max=cone_theta, c=self.pcs_const, full_in_ref_frame=self.full_in_ref_frame, r_pivot_atom=self.r_pivot_atom, r_pivot_atom_rev=self.r_pivot_atom_rev, r_ln_pivot=self.r_ln_pivot, A=self.A_3D, R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=sobol_data.Ri_prime, pcs_theta=self.pcs_theta, pcs_theta_err=self.pcs_theta_err, missing_pcs=self.missing_pcs)
1129
1130
1131 for align_index in range(self.num_align):
1132 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1133
1134
1135 return chi2_sum
1136
1137
1139 """SciPy quadratic integration target function for the torsionless isotropic cone model.
1140
1141 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Scipy quadratic integration is used for the PCS.
1142
1143
1144 @param params: The vector of parameter values {beta, gamma, theta, phi, cone_theta} where the first 2 are the tensor rotation Euler angles, the next two are the polar and azimuthal angles of the cone axis, and cone_theta is cone opening angle.
1145 @type params: list of float
1146 @return: The chi-squared or SSE value.
1147 @rtype: float
1148 """
1149
1150
1151 if self.scaling_flag:
1152 params = dot(params, self.scaling_matrix)
1153
1154
1155 if self.pivot_opt:
1156 pivot = outer(self.spin_ones_struct, params[:3])
1157 self._translation_vector = params[3:6]
1158 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, cone_theta = params[6:]
1159 else:
1160 pivot = self.pivot
1161 self._translation_vector = params[:3]
1162 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_theta, axis_phi, cone_theta = params[3:]
1163
1164
1165 spherical_to_cartesian([1.0, axis_theta, axis_phi], self.cone_axis)
1166
1167
1168 two_vect_to_R(self.z_axis, self.cone_axis, self.R_eigen)
1169
1170
1171 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
1172
1173
1174 frame_order_2nd = compile_2nd_matrix_iso_cone_torsionless(self.frame_order_2nd, Rx2_eigen, cone_theta)
1175
1176
1177 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
1178
1179
1180 RT_eigen = transpose(self.R_eigen)
1181 RT_ave = transpose(self.R_ave)
1182
1183
1184 if self.pcs_flag:
1185 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1186
1187
1188 chi2_sum = 0.0
1189
1190
1191 if self.rdc_flag:
1192
1193 for align_index in range(self.num_align):
1194
1195 for j in range(self.num_interatom):
1196
1197 if not self.missing_rdc[align_index, j]:
1198 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1199
1200
1201 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1202
1203
1204 if self.pcs_flag:
1205
1206 for align_index in range(self.num_align):
1207
1208 for j in range(self.num_spins):
1209
1210 if not self.missing_pcs[align_index, j]:
1211
1212 if self.full_in_ref_frame[align_index]:
1213 r_pivot_atom = self.r_pivot_atom[j]
1214 else:
1215 r_pivot_atom = self.r_pivot_atom_rev[j]
1216
1217
1218 self.pcs_theta[align_index, j] = pcs_numeric_quad_int_iso_cone_torsionless(theta_max=cone_theta, c=self.pcs_const[align_index, j], r_pivot_atom=r_pivot_atom, r_ln_pivot=self.r_ln_pivot[0], A=self.A_3D[align_index], R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=self.Ri_prime)
1219
1220
1221 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1222
1223
1224 return chi2_sum
1225
1226
1228 """Quasi-random Sobol' integration target function for the pseudo-ellipse model.
1229
1230 This function optimises the model parameters using the RDC and PCS base data. Quasi-random, Sobol' sequence based, numerical integration is used for the PCS.
1231
1232
1233 @param params: The vector of parameter values {alpha, beta, gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y, cone_sigma_max} where the first 3 are the average position rotation Euler angles, the next 3 are the Euler angles defining the eigenframe, and the last 3 are the pseudo-elliptic cone geometric parameters.
1234 @type params: list of float
1235 @return: The chi-squared or SSE value.
1236 @rtype: float
1237 """
1238
1239
1240 if self.scaling_flag:
1241 params = dot(params, self.scaling_matrix)
1242
1243
1244 if self.pivot_opt:
1245 pivot = outer(self.spin_ones_struct, params[:3])
1246 self._translation_vector = params[3:6]
1247 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y, cone_sigma_max = params[6:]
1248 else:
1249 pivot = self.pivot
1250 self._translation_vector = params[:3]
1251 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y, cone_sigma_max = params[3:]
1252
1253
1254 euler_to_R_zyz(eigen_alpha, eigen_beta, eigen_gamma, self.R_eigen)
1255
1256
1257 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
1258
1259
1260 frame_order_2nd = compile_2nd_matrix_pseudo_ellipse(self.frame_order_2nd, Rx2_eigen, cone_theta_x, cone_theta_y, cone_sigma_max)
1261
1262
1263 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
1264
1265
1266 RT_eigen = transpose(self.R_eigen)
1267 RT_ave = transpose(self.R_ave)
1268
1269
1270 if self.pcs_flag:
1271 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1272
1273
1274 chi2_sum = 0.0
1275
1276
1277 if self.rdc_flag:
1278
1279 for align_index in range(self.num_align):
1280
1281 for j in range(self.num_interatom):
1282
1283 if not self.missing_rdc[align_index, j]:
1284 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1285
1286
1287 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1288
1289
1290 if self.pcs_flag:
1291
1292 pcs_numeric_qr_int_pseudo_ellipse(points=sobol_data.sobol_angles, max_points=self.sobol_max_points, theta_x=cone_theta_x, theta_y=cone_theta_y, sigma_max=cone_sigma_max, c=self.pcs_const, full_in_ref_frame=self.full_in_ref_frame, r_pivot_atom=self.r_pivot_atom, r_pivot_atom_rev=self.r_pivot_atom_rev, r_ln_pivot=self.r_ln_pivot, A=self.A_3D, R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=sobol_data.Ri_prime, pcs_theta=self.pcs_theta, pcs_theta_err=self.pcs_theta_err, missing_pcs=self.missing_pcs)
1293
1294
1295 for align_index in range(self.num_align):
1296 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1297
1298
1299 return chi2_sum
1300
1301
1303 """SciPy quadratic integration target function for the pseudo-ellipse model.
1304
1305 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Scipy quadratic integration is used for the PCS.
1306
1307
1308 @param params: The vector of parameter values {alpha, beta, gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y, cone_sigma_max} where the first 3 are the average position rotation Euler angles, the next 3 are the Euler angles defining the eigenframe, and the last 3 are the pseudo-elliptic cone geometric parameters.
1309 @type params: list of float
1310 @return: The chi-squared or SSE value.
1311 @rtype: float
1312 """
1313
1314
1315 if self.scaling_flag:
1316 params = dot(params, self.scaling_matrix)
1317
1318
1319 if self.pivot_opt:
1320 pivot = outer(self.spin_ones_struct, params[:3])
1321 self._translation_vector = params[3:6]
1322 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y, cone_sigma_max = params[6:]
1323 else:
1324 pivot = self.pivot
1325 self._translation_vector = params[:3]
1326 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y, cone_sigma_max = params[3:]
1327
1328
1329 euler_to_R_zyz(eigen_alpha, eigen_beta, eigen_gamma, self.R_eigen)
1330
1331
1332 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
1333
1334
1335 frame_order_2nd = compile_2nd_matrix_pseudo_ellipse(self.frame_order_2nd, Rx2_eigen, cone_theta_x, cone_theta_y, cone_sigma_max)
1336
1337
1338 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
1339
1340
1341 RT_eigen = transpose(self.R_eigen)
1342 RT_ave = transpose(self.R_ave)
1343
1344
1345 if self.pcs_flag:
1346 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1347
1348
1349 chi2_sum = 0.0
1350
1351
1352 if self.rdc_flag:
1353
1354 for align_index in range(self.num_align):
1355
1356 for j in range(self.num_interatom):
1357
1358 if not self.missing_rdc[align_index, j]:
1359 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1360
1361
1362 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1363
1364
1365 if self.pcs_flag:
1366
1367 for align_index in range(self.num_align):
1368
1369 for j in range(self.num_spins):
1370
1371 if not self.missing_pcs[align_index, j]:
1372
1373 if self.full_in_ref_frame[align_index]:
1374 r_pivot_atom = self.r_pivot_atom[j]
1375 else:
1376 r_pivot_atom = self.r_pivot_atom_rev[j]
1377
1378
1379 self.pcs_theta[align_index, j] = pcs_numeric_quad_int_pseudo_ellipse(theta_x=cone_theta_x, theta_y=cone_theta_y, sigma_max=cone_sigma_max, c=self.pcs_const[align_index, j], r_pivot_atom=r_pivot_atom, r_ln_pivot=self.r_ln_pivot[0], A=self.A_3D[align_index], R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=self.Ri_prime)
1380
1381
1382 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1383
1384
1385 return chi2_sum
1386
1387
1389 """Quasi-random Sobol' integration target function for the free-rotor pseudo-ellipse model.
1390
1391 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Simple numerical integration is used for the PCS.
1392
1393
1394 @param params: The vector of parameter values {alpha, beta, gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y} where the first 3 are the average position rotation Euler angles, the next 3 are the Euler angles defining the eigenframe, and the last 2 are the free_rotor pseudo-elliptic cone geometric parameters.
1395 @type params: list of float
1396 @return: The chi-squared or SSE value.
1397 @rtype: float
1398 """
1399
1400
1401 if self.scaling_flag:
1402 params = dot(params, self.scaling_matrix)
1403
1404
1405 if self.pivot_opt:
1406 pivot = outer(self.spin_ones_struct, params[:3])
1407 self._translation_vector = params[3:6]
1408 ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y = params[6:]
1409 else:
1410 pivot = self.pivot
1411 self._translation_vector = params[:3]
1412 ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y = params[3:]
1413
1414
1415 euler_to_R_zyz(eigen_alpha, eigen_beta, eigen_gamma, self.R_eigen)
1416
1417
1418 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
1419
1420
1421 frame_order_2nd = compile_2nd_matrix_pseudo_ellipse_free_rotor(self.frame_order_2nd, Rx2_eigen, cone_theta_x, cone_theta_y)
1422
1423
1424 self.reduce_and_rot(0.0, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
1425
1426
1427 RT_eigen = transpose(self.R_eigen)
1428 RT_ave = transpose(self.R_ave)
1429
1430
1431 if self.pcs_flag:
1432 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1433
1434
1435 chi2_sum = 0.0
1436
1437
1438 if self.rdc_flag:
1439
1440 for align_index in range(self.num_align):
1441
1442 for j in range(self.num_interatom):
1443
1444 if not self.missing_rdc[align_index, j]:
1445 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1446
1447
1448 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1449
1450
1451 if self.pcs_flag:
1452
1453 pcs_numeric_qr_int_pseudo_ellipse(points=sobol_data.sobol_angles, max_points=self.sobol_max_points, theta_x=cone_theta_x, theta_y=cone_theta_y, sigma_max=pi, c=self.pcs_const, full_in_ref_frame=self.full_in_ref_frame, r_pivot_atom=self.r_pivot_atom, r_pivot_atom_rev=self.r_pivot_atom_rev, r_ln_pivot=self.r_ln_pivot, A=self.A_3D, R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=sobol_data.Ri_prime, pcs_theta=self.pcs_theta, pcs_theta_err=self.pcs_theta_err, missing_pcs=self.missing_pcs)
1454
1455
1456 for align_index in range(self.num_align):
1457 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1458
1459
1460 return chi2_sum
1461
1462
1464 """SciPy quadratic integration target function for the free-rotor pseudo-ellipse model.
1465
1466 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Scipy quadratic integration is used for the PCS.
1467
1468
1469 @param params: The vector of parameter values {alpha, beta, gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y} where the first 3 are the average position rotation Euler angles, the next 3 are the Euler angles defining the eigenframe, and the last 2 are the free_rotor pseudo-elliptic cone geometric parameters.
1470 @type params: list of float
1471 @return: The chi-squared or SSE value.
1472 @rtype: float
1473 """
1474
1475
1476 if self.scaling_flag:
1477 params = dot(params, self.scaling_matrix)
1478
1479
1480 if self.pivot_opt:
1481 pivot = outer(self.spin_ones_struct, params[:3])
1482 self._translation_vector = params[3:6]
1483 ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y = params[6:]
1484 else:
1485 pivot = self.pivot
1486 self._translation_vector = params[:3]
1487 ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y = params[3:]
1488
1489
1490 euler_to_R_zyz(eigen_alpha, eigen_beta, eigen_gamma, self.R_eigen)
1491
1492
1493 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
1494
1495
1496 frame_order_2nd = compile_2nd_matrix_pseudo_ellipse_free_rotor(self.frame_order_2nd, Rx2_eigen, cone_theta_x, cone_theta_y)
1497
1498
1499 self.reduce_and_rot(0.0, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
1500
1501
1502 RT_eigen = transpose(self.R_eigen)
1503 RT_ave = transpose(self.R_ave)
1504
1505
1506 if self.pcs_flag:
1507 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1508
1509
1510 chi2_sum = 0.0
1511
1512
1513 if self.rdc_flag:
1514
1515 for align_index in range(self.num_align):
1516
1517 for j in range(self.num_interatom):
1518
1519 if not self.missing_rdc[align_index, j]:
1520 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1521
1522
1523 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1524
1525
1526 if self.pcs_flag:
1527
1528 for align_index in range(self.num_align):
1529
1530 for j in range(self.num_spins):
1531
1532 if not self.missing_pcs[align_index, j]:
1533
1534 if self.full_in_ref_frame[align_index]:
1535 r_pivot_atom = self.r_pivot_atom[j]
1536 else:
1537 r_pivot_atom = self.r_pivot_atom_rev[j]
1538
1539
1540 self.pcs_theta[align_index, j] = pcs_numeric_quad_int_pseudo_ellipse(theta_x=cone_theta_x, theta_y=cone_theta_y, sigma_max=pi, c=self.pcs_const[align_index, j], r_pivot_atom=r_pivot_atom, r_ln_pivot=self.r_ln_pivot[0], A=self.A_3D[align_index], R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=self.Ri_prime)
1541
1542
1543 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1544
1545
1546 return chi2_sum
1547
1548
1550 """Quasi-random Sobol' integration target function for the torsionless pseudo-ellipse model.
1551
1552 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Simple numerical integration is used for the PCS.
1553
1554
1555 @param params: The vector of parameter values {alpha, beta, gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y} where the first 3 are the average position rotation Euler angles, the next 3 are the Euler angles defining the eigenframe, and the last 2 are the torsionless pseudo-elliptic cone geometric parameters.
1556 @type params: list of float
1557 @return: The chi-squared or SSE value.
1558 @rtype: float
1559 """
1560
1561
1562 if self.scaling_flag:
1563 params = dot(params, self.scaling_matrix)
1564
1565
1566 if self.pivot_opt:
1567 pivot = outer(self.spin_ones_struct, params[:3])
1568 self._translation_vector = params[3:6]
1569 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y = params[6:]
1570 else:
1571 pivot = self.pivot
1572 self._translation_vector = params[:3]
1573 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y = params[3:]
1574
1575
1576 euler_to_R_zyz(eigen_alpha, eigen_beta, eigen_gamma, self.R_eigen)
1577
1578
1579 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
1580
1581
1582 frame_order_2nd = compile_2nd_matrix_pseudo_ellipse_torsionless(self.frame_order_2nd, Rx2_eigen, cone_theta_x, cone_theta_y)
1583
1584
1585 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
1586
1587
1588 RT_eigen = transpose(self.R_eigen)
1589 RT_ave = transpose(self.R_ave)
1590
1591
1592 if self.pcs_flag:
1593 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1594
1595
1596 chi2_sum = 0.0
1597
1598
1599 if self.rdc_flag:
1600
1601 for align_index in range(self.num_align):
1602
1603 for j in range(self.num_interatom):
1604
1605 if not self.missing_rdc[align_index, j]:
1606 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1607
1608
1609 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1610
1611
1612 if self.pcs_flag:
1613
1614 pcs_numeric_qr_int_pseudo_ellipse_torsionless(points=sobol_data.sobol_angles, max_points=self.sobol_max_points, theta_x=cone_theta_x, theta_y=cone_theta_y, c=self.pcs_const, full_in_ref_frame=self.full_in_ref_frame, r_pivot_atom=self.r_pivot_atom, r_pivot_atom_rev=self.r_pivot_atom_rev, r_ln_pivot=self.r_ln_pivot, A=self.A_3D, R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=sobol_data.Ri_prime, pcs_theta=self.pcs_theta, pcs_theta_err=self.pcs_theta_err, missing_pcs=self.missing_pcs)
1615
1616
1617 for align_index in range(self.num_align):
1618 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1619
1620
1621 return chi2_sum
1622
1623
1625 """SciPy quadratic integration target function for the torsionless pseudo-ellipse model.
1626
1627 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Scipy quadratic integration is used for the PCS.
1628
1629
1630 @param params: The vector of parameter values {alpha, beta, gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y} where the first 3 are the average position rotation Euler angles, the next 3 are the Euler angles defining the eigenframe, and the last 2 are the torsionless pseudo-elliptic cone geometric parameters.
1631 @type params: list of float
1632 @return: The chi-squared or SSE value.
1633 @rtype: float
1634 """
1635
1636
1637 if self.scaling_flag:
1638 params = dot(params, self.scaling_matrix)
1639
1640
1641 if self.pivot_opt:
1642 pivot = outer(self.spin_ones_struct, params[:3])
1643 self._translation_vector = params[3:6]
1644 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y = params[6:]
1645 else:
1646 pivot = self.pivot
1647 self._translation_vector = params[:3]
1648 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, eigen_alpha, eigen_beta, eigen_gamma, cone_theta_x, cone_theta_y = params[3:]
1649
1650
1651 euler_to_R_zyz(eigen_alpha, eigen_beta, eigen_gamma, self.R_eigen)
1652
1653
1654 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
1655
1656
1657 frame_order_2nd = compile_2nd_matrix_pseudo_ellipse_torsionless(self.frame_order_2nd, Rx2_eigen, cone_theta_x, cone_theta_y)
1658
1659
1660 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
1661
1662
1663 RT_eigen = transpose(self.R_eigen)
1664 RT_ave = transpose(self.R_ave)
1665
1666
1667 if self.pcs_flag:
1668 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1669
1670
1671 chi2_sum = 0.0
1672
1673
1674 if self.rdc_flag:
1675
1676 for align_index in range(self.num_align):
1677
1678 for j in range(self.num_interatom):
1679
1680 if not self.missing_rdc[align_index, j]:
1681 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1682
1683
1684 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1685
1686
1687 if self.pcs_flag:
1688
1689 for align_index in range(self.num_align):
1690
1691 for j in range(self.num_spins):
1692
1693 if not self.missing_pcs[align_index, j]:
1694
1695 if self.full_in_ref_frame[align_index]:
1696 r_pivot_atom = self.r_pivot_atom[j]
1697 else:
1698 r_pivot_atom = self.r_pivot_atom_rev[j]
1699
1700
1701 self.pcs_theta[align_index, j] = pcs_numeric_quad_int_pseudo_ellipse_torsionless(theta_x=cone_theta_x, theta_y=cone_theta_y, c=self.pcs_const[align_index, j], r_pivot_atom=r_pivot_atom, r_ln_pivot=self.r_ln_pivot[0], A=self.A_3D[align_index], R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=self.Ri_prime)
1702
1703
1704 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1705
1706
1707 return chi2_sum
1708
1709
1711 """Target function for rigid model optimisation.
1712
1713 This function optimises the isotropic cone model parameters using the RDC and PCS base data.
1714
1715
1716 @param params: The vector of parameter values. These are the tensor rotation angles {alpha, beta, gamma}.
1717 @type params: list of float
1718 @return: The chi-squared or SSE value.
1719 @rtype: float
1720 """
1721
1722
1723 if self.scaling_flag:
1724 params = dot(params, self.scaling_matrix)
1725
1726
1727 self._translation_vector = params[:3]
1728 ave_pos_alpha, ave_pos_beta, ave_pos_gamma = params[3:6]
1729
1730
1731 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma)
1732
1733
1734 RT_ave = transpose(self.R_ave)
1735
1736
1737 chi2_sum = 0.0
1738
1739
1740 if self.rdc_flag:
1741
1742 for align_index in range(self.num_align):
1743
1744 for j in range(self.num_interatom):
1745
1746 if not self.missing_rdc[align_index, j]:
1747 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1748
1749
1750 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1751
1752
1753 if self.pcs_flag:
1754
1755 self.calc_vectors(pivot=self.pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1756 r_ln_atom = self.r_ln_pivot + self.r_pivot_atom
1757 if min(self.full_in_ref_frame) == 0:
1758 r_ln_atom_rev = self.r_ln_pivot + self.r_pivot_atom_rev
1759
1760
1761 length = 1.0 / norm(r_ln_atom, axis=1)**5
1762 if min(self.full_in_ref_frame) == 0:
1763 length_rev = 1.0 / norm(r_ln_atom, axis=1)**5
1764
1765
1766 for align_index in range(self.num_align):
1767
1768 for j in range(self.num_spins):
1769
1770 if not self.missing_pcs[align_index, j]:
1771
1772 if self.full_in_ref_frame[align_index]:
1773 r_ln_atom_i = r_ln_atom[j]
1774 length_i = length[j]
1775 else:
1776 r_ln_atom_i = r_ln_atom_rev[j]
1777 length_i = length_rev[j]
1778
1779
1780 self.pcs_theta[align_index, j] = pcs_tensor(self.pcs_const[align_index, j] * length_i, r_ln_atom_i, self.A_3D[align_index])
1781
1782
1783 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1784
1785
1786 return chi2_sum
1787
1788
1790 """Quasi-random Sobol' integration target function for the rotor model.
1791
1792 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Quasi-random, Sobol' sequence based, numerical integration is used for the PCS.
1793
1794
1795 @param params: The vector of parameter values. These are the tensor rotation angles {alpha, beta, gamma, theta, phi, sigma_max}.
1796 @type params: list of float
1797 @return: The chi-squared or SSE value.
1798 @rtype: float
1799 """
1800
1801
1802 if self.scaling_flag:
1803 params = dot(params, self.scaling_matrix)
1804
1805
1806 if self.pivot_opt:
1807 pivot = outer(self.spin_ones_struct, params[:3])
1808 self._translation_vector = params[3:6]
1809 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_alpha, sigma_max = params[6:]
1810 else:
1811 pivot = self.pivot
1812 self._translation_vector = params[:3]
1813 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_alpha, sigma_max = params[3:]
1814
1815
1816 self.cone_axis = create_rotor_axis_alpha(alpha=axis_alpha, pivot=pivot[0], point=self.com)
1817
1818
1819 two_vect_to_R(self.z_axis, self.cone_axis, self.R_eigen)
1820
1821
1822 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
1823
1824
1825 frame_order_2nd = compile_2nd_matrix_rotor(self.frame_order_2nd, Rx2_eigen, sigma_max)
1826
1827
1828 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
1829
1830
1831 RT_eigen = transpose(self.R_eigen)
1832 RT_ave = transpose(self.R_ave)
1833
1834
1835 if self.pcs_flag:
1836 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1837
1838
1839 chi2_sum = 0.0
1840
1841
1842 if self.rdc_flag:
1843
1844 for align_index in range(self.num_align):
1845
1846 for j in range(self.num_interatom):
1847
1848 if not self.missing_rdc[align_index, j]:
1849 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1850
1851
1852 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1853
1854
1855 if self.pcs_flag:
1856
1857 pcs_numeric_qr_int_rotor(points=sobol_data.sobol_angles, max_points=self.sobol_max_points, sigma_max=sigma_max, c=self.pcs_const, full_in_ref_frame=self.full_in_ref_frame, r_pivot_atom=self.r_pivot_atom, r_pivot_atom_rev=self.r_pivot_atom_rev, r_ln_pivot=self.r_ln_pivot, A=self.A_3D, R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=sobol_data.Ri_prime, pcs_theta=self.pcs_theta, pcs_theta_err=self.pcs_theta_err, missing_pcs=self.missing_pcs)
1858
1859
1860 for align_index in range(self.num_align):
1861 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1862
1863
1864 return chi2_sum
1865
1866
1868 """SciPy quadratic integration target function for rotor model.
1869
1870 This function optimises the isotropic cone model parameters using the RDC and PCS base data. Scipy quadratic integration is used for the PCS.
1871
1872
1873 @param params: The vector of parameter values. These are the tensor rotation angles {alpha, beta, gamma, theta, phi, sigma_max}.
1874 @type params: list of float
1875 @return: The chi-squared or SSE value.
1876 @rtype: float
1877 """
1878
1879
1880 if self.scaling_flag:
1881 params = dot(params, self.scaling_matrix)
1882
1883
1884 if self.pivot_opt:
1885 pivot = outer(self.spin_ones_struct, params[:3])
1886 self._translation_vector = params[3:6]
1887 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_alpha, sigma_max = params[6:]
1888 else:
1889 pivot = self.pivot
1890 self._translation_vector = params[:3]
1891 ave_pos_alpha, ave_pos_beta, ave_pos_gamma, axis_alpha, sigma_max = params[3:]
1892
1893
1894 self.cone_axis = create_rotor_axis_alpha(alpha=axis_alpha, pivot=pivot[0], point=self.com)
1895
1896
1897 two_vect_to_R(self.z_axis, self.cone_axis, self.R_eigen)
1898
1899
1900 Rx2_eigen = kron_prod(self.R_eigen, self.R_eigen)
1901
1902
1903 frame_order_2nd = compile_2nd_matrix_rotor(self.frame_order_2nd, Rx2_eigen, sigma_max)
1904
1905
1906 self.reduce_and_rot(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, frame_order_2nd)
1907
1908
1909 RT_eigen = transpose(self.R_eigen)
1910 RT_ave = transpose(self.R_ave)
1911
1912
1913 if self.pcs_flag:
1914 self.calc_vectors(pivot=pivot, R_ave=self.R_ave, RT_ave=RT_ave)
1915
1916
1917 chi2_sum = 0.0
1918
1919
1920 if self.rdc_flag:
1921
1922 for align_index in range(self.num_align):
1923
1924 for j in range(self.num_interatom):
1925
1926 if not self.missing_rdc[align_index, j]:
1927 self.rdc_theta[align_index, j] = rdc_tensor(self.dip_const[j], self.rdc_vect[j], self.A_3D_bc[align_index])
1928
1929
1930 chi2_sum = chi2_sum + chi2(self.rdc[align_index], self.rdc_theta[align_index], self.rdc_error[align_index])
1931
1932
1933 if self.pcs_flag:
1934
1935 for align_index in range(self.num_align):
1936
1937 for j in range(self.num_spins):
1938
1939 if not self.missing_pcs[align_index, j]:
1940
1941 if self.full_in_ref_frame[align_index]:
1942 r_pivot_atom = self.r_pivot_atom[j]
1943 else:
1944 r_pivot_atom = self.r_pivot_atom_rev[j]
1945
1946
1947 self.pcs_theta[align_index, j] = pcs_numeric_quad_int_rotor(sigma_max=sigma_max, c=self.pcs_const[align_index, j], r_pivot_atom=r_pivot_atom, r_ln_pivot=self.r_ln_pivot[0], A=self.A_3D[align_index], R_eigen=self.R_eigen, RT_eigen=RT_eigen, Ri_prime=self.Ri_prime)
1948
1949
1950 chi2_sum = chi2_sum + chi2(self.pcs[align_index], self.pcs_theta[align_index], self.pcs_error[align_index])
1951
1952
1953 return chi2_sum
1954
1955
1956 - def calc_vectors(self, pivot=None, pivot2=None, R_ave=None, RT_ave=None):
1957 """Calculate the pivot to atom and lanthanide to pivot vectors for the target functions.
1958
1959 @keyword pivot: The pivot point.
1960 @type pivot: numpy rank-1, 3D array
1961 @keyword pivot2: The 2nd pivot point.
1962 @type pivot2: numpy rank-1, 3D array
1963 @keyword R_ave: The rotation matrix for rotating from the reference frame to the average position.
1964 @type R_ave: numpy rank-2, 3D array
1965 @keyword RT_ave: The transpose of R_ave.
1966 @type RT_ave: numpy rank-2, 3D array
1967 """
1968
1969
1970 if self.pivot_opt:
1971 subtract(pivot, self.paramag_centre, self.r_ln_pivot)
1972 if pivot2 is not None:
1973 subtract(pivot2, self.paramag_centre, self.r_ln_pivot)
1974
1975
1976 vect = self.atomic_pos - self.ave_pos_pivot
1977
1978
1979 self.r_pivot_atom[:] = dot(vect, RT_ave)
1980 add(self.r_pivot_atom, self.ave_pos_pivot, self.r_pivot_atom)
1981 add(self.r_pivot_atom, self._translation_vector, self.r_pivot_atom)
1982 subtract(self.r_pivot_atom, pivot, self.r_pivot_atom)
1983
1984
1985 if min(self.full_in_ref_frame) == 0:
1986 self.r_pivot_atom_rev[:] = dot(vect, R_ave)
1987 add(self.r_pivot_atom_rev, self.ave_pos_pivot, self.r_pivot_atom_rev)
1988 add(self.r_pivot_atom_rev, self._translation_vector, self.r_pivot_atom_rev)
1989 subtract(self.r_pivot_atom_rev, pivot, self.r_pivot_atom_rev)
1990
1991
1992 if pivot2 is not None:
1993 self.r_inter_pivot = pivot - pivot2
1994
1995
1997 """Create the Sobol' quasi-random data for numerical integration.
1998
1999 This uses the external sobol_lib module to create the data. The algorithm is that modified by Antonov and Saleev.
2000
2001
2002 @keyword dims: The list of parameters.
2003 @type dims: list of str
2004 """
2005
2006
2007 if self.quad_int:
2008 return
2009
2010
2011 m = len(dims)
2012
2013
2014 total_num = int(self.sobol_max_points * self.sobol_oversample * 10**m)
2015
2016
2017 if total_num == sobol_data.total_num and self.model == sobol_data.model:
2018 return
2019
2020
2021 print("Generating the torsion-tilt angle sampling via the Sobol' sequence for numerical PCS integration.")
2022
2023
2024 sobol_data.model = self.model
2025 sobol_data.total_num = total_num
2026 sobol_data.sobol_angles = zeros((m, total_num), float32)
2027 sobol_data.Ri_prime = zeros((total_num, 3, 3), float32)
2028 sobol_data.Ri2_prime = zeros((total_num, 3, 3), float32)
2029
2030
2031 points = i4_sobol_generate(m, total_num, 1000)
2032
2033
2034 for i in range(total_num):
2035
2036 theta = None
2037 phi = None
2038 sigma = None
2039 for j in range(m):
2040
2041 if dims[j] in ['theta']:
2042 theta = acos(2.0*points[j, i] - 1.0)
2043 sobol_data.sobol_angles[j, i] = theta
2044
2045
2046 if dims[j] in ['phi']:
2047 phi = 2.0 * pi * points[j, i]
2048 sobol_data.sobol_angles[j, i] = phi
2049
2050
2051 if dims[j] in ['sigma']:
2052 sigma = 2.0 * pi * (points[j, i] - 0.5)
2053 sobol_data.sobol_angles[j, i] = sigma
2054
2055
2056 if dims[j] in ['sigma2']:
2057 sigma2 = 2.0 * pi * (points[j, i] - 0.5)
2058 sobol_data.sobol_angles[j, i] = sigma2
2059
2060
2061 if 'sigma2' in dims:
2062
2063 c_sigma = cos(sigma)
2064 s_sigma = sin(sigma)
2065 sobol_data.Ri_prime[i, 0, 0] = c_sigma
2066 sobol_data.Ri_prime[i, 0, 2] = s_sigma
2067 sobol_data.Ri_prime[i, 1, 1] = 1.0
2068 sobol_data.Ri_prime[i, 2, 0] = -s_sigma
2069 sobol_data.Ri_prime[i, 2, 2] = c_sigma
2070
2071
2072 c_sigma2 = cos(sigma2)
2073 s_sigma2 = sin(sigma2)
2074 sobol_data.Ri2_prime[i, 0, 0] = 1.0
2075 sobol_data.Ri2_prime[i, 1, 1] = c_sigma2
2076 sobol_data.Ri2_prime[i, 1, 2] = -s_sigma2
2077 sobol_data.Ri2_prime[i, 2, 1] = s_sigma2
2078 sobol_data.Ri2_prime[i, 2, 2] = c_sigma2
2079
2080
2081 elif theta != None and phi != None and sigma != None:
2082 tilt_torsion_to_R(phi, theta, sigma, sobol_data.Ri_prime[i])
2083
2084
2085 elif sigma == None:
2086 c_theta = cos(theta)
2087 s_theta = sin(theta)
2088 c_phi = cos(phi)
2089 s_phi = sin(phi)
2090 c_phi_c_theta = c_phi * c_theta
2091 s_phi_c_theta = s_phi * c_theta
2092 sobol_data.Ri_prime[i, 0, 0] = c_phi_c_theta*c_phi + s_phi**2
2093 sobol_data.Ri_prime[i, 0, 1] = c_phi_c_theta*s_phi - c_phi*s_phi
2094 sobol_data.Ri_prime[i, 0, 2] = c_phi*s_theta
2095 sobol_data.Ri_prime[i, 1, 0] = s_phi_c_theta*c_phi - c_phi*s_phi
2096 sobol_data.Ri_prime[i, 1, 1] = s_phi_c_theta*s_phi + c_phi**2
2097 sobol_data.Ri_prime[i, 1, 2] = s_phi*s_theta
2098 sobol_data.Ri_prime[i, 2, 0] = -s_theta*c_phi
2099 sobol_data.Ri_prime[i, 2, 1] = -s_theta*s_phi
2100 sobol_data.Ri_prime[i, 2, 2] = c_theta
2101
2102
2103 else:
2104 c_sigma = cos(sigma)
2105 s_sigma = sin(sigma)
2106 sobol_data.Ri_prime[i, 0, 0] = c_sigma
2107 sobol_data.Ri_prime[i, 0, 1] = -s_sigma
2108 sobol_data.Ri_prime[i, 1, 0] = s_sigma
2109 sobol_data.Ri_prime[i, 1, 1] = c_sigma
2110 sobol_data.Ri_prime[i, 2, 2] = 1.0
2111
2112
2113 print(" Oversampled to %s points." % total_num)
2114
2115
2116 - def reduce_and_rot(self, ave_pos_alpha=None, ave_pos_beta=None, ave_pos_gamma=None, daeg=None):
2117 """Reduce and rotate the alignments tensors using the frame order matrix and Euler angles.
2118
2119 @keyword ave_pos_alpha: The alpha Euler angle describing the average domain position, the tensor rotation.
2120 @type ave_pos_alpha: float
2121 @keyword ave_pos_beta: The beta Euler angle describing the average domain position, the tensor rotation.
2122 @type ave_pos_beta: float
2123 @keyword ave_pos_gamma: The gamma Euler angle describing the average domain position, the tensor rotation.
2124 @type ave_pos_gamma: float
2125 @keyword daeg: The 2nd degree frame order matrix.
2126 @type daeg: rank-2, 9D array
2127 """
2128
2129
2130 euler_to_R_zyz(ave_pos_alpha, ave_pos_beta, ave_pos_gamma, self.R_ave)
2131
2132
2133 for align_index in range(self.num_tensors):
2134
2135 index1 = align_index*5
2136 index2 = align_index*5+5
2137
2138
2139 if daeg is not None:
2140
2141 reduce_alignment_tensor(daeg, self.full_tensors[index1:index2], self.A_5D_bc[index1:index2])
2142
2143
2144 to_tensor(self.tensor_3D, self.A_5D_bc[index1:index2])
2145
2146
2147 else:
2148
2149 to_tensor(self.tensor_3D, self.full_tensors[index1:index2])
2150
2151
2152 if self.full_in_ref_frame[align_index]:
2153 self.A_3D_bc[align_index] = dot(transpose(self.R_ave), dot(self.tensor_3D, self.R_ave))
2154
2155
2156 else:
2157 self.A_3D_bc[align_index] = dot(self.R_ave, dot(self.tensor_3D, transpose(self.R_ave)))
2158
2159
2160 to_5D(self.A_5D_bc[index1:index2], self.A_3D_bc[align_index])
2161
2162
2163
2165 """Temporary storage of the Sobol' data for speed."""
2166
2168 """Set up the object."""
2169
2170
2171 self.model = None
2172 self.Ri_prime = None
2173 self.Ri2_prime = None
2174 self.sobol_angles = None
2175 self.total_num = None
2176
2177
2178
2179 sobol_data = Sobol_data()
2180