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 pseudo-ellipse frame order model."""
24
25
26 from math import cos, pi, sin, sqrt
27 from numpy import divide, dot, eye, float64, multiply, sinc, swapaxes, tensordot
28 from numpy import cos as np_cos
29 from numpy import sin as np_sin
30 from numpy import sqrt as np_sqrt
31 try:
32 from scipy.integrate import quad, tplquad
33 except ImportError:
34 pass
35
36
37 from lib.geometry.pec import pec
38 from lib.frame_order.matrix_ops import pcs_pivot_motion_full_qr_int, pcs_pivot_motion_full_quad_int, rotate_daeg
39
40
42 """Generate the 1st degree Frame Order matrix for the pseudo-ellipse.
43
44 @param matrix: The Frame Order matrix, 1st degree to be populated.
45 @type matrix: numpy 3D, rank-2 array
46 @param R_eigen: The eigenframe rotation matrix.
47 @type R_eigen: numpy 3D, rank-2 array
48 @param theta_x: The cone opening angle along x.
49 @type theta_x: float
50 @param theta_y: The cone opening angle along y.
51 @type theta_y: float
52 @param sigma_max: The maximum torsion angle.
53 @type sigma_max: float
54 """
55
56
57 fact = 2.0 * pec(theta_x, theta_y)
58
59
60 if fact == 0.0:
61 fact = 1e100
62 else:
63 fact = 1.0 / fact
64
65
66 sinc_smax = sinc(sigma_max/pi)
67
68
69 matrix[0, 0] = fact * sinc_smax * (2.0*pi + quad(part_int_daeg1_pseudo_ellipse_00, -pi, pi, args=(theta_x, theta_y), full_output=1)[0])
70 matrix[1, 1] = fact * sinc_smax * (2.0*pi + quad(part_int_daeg1_pseudo_ellipse_11, -pi, pi, args=(theta_x, theta_y), full_output=1)[0])
71 matrix[2, 2] = fact * quad(part_int_daeg1_pseudo_ellipse_22, -pi, pi, args=(theta_x, theta_y), full_output=1)[0]
72
73
74 return rotate_daeg(matrix, R_eigen)
75
76
78 """Generate the 2nd degree Frame Order matrix for the pseudo-ellipse.
79
80 @param matrix: The Frame Order matrix, 2nd degree to be populated.
81 @type matrix: numpy 9D, rank-2 array
82 @param Rx2_eigen: The Kronecker product of the eigenframe rotation matrix with itself.
83 @type Rx2_eigen: numpy 9D, rank-2 array
84 @param theta_x: The cone opening angle along x.
85 @type theta_x: float
86 @param theta_y: The cone opening angle along y.
87 @type theta_y: float
88 @param sigma_max: The maximum torsion angle.
89 @type sigma_max: float
90 """
91
92
93 if theta_x == 0.0 and sigma_max == 0.0:
94
95 matrix[:] = 0.0
96 for i in range(len(matrix)):
97 matrix[i, i] = 1.0
98
99
100 return rotate_daeg(matrix, Rx2_eigen)
101
102
103 fact = 12.0 * pec(theta_x, theta_y)
104
105
106 if fact == 0.0:
107 fact = 1e100
108 else:
109 fact = 1.0 / fact
110
111
112 sinc_smax = sinc(sigma_max/pi)
113 sinc_2smax = sinc(2.0*sigma_max/pi)
114
115
116 matrix[0, 0] = fact * (4.0*pi*(sinc_2smax + 2.0) + quad(part_int_daeg2_pseudo_ellipse_00, -pi, pi, args=(theta_x, theta_y, sinc_2smax), full_output=1)[0])
117 matrix[1, 1] = fact * (4.0*pi*sinc_2smax + quad(part_int_daeg2_pseudo_ellipse_11, -pi, pi, args=(theta_x, theta_y, sinc_2smax), full_output=1)[0])
118 matrix[2, 2] = fact * 2.0*sinc_smax * (5.0*pi - quad(part_int_daeg2_pseudo_ellipse_22, -pi, pi, args=(theta_x, theta_y), full_output=1)[0])
119 matrix[3, 3] = matrix[1, 1]
120 matrix[4, 4] = fact * (4.0*pi*(sinc_2smax + 2.0) + quad(part_int_daeg2_pseudo_ellipse_44, -pi, pi, args=(theta_x, theta_y, sinc_2smax), full_output=1)[0])
121 matrix[5, 5] = fact * 2.0*sinc_smax * (5.0*pi - quad(part_int_daeg2_pseudo_ellipse_55, -pi, pi, args=(theta_x, theta_y), full_output=1)[0])
122 matrix[6, 6] = matrix[2, 2]
123 matrix[7, 7] = matrix[5, 5]
124 matrix[8, 8] = 4.0 * fact * (2.0*pi - quad(part_int_daeg2_pseudo_ellipse_88, -pi, pi, args=(theta_x, theta_y), full_output=1)[0])
125
126
127 matrix[0, 4] = fact * (4.0*pi*(2.0 - sinc_2smax) + quad(part_int_daeg2_pseudo_ellipse_04, -pi, pi, args=(theta_x, theta_y, sinc_2smax), full_output=1)[0])
128 matrix[4, 0] = fact * (4.0*pi*(2.0 - sinc_2smax) + quad(part_int_daeg2_pseudo_ellipse_40, -pi, pi, args=(theta_x, theta_y, sinc_2smax), full_output=1)[0])
129 matrix[0, 8] = 4.0 * fact * (2.0*pi - quad(part_int_daeg2_pseudo_ellipse_08, -pi, pi, args=(theta_x, theta_y), full_output=1)[0])
130 matrix[8, 0] = fact * (8.0*pi + quad(part_int_daeg2_pseudo_ellipse_80, -pi, pi, args=(theta_x, theta_y, sinc_2smax), full_output=1)[0])
131 matrix[4, 8] = 4.0 * fact * (2.0*pi - quad(part_int_daeg2_pseudo_ellipse_48, -pi, pi, args=(theta_x, theta_y), full_output=1)[0])
132 matrix[8, 4] = fact * (8.0*pi - quad(part_int_daeg2_pseudo_ellipse_84, -pi, pi, args=(theta_x, theta_y, sinc_2smax), full_output=1)[0])
133
134
135 matrix[1, 3] = matrix[3, 1] = fact * (4.0*pi*sinc_2smax + quad(part_int_daeg2_pseudo_ellipse_13, -pi, pi, args=(theta_x, theta_y, sinc_2smax), full_output=1)[0])
136 matrix[2, 6] = matrix[6, 2] = -fact * 4.0 * sinc_smax * (2.0*pi + quad(part_int_daeg2_pseudo_ellipse_26, -pi, pi, args=(theta_x, theta_y), full_output=1)[0])
137 matrix[5, 7] = matrix[7, 5] = -fact * 4.0 * sinc_smax * (2.0*pi + quad(part_int_daeg2_pseudo_ellipse_57, -pi, pi, args=(theta_x, theta_y), full_output=1)[0])
138
139
140 return rotate_daeg(matrix, Rx2_eigen)
141
142
144 """The theta-sigma partial integral of the 1st degree Frame Order matrix element xx for the pseudo-ellipse.
145
146 @param phi: The azimuthal tilt-torsion angle.
147 @type phi: float
148 @param x: The cone opening angle along x.
149 @type x: float
150 @param y: The cone opening angle along y.
151 @type y: float
152 @return: The theta-sigma partial integral.
153 @rtype: float
154 """
155
156
157 tmax = tmax_pseudo_ellipse(phi, x, y)
158
159
160 return cos(phi)**2 * sin(tmax)**2 - 2.0 * sin(phi)**2 * cos(tmax)
161
162
164 """The theta-sigma partial integral of the 1st degree Frame Order matrix element yy for the pseudo-ellipse.
165
166 @param phi: The azimuthal tilt-torsion angle.
167 @type phi: float
168 @param x: The cone opening angle along x.
169 @type x: float
170 @param y: The cone opening angle along y.
171 @type y: float
172 @return: The theta-sigma partial integral.
173 @rtype: float
174 """
175
176
177 tmax = tmax_pseudo_ellipse(phi, x, y)
178
179
180 return sin(phi)**2 * sin(tmax)**2 - 2.0 * cos(phi)**2 * cos(tmax)
181
182
184 """The theta-sigma partial integral of the 1st degree Frame Order matrix element zz for the pseudo-ellipse.
185
186 @param phi: The azimuthal tilt-torsion angle.
187 @type phi: float
188 @param x: The cone opening angle along x.
189 @type x: float
190 @param y: The cone opening angle along y.
191 @type y: float
192 @return: The theta-sigma partial integral.
193 @rtype: float
194 """
195
196
197 tmax = tmax_pseudo_ellipse(phi, x, y)
198
199
200 return sin(tmax)**2
201
202
204 """The theta-sigma partial integral of the 2nd degree Frame Order matrix element 11 for the pseudo-ellipse.
205
206 @param phi: The azimuthal tilt-torsion angle.
207 @type phi: float
208 @param x: The cone opening angle along x.
209 @type x: float
210 @param y: The cone opening angle along y.
211 @type y: float
212 @param sinc_2smax: The pre-calculated value of sinc(2*sigma_max).
213 @type sinc_2smax: float
214 @return: The theta-sigma partial integral.
215 @rtype: float
216 """
217
218
219 tmax = tmax_pseudo_ellipse(phi, x, y)
220
221
222 cos_tmax = cos(tmax)
223 sin_tmax2 = sin(tmax)**2
224 cos_phi2 = cos(phi)**2
225
226
227 a = sinc_2smax * (2.0 * sin_tmax2 * cos_phi2 * ((2.0*cos_phi2 - 1.0)*cos_tmax - 6.0*(cos_phi2 - 1.0)) - 2.0*cos_tmax * (2.0*cos_phi2*(4.0*cos_phi2 - 5.0) + 3.0))
228 b = 2.0*cos_phi2*cos_tmax*(sin_tmax2 + 2.0) - 6.0*cos_tmax
229
230
231 return a + b
232
233
235 """The theta-sigma partial integral of the 2nd degree Frame Order matrix element 22 for the pseudo-ellipse.
236
237 @param phi: The azimuthal tilt-torsion angle.
238 @type phi: float
239 @param x: The cone opening angle along x.
240 @type x: float
241 @param y: The cone opening angle along y.
242 @type y: float
243 @param sinc_2smax: The pre-calculated value of sinc(2*sigma_max).
244 @type sinc_2smax: float
245 @return: The theta-sigma partial integral.
246 @rtype: float
247 """
248
249
250 tmax = tmax_pseudo_ellipse(phi, x, y)
251
252
253 cos_tmax = cos(tmax)
254 sin_tmax2 = sin(tmax)**2
255 cos_phi2 = cos(phi)**2
256 sin_phi2 = sin(phi)**2
257
258
259 a = sinc_2smax * (2.0 * sin_tmax2 * cos_phi2 * ((2.0*sin_phi2 - 1.0)*cos_tmax - 6.0*sin_phi2) + 2.0*cos_tmax * (2.0*cos_phi2*(4.0*cos_phi2 - 5.0) + 3.0))
260 b = 2.0*cos_phi2*cos_tmax*(sin_tmax2 + 2.0) - 6.0*cos_tmax
261
262
263 return a + b
264
265
267 """The theta-sigma partial integral of the 2nd degree Frame Order matrix element 33 for the pseudo-ellipse.
268
269 @param phi: The azimuthal tilt-torsion angle.
270 @type phi: float
271 @param x: The cone opening angle along x.
272 @type x: float
273 @param y: The cone opening angle along y.
274 @type y: float
275 @return: The theta-sigma partial integral.
276 @rtype: float
277 """
278
279
280 tmax = tmax_pseudo_ellipse(phi, x, y)
281
282
283 return cos(tmax) * cos(phi)**2 * (sin(tmax)**2 + 2.0)
284
285
287 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
288
289 @param phi: The azimuthal tilt-torsion angle.
290 @type phi: float
291 @param x: The cone opening angle along x.
292 @type x: float
293 @param y: The cone opening angle along y.
294 @type y: float
295 @param sinc_2smax: The pre-calculated value of sinc(2*sigma_max).
296 @type sinc_2smax: float
297 @return: The theta-sigma partial integral.
298 @rtype: float
299 """
300
301
302 tmax = tmax_pseudo_ellipse(phi, x, y)
303
304
305 cos_tmax = cos(tmax)
306 sin_tmax2 = sin(tmax)**2
307 cos_phi2 = cos(phi)**2
308 sin_phi2 = sin(phi)**2
309 cos_sin_phi2 = cos_phi2 * sin_phi2
310
311
312 a = sinc_2smax * ((4.0*cos_sin_phi2*(cos_tmax - 3.0) + 3.0)*sin_tmax2 - 16.0*cos_sin_phi2*cos_tmax) + 3.0*sin_tmax2
313
314
315 return a
316
317
319 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
320
321 @param phi: The azimuthal tilt-torsion angle.
322 @type phi: float
323 @param x: The cone opening angle along x.
324 @type x: float
325 @param y: The cone opening angle along y.
326 @type y: float
327 @param sinc_2smax: The pre-calculated value of sinc(2*sigma_max).
328 @type sinc_2smax: float
329 @return: The theta-sigma partial integral.
330 @rtype: float
331 """
332
333
334 tmax = tmax_pseudo_ellipse(phi, x, y)
335
336
337 cos_tmax = cos(tmax)
338 sin_tmax2 = sin(tmax)**2
339 cos_sin_phi2 = cos(phi)**2 * sin(phi)**2
340
341
342 return sinc_2smax * (sin_tmax2 * (4.0*cos_sin_phi2*cos_tmax - 12.0*cos_sin_phi2 + 3) - 16.0*cos_sin_phi2*cos_tmax) - 3.0*sin_tmax2
343
344
346 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
347
348 @param phi: The azimuthal tilt-torsion angle.
349 @type phi: float
350 @param x: The cone opening angle along x.
351 @type x: float
352 @param y: The cone opening angle along y.
353 @type y: float
354 @return: The theta-sigma partial integral.
355 @rtype: float
356 """
357
358
359 tmax = tmax_pseudo_ellipse(phi, x, y)
360
361
362 cos_tmax = cos(tmax)
363 cos_phi2 = cos(phi)**2
364 sin_phi2 = sin(phi)**2
365
366
367 a = 2.0*cos_phi2*cos_tmax**3 + 3.0*sin_phi2*cos_tmax**2
368
369
370 return a
371
372
374 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
375
376 @param phi: The azimuthal tilt-torsion angle.
377 @type phi: float
378 @param x: The cone opening angle along x.
379 @type x: float
380 @param y: The cone opening angle along y.
381 @type y: float
382 @return: The theta-sigma partial integral.
383 @rtype: float
384 """
385
386
387 tmax = tmax_pseudo_ellipse(phi, x, y)
388
389
390 cos_tmax = cos(tmax)
391
392
393 return cos(phi)**2 * (cos_tmax**3 - 3.0*cos_tmax)
394
395
397 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
398
399 @param phi: The azimuthal tilt-torsion angle.
400 @type phi: float
401 @param x: The cone opening angle along x.
402 @type x: float
403 @param y: The cone opening angle along y.
404 @type y: float
405 @param sinc_2smax: The pre-calculated value of sinc(2*sigma_max).
406 @type sinc_2smax: float
407 @return: The theta-sigma partial integral.
408 @rtype: float
409 """
410
411
412 tmax = tmax_pseudo_ellipse(phi, x, y)
413
414
415 cos_tmax = cos(tmax)
416 sin_tmax2 = sin(tmax)**2
417 cos_phi2 = cos(phi)**2
418 sin_phi2 = sin(phi)**2
419
420
421 a = sinc_2smax * (2.0 * sin_tmax2 * sin_phi2 * ((2.0*cos_phi2 - 1.0)*cos_tmax - 6.0*cos_phi2) + 2.0*cos_tmax * (2.0*sin_phi2*(4.0*sin_phi2 - 5.0) + 3.0))
422 b = 2.0*sin_phi2*cos_tmax*(sin_tmax2 + 2.0) - 6.0*cos_tmax
423
424
425 return a + b
426
427
429 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
430
431 @param phi: The azimuthal tilt-torsion angle.
432 @type phi: float
433 @param x: The cone opening angle along x.
434 @type x: float
435 @param y: The cone opening angle along y.
436 @type y: float
437 @param sinc_2smax: The pre-calculated value of sinc(2*sigma_max).
438 @type sinc_2smax: float
439 @return: The theta-sigma partial integral.
440 @rtype: float
441 """
442
443
444 tmax = tmax_pseudo_ellipse(phi, x, y)
445
446
447 cos_tmax = cos(tmax)
448 sin_tmax2 = sin(tmax)**2
449 cos_phi2 = cos(phi)**2
450 sin_phi2 = sin(phi)**2
451
452
453 a = sinc_2smax * (2.0 * sin_tmax2 * sin_phi2 * ((2.0*sin_phi2 - 1.0)*cos_tmax + 6.0*cos_phi2) - 2.0*cos_tmax * (2.0*sin_phi2*(4.0*sin_phi2 - 5.0) + 3.0))
454 b = 2.0*sin_phi2*cos_tmax*(sin_tmax2 + 2.0) - 6.0*cos_tmax
455
456
457 return a + b
458
459
461 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
462
463 @param phi: The azimuthal tilt-torsion angle.
464 @type phi: float
465 @param x: The cone opening angle along x.
466 @type x: float
467 @param y: The cone opening angle along y.
468 @type y: float
469 @return: The theta-sigma partial integral.
470 @rtype: float
471 """
472
473
474 tmax = tmax_pseudo_ellipse(phi, x, y)
475
476
477 return cos(tmax) * sin(phi)**2 * (sin(tmax)**2 + 2.0)
478
479
481 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
482
483 @param phi: The azimuthal tilt-torsion angle.
484 @type phi: float
485 @param x: The cone opening angle along x.
486 @type x: float
487 @param y: The cone opening angle along y.
488 @type y: float
489 @return: The theta-sigma partial integral.
490 @rtype: float
491 """
492
493
494 tmax = tmax_pseudo_ellipse(phi, x, y)
495
496
497 cos_tmax = cos(tmax)
498 sin_phi2 = sin(phi)**2
499 cos_phi2 = cos(phi)**2
500
501
502 return 2.0*sin_phi2*cos_tmax**3 + 3.0*cos_phi2*cos_tmax**2
503
504
506 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
507
508 @param phi: The azimuthal tilt-torsion angle.
509 @type phi: float
510 @param x: The cone opening angle along x.
511 @type x: float
512 @param y: The cone opening angle along y.
513 @type y: float
514 @return: The theta-sigma partial integral.
515 @rtype: float
516 """
517
518
519 tmax = tmax_pseudo_ellipse(phi, x, y)
520
521
522 cos_tmax = cos(tmax)
523
524
525 return sin(phi)**2 * (cos_tmax**3 - 3.0*cos_tmax)
526
527
529 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
530
531 @param phi: The azimuthal tilt-torsion angle.
532 @type phi: float
533 @param x: The cone opening angle along x.
534 @type x: float
535 @param y: The cone opening angle along y.
536 @type y: float
537 @param sinc_2smax: The pre-calculated value of sinc(2*sigma_max).
538 @type sinc_2smax: float
539 @return: The theta-sigma partial integral.
540 @rtype: float
541 """
542
543
544 tmax = tmax_pseudo_ellipse(phi, x, y)
545
546
547 cos_tmax = cos(tmax)
548 sin_tmax2 = sin(tmax)**2
549 cos_phi2 = cos(phi)**2
550
551
552 return sinc_2smax * (2.0*(1.0 - 2.0*cos_phi2)*cos_tmax*(sin_tmax2 + 2.0)) + 2.0*cos_tmax**3 - 6.0*cos_tmax
553
554
556 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
557
558 @param phi: The azimuthal tilt-torsion angle.
559 @type phi: float
560 @param x: The cone opening angle along x.
561 @type x: float
562 @param y: The cone opening angle along y.
563 @type y: float
564 @param sinc_2smax: The pre-calculated value of sinc(2*sigma_max).
565 @type sinc_2smax: float
566 @return: The theta-sigma partial integral.
567 @rtype: float
568 """
569
570
571 tmax = tmax_pseudo_ellipse(phi, x, y)
572
573
574 cos_tmax = cos(tmax)
575 sin_tmax2 = sin(tmax)**2
576 cos_phi2 = cos(phi)**2
577
578
579 return sinc_2smax * (2.0*(1.0 - 2.0*cos_phi2)*cos_tmax*(sin_tmax2 + 2.0)) - 2.0*cos_tmax**3 + 6.0*cos_tmax
580
581
583 """The theta-sigma partial integral of the 2nd degree Frame Order matrix for the pseudo-ellipse.
584
585 @param phi: The azimuthal tilt-torsion angle.
586 @type phi: float
587 @param x: The cone opening angle along x.
588 @type x: float
589 @param y: The cone opening angle along y.
590 @type y: float
591 @return: The theta-sigma partial integral.
592 @rtype: float
593 """
594
595
596 tmax = tmax_pseudo_ellipse(phi, x, y)
597
598
599 return cos(tmax)**3
600
601
602 -def pcs_numeric_qr_int_pseudo_ellipse(points=None, max_points=None, theta_x=None, theta_y=None, sigma_max=None, c=None, full_in_ref_frame=None, r_pivot_atom=None, r_pivot_atom_rev=None, r_ln_pivot=None, A=None, R_eigen=None, RT_eigen=None, Ri_prime=None, pcs_theta=None, pcs_theta_err=None, missing_pcs=None):
603 """Determine the averaged PCS value via numerical integration.
604
605 @keyword points: The Sobol points in the torsion-tilt angle space.
606 @type points: numpy rank-2, 3D array
607 @keyword max_points: The maximum number of Sobol' points to use. Once this number is reached, the loop over the Sobol' torsion-tilt angles is terminated.
608 @type max_points: int
609 @keyword theta_x: The x-axis half cone angle.
610 @type theta_x: float
611 @keyword theta_y: The y-axis half cone angle.
612 @type theta_y: float
613 @keyword sigma_max: The maximum torsion angle.
614 @type sigma_max: float
615 @keyword c: The PCS constant (without the interatomic distance and in Angstrom units).
616 @type c: float
617 @keyword full_in_ref_frame: An array of flags specifying if the tensor in the reference frame is the full or reduced tensor.
618 @type full_in_ref_frame: numpy rank-1 array
619 @keyword r_pivot_atom: The pivot point to atom vector.
620 @type r_pivot_atom: numpy rank-1, 3D array
621 @keyword r_pivot_atom_rev: The reversed pivot point to atom vector.
622 @type r_pivot_atom_rev: numpy rank-2, 3D array
623 @keyword r_ln_pivot: The lanthanide position to pivot point vector.
624 @type r_ln_pivot: numpy rank-1, 3D array
625 @keyword A: The full alignment tensor of the non-moving domain.
626 @type A: numpy rank-2, 3D array
627 @keyword R_eigen: The eigenframe rotation matrix.
628 @type R_eigen: numpy rank-2, 3D array
629 @keyword RT_eigen: The transpose of the eigenframe rotation matrix (for faster calculations).
630 @type RT_eigen: numpy rank-2, 3D array
631 @keyword Ri_prime: The array of pre-calculated rotation matrices for the in-frame pseudo-elliptic cone motion, used to calculate the PCS for each state i in the numerical integration.
632 @type Ri_prime: numpy rank-3, array of 3D arrays
633 @keyword pcs_theta: The storage structure for the back-calculated PCS values.
634 @type pcs_theta: numpy rank-2 array
635 @keyword pcs_theta_err: The storage structure for the back-calculated PCS errors.
636 @type pcs_theta_err: numpy rank-2 array
637 @keyword missing_pcs: A structure used to indicate which PCS values are missing.
638 @type missing_pcs: numpy rank-2 array
639 """
640
641
642 pcs_theta[:] = 0.0
643 pcs_theta_err[:] = 0.0
644
645
646 Ri = dot(R_eigen, tensordot(Ri_prime, RT_eigen, axes=1))
647 Ri = swapaxes(Ri, 0, 1)
648
649
650 theta, phi, sigma = points
651
652
653 theta_max = tmax_pseudo_ellipse_array(phi, theta_x, theta_y)
654
655
656 num = 0
657 for i in range(len(points[0])):
658
659 if num == max_points:
660 break
661
662
663 if abs(sigma[i]) > sigma_max:
664 continue
665
666
667 if theta[i] > theta_y:
668 continue
669
670
671 if theta[i] > theta_max[i]:
672 continue
673
674
675 pcs_pivot_motion_full_qr_int(full_in_ref_frame=full_in_ref_frame, r_pivot_atom=r_pivot_atom, r_pivot_atom_rev=r_pivot_atom_rev, r_ln_pivot=r_ln_pivot, A=A, Ri=Ri[i], pcs_theta=pcs_theta, pcs_theta_err=pcs_theta_err, missing_pcs=missing_pcs)
676
677
678 num += 1
679
680
681 if num == 0:
682
683 Ri_prime = eye(3, dtype=float64)
684 Ri = dot(R_eigen, tensordot(Ri_prime, RT_eigen, axes=1))
685 Ri = swapaxes(Ri, 0, 1)
686
687
688 pcs_pivot_motion_full_qr_int(full_in_ref_frame=full_in_ref_frame, r_pivot_atom=r_pivot_atom, r_pivot_atom_rev=r_pivot_atom_rev, r_ln_pivot=r_ln_pivot, A=A, Ri=Ri, pcs_theta=pcs_theta, pcs_theta_err=pcs_theta_err, missing_pcs=missing_pcs)
689
690
691 multiply(c, pcs_theta, pcs_theta)
692
693
694 else:
695 multiply(c, pcs_theta, pcs_theta)
696 divide(pcs_theta, float(num), pcs_theta)
697
698
699 -def pcs_numeric_quad_int_pseudo_ellipse(theta_x=None, theta_y=None, sigma_max=None, c=None, r_pivot_atom=None, r_ln_pivot=None, A=None, R_eigen=None, RT_eigen=None, Ri_prime=None):
700 """Determine the averaged PCS value via numerical integration.
701
702 @keyword theta_x: The x-axis half cone angle.
703 @type theta_x: float
704 @keyword theta_y: The y-axis half cone angle.
705 @type theta_y: float
706 @keyword sigma_max: The maximum torsion angle.
707 @type sigma_max: float
708 @keyword c: The PCS constant (without the interatomic distance and in Angstrom units).
709 @type c: float
710 @keyword r_pivot_atom: The pivot point to atom vector.
711 @type r_pivot_atom: numpy rank-1, 3D array
712 @keyword r_ln_pivot: The lanthanide position to pivot point vector.
713 @type r_ln_pivot: numpy rank-1, 3D array
714 @keyword A: The full alignment tensor of the non-moving domain.
715 @type A: numpy rank-2, 3D array
716 @keyword R_eigen: The eigenframe rotation matrix.
717 @type R_eigen: numpy rank-2, 3D array
718 @keyword RT_eigen: The transpose of the eigenframe rotation matrix (for faster calculations).
719 @type RT_eigen: numpy rank-2, 3D array
720 @keyword Ri_prime: The empty rotation matrix for the in-frame isotropic cone motion, used to calculate the PCS for each state i in the numerical integration.
721 @type Ri_prime: numpy rank-2, 3D array
722 @return: The averaged PCS value.
723 @rtype: float
724 """
725
726 def pseudo_ellipse(theta, phi):
727 """The pseudo-ellipse wrapper formula."""
728
729 return tmax_pseudo_ellipse(phi, theta_x, theta_y)
730
731
732 result = tplquad(pcs_pivot_motion_full_quad_int, -sigma_max, sigma_max, lambda phi: -pi, lambda phi: pi, lambda theta, phi: 0.0, pseudo_ellipse, args=(r_pivot_atom, r_ln_pivot, A, R_eigen, RT_eigen, Ri_prime))
733
734
735 SA = 2.0 * sigma_max * pec(theta_x, theta_y)
736
737
738 return c * result[0] / SA
739
740
742 """The pseudo-ellipse tilt-torsion polar angle.
743
744 @param phi: The azimuthal tilt-torsion angle.
745 @type phi: float
746 @param theta_x: The cone opening angle along x.
747 @type theta_x: float
748 @param theta_y: The cone opening angle along y.
749 @type theta_y: float
750 @return: The theta max angle for the given phi angle.
751 @rtype: float
752 """
753
754
755 if theta_x == 0.0:
756 return 0.0
757 elif theta_y == 0.0:
758 return 0.0
759
760
761 return theta_x * theta_y / sqrt((cos(phi)*theta_y)**2 + (sin(phi)*theta_x)**2)
762
763
765 """The pseudo-ellipse tilt-torsion polar angle for numpy arrays.
766
767 @param phi: The azimuthal tilt-torsion angle.
768 @type phi: numpy rank-1 float64 array
769 @param theta_x: The cone opening angle along x.
770 @type theta_x: float
771 @param theta_y: The cone opening angle along y.
772 @type theta_y: float
773 @return: The array theta max angles for the given phi angle array.
774 @rtype: numpy rank-1 float64 array
775 """
776
777
778 if theta_x == 0.0:
779 return 0.0 * phi
780 elif theta_y == 0.0:
781 return 0.0 * phi
782
783
784 return theta_x * theta_y / np_sqrt((np_cos(phi)*theta_y)**2 + (np_sin(phi)*theta_x)**2)
785