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

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