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

Source Code for Module data_store.align_tensor

   1  ############################################################################### 
   2  #                                                                             # 
   3  # Copyright (C) 2003-2014 Edward d'Auvergne                                   # 
   4  #                                                                             # 
   5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
   6  #                                                                             # 
   7  # This program 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 3 of the License, or           # 
  10  # (at your option) any later version.                                         # 
  11  #                                                                             # 
  12  # This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.       # 
  19  #                                                                             # 
  20  ############################################################################### 
  21   
  22  # Module docstring. 
  23  """The alignment tensor objects of the relax data store.""" 
  24   
  25  # Python module imports. 
  26  from re import search 
  27  from numpy import eye, float64, zeros 
  28  from numpy.linalg import det, eig, eigvals 
  29   
  30  # relax module imports. 
  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 # Initialise the tensor. 58 tensor = zeros((3, 3), float64) 59 60 # Populate the diagonal elements. 61 tensor[0, 0] = Axx 62 tensor[1, 1] = Ayy 63 tensor[2, 2] = Azz 64 65 # Populate the off diagonal elements. 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 # Return the tensor. 71 return tensor
72 73
74 -def calc_A_5D(Axx, Ayy, Azz, Axy, Axz, Ayz):
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 # Initialise the tensor. 94 tensor = zeros(5, float64) 95 96 # Populate the tensor. 97 tensor[0] = Axx 98 tensor[1] = Ayy 99 tensor[2] = Axy 100 tensor[3] = Axz 101 tensor[4] = Ayz 102 103 # Return the tensor. 104 return tensor
105 106
107 -def calc_A_diag(A):
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 # The eigenvalues. 126 vals = eigvals(A) 127 128 # Find the |x| < |y| < |z| indices. 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 # Empty tensor. 138 tensor_diag = zeros((3, 3), float64) 139 140 # Fill the elements. 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 # Return the tensor. 146 return tensor_diag
147 148
149 -def calc_Aa(A_diag):
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 # Return Aa. 166 return 1.5 * A_diag[2, 2]
167 168
169 -def calc_Ar(A_diag):
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 # Return Ar. 186 return A_diag[0, 0] - A_diag[1, 1]
187 188
189 -def calc_Axxyy(Axx, Ayy):
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 # Calculate and return the Axx-yy value. 205 return Axx - Ayy
206 207
208 -def calc_Azz(Axx, Ayy):
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 # Calculate and return the Azz value. 224 return - Axx - Ayy
225 226
227 -def calc_eigvals(A):
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 # The eigenvalues. 237 vals = eigvals(A) 238 239 # Find the |x| < |y| < |z| indices. 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 # Return the sorted eigenvalues. 249 return [vals[x_index], vals[y_index], vals[z_index]]
250 251
252 -def calc_eta(A_diag):
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 # Zero Azz value, so return NaN. 269 if A_diag[2, 2] == 0: 270 return nan 271 272 # Return eta. 273 return (A_diag[0, 0] - A_diag[1, 1]) / A_diag[2, 2]
274 275
276 -def calc_euler(rotation):
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 # Initialise the tensor. 308 tensor = zeros((3, 3), float64) 309 310 # Populate the diagonal elements. 311 tensor[0, 0] = Sxx 312 tensor[1, 1] = Syy 313 tensor[2, 2] = Szz 314 315 # Populate the off diagonal elements. 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 # Return the tensor. 321 return tensor
322 323
324 -def calc_S_5D(Sxx, Syy, Szz, Sxy, Sxz, Syz):
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 # Initialise the tensor. 344 tensor = zeros(5, float64) 345 346 # Populate the tensor. 347 tensor[0] = Sxx 348 tensor[1] = Syy 349 tensor[2] = Sxy 350 tensor[3] = Sxz 351 tensor[4] = Syz 352 353 # Return the tensor. 354 return tensor
355 356
357 -def calc_S_diag(tensor):
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 # The eigenvalues. 376 vals = eigvals(tensor) 377 378 # Find the |x| < |y| < |z| indices. 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 # Empty tensor. 388 tensor_diag = zeros((3, 3), float64) 389 390 # Fill the elements. 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 # Return the tensor. 396 return tensor_diag
397 398
399 -def calc_Sxx(Axx):
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 # Calculate and return the Axx value. 412 return 3.0/2.0 * Axx
413 414
415 -def calc_Sxxyy(Sxx, Syy):
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 # Calculate and return the Sxx-yy value. 431 return Sxx - Syy
432 433
434 -def calc_Sxy(Axy):
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 # Calculate and return the Axy value. 447 return 3.0/2.0 * Axy
448 449
450 -def calc_Sxz(Axz):
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 # Calculate and return the Axz value. 463 return 3.0/2.0 * Axz
464 465
466 -def calc_Syy(Ayy):
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 # Calculate and return the Ayy value. 479 return 3.0/2.0 * Ayy
480 481
482 -def calc_Syz(Ayz):
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 # Calculate and return the Ayz value. 495 return 3.0/2.0 * Ayz
496 497
498 -def calc_Szz(Sxx, Syy):
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 # Calculate and return the Szz value. 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 # Initialise the tensor. 537 tensor = zeros((3, 3), float64) 538 539 # Populate the diagonal elements. 540 tensor[0, 0] = Axx 541 tensor[1, 1] = Ayy 542 tensor[2, 2] = Azz 543 544 # Populate the off diagonal elements. 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 # Add 1/3 the identity matrix. 550 tensor = tensor + eye(3)/3.0 551 552 # Return the tensor. 553 return tensor
554 555
556 -def calc_P_5D(Axx, Ayy, Azz, Axy, Axz, Ayz):
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 # Initialise the tensor. 576 tensor = zeros(5, float64) 577 578 # Populate the tensor. 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 # Return the tensor. 586 return tensor
587 588
589 -def calc_P_diag(tensor):
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 # The eigenvalues. 608 vals = eigvals(tensor) 609 610 # Find the |x| < |y| < |z| indices. 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 # Empty tensor. 620 tensor_diag = zeros((3, 3), float64) 621 622 # Fill the elements. 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 # Add 1/3 the identity matrix. 628 tensor = tensor + eye(3)/3.0 629 630 # Return the tensor. 631 return tensor_diag
632 633
634 -def calc_Pxx(Axx):
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 # Calculate and return the Pxx value. 647 return Axx + 1.0/3.0
648 649
650 -def calc_Pxxyy(Pxx, Pyy):
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 # Calculate and return the Pxx-yy value. 666 return Pxx - Pyy
667 668
669 -def calc_Pxy(Axy):
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 # Calculate and return the Pxy value. 682 return Axy
683 684
685 -def calc_Pxz(Axz):
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 # Calculate and return the Pxz value. 698 return Axz
699 700
701 -def calc_Pyy(Ayy):
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 # Calculate and return the Pyy value. 714 return Ayy + 1.0/3.0
715 716
717 -def calc_Pyz(Ayz):
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 # Calculate and return the Pyz value. 730 return Ayz
731 732
733 -def calc_Pzz(Pxx, Pyy):
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 # Calculate and return the Pzz value. 749 return 1.0 - Pxx - Pyy
750 751
752 -def calc_R(Aa, Ar):
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 # Zero Aa value, so return NaN. 769 if Aa == 0: 770 return nan 771 772 # Return R. 773 return Ar / Aa
774 775
776 -def calc_rotation(A):
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 # The eigenvalues. 791 vals, rot = eig(A) 792 793 # Find the |x| < |y| < |z| indices. 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 # Empty rotation matrix for index permutations. 803 rot_perm = zeros((3, 3), float64) 804 805 # Permute the rotation matrix. 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 # Switch from the left handed to right handed universe if required. 812 if abs(det(rot_perm) - 1.0) > 1e-7: 813 rot_perm[:, 0] = -rot_perm[:, 0] 814 815 # Return the permuted rotation matrix. 816 return rot_perm
817 818
819 -def calc_unit_x(rotation):
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 # Return the x unit vector. 832 return rotation[:, 0]
833 834
835 -def calc_unit_y(rotation):
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 # Return the y unit vector. 848 return rotation[:, 1]
849 850
851 -def calc_unit_z(rotation):
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 # Return the z unit vector. 864 return rotation[:, 2]
865 866
867 -def dependency_generator():
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 # Primary objects (only dependant on the modifiable objects). 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 # Secondary objects (dependant on the primary objects). 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 # Tertiary objects (dependant on the secondary objects). 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 # Quaternary objects (dependant on the tertiary objects). 920 yield ('R', ['Axx', 'Ayy', 'Axy', 'Axz', 'Ayz'], ['Aa', 'Ar'])
921 922 923 924 # Alignment tensor specific data. 925 ################################# 926
927 -class AlignTensorList(list):
928 """List type data container for holding all the alignment tensors. 929 930 The elements of the list should be AlignTensorData instances. 931 """ 932
933 - def __repr__(self):
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
944 - def add_item(self, name):
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 # Create the instance. 954 obj = AlignTensorData(name) 955 956 # Append the object. 957 self.append(obj) 958 959 # Return the object. 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 # Recreate all the alignment tensor data structures. 973 xml_to_object(align_tensor_super_node, self, file_version=file_version, blacklist=['align_tensor']) 974 975 # Get the individual tensors. 976 align_tensor_nodes = align_tensor_super_node.getElementsByTagName('align_tensor') 977 978 # Loop over the child nodes. 979 for align_tensor_node in align_tensor_nodes: 980 # Add the alignment tensor data container. 981 self.add_item(align_tensor_node.getAttribute('name')) 982 983 # A temporary object to pack the structures from the XML data into. 984 temp_obj = Element() 985 986 # Recreate all the other data structures (into the temporary object). 987 xml_to_object(align_tensor_node, temp_obj, file_version=file_version) 988 989 # Loop over all modifiable objects in the temporary object and make soft copies of them. 990 for name in self[-1]._mod_attr: 991 # Skip if missing from the object. 992 if not hasattr(temp_obj, name): 993 continue 994 995 # The category. 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 # Get the object. 1007 value = getattr(temp_obj, name) 1008 1009 # Normal parameters. 1010 if category == 'val': 1011 self[-1].set(param=param, value=value) 1012 1013 # Errors. 1014 elif category == 'err': 1015 self[-1].set(param=param, value=value, category='err') 1016 1017 # Simulation objects objects. 1018 else: 1019 # Set the simulation number if needed. 1020 if not hasattr(self[-1], '_sim_num') or self[-1]._sim_num == None: 1021 self[-1].set_sim_num(len(value)) 1022 1023 # Recreate the list elements. 1024 for i in range(len(value)): 1025 self[-1].set(param=param, value=value[i], category='sim', sim_index=i) 1026 1027 # Delete the temporary object. 1028 del temp_obj
1029 1030
1031 - def names(self):
1032 """Return a list of the alignment tensor names.""" 1033 1034 # Loop over the tensors. 1035 names = [] 1036 for i in range(len(self)): 1037 names.append(self[i].name) 1038 1039 # Return the list. 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 # Create the alignment tensors element and add it to the higher level element. 1053 tensor_list_element = doc.createElement('align_tensors') 1054 element.appendChild(tensor_list_element) 1055 1056 # Set the alignment tensor attributes. 1057 tensor_list_element.setAttribute('desc', 'Alignment tensor list') 1058 1059 # Add all simple python objects within the PipeContainer to the pipe element. 1060 fill_object_contents(doc, tensor_list_element, object=self, blacklist=list(list(self.__class__.__dict__.keys()) + list(list.__dict__.keys()))) 1061 1062 # Loop over the tensors. 1063 for i in range(len(self)): 1064 # Create an XML element for a single tensor. 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 # The blacklist. 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 # Add all simple python objects within the PipeContainer to the pipe element. 1077 fill_object_contents(doc, tensor_element, object=self[i], blacklist=blacklist)
1078 1079
1080 -class AlignTensorData(Element):
1081 """An empty data container for the alignment tensor elements.""" 1082 1083 # List of modifiable attributes. 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 # Store the values. 1107 self.__dict__['name'] = name 1108 self.__dict__['fixed'] = fixed 1109 1110 # The number of simulations. 1111 self.__dict__['_sim_num'] = None
1112 1113
1114 - def __setattr__(self, name, value):
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 # Only update if the parameter name is within the 'update_if_set' list. 1144 if not param_name in update_if_set: 1145 return 1146 1147 # Get the function for calculating the value. 1148 fn = globals()['calc_'+target] 1149 1150 1151 # The value. 1152 ############ 1153 1154 if category == 'val': 1155 # Get all the dependencies if possible. 1156 missing_dep = 0 1157 deps = () 1158 for dep_name in depends: 1159 # Test if the object exists. 1160 if not hasattr(self, dep_name): 1161 missing_dep = 1 1162 break 1163 1164 # Get the object and place it into the 'deps' tuple. 1165 deps = deps+(getattr(self, dep_name),) 1166 1167 # Only update the object if its dependencies exist. 1168 if not missing_dep: 1169 # Calculate the value. 1170 value = fn(*deps) 1171 1172 # Set the attribute. 1173 self.__dict__[target] = value 1174 1175 1176 # The error. 1177 ############ 1178 1179 if category == 'err': 1180 # Get all the dependencies if possible. 1181 missing_dep = 0 1182 deps = () 1183 for dep_name in depends: 1184 # Test if the error object exists. 1185 if not hasattr(self, dep_name+'_err'): 1186 missing_dep = 1 1187 break 1188 1189 # Get the object and place it into the 'deps' tuple. 1190 deps = deps+(getattr(self, dep_name+'_err'),) 1191 1192 # Only update the error object if its dependencies exist. 1193 if not missing_dep: 1194 # Calculate the value. 1195 value = fn(*deps) 1196 1197 # Set the attribute. 1198 self.__dict__[target+'_err'] = value 1199 1200 1201 # The Monte Carlo simulations. 1202 ############################## 1203 1204 if category == 'sim': 1205 # Get all the dependencies if possible. 1206 missing_dep = 0 1207 deps = [] 1208 for dep_name in depends: 1209 # Modify the dependency name. 1210 if dep_name != 'type': 1211 dep_name = dep_name+'_sim' 1212 1213 # Test if the MC sim object exists. 1214 if not hasattr(self, dep_name): 1215 missing_dep = 1 1216 break 1217 1218 # Get the object and place it into the 'deps' tuple. 1219 deps.append(getattr(self, dep_name)) 1220 1221 # Only create the MC simulation object if its dependencies exist. 1222 if not missing_dep: 1223 # Initialise an empty array to store the MC simulation object elements (if it doesn't already exist). 1224 if not target+'_sim' in self.__dict__: 1225 self.__dict__[target+'_sim'] = AlignTensorSimList(elements=self._sim_num) 1226 1227 # Repackage the deps structure. 1228 args = [] 1229 skip = False 1230 for i in range(self._sim_num): 1231 args.append(()) 1232 1233 # Loop over the dependent structures. 1234 for j in range(len(deps)): 1235 # None, so skip. 1236 if deps[j] == None or deps[j][i] == None: 1237 skip = True 1238 1239 # String data type. 1240 if isinstance(deps[j], str): 1241 args[-1] = args[-1] + (deps[j],) 1242 1243 # List data type. 1244 else: 1245 args[-1] = args[-1] + (deps[j][i],) 1246 1247 # Loop over the sims and set the values. 1248 if not skip: 1249 for i in range(self._sim_num): 1250 # Calculate the value. 1251 value = fn(*args[i]) 1252 1253 # Set the attribute. 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 # Check the type. 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 # Test if the attribute that is trying to be set is modifiable. 1275 if not param in self._mod_attr: 1276 raise RelaxError("The object '%s' is not modifiable." % param) 1277 1278 # Set a parameter value. 1279 if category == 'val': 1280 self.__dict__[param] = value 1281 1282 # Set an error. 1283 elif category == 'err': 1284 self.__dict__[param+'_err'] = value 1285 1286 # Set a simulation value. 1287 else: 1288 # Check that the simulation number has been set. 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 # The simulation parameter name. 1293 sim_param = param+'_sim' 1294 1295 # No object, so create it. 1296 if not hasattr(self, sim_param): 1297 self.__dict__[sim_param] = AlignTensorSimList(elements=self._sim_num) 1298 1299 # The object. 1300 obj = getattr(self, sim_param) 1301 1302 # Set the value. 1303 obj._set(value=value, sim_index=sim_index) 1304 1305 # Skip the updating process for certain objects. 1306 if param in ['type']: 1307 return 1308 1309 # Update the data structures. 1310 for target, update_if_set, depends in dependency_generator(): 1311 self._update_object(param, target, update_if_set, depends, category)
1312 1313
1314 - def set_fixed(self, flag):
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
1324 - def set_sim_num(self, sim_number=None):
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 # Store the value. 1332 self.__dict__['_sim_num'] = sim_number
1333 1334 1335
1336 -class AlignTensorSimList(list):
1337 """Empty data container for Monte Carlo simulation alignment tensor data.""" 1338
1339 - def __init__(self, elements=None):
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 # Initialise a length. 1347 for i in range(elements): 1348 self._append(None)
1349 1350
1351 - def __setitem__(self, slice_obj, value):
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
1357 - def _append(self, value):
1358 """The secret append method. 1359 1360 @param value: The value to append to the list. 1361 @type value: anything 1362 """ 1363 1364 # Execute the base class method. 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 # Execute the base class method. 1378 super(AlignTensorSimList, self).__setitem__(sim_index, value)
1379 1380
1381 - def append(self, value):
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