1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 """The alignment tensor objects of the relax data store."""
26
27
28 from math import pi, sqrt
29 from numpy import eye, float64, zeros
30 from numpy.linalg import det, eig, eigvals
31 from re import search
32
33
34 from data_store.data_classes import Element
35 from lib.float import nan
36 from lib.geometry.rotations import R_to_euler_zyz
37 from lib.errors import RelaxError
38 from lib.xml import fill_object_contents, xml_to_object
39
40
41
42 fact_A2 = sqrt(2.0*pi / 15.0)
43 fact_A1 = sqrt(8.0*pi / 15.0)
44 fact_A0 = sqrt(4.0*pi / 5.0)
45
46
47 -def calc_A(Axx, Ayy, Azz, Axy, Axz, Ayz):
48 """Function for calculating the alignment tensor (in the structural frame).
49
50 @param Axx: The Axx tensor element.
51 @type Axx: float
52 @param Ayy: The Ayy tensor element.
53 @type Ayy: float
54 @param Azz: The Azz tensor element.
55 @type Azz: float
56 @param Axy: The Axy tensor element.
57 @type Axy: float
58 @param Axz: The Axz tensor element.
59 @type Axz: float
60 @param Ayz: The Ayz tensor element.
61 @type Ayz: float
62 @return: The alignment tensor (within the structural frame).
63 @rtype: 3x3 numpy float64 array
64 """
65
66
67 tensor = zeros((3, 3), float64)
68
69
70 tensor[0, 0] = Axx
71 tensor[1, 1] = Ayy
72 tensor[2, 2] = Azz
73
74
75 tensor[0, 1] = tensor[1, 0] = Axy
76 tensor[0, 2] = tensor[2, 0] = Axz
77 tensor[1, 2] = tensor[2, 1] = Ayz
78
79
80 return tensor
81
82
84 """Function for calculating the alignment tensor in the 5D vector notation.
85
86 @param Axx: The Axx tensor element.
87 @type Axx: float
88 @param Ayy: The Ayy tensor element.
89 @type Ayy: float
90 @param Azz: The Azz tensor element.
91 @type Azz: float
92 @param Axy: The Axy tensor element.
93 @type Axy: float
94 @param Axz: The Axz tensor element.
95 @type Axz: float
96 @param Ayz: The Ayz tensor element.
97 @type Ayz: float
98 @return: The alignment 5D tensor (within the structural frame).
99 @rtype: numpy rank-1 5D tensor
100 """
101
102
103 tensor = zeros(5, float64)
104
105
106 tensor[0] = Axx
107 tensor[1] = Ayy
108 tensor[2] = Axy
109 tensor[3] = Axz
110 tensor[4] = Ayz
111
112
113 return tensor
114
115
117 """Calculate the diagonalised alignment tensor.
118
119 The diagonalised alignment tensor is defined as::
120
121 | Axx' 0 0 |
122 tensor = | 0 Ayy' 0 |.
123 | 0 0 Azz'|
124
125 The diagonalised alignment tensor is calculated by eigenvalue decomposition.
126
127
128 @param A: The full alignment tensor.
129 @type A: numpy array ((3, 3), float64)
130 @return: The diagonalised alignment tensor.
131 @rtype: numpy array ((3, 3), float64)
132 """
133
134
135 vals = eigvals(A)
136
137
138 abs_vals = abs(vals).tolist()
139 Axx_index = abs_vals.index(min(abs_vals))
140 Azz_index = abs_vals.index(max(abs_vals))
141 last_index = list(range(3))
142 last_index.pop(max(Axx_index, Azz_index))
143 last_index.pop(min(Axx_index, Azz_index))
144 Ayy_index = last_index[0]
145
146
147 tensor_diag = zeros((3, 3), float64)
148
149
150 tensor_diag[0, 0] = vals[Axx_index]
151 tensor_diag[1, 1] = vals[Ayy_index]
152 tensor_diag[2, 2] = vals[Azz_index]
153
154
155 return tensor_diag
156
157
159 """Calculate the anisotropic parameter Aa.
160
161 This is given by::
162
163 Aa = 3/2Azz = Szz,
164
165 where Azz and Szz are the eigenvalues.
166
167
168 @param A_diag: The full alignment tensor, diagonalised.
169 @type A_diag: numpy array ((3, 3), float64)
170 @return: The Aa parameter
171 @rtype: float
172 """
173
174
175 return 1.5 * A_diag[2, 2]
176
177
179 """Calculate the rhombic parameter Ar.
180
181 This is given by::
182
183 Ar = Axx - Ayy,
184
185 where Axx and Ayy are the eigenvalues.
186
187
188 @param A_diag: The full alignment tensor, diagonalised.
189 @type A_diag: numpy array ((3, 3), float64)
190 @return: The Ar parameter
191 @rtype: float
192 """
193
194
195 return A_diag[0, 0] - A_diag[1, 1]
196
197
199 """Function for calculating the Axx-yy value.
200
201 The equation for calculating the parameter is::
202
203 Axx-yy = Axx - Ayy.
204
205 @param Axx: The Axx component of the alignment tensor.
206 @type Axx: float
207 @param Ayy: The Ayy component of the alignment tensor.
208 @type Ayy: float
209 @return: The Axx-yy component of the alignment tensor.
210 @rtype: float
211 """
212
213
214 return Axx - Ayy
215
216
218 """Function for calculating the Azz value.
219
220 The equation for calculating the parameter is::
221
222 Azz = - Axx - Ayy.
223
224 @param Axx: The Axx component of the alignment tensor.
225 @type Axx: float
226 @param Ayy: The Ayy component of the alignment tensor.
227 @type Ayy: float
228 @return: The Azz component of the alignment tensor.
229 @rtype: float
230 """
231
232
233 return - Axx - Ayy
234
235
237 """Calculate the eigenvalues and eigenvectors of the alignment tensor (A).
238
239 @param A: The full alignment tensor.
240 @type A: numpy array ((3, 3), float64)
241 @return: The eigensystem.
242 @rtype: tuple of numpy array (float64)
243 """
244
245
246 vals = eigvals(A)
247
248
249 abs_vals = abs(vals).tolist()
250 x_index = abs_vals.index(min(abs_vals))
251 z_index = abs_vals.index(max(abs_vals))
252 last_index = list(range(3))
253 last_index.pop(max(x_index, z_index))
254 last_index.pop(min(x_index, z_index))
255 y_index = last_index[0]
256
257
258 return [vals[x_index], vals[y_index], vals[z_index]]
259
260
262 """Calculate the asymmetry parameter eta.
263
264 This is given by::
265
266 eta = (Axx - Ayy) / Azz
267
268 where Aii are the eigenvalues.
269
270
271 @param A_diag: The full alignment tensor, diagonalised.
272 @type A_diag: numpy array ((3, 3), float64)
273 @return: The eta parameter
274 @rtype: float
275 """
276
277
278 if A_diag[2, 2] == 0:
279 return nan
280
281
282 return (A_diag[0, 0] - A_diag[1, 1]) / A_diag[2, 2]
283
284
286 """Calculate the zyz notation Euler angles.
287
288 @param rotation: The rotation matrix.
289 @type rotation: numpy 3D, rank-2 array
290 @return: The Euler angles alpha, beta, and gamma in zyz notation.
291 @rtype: tuple of float
292 """
293
294 return R_to_euler_zyz(rotation)
295
296
297 -def calc_S(Sxx, Syy, Szz, Sxy, Sxz, Syz):
298 """Function for calculating the alignment tensor (in the structural frame).
299
300 @param Sxx: The Sxx tensor element.
301 @type Sxx: float
302 @param Syy: The Syy tensor element.
303 @type Syy: float
304 @param Szz: The Szz tensor element.
305 @type Szz: float
306 @param Sxy: The Sxy tensor element.
307 @type Sxy: float
308 @param Sxz: The Sxz tensor element.
309 @type Sxz: float
310 @param Syz: The Syz tensor element.
311 @type Syz: float
312 @return: The alignment tensor (within the structural frame).
313 @rtype: 3x3 numpy float64 array
314 """
315
316
317 tensor = zeros((3, 3), float64)
318
319
320 tensor[0, 0] = Sxx
321 tensor[1, 1] = Syy
322 tensor[2, 2] = Szz
323
324
325 tensor[0, 1] = tensor[1, 0] = Sxy
326 tensor[0, 2] = tensor[2, 0] = Sxz
327 tensor[1, 2] = tensor[2, 1] = Syz
328
329
330 return tensor
331
332
334 """Function for calculating the alignment tensor in the 5D vector notation.
335
336 @param Sxx: The Sxx tensor element.
337 @type Sxx: float
338 @param Syy: The Syy tensor element.
339 @type Syy: float
340 @param Szz: The Szz tensor element.
341 @type Szz: float
342 @param Sxy: The Sxy tensor element.
343 @type Sxy: float
344 @param Sxz: The Sxz tensor element.
345 @type Sxz: float
346 @param Syz: The Syz tensor element.
347 @type Syz: float
348 @return: The alignment 5D tensor (within the structural frame).
349 @rtype: numpy rank-1 5D tensor
350 """
351
352
353 tensor = zeros(5, float64)
354
355
356 tensor[0] = Sxx
357 tensor[1] = Syy
358 tensor[2] = Sxy
359 tensor[3] = Sxz
360 tensor[4] = Syz
361
362
363 return tensor
364
365
367 """Calculate the diagonalised alignment tensor.
368
369 The diagonalised alignment tensor is defined as::
370
371 | Sxx' 0 0 |
372 tensor = | 0 Syy' 0 |.
373 | 0 0 Szz'|
374
375 The diagonalised alignment tensor is calculated by eigenvalue decomposition.
376
377
378 @param tensor: The full alignment tensor in its eigenframe.
379 @type tensor: numpy array ((3, 3), float64)
380 @return: The diagonalised alignment tensor.
381 @rtype: numpy array ((3, 3), float64)
382 """
383
384
385 vals = eigvals(tensor)
386
387
388 abs_vals = abs(vals).tolist()
389 Sxx_index = abs_vals.index(min(abs_vals))
390 Szz_index = abs_vals.index(max(abs_vals))
391 last_index = list(range(3))
392 last_index.pop(max(Sxx_index, Szz_index))
393 last_index.pop(min(Sxx_index, Szz_index))
394 Syy_index = last_index[0]
395
396
397 tensor_diag = zeros((3, 3), float64)
398
399
400 tensor_diag[0, 0] = vals[Sxx_index]
401 tensor_diag[1, 1] = vals[Syy_index]
402 tensor_diag[2, 2] = vals[Szz_index]
403
404
405 return tensor_diag
406
407
409 r"""Function for calculating the A0 irreducible component of the Saupe order matrix.
410
411 The equation for calculating the parameter is::
412
413 / 4pi \ 1/2
414 A0 = | --- | Szz .
415 \ 5 /
416
417
418 @param Szz: The Szz component of the Saupe order matrix.
419 @type Szz: float
420 @return: The A0 irreducible component of the Saupe order matrix.
421 @rtype: float
422 """
423
424
425 return fact_A0 * Szz
426
427
429 r"""Function for calculating the A1 irreducible component of the Saupe order matrix.
430
431 The equation for calculating the parameter is::
432
433 / 8pi \ 1/2
434 A1 = | --- | (Sxz + iSyz) .
435 \ 15 /
436
437
438 @param Sxz: The Sxz component of the Saupe order matrix.
439 @type Sxz: float
440 @param Syz: The Syz component of the Saupe order matrix.
441 @type Syz: float
442 @return: The A1 irreducible component of the Saupe order matrix.
443 @rtype: float
444 """
445
446
447 return fact_A1 * (Sxz + 1.j*Syz)
448
449
451 r"""Function for calculating the A2 irreducible component of the Saupe order matrix.
452
453 The equation for calculating the parameter is::
454
455 / 2pi \ 1/2
456 A2 = | --- | (Sxx - Syy + 2iSxy) .
457 \ 15 /
458
459
460 @param Sxx: The Sxx component of the Saupe order matrix.
461 @type Sxx: float
462 @param Syy: The Syy component of the Saupe order matrix.
463 @type Syy: float
464 @return: The A2 irreducible component of the Saupe order matrix.
465 @rtype: float
466 """
467
468
469 return fact_A2 * (Sxx - Syy + 2.j*Sxy)
470
471
473 r"""Function for calculating the A-1 irreducible component of the Saupe order matrix.
474
475 The equation for calculating the parameter is::
476
477 / 8pi \ 1/2
478 A-1 = - | --- | (Sxz - iSyz) .
479 \ 15 /
480
481
482 @param Sxz: The Sxz component of the Saupe order matrix.
483 @type Sxz: float
484 @param Syz: The Syz component of the Saupe order matrix.
485 @type Syz: float
486 @return: The A-1 irreducible component of the Saupe order matrix.
487 @rtype: float
488 """
489
490
491 return -fact_A1 * (Sxz - 1.j*Syz)
492
493
495 r"""Function for calculating the A-2 irreducible component of the Saupe order matrix.
496
497 The equation for calculating the parameter is::
498
499 / 2pi \ 1/2
500 A-2 = | --- | (Sxx - Syy - 2iSxy) ,
501 \ 15 /
502
503
504 @param Sxx: The Sxx component of the Saupe order matrix.
505 @type Sxx: float
506 @param Syy: The Syy component of the Saupe order matrix.
507 @type Syy: float
508 @return: The A-2 irreducible component of the Saupe order matrix.
509 @rtype: float
510 """
511
512
513 return fact_A2 * (Sxx - Syy - 2.j*Sxy)
514
515
517 """Function for calculating the Axx value.
518
519 The equation for calculating the parameter is::
520
521 Sxx = 3/2 Axx.
522
523 @param Axx: The Axx component of the alignment tensor.
524 @type Axx: float
525 @rtype: float
526 """
527
528
529 return 3.0/2.0 * Axx
530
531
533 """Function for calculating the Sxx-yy value.
534
535 The equation for calculating the parameter is::
536
537 Sxx-yy = Sxx - Syy.
538
539 @param Sxx: The Sxx component of the Saupe order matrix.
540 @type Sxx: float
541 @param Syy: The Syy component of the Saupe order matrix.
542 @type Syy: float
543 @return: The Sxx-yy component of the Saupe order matrix.
544 @rtype: float
545 """
546
547
548 return Sxx - Syy
549
550
552 """Function for calculating the Axy value.
553
554 The equation for calculating the parameter is::
555
556 Sxy = 3/2 Axy.
557
558 @param Axy: The Axy component of the alignment tensor.
559 @type Axy: float
560 @rtype: float
561 """
562
563
564 return 3.0/2.0 * Axy
565
566
568 """Function for calculating the Axz value.
569
570 The equation for calculating the parameter is::
571
572 Sxz = 3/2 Axz.
573
574 @param Axz: The Axz component of the alignment tensor.
575 @type Axz: float
576 @rtype: float
577 """
578
579
580 return 3.0/2.0 * Axz
581
582
584 """Function for calculating the Ayy value.
585
586 The equation for calculating the parameter is::
587
588 Syy = 3/2 Ayy.
589
590 @param Ayy: The Ayy component of the alignment tensor.
591 @type Ayy: float
592 @rtype: float
593 """
594
595
596 return 3.0/2.0 * Ayy
597
598
600 """Function for calculating the Ayz value.
601
602 The equation for calculating the parameter is::
603
604 Syz = 3/2 Ayz.
605
606 @param Ayz: The Ayz component of the alignment tensor.
607 @type Ayz: float
608 @rtype: float
609 """
610
611
612 return 3.0/2.0 * Ayz
613
614
616 """Function for calculating the Szz value.
617
618 The equation for calculating the parameter is::
619
620 Szz = - Sxx - Syy.
621
622 @param Sxx: The Sxx component of the Saupe order matrix.
623 @type Sxx: float
624 @param Syy: The Syy component of the Saupe order matrix.
625 @type Syy: float
626 @return: The Szz component of the Saupe order matrix.
627 @rtype: float
628 """
629
630
631 return - Sxx - Syy
632
633
634 -def calc_P(Axx, Ayy, Azz, Axy, Axz, Ayz):
635 """Function for calculating the alignment tensor (in the structural frame).
636
637 @param Axx: The Axx tensor element.
638 @type Axx: float
639 @param Ayy: The Ayy tensor element.
640 @type Ayy: float
641 @param Azz: The Azz tensor element.
642 @type Azz: float
643 @param Axy: The Axy tensor element.
644 @type Axy: float
645 @param Axz: The Axz tensor element.
646 @type Axz: float
647 @param Ayz: The Ayz tensor element.
648 @type Ayz: float
649 @return: The alignment tensor (within the structural frame).
650 @rtype: 3x3 numpy float64 array
651 """
652
653
654 tensor = zeros((3, 3), float64)
655
656
657 tensor[0, 0] = Axx
658 tensor[1, 1] = Ayy
659 tensor[2, 2] = Azz
660
661
662 tensor[0, 1] = tensor[1, 0] = Axy
663 tensor[0, 2] = tensor[2, 0] = Axz
664 tensor[1, 2] = tensor[2, 1] = Ayz
665
666
667 tensor = tensor + eye(3)/3.0
668
669
670 return tensor
671
672
674 """Function for calculating the alignment tensor in the 5D vector notation.
675
676 @param Axx: The Axx tensor element.
677 @type Axx: float
678 @param Ayy: The Ayy tensor element.
679 @type Ayy: float
680 @param Azz: The Azz tensor element.
681 @type Azz: float
682 @param Axy: The Axy tensor element.
683 @type Axy: float
684 @param Axz: The Axz tensor element.
685 @type Axz: float
686 @param Ayz: The Ayz tensor element.
687 @type Ayz: float
688 @return: The alignment 5D tensor (within the structural frame).
689 @rtype: numpy rank-1 5D tensor
690 """
691
692
693 tensor = zeros(5, float64)
694
695
696 tensor[0] = Axx + 1.0/3.0
697 tensor[1] = Ayy + 1.0/3.0
698 tensor[2] = Axy
699 tensor[3] = Axz
700 tensor[4] = Ayz
701
702
703 return tensor
704
705
707 """Calculate the diagonalised alignment tensor.
708
709 The diagonalised alignment tensor is defined as::
710
711 | Pxx' 0 0 |
712 tensor = | 0 Pyy' 0 |.
713 | 0 0 Pzz'|
714
715 The diagonalised alignment tensor is calculated by eigenvalue decomposition.
716
717
718 @param tensor: The full alignment tensor in its eigenframe.
719 @type tensor: numpy array ((3, 3), float64)
720 @return: The diagonalised alignment tensor.
721 @rtype: numpy array ((3, 3), float64)
722 """
723
724
725 vals = eigvals(tensor)
726
727
728 abs_vals = abs(vals).tolist()
729 Pxx_index = abs_vals.index(min(abs_vals))
730 Pzz_index = abs_vals.index(max(abs_vals))
731 last_index = list(range(3))
732 last_index.pop(max(Pxx_index, Pzz_index))
733 last_index.pop(min(Pxx_index, Pzz_index))
734 Pyy_index = last_index[0]
735
736
737 tensor_diag = zeros((3, 3), float64)
738
739
740 tensor_diag[0, 0] = vals[Pxx_index]
741 tensor_diag[1, 1] = vals[Pyy_index]
742 tensor_diag[2, 2] = vals[Pzz_index]
743
744
745 tensor = tensor + eye(3)/3.0
746
747
748 return tensor_diag
749
750
752 """Function for calculating the Pxx value.
753
754 The equation for calculating the parameter is::
755
756 Pxx = Axx + 1/3.
757
758 @param Axx: The Axx component of the alignment tensor.
759 @type Axx: float
760 @rtype: float
761 """
762
763
764 return Axx + 1.0/3.0
765
766
768 """Function for calculating the Pxx-yy value.
769
770 The equation for calculating the parameter is::
771
772 Pxx-yy = Pxx - Pyy.
773
774 @param Pxx: The Pxx component of the alignment tensor.
775 @type Pxx: float
776 @param Pyy: The Pyy component of the alignment tensor.
777 @type Pyy: float
778 @return: The Pxx-yy component of the alignment tensor.
779 @rtype: float
780 """
781
782
783 return Pxx - Pyy
784
785
787 """Function for calculating the Pxy value.
788
789 The equation for calculating the parameter is::
790
791 Pxy = Axy.
792
793 @param Axy: The Axy component of the alignment tensor.
794 @type Axy: float
795 @rtype: float
796 """
797
798
799 return Axy
800
801
803 """Function for calculating the Pxz value.
804
805 The equation for calculating the parameter is::
806
807 Pxz = Axz.
808
809 @param Axz: The Axz component of the alignment tensor.
810 @type Axz: float
811 @rtype: float
812 """
813
814
815 return Axz
816
817
819 """Function for calculating the Pyy value.
820
821 The equation for calculating the parameter is::
822
823 Pyy = Ayy + 1/3.
824
825 @param Ayy: The Ayy component of the alignment tensor.
826 @type Ayy: float
827 @rtype: float
828 """
829
830
831 return Ayy + 1.0/3.0
832
833
835 """Function for calculating the Pyz value.
836
837 The equation for calculating the parameter is::
838
839 Pyz = Ayz.
840
841 @param Ayz: The Ayz component of the alignment tensor.
842 @type Ayz: float
843 @rtype: float
844 """
845
846
847 return Ayz
848
849
851 """Function for calculating the Pzz value.
852
853 The equation for calculating the parameter is::
854
855 Pzz = 1 - Pxx - Pyy.
856
857 @param Pxx: The Pxx component of the alignment tensor.
858 @type Pxx: float
859 @param Pyy: The Pyy component of the alignment tensor.
860 @type Pyy: float
861 @return: The Pzz component of the alignment tensor.
862 @rtype: float
863 """
864
865
866 return 1.0 - Pxx - Pyy
867
868
870 """Calculate the rhombicity parameter R.
871
872 This is given by::
873
874 R = Ar / Aa.
875
876
877 @param Aa: The Aa parameter.
878 @type Aa: float
879 @param Ar: The Ar parameter.
880 @type Ar: float
881 @return: The R parameter.
882 @rtype: float
883 """
884
885
886 if Aa == 0:
887 return nan
888
889
890 return Ar / Aa
891
892
894 """Calculate the rotation matrix from the molecular frame to the tensor frame.
895
896 This is defined by::
897
898 | Azz | >= | Ayy | >= | Axx |.
899
900
901 @param A: The full alignment tensor.
902 @type A: numpy array ((3, 3), float64)
903 @return: The array of x, y, and z indices.
904 @rtype: list
905 """
906
907
908 vals, rot = eig(A)
909
910
911 abs_vals = abs(vals).tolist()
912 x_index = abs_vals.index(min(abs_vals))
913 z_index = abs_vals.index(max(abs_vals))
914 last_index = list(range(3))
915 last_index.pop(max(x_index, z_index))
916 last_index.pop(min(x_index, z_index))
917 y_index = last_index[0]
918
919
920 rot_perm = zeros((3, 3), float64)
921
922
923 perm = [x_index, y_index, z_index]
924 for i in range(3):
925 for j in range(3):
926 rot_perm[i, j] = rot[i, perm[j]]
927
928
929 if abs(det(rot_perm) - 1.0) > 1e-7:
930 rot_perm[:, 0] = -rot_perm[:, 0]
931
932
933 return rot_perm
934
935
937 """Calculate the x unit vector.
938
939 This is given by the eigenvalue decomposition.
940
941
942 @param rotation: The rotation matrix.
943 @type rotation: numpy 3D, rank-2 array
944 @return: The x unit vector.
945 @rtype: numpy array (float64)
946 """
947
948
949 return rotation[:, 0]
950
951
953 """Calculate the y unit vector.
954
955 This is given by the eigenvalue decomposition.
956
957
958 @param rotation: The rotation matrix.
959 @type rotation: numpy 3D, rank-2 array
960 @return: The y unit vector.
961 @rtype: numpy array (float64)
962 """
963
964
965 return rotation[:, 1]
966
967
969 """Calculate the z unit vector.
970
971 This is given by the eigenvalue decomposition.
972
973
974 @param rotation: The rotation matrix.
975 @type rotation: numpy 3D, rank-2 array
976 @return: The z unit vector.
977 @rtype: numpy array (float64)
978 """
979
980
981 return rotation[:, 2]
982
983
985 """Generator for the automatic updating the alignment tensor data structures.
986
987 @return: This generator successively yields three objects, the target object to update, the list of parameters which if modified cause the target to be updated, and the list of parameters that the target depends upon.
988 """
989
990
991 yield ('A', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['Axx', 'Ayy', 'Azz', 'Axy', 'Axz', 'Ayz'])
992 yield ('A_5D', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['Axx', 'Ayy', 'Azz', 'Axy', 'Axz', 'Ayz'])
993 yield ('Axxyy', ['Axx', 'Ayy'], ['Axx', 'Ayy'])
994 yield ('Azz', ['Axx', 'Ayy'], ['Axx', 'Ayy'])
995
996 yield ('P', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['Axx', 'Ayy', 'Azz', 'Axy', 'Axz', 'Ayz'])
997 yield ('P_5D', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['Axx', 'Ayy', 'Azz', 'Axy', 'Axz', 'Ayz'])
998 yield ('Pxx', ['Axx'], ['Axx'])
999 yield ('Pxxyy', ['Axx', 'Ayy'], ['Axx', 'Ayy'])
1000 yield ('Pxy', ['Axy'], ['Axy'])
1001 yield ('Pxz', ['Axz'], ['Axz'])
1002 yield ('Pyy', ['Ayy'], ['Ayy'])
1003 yield ('Pyz', ['Ayz'], ['Ayz'])
1004
1005 yield ('Sxx', ['Axx'], ['Axx'])
1006 yield ('Sxy', ['Axy'], ['Axy'])
1007 yield ('Sxz', ['Axz'], ['Axz'])
1008 yield ('Syy', ['Ayy'], ['Ayy'])
1009 yield ('Syz', ['Ayz'], ['Ayz'])
1010
1011
1012 yield ('A_diag', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['A'])
1013 yield ('eigvals', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['A'])
1014 yield ('rotation', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['A'])
1015
1016 yield ('P_diag', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['P'])
1017 yield ('Pzz', ['Axx', 'Ayy'], ['Pxx', 'Pyy'])
1018
1019 yield ('S', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['Sxx', 'Syy', 'Szz', 'Sxy', 'Sxz', 'Syz'])
1020 yield ('S_5D', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['Sxx', 'Syy', 'Szz', 'Sxy', 'Sxz', 'Syz'])
1021 yield ('S_diag', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['S'])
1022 yield ('Sxxyy', ['Axx', 'Ayy'], ['Sxx', 'Syy'])
1023 yield ('Szz', ['Axx', 'Ayy'], ['Sxx', 'Syy'])
1024
1025 yield ('Am2', ['Axx', 'Ayy', 'Axy'], ['Sxx', 'Syy', 'Sxy'])
1026 yield ('Am1', ['Axy', 'Ayz'], ['Sxz', 'Syz'])
1027 yield ('A0', ['Axx', 'Ayy'], ['Szz'])
1028 yield ('A1', ['Axy', 'Ayz'], ['Sxz', 'Syz'])
1029 yield ('A2', ['Axx', 'Ayy', 'Axy'], ['Sxx', 'Syy', 'Sxy'])
1030
1031
1032 yield ('Aa', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['A_diag'])
1033 yield ('Ar', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['A_diag'])
1034 yield ('eta', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['A_diag'])
1035
1036 yield ('unit_x', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['rotation'])
1037 yield ('unit_y', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['rotation'])
1038 yield ('unit_z', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['rotation'])
1039
1040 yield ('euler', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['rotation'])
1041
1042
1043 yield ('R', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['Aa', 'Ar'])
1044
1045
1046
1047
1048
1049
1051 """List type data container for holding all the alignment tensors.
1052
1053 The elements of the list should be AlignTensorData instances.
1054 """
1055
1057 """Replacement function for displaying an instance of this class."""
1058
1059 text = "Alignment tensors.\n\n"
1060 text = text + "%-8s%-20s\n" % ("Index", "Name")
1061 for i in range(len(self)):
1062 text = text + "%-8i%-20s\n" % (i, self[i].name)
1063 text = text + "\nThese can be accessed by typing 'pipe.align_tensor[index]'.\n"
1064 return text
1065
1066
1068 """Append a new AlignTensorData instance to the list.
1069
1070 @param name: The tensor ID string.
1071 @type name: str
1072 @return: The tensor object.
1073 @rtype: AlignTensorData instance
1074 """
1075
1076
1077 obj = AlignTensorData(name)
1078
1079
1080 self.append(obj)
1081
1082
1083 return obj
1084
1085
1086 - def from_xml(self, align_tensor_super_node, file_version=1):
1087 """Recreate the alignment tensor data structure from the XML alignment tensor node.
1088
1089 @param align_tensor_super_node: The alignment tensor XML nodes.
1090 @type align_tensor_super_node: xml.dom.minicompat.Element instance
1091 @keyword file_version: The relax XML version of the XML file.
1092 @type file_version: int
1093 """
1094
1095
1096 xml_to_object(align_tensor_super_node, self, file_version=file_version, blacklist=['align_tensor'])
1097
1098
1099 align_tensor_nodes = align_tensor_super_node.getElementsByTagName('align_tensor')
1100
1101
1102 for align_tensor_node in align_tensor_nodes:
1103
1104 self.add_item(align_tensor_node.getAttribute('name'))
1105
1106
1107 temp_obj = Element()
1108
1109
1110 xml_to_object(align_tensor_node, temp_obj, file_version=file_version)
1111
1112
1113 for name in self[-1]._mod_attr:
1114
1115 if not hasattr(temp_obj, name):
1116 continue
1117
1118
1119 if search('_err$', name):
1120 category = 'err'
1121 param = name.replace('_err', '')
1122 elif search('_sim$', name):
1123 category = 'sim'
1124 param = name.replace('_sim', '')
1125 else:
1126 category = 'val'
1127 param = name
1128
1129
1130 value = getattr(temp_obj, name)
1131
1132
1133 if category == 'val':
1134 self[-1].set(param=param, value=value, category=category, update=False)
1135
1136
1137 elif category == 'err':
1138 self[-1].set(param=param, value=value, category=category, update=False)
1139
1140
1141 else:
1142
1143 if not hasattr(self[-1], '_sim_num') or self[-1]._sim_num == None:
1144 self[-1].set_sim_num(len(value))
1145
1146
1147 for i in range(len(value)):
1148 self[-1].set(param=param, value=value[i], category=category, sim_index=i, update=False)
1149
1150
1151 for target, update_if_set, depends in dependency_generator():
1152 self[-1]._update_object(param, target, update_if_set, depends, category)
1153
1154
1155 del temp_obj
1156
1157
1159 """Return a list of the alignment tensor names."""
1160
1161
1162 names = []
1163 for i in range(len(self)):
1164 names.append(self[i].name)
1165
1166
1167 return names
1168
1169
1170 - def to_xml(self, doc, element):
1171 """Create an XML element for the alignment tensors.
1172
1173 @param doc: The XML document object.
1174 @type doc: xml.dom.minidom.Document instance
1175 @param element: The element to add the alignment tensors XML element to.
1176 @type element: XML element object
1177 """
1178
1179
1180 tensor_list_element = doc.createElement('align_tensors')
1181 element.appendChild(tensor_list_element)
1182
1183
1184 tensor_list_element.setAttribute('desc', 'Alignment tensor list')
1185
1186
1187 fill_object_contents(doc, tensor_list_element, object=self, blacklist=list(self.__class__.__dict__.keys())+list(list.__dict__.keys()))
1188
1189
1190 for i in range(len(self)):
1191
1192 tensor_element = doc.createElement('align_tensor')
1193 tensor_list_element.appendChild(tensor_element)
1194 tensor_element.setAttribute('index', repr(i))
1195 tensor_element.setAttribute('desc', 'Alignment tensor')
1196
1197
1198 blacklist = ['type', 'is_empty'] + list(self[i].__class__.__dict__.keys())
1199 for name in dir(self):
1200 if name not in self[i]._mod_attr:
1201 blacklist.append(name)
1202
1203
1204 fill_object_contents(doc, tensor_element, object=self[i], blacklist=blacklist)
1205
1206
1208 """An empty data container for the alignment tensor elements."""
1209
1210
1211 _mod_attr = [
1212 'name',
1213 'Axx', 'Axx_sim', 'Axx_err',
1214 'Ayy', 'Ayy_sim', 'Ayy_err',
1215 'Axy', 'Axy_sim', 'Axy_err',
1216 'Axz', 'Axz_sim', 'Axz_err',
1217 'Ayz', 'Ayz_sim', 'Ayz_err',
1218 'align_id',
1219 'domain',
1220 'red',
1221 'fixed'
1222 ]
1223
1224 - def __init__(self, name, fixed=False):
1225 """Set up the tensor data.
1226
1227 @param name: The tensor ID string.
1228 @type name: str
1229 @keyword fixed: The optimisation flag.
1230 @type fixed: bool
1231 """
1232
1233
1234 self.__dict__['name'] = name
1235 self.__dict__['fixed'] = fixed
1236
1237
1238 self.__dict__['_sim_num'] = None
1239
1240
1242 """Make this object read-only."""
1243
1244 raise RelaxError("The alignment tensor is a read-only object. The alignment tensor set() method must be used instead.")
1245
1246
1247 - def _update_object(self, param_name, target, update_if_set, depends, category, sim_index=None):
1248 """Function for updating the target object, its error, and the MC simulations.
1249
1250 If the base name of the object is not within the 'update_if_set' list, this function returns
1251 without doing anything (to avoid wasting time). Dependant upon the category the object
1252 (target), its error (target+'_err'), or all Monte Carlo simulations (target+'_sim') are
1253 updated.
1254
1255 @param param_name: The parameter name which is being set in the __setattr__() function.
1256 @type param_name: str
1257 @param target: The name of the object to update.
1258 @type target: str
1259 @param update_if_set: If the parameter being set by the __setattr__() function is not within this list of parameters, don't waste time updating the target.
1260 @param depends: An array of names objects that the target is dependent upon.
1261 @type depends: array of str
1262 @param category: The category of the object to update (one of 'val', 'err', or 'sim').
1263 @type category: str
1264 @keyword sim_index: The index for a Monte Carlo simulation for simulated parameter.
1265 @type sim_index: int or None
1266 @return: None
1267 """
1268
1269
1270 if not param_name in update_if_set:
1271 return
1272
1273
1274 fn = globals()['calc_'+target]
1275
1276
1277
1278
1279
1280 if category == 'val':
1281
1282 missing_dep = 0
1283 deps = ()
1284 for dep_name in depends:
1285
1286 if not hasattr(self, dep_name):
1287 missing_dep = 1
1288 break
1289
1290
1291 deps = deps+(getattr(self, dep_name),)
1292
1293
1294 if not missing_dep:
1295
1296 value = fn(*deps)
1297
1298
1299 self.__dict__[target] = value
1300
1301
1302
1303
1304
1305 if category == 'err':
1306
1307 missing_dep = 0
1308 deps = ()
1309 for dep_name in depends:
1310
1311 if not hasattr(self, dep_name+'_err'):
1312 missing_dep = 1
1313 break
1314
1315
1316 deps = deps+(getattr(self, dep_name+'_err'),)
1317
1318
1319 if not missing_dep:
1320
1321 value = fn(*deps)
1322
1323
1324 self.__dict__[target+'_err'] = value
1325
1326
1327
1328
1329
1330 if category == 'sim':
1331
1332 if sim_index != None:
1333 sim_indices = [sim_index]
1334 else:
1335 sim_indices = list(range(self._sim_num))
1336
1337
1338 missing_dep = 0
1339 deps = []
1340 for dep_name in depends:
1341
1342 if dep_name != 'type':
1343 dep_name = dep_name+'_sim'
1344
1345
1346 if not hasattr(self, dep_name):
1347 missing_dep = 1
1348 break
1349
1350
1351 deps.append(getattr(self, dep_name))
1352
1353
1354 if not missing_dep:
1355
1356 if not target+'_sim' in self.__dict__:
1357 self.__dict__[target+'_sim'] = AlignTensorSimList(elements=self._sim_num)
1358
1359
1360 args = []
1361 skip = False
1362 for i in sim_indices:
1363 args.append(())
1364
1365
1366 for j in range(len(deps)):
1367
1368 if deps[j] is None or deps[j][i] is None:
1369 skip = True
1370
1371
1372 if isinstance(deps[j], str):
1373 args[-1] = args[-1] + (deps[j],)
1374
1375
1376 else:
1377 args[-1] = args[-1] + (deps[j][i],)
1378
1379
1380 if not skip:
1381 for i in sim_indices:
1382
1383 value = fn(*args[sim_indices.index(i)])
1384
1385
1386 self.__dict__[target+'_sim']._set(value=value, sim_index=i)
1387
1388
1389 - def set(self, param=None, value=None, category='val', sim_index=None, update=True):
1390 """Set a alignment tensor parameter.
1391
1392 @keyword param: The name of the parameter to set.
1393 @type param: str
1394 @keyword value: The parameter value.
1395 @type value: anything
1396 @keyword category: The type of parameter to set. This can be 'val' for the normal parameter, 'err' for the parameter error, or 'sim' for Monte Carlo or other simulated parameters.
1397 @type category: str
1398 @keyword sim_index: The index for a Monte Carlo simulation for simulated parameter.
1399 @type sim_index: int or None
1400 @keyword update: A flag which if True will cause all the alignment tensor objects to be updated correctly. This can be turned off for speed, as long as the _update_object() method is called prior to using the tensor.
1401 @type update: bool
1402 """
1403
1404
1405 if category not in ['val', 'err', 'sim']:
1406 raise RelaxError("The category of the parameter '%s' is incorrectly set to %s - it must be one of 'val', 'err' or 'sim'." % (param, category))
1407
1408
1409 if not param in self._mod_attr:
1410 raise RelaxError("The object '%s' is not modifiable." % param)
1411
1412
1413 if category == 'val':
1414 self.__dict__[param] = value
1415
1416
1417 elif category == 'err':
1418 self.__dict__[param+'_err'] = value
1419
1420
1421 else:
1422
1423 if self._sim_num == None:
1424 raise RelaxError("The alignment tensor simulation number has not yet been specified, therefore a simulation value cannot be set.")
1425
1426
1427 sim_param = param+'_sim'
1428
1429
1430 if not hasattr(self, sim_param):
1431 self.__dict__[sim_param] = AlignTensorSimList(elements=self._sim_num)
1432
1433
1434 obj = getattr(self, sim_param)
1435
1436
1437 obj._set(value=value, sim_index=sim_index)
1438
1439
1440 if param in ['type']:
1441 return
1442
1443
1444 if update:
1445 for target, update_if_set, depends in dependency_generator():
1446 self._update_object(param, target, update_if_set, depends, category, sim_index=sim_index)
1447
1448
1450 """Set if the alignment tensor should be fixed during optimisation or not.
1451
1452 @param flag: The fixed flag.
1453 @type flag: bool
1454 """
1455
1456 self.__dict__['fixed'] = flag
1457
1458
1460 """Set the number of Monte Carlo simulations for the construction of the simulation structures.
1461
1462 @keyword sim_number: The number of Monte Carlo simulations.
1463 @type sim_number: int
1464 """
1465
1466
1467 self.__dict__['_sim_num'] = sim_number
1468
1469
1470
1472 """Empty data container for Monte Carlo simulation alignment tensor data."""
1473
1475 """Initialise the Monte Carlo simulation parameter list.
1476
1477 @keyword elements: The number of elements to initialise the length of the list to.
1478 @type elements: None or int
1479 """
1480
1481
1482 for i in range(elements):
1483 self._append(None)
1484
1485
1487 """This is a read-only object!"""
1488
1489 raise RelaxError("The alignment tensor is a read-only object. The alignment tensor set() method must be used instead.")
1490
1491
1493 """The secret append method.
1494
1495 @param value: The value to append to the list.
1496 @type value: anything
1497 """
1498
1499
1500 super(AlignTensorSimList, self).append(value)
1501
1502
1503 - def _set(self, value=None, sim_index=None):
1504 """Replacement secret method for __setitem__().
1505
1506 @keyword value: The value to set.
1507 @type value: anything
1508 @keyword sim_index: The index of the simulation value to set.
1509 @type sim_index: int
1510 """
1511
1512
1513 super(AlignTensorSimList, self).__setitem__(sim_index, value)
1514