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