Package data :: Module align_tensor
[hide private]
[frames] | no frames]

Source Code for Module data.align_tensor

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