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

Source Code for Module data_store.diff_tensor

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