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

Source Code for Module data.diff_tensor

   1  ############################################################################### 
   2  #                                                                             # 
   3  # Copyright (C) 2003-2012 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  # Python module imports. 
  23  from copy import deepcopy 
  24  from re import search 
  25  from math import cos, sin 
  26  from numpy import array, float64, dot, identity, transpose, zeros 
  27  import sys 
  28   
  29  # relax module imports. 
  30  from compat import py_version 
  31  from data.data_classes import Element 
  32  from data.relax_xml import fill_object_contents, xml_to_object 
  33  from maths_fns.coord_transform import spherical_to_cartesian 
  34  from maths_fns.rotation_matrix import two_vect_to_R 
  35  from relax_errors import RelaxError 
  36   
  37   
38 -def calc_Diso(tm):
39 """Function for calculating the Diso value. 40 41 The equation for calculating the parameter is:: 42 43 Diso = 1 / (6tm). 44 45 @keyword tm: The global correlation time. 46 @type tm: float 47 @return: The isotropic diffusion rate (Diso). 48 @rtype: float 49 """ 50 51 # Calculated and return the Diso value. 52 return 1.0 / (6.0 * tm)
53 54
55 -def calc_Dpar(Diso, Da):
56 """Function for calculating the Dpar value. 57 58 The equation for calculating the parameter is:: 59 60 Dpar = Diso + 2/3 Da. 61 62 @keyword Diso: The isotropic diffusion rate. 63 @type Diso: float 64 @keyword Da: The anisotropic diffusion rate. 65 @type Da: float 66 @return: The diffusion rate parallel to the unique axis of the spheroid. 67 @rtype: float 68 """ 69 70 # Dpar value. 71 return Diso + 2.0/3.0 * Da
72 73
74 -def calc_Dpar_unit(theta, phi):
75 """Function for calculating the Dpar unit vector. 76 77 The unit vector parallel to the unique axis of the diffusion tensor is:: 78 79 | sin(theta) * cos(phi) | 80 Dpar_unit = | sin(theta) * sin(phi) |. 81 | cos(theta) | 82 83 @keyword theta: The azimuthal angle in radians. 84 @type theta: float 85 @keyword phi: The polar angle in radians. 86 @type phi: float 87 @return: The Dpar unit vector. 88 @rtype: numpy array 89 """ 90 91 # Initilise the vector. 92 Dpar_unit = zeros(3, float64) 93 94 # Calculate the x, y, and z components. 95 Dpar_unit[0] = sin(theta) * cos(phi) 96 Dpar_unit[1] = sin(theta) * sin(phi) 97 Dpar_unit[2] = cos(theta) 98 99 # Return the unit vector. 100 return Dpar_unit
101 102
103 -def calc_Dper(Diso, Da):
104 """Function for calculating the Dper value. 105 106 The equation for calculating the parameter is:: 107 108 Dper = Diso - 1/3 Da. 109 110 @keyword Diso: The isotropic diffusion rate. 111 @type Diso: float 112 @keyword Da: The anisotropic diffusion rate. 113 @type Da: float 114 @return: The diffusion rate perpendicular to the unique axis of the spheroid. 115 @rtype: float 116 """ 117 118 # Dper value. 119 return Diso - 1.0/3.0 * Da
120 121
122 -def calc_Dratio(Dpar, Dper):
123 """Function for calculating the Dratio value. 124 125 The equation for calculating the parameter is:: 126 127 Dratio = Dpar / Dper. 128 129 @keyword Dpar: The diffusion rate parallel to the unique axis of the spheroid. 130 @type Dpar: float 131 @keyword Dper: The diffusion rate perpendicular to the unique axis of the spheroid. 132 @type Dper: float 133 @return: The ratio of the parallel and perpendicular diffusion rates. 134 @rtype: float 135 """ 136 137 # Dratio value. 138 return Dpar / Dper
139 140
141 -def calc_Dx(Diso, Da, Dr):
142 """Function for calculating the Dx value. 143 144 The equation for calculating the parameter is:: 145 146 Dx = Diso - 1/3 Da(1 + 3Dr). 147 148 @keyword Diso: The isotropic diffusion rate. 149 @type Diso: float 150 @keyword Da: The anisotropic diffusion rate. 151 @type Da: float 152 @keyword Dr: The rhombic component of the diffusion tensor. 153 @type Dr: float 154 @return: The diffusion rate parallel to the x-axis of the ellipsoid. 155 @rtype: float 156 """ 157 158 # Dx value. 159 return Diso - 1.0/3.0 * Da * (1.0 + 3.0*Dr)
160 161
162 -def calc_Dx_unit(alpha, beta, gamma):
163 """Function for calculating the Dx unit vector. 164 165 The unit Dx vector is:: 166 167 | -sin(alpha) * sin(gamma) + cos(alpha) * cos(beta) * cos(gamma) | 168 Dx_unit = | -sin(alpha) * cos(gamma) - cos(alpha) * cos(beta) * sin(gamma) |. 169 | cos(alpha) * sin(beta) | 170 171 @keyword alpha: The Euler angle alpha in radians using the z-y-z convention. 172 @type alpha: float 173 @keyword beta: The Euler angle beta in radians using the z-y-z convention. 174 @type beta: float 175 @keyword gamma: The Euler angle gamma in radians using the z-y-z convention. 176 @type gamma: float 177 @return: The Dx unit vector. 178 @rtype: numpy array 179 """ 180 181 # Initilise the vector. 182 Dx_unit = zeros(3, float64) 183 184 # Calculate the x, y, and z components. 185 Dx_unit[0] = -sin(alpha) * sin(gamma) + cos(alpha) * cos(beta) * cos(gamma) 186 Dx_unit[1] = -sin(alpha) * cos(gamma) - cos(alpha) * cos(beta) * sin(gamma) 187 Dx_unit[2] = cos(alpha) * sin(beta) 188 189 # Return the unit vector. 190 return Dx_unit
191 192
193 -def calc_Dy(Diso, Da, Dr):
194 """Function for calculating the Dy value. 195 196 The equation for calculating the parameter is:: 197 198 Dy = Diso - 1/3 Da(1 - 3Dr), 199 200 @keyword Diso: The isotropic diffusion rate. 201 @type Diso: float 202 @keyword Da: The anisotropic diffusion rate. 203 @type Da: float 204 @keyword Dr: The rhombic component of the diffusion tensor. 205 @type Dr: float 206 @return: The Dy value. 207 @rtype: float 208 """ 209 210 # Dy value. 211 return Diso - 1.0/3.0 * Da * (1.0 - 3.0*Dr)
212 213
214 -def calc_Dy_unit(alpha, beta, gamma):
215 """Function for calculating the Dy unit vector. 216 217 The unit Dy vector is:: 218 219 | cos(alpha) * sin(gamma) + sin(alpha) * cos(beta) * cos(gamma) | 220 Dy_unit = | cos(alpha) * cos(gamma) - sin(alpha) * cos(beta) * sin(gamma) |. 221 | sin(alpha) * sin(beta) | 222 223 @keyword alpha: The Euler angle alpha in radians using the z-y-z convention. 224 @type alpha: float 225 @keyword beta: The Euler angle beta in radians using the z-y-z convention. 226 @type beta: float 227 @keyword gamma: The Euler angle gamma in radians using the z-y-z convention. 228 @type gamma: float 229 @return: The Dy unit vector. 230 @rtype: numpy array 231 """ 232 233 # Initilise the vector. 234 Dy_unit = zeros(3, float64) 235 236 # Calculate the x, y, and z components. 237 Dy_unit[0] = cos(alpha) * sin(gamma) + sin(alpha) * cos(beta) * cos(gamma) 238 Dy_unit[1] = cos(alpha) * cos(gamma) - sin(alpha) * cos(beta) * sin(gamma) 239 Dy_unit[2] = sin(alpha) * sin(beta) 240 241 # Return the unit vector. 242 return Dy_unit
243 244
245 -def calc_Dz(Diso, Da):
246 """Function for calculating the Dz value. 247 248 The equation for calculating the parameter is:: 249 250 Dz = Diso + 2/3 Da. 251 252 @keyword Diso: The isotropic diffusion rate. 253 @type Diso: float 254 @keyword Da: The anisotropic diffusion rate. 255 @type Da: float 256 @return: The Dz value. 257 @rtype: float 258 """ 259 260 # Dz value. 261 return Diso + 2.0/3.0 * Da
262 263
264 -def calc_Dz_unit(beta, gamma):
265 """Function for calculating the Dz unit vector. 266 267 The unit Dz vector is:: 268 269 | -sin(beta) * cos(gamma) | 270 Dz_unit = | sin(beta) * sin(gamma) |. 271 | cos(beta) | 272 273 @keyword beta: The Euler angle beta in radians using the z-y-z convention. 274 @type beta: float 275 @keyword gamma: The Euler angle gamma in radians using the z-y-z convention. 276 @type gamma: float 277 @return: The Dz unit vector. 278 @rtype: numpy array 279 """ 280 281 # Initilise the vector. 282 Dz_unit = zeros(3, float64) 283 284 # Calculate the x, y, and z components. 285 Dz_unit[0] = -sin(beta) * cos(gamma) 286 Dz_unit[1] = sin(beta) * sin(gamma) 287 Dz_unit[2] = cos(beta) 288 289 # Return the unit vector. 290 return Dz_unit
291 292
293 -def calc_rotation(diff_type, *args):
294 """Function for calculating the rotation matrix. 295 296 Spherical diffusion 297 =================== 298 299 As the orientation of the diffusion tensor within the structural frame is undefined when the molecule diffuses as a sphere, the rotation matrix is simply the identity matrix:: 300 301 | 1 0 0 | 302 R = | 0 1 0 |. 303 | 0 0 1 | 304 305 306 Spheroidal diffusion 307 ==================== 308 309 The rotation matrix required to shift from the diffusion tensor frame to the structural frame is generated from the unique axis of the diffusion tensor. 310 311 312 Ellipsoidal diffusion 313 ===================== 314 315 The rotation matrix required to shift from the diffusion tensor frame to the structural frame is equal to:: 316 317 R = | Dx_unit Dy_unit Dz_unit |, 318 319 | Dx_unit[0] Dy_unit[0] Dz_unit[0] | 320 = | Dx_unit[1] Dy_unit[1] Dz_unit[1] |. 321 | Dx_unit[2] Dy_unit[2] Dz_unit[2] | 322 323 @param args: All the function arguments. 324 @type args: tuple 325 @param theta: The azimuthal angle in radians. 326 @type theta: float 327 @param phi: The polar angle in radians. 328 @type phi: float 329 @param Dx_unit: The Dx unit vector. 330 @type Dx_unit: numpy array 331 @param Dy_unit: The Dy unit vector. 332 @type Dy_unit: numpy array 333 @param Dz_unit: The Dz unit vector. 334 @type Dz_unit: numpy array 335 @return: The rotation matrix. 336 @rtype: numpy 3x3 array 337 """ 338 339 # The rotation matrix for the sphere. 340 if diff_type == 'sphere': 341 return identity(3, float64) 342 343 # The rotation matrix for the spheroid. 344 elif diff_type == 'spheroid': 345 # Unpack the arguments. 346 spheroid_type, theta, phi = args 347 348 # Initialise the rotation matrix. 349 R = zeros((3, 3), float64) 350 351 # The unique axis in the diffusion frame. 352 if spheroid_type == 'prolate': 353 axis = array([0, 0, 1], float64) 354 else: 355 axis = array([1, 0, 0], float64) 356 357 # The spherical coordinate vector. 358 spher_vect = array([1, theta, phi], float64) 359 360 # The diffusion tensor axis in the PDB frame. 361 diff_axis = zeros(3, float64) 362 spherical_to_cartesian(spher_vect, diff_axis) 363 364 # The rotation matrix. 365 two_vect_to_R(diff_axis, axis, R) 366 367 # Return the rotation. 368 return R 369 370 # The rotation matrix for the ellipsoid. 371 elif diff_type == 'ellipsoid': 372 # Unpack the arguments. 373 Dx_unit, Dy_unit, Dz_unit = args 374 375 # Initialise the rotation matrix. 376 rotation = identity(3, float64) 377 378 # First column of the rotation matrix. 379 rotation[:, 0] = Dx_unit 380 381 # Second column of the rotation matrix. 382 rotation[:, 1] = Dy_unit 383 384 # Third column of the rotation matrix. 385 rotation[:, 2] = Dz_unit 386 387 # Return the tensor. 388 return rotation 389 390 # Raise an error. 391 else: 392 raise RelaxError('The diffusion tensor has not been specified')
393 394
395 -def calc_spheroid_type(Da, spheroid_type, flag):
396 """Determine the spheroid type. 397 398 @param Da: The diffusion tensor anisotropy. 399 @type Da: float 400 @param spheroid_type: The current value of spheroid_type. 401 @type spheroid_type: str 402 @param flag: A flag which if True will cause the current spheroid_type value to be returned. 403 @type flag: bool 404 @return: The spheroid type, either 'oblate' or 'prolate'. 405 @rtype: str 406 """ 407 408 # Do not change. 409 if flag: 410 return spheroid_type 411 412 # The spheroid type. 413 if Da > 0.0: 414 return 'prolate' 415 else: 416 return 'oblate'
417 418
419 -def calc_tensor(rotation, tensor_diag):
420 """Function for calculating the diffusion tensor (in the structural frame). 421 422 The diffusion tensor is calculated using the diagonalised tensor and the rotation matrix 423 through the equation:: 424 425 R . tensor_diag . R^T. 426 427 @keyword rotation: The rotation matrix. 428 @type rotation: numpy 3x3 array 429 @keyword tensor_diag: The diagonalised diffusion tensor. 430 @type tensor_diag: numpy 3x3 array 431 @return: The diffusion tensor (within the structural frame). 432 @rtype: numpy 3x3 array 433 """ 434 435 # Rotation (R . tensor_diag . R^T). 436 return dot(rotation, dot(tensor_diag, transpose(rotation)))
437 438
439 -def calc_tensor_diag(diff_type, *args):
440 """Function for calculating the diagonalised diffusion tensor. 441 442 The diagonalised spherical diffusion tensor is defined as:: 443 444 | Diso 0 0 | 445 tensor = | 0 Diso 0 |. 446 | 0 0 Diso | 447 448 The diagonalised spheroidal tensor is defined as:: 449 450 | Dper 0 0 | 451 tensor = | 0 Dper 0 |. 452 | 0 0 Dpar | 453 454 The diagonalised ellipsoidal diffusion tensor is defined as:: 455 456 | Dx 0 0 | 457 tensor = | 0 Dy 0 |. 458 | 0 0 Dz | 459 460 @param args: All the arguments. 461 @type args: tuple 462 @param Diso: The Diso parameter of the sphere. 463 @type Diso: float 464 @param Dpar: The Dpar parameter of the spheroid. 465 @type Dpar: float 466 @param Dper: The Dper parameter of the spheroid. 467 @type Dper: float 468 @param Dx: The Dx parameter of the ellipsoid. 469 @type Dx: float 470 @param Dy: The Dy parameter of the ellipsoid. 471 @type Dy: float 472 @param Dz: The Dz parameter of the ellipsoid. 473 @type Dz: float 474 @return: The diagonalised diffusion tensor. 475 @rtype: numpy 3x3 array 476 """ 477 478 # Spherical diffusion tensor. 479 if diff_type == 'sphere': 480 # Unpack the arguments. 481 Diso, = args 482 483 # Initialise the tensor. 484 tensor = zeros((3, 3), float64) 485 486 # Populate the diagonal elements. 487 tensor[0, 0] = Diso 488 tensor[1, 1] = Diso 489 tensor[2, 2] = Diso 490 491 # Return the tensor. 492 return tensor 493 494 # Spheroidal diffusion tensor. 495 elif diff_type == 'spheroid': 496 # Unpack the arguments. 497 Dpar, Dper = args 498 499 # Initialise the tensor. 500 tensor = zeros((3, 3), float64) 501 502 # Populate the diagonal elements. 503 if Dpar > Dper: 504 tensor[0, 0] = Dper 505 tensor[1, 1] = Dper 506 tensor[2, 2] = Dpar 507 else: 508 tensor[0, 0] = Dpar 509 tensor[1, 1] = Dper 510 tensor[2, 2] = Dper 511 512 # Return the tensor. 513 return tensor 514 515 # Ellipsoidal diffusion tensor. 516 elif diff_type == 'ellipsoid': 517 # Unpack the arguments. 518 Dx, Dy, Dz = args 519 520 # Initialise the tensor. 521 tensor = zeros((3, 3), float64) 522 523 # Populate the diagonal elements. 524 tensor[0, 0] = Dx 525 tensor[1, 1] = Dy 526 tensor[2, 2] = Dz 527 528 # Return the tensor. 529 return tensor
530 531
532 -def dependency_generator(diff_type):
533 """Generator for the automatic updating the diffusion tensor data structures. 534 535 The order of the yield statements is important! 536 537 @param diff_type: The type of Brownian rotational diffusion. 538 @type diff_type: str 539 @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. 540 """ 541 542 # Spherical diffusion. 543 if diff_type == 'sphere': 544 yield ('Diso', ['tm'], ['tm']) 545 yield ('tensor_diag', ['tm'], ['type', 'Diso']) 546 yield ('rotation', ['tm'], ['type']) 547 yield ('tensor', ['tm'], ['rotation', 'tensor_diag']) 548 549 # Spheroidal diffusion. 550 elif diff_type == 'spheroid': 551 yield ('Diso', ['tm'], ['tm']) 552 yield ('Dpar', ['tm', 'Da'], ['Diso', 'Da']) 553 yield ('Dper', ['tm', 'Da'], ['Diso', 'Da']) 554 yield ('Dratio', ['tm', 'Da'], ['Dpar', 'Dper']) 555 yield ('Dpar_unit', ['theta', 'phi'], ['theta', 'phi']) 556 yield ('tensor_diag', ['tm', 'Da'], ['type', 'Dpar', 'Dper']) 557 yield ('rotation', ['theta', 'phi'], ['type', 'spheroid_type', 'theta', 'phi']) 558 yield ('tensor', ['tm', 'Da', 'theta', 'phi'], ['rotation', 'tensor_diag']) 559 yield ('spheroid_type', ['Da'], ['Da', 'spheroid_type', '_spheroid_type']) 560 561 # Ellipsoidal diffusion. 562 elif diff_type == 'ellipsoid': 563 yield ('Diso', ['tm'], ['tm']) 564 yield ('Dx', ['tm', 'Da', 'Dr'], ['Diso', 'Da', 'Dr']) 565 yield ('Dy', ['tm', 'Da', 'Dr'], ['Diso', 'Da', 'Dr']) 566 yield ('Dz', ['tm', 'Da'], ['Diso', 'Da']) 567 yield ('Dx_unit', ['alpha', 'beta', 'gamma'], ['alpha', 'beta', 'gamma']) 568 yield ('Dy_unit', ['alpha', 'beta', 'gamma'], ['alpha', 'beta', 'gamma']) 569 yield ('Dz_unit', ['beta', 'gamma'], ['beta', 'gamma']) 570 yield ('tensor_diag', ['tm', 'Da', 'Dr'], ['type', 'Dx', 'Dy', 'Dz']) 571 yield ('rotation', ['alpha', 'beta', 'gamma'], ['type', 'Dx_unit', 'Dy_unit', 'Dz_unit']) 572 yield ('tensor', ['tm', 'Da', 'Dr', 'alpha', 'beta', 'gamma'], ['rotation', 'tensor_diag'])
573 574 575 576 # Diffusion tensor specific data. 577 ################################# 578
579 -class DiffTensorData(Element):
580 """An empty data container for the diffusion tensor elements.""" 581 582 # List of modifiable attributes. 583 _mod_attr = [ 584 'type', 585 'fixed', 586 'spheroid_type', 587 'tm', 'tm_sim', 'tm_err', 588 'Da', 'Da_sim', 'Da_err', 589 'Dr', 'Dr_sim', 'Dr_err', 590 'theta', 'theta_sim', 'theta_err', 591 'phi', 'phi_sim', 'phi_err', 592 'alpha', 'alpha_sim', 'alpha_err', 593 'beta', 'beta_sim', 'beta_err', 594 'gamma', 'gamma_sim', 'gamma_err' 595 ] 596
597 - def __deepcopy__(self, memo):
598 """Replacement deepcopy method.""" 599 600 # Make a new object. 601 new_obj = self.__class__.__new__(self.__class__) 602 603 # Initialise it. 604 new_obj.__init__() 605 606 # Copy over the simulation number. 607 new_obj.__dict__['_sim_num'] = self._sim_num 608 609 # Loop over all modifiable objects in self and make deepcopies of them. 610 for name in self._mod_attr: 611 # Skip if missing from the object. 612 if not hasattr(self, name): 613 continue 614 615 # The category. 616 if search('_err$', name): 617 category = 'err' 618 param = name.replace('_err', '') 619 elif search('_sim$', name): 620 category = 'sim' 621 param = name.replace('_sim', '') 622 else: 623 category = 'val' 624 param = name 625 626 # Get the object. 627 value = getattr(self, name) 628 629 # Normal parameters. 630 if category == 'val': 631 new_obj.set(param=param, value=deepcopy(value, memo)) 632 633 # Errors. 634 elif category == 'err': 635 new_obj.set(param=param, value=deepcopy(value, memo), category='err') 636 637 # Simulation objects objects. 638 else: 639 # Recreate the list elements. 640 for i in range(len(value)): 641 new_obj.set(param=param, value=value[i], category='sim', sim_index=i) 642 643 # Return the new object. 644 return new_obj
645 646
647 - def __init__(self):
648 """Initialise a few instance variables.""" 649 650 # Set the initial diffusion type to None. 651 self.__dict__['type'] = None 652 653 # Initialise the spheroid type flag. 654 self.__dict__['_spheroid_type'] = False 655 656 # The number of simulations. 657 self.__dict__['_sim_num'] = None
658 659
660 - def __setattr__(self, name, value):
661 """Make this object read-only.""" 662 663 raise RelaxError("The diffusion tensor is a read-only object. The diffusion tensor set() method must be used instead.")
664 665
666 - def _update_object(self, param_name, target, update_if_set, depends, category):
667 """Function for updating the target object, its error, and the MC simulations. 668 669 If the base name of the object is not within the 'update_if_set' list, this function returns 670 without doing anything (to avoid wasting time). Dependant upon the category the object 671 (target), its error (target+'_err'), or all Monte Carlo simulations (target+'_sim') are 672 updated. 673 674 @param param_name: The parameter name which is being set in the __setattr__() function. 675 @type param_name: str 676 @param target: The name of the object to update. 677 @type target: str 678 @param update_if_set: If the parameter being set by the __setattr__() function is not 679 within this list of parameters, don't waste time updating the 680 target. 681 @param depends: An array of names objects that the target is dependent upon. 682 @type depends: array of str 683 @param category: The category of the object to update (one of 'val', 'err', or 684 'sim'). 685 @type category: str 686 @return: None 687 """ 688 689 # Only update if the parameter name is within the 'update_if_set' list. 690 if not param_name in update_if_set: 691 return 692 693 # Get the function for calculating the value. 694 fn = globals()['calc_'+target] 695 696 697 # The value. 698 ############ 699 700 if category == 'val': 701 # Get all the dependencies if possible. 702 missing_dep = 0 703 deps = () 704 for dep_name in depends: 705 # Test if the object exists. 706 if not hasattr(self, dep_name): 707 missing_dep = 1 708 break 709 710 # Get the object and place it into the 'deps' tuple. 711 deps = deps+(getattr(self, dep_name),) 712 713 # Only update the object if its dependencies exist. 714 if not missing_dep: 715 # Calculate the value. 716 value = fn(*deps) 717 718 # Set the attribute. 719 self.__dict__[target] = value 720 721 722 # The error. 723 ############ 724 725 if category == 'err': 726 # Get all the dependencies if possible. 727 missing_dep = 0 728 deps = () 729 for dep_name in depends: 730 # Test if the error object exists. 731 if not hasattr(self, dep_name+'_err'): 732 missing_dep = 1 733 break 734 735 # Get the object and place it into the 'deps' tuple. 736 deps = deps+(getattr(self, dep_name+'_err'),) 737 738 # Only update the error object if its dependencies exist. 739 if not missing_dep: 740 # Calculate the value. 741 value = fn(*deps) 742 743 # Set the attribute. 744 self.__dict__[target+'_err'] = value 745 746 747 # The Monte Carlo simulations. 748 ############################## 749 750 if category == 'sim': 751 # Get all the dependencies if possible. 752 missing_dep = 0 753 deps = [] 754 for dep_name in depends: 755 # Modify the dependency name. 756 if dep_name not in ['type', 'spheroid_type']: 757 dep_name = dep_name+'_sim' 758 759 # Test if the MC sim object exists. 760 if not hasattr(self, dep_name) or getattr(self, dep_name) == None or not len(getattr(self, dep_name)): 761 missing_dep = 1 762 break 763 764 # Get the object and place it into the 'deps' tuple. 765 deps.append(getattr(self, dep_name)) 766 767 # Only create the MC simulation object if its dependencies exist. 768 if not missing_dep: 769 # Initialise an empty array to store the MC simulation object elements (if it doesn't already exist). 770 if not target+'_sim' in self.__dict__: 771 self.__dict__[target+'_sim'] = DiffTensorSimList(elements=self._sim_num) 772 773 # Repackage the deps structure. 774 args = [] 775 skip = False 776 for i in range(self._sim_num): 777 args.append(()) 778 779 # Loop over the dependent structures. 780 for j in range(len(deps)): 781 # None, so skip. 782 if deps[j] == None or deps[j][i] == None: 783 skip = True 784 785 # String data type. 786 if isinstance(deps[j], str): 787 args[-1] = args[-1] + (deps[j],) 788 789 # List data type. 790 else: 791 args[-1] = args[-1] + (deps[j][i],) 792 793 # Loop over the sims and set the values. 794 if not skip: 795 for i in range(self._sim_num): 796 # Calculate the value. 797 value = fn(*args[i]) 798 799 # Set the attribute. 800 self.__dict__[target+'_sim']._set(value=value, sim_index=i)
801 802
803 - def from_xml(self, diff_tensor_node, file_version=1):
804 """Recreate the diffusion tensor data structure from the XML diffusion tensor node. 805 806 @param diff_tensor_node: The diffusion tensor XML node. 807 @type diff_tensor_node: xml.dom.minicompat.Element instance 808 @keyword file_version: The relax XML version of the XML file. 809 @type file_version: int 810 """ 811 812 # First set the diffusion type. Doing this first is essential for the proper reconstruction of the object. 813 self.__dict__['type'] = str(diff_tensor_node.getAttribute('type')) 814 815 # A temporary object to pack the structures from the XML data into. 816 temp_obj = Element() 817 818 # Recreate all the other data structures (into the temporary object). 819 xml_to_object(diff_tensor_node, temp_obj, file_version=file_version) 820 821 # Loop over all modifiable objects in the temporary object and make soft copies of them. 822 for name in self._mod_attr: 823 # Skip if missing from the object. 824 if not hasattr(temp_obj, name): 825 continue 826 827 # The category. 828 if search('_err$', name): 829 category = 'err' 830 param = name.replace('_err', '') 831 elif search('_sim$', name): 832 category = 'sim' 833 param = name.replace('_sim', '') 834 else: 835 category = 'val' 836 param = name 837 838 # Get the object. 839 value = getattr(temp_obj, name) 840 841 # Normal parameters. 842 if category == 'val': 843 self.set(param=param, value=value) 844 845 # Errors. 846 elif category == 'err': 847 self.set(param=param, value=value, category='err') 848 849 # Simulation objects objects. 850 else: 851 # Recreate the list elements. 852 for i in range(len(value)): 853 self.set(param=param, value=value[i], category='sim', sim_index=i) 854 855 # Delete the temporary object. 856 del temp_obj
857 858
859 - def set(self, param=None, value=None, category='val', sim_index=None):
860 """Set a diffusion tensor parameter. 861 862 @keyword param: The name of the parameter to set. 863 @type param: str 864 @keyword value: The parameter value. 865 @type value: anything 866 @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. 867 @type category: str 868 @keyword sim_index: The index for a Monte Carlo simulation for simulated parameter. 869 @type sim_index: int or None 870 """ 871 872 # Check the type. 873 if category not in ['val', 'err', 'sim']: 874 raise RelaxError("The category of the parameter '%s' is incorrectly set to %s - it must be one of 'val', 'err' or 'sim'." % (param, category)) 875 876 # Test if the attribute that is trying to be set is modifiable. 877 if not param in self._mod_attr: 878 raise RelaxError("The object '%s' is not a modifiable attribute." % param) 879 880 # Set a parameter value. 881 if category == 'val': 882 self.__dict__[param] = value 883 884 # Set an error. 885 elif category == 'err': 886 self.__dict__[param+'_err'] = value 887 888 # Set a simulation value. 889 else: 890 # Check that the simulation number has been set. 891 if self._sim_num == None: 892 raise RelaxError("The diffusion tensor simulation number has not yet been specified, therefore a simulation value cannot be set.") 893 894 # The simulation parameter name. 895 sim_param = param+'_sim' 896 897 # No object, so create it. 898 if not hasattr(self, sim_param): 899 self.__dict__[sim_param] = DiffTensorSimList(elements=self._sim_num) 900 901 # The object. 902 obj = getattr(self, sim_param) 903 904 # Set the value. 905 obj._set(value=value, sim_index=sim_index) 906 907 # Flag for the spheroid type. 908 if param == 'spheroid_type' and value: 909 self.__dict__['_spheroid_type'] = True 910 911 # Skip the updating process for certain objects. 912 if param in ['type', 'fixed', 'spheroid_type']: 913 return 914 915 # Update the data structures. 916 for target, update_if_set, depends in dependency_generator(self.type): 917 self._update_object(param, target, update_if_set, depends, category)
918 919
920 - def set_fixed(self, flag):
921 """Set if the diffusion tensor should be fixed during optimisation or not. 922 923 @param flag: The fixed flag. 924 @type flag: bool 925 """ 926 927 self.__dict__['fixed'] = flag
928 929
930 - def set_sim_num(self, sim_number=None):
931 """Set the number of Monte Carlo simulations for the construction of the simulation structures. 932 933 @keyword sim_number: The number of Monte Carlo simulations. 934 @type sim_number: int 935 """ 936 937 # Check if not already set. 938 if self._sim_num != None: 939 raise RelaxError("The number of simulations has already been set.") 940 941 # Store the value. 942 self.__dict__['_sim_num'] = sim_number
943 944
945 - def set_type(self, value):
946 """Set the diffusion tensor type. 947 948 @param value: The diffusion tensor type. This can be one of 'sphere', 'spheroid' or 'ellipsoid'. 949 @type value: str 950 """ 951 952 # Checks. 953 allowed = ['sphere', 'spheroid', 'ellipsoid'] 954 if value not in allowed: 955 raise RelaxError("The diffusion tensor type '%s' must be one of %s." % (value, allowed)) 956 957 # Set the type. 958 self.__dict__['type'] = value
959 960
961 - def to_xml(self, doc, element):
962 """Create an XML element for the diffusion tensor. 963 964 @param doc: The XML document object. 965 @type doc: xml.dom.minidom.Document instance 966 @param element: The element to add the diffusion tensor element to. 967 @type element: XML element object 968 """ 969 970 # Create the diffusion tensor element and add it to the higher level element. 971 tensor_element = doc.createElement('diff_tensor') 972 element.appendChild(tensor_element) 973 974 # Set the diffusion tensor attributes. 975 tensor_element.setAttribute('desc', 'Diffusion tensor') 976 tensor_element.setAttribute('type', self.type) 977 978 # The blacklist. 979 blacklist = ['type', 'is_empty'] + list(self.__class__.__dict__.keys()) 980 for name in dir(self): 981 if name not in self._mod_attr: 982 blacklist.append(name) 983 984 # Add all simple python objects within the PipeContainer to the pipe element. 985 fill_object_contents(doc, tensor_element, object=self, blacklist=blacklist)
986 987 988
989 -class DiffTensorSimList(list):
990 """Empty data container for Monte Carlo simulation diffusion tensor data.""" 991
992 - def __deepcopy__(self, memo):
993 """Replacement deepcopy method.""" 994 995 # Make a new object. 996 new_obj = self.__class__.__new__(self.__class__) 997 998 # Loop over all objects in self and make deepcopies of them. 999 for name in dir(self): 1000 # Skip all names begining with '_'. 1001 if search('^_', name): 1002 continue 1003 1004 # Skip the class methods. 1005 if name in list(self.__class__.__dict__.keys()) or name in dir(list): 1006 continue 1007 1008 # Get the object. 1009 value = getattr(self, name) 1010 1011 # Replace the object with a deepcopy of it. 1012 setattr(new_obj, name, deepcopy(value, memo)) 1013 1014 # Return the new object. 1015 return new_obj
1016 1017
1018 - def __init__(self, elements=None):
1019 """Initialise the Monte Carlo simulation parameter list. 1020 1021 @keyword elements: The number of elements to initialise the length of the list to. 1022 @type elements: None or int 1023 """ 1024 1025 # Initialise a length. 1026 for i in range(elements): 1027 self._append(None)
1028 1029
1030 - def __setitem__(self, slice_obj, value):
1031 """This is a read-only object!""" 1032 1033 raise RelaxError("The diffusion tensor is a read-only object. The diffusion tensor set() method must be used instead.")
1034 1035
1036 - def _append(self, value):
1037 """The secret append method. 1038 1039 @param value: The value to append to the list. 1040 @type value: anything 1041 """ 1042 1043 # Execute the base class method. 1044 super(DiffTensorSimList, self).append(value)
1045 1046
1047 - def _set(self, value=None, sim_index=None):
1048 """Replacement secret method for __setitem__(). 1049 1050 @keyword value: The value to set. 1051 @type value: anything 1052 @keyword sim_index: The index of the simulation value to set. 1053 @type sim_index: int 1054 """ 1055 1056 # Execute the base class method. 1057 super(DiffTensorSimList, self).__setitem__(sim_index, value)
1058 1059
1060 - def append(self, value):
1061 """This is a read-only object!""" 1062 1063 raise RelaxError("The diffusion tensor is a read-only object. The diffusion tensor set() method must be used instead.")
1064