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