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.                                     # 
   6  #                                                                             # 
   7  # relax is free software; you can redistribute it and/or modify               # 
   8  # it under the terms of the GNU General Public License as published by        # 
   9  # the Free Software Foundation; either version 2 of the License, or           # 
  10  # (at your option) any later version.                                         # 
  11  #                                                                             # 
  12  # relax is distributed in the hope that it will be useful,                    # 
  13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
  14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
  15  # GNU General Public License for more details.                                # 
  16  #                                                                             # 
  17  # You should have received a copy of the GNU General Public License           # 
  18  # along with relax; if not, write to the Free Software                        # 
  19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
  20  #                                                                             # 
  21  ############################################################################### 
  22   
  23  # Python module imports. 
  24  from copy import deepcopy 
  25  from re import search 
  26  from math import cos, sin 
  27  from numpy import array, float64, dot, identity, transpose, zeros 
  28  from types import ListType 
  29   
  30  # relax module imports. 
  31  from data_classes import Element 
  32  from maths_fns.coord_transform import spherical_to_cartesian 
  33  from maths_fns.rotation_matrix import two_vect_to_R 
  34  from relax_errors import RelaxError 
  35  from relax_xml import fill_object_contents, xml_to_object 
  36   
  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. 325 @type args: tuple 326 @param theta: The azimuthal angle in radians. 327 @type theta: float 328 @param phi: The polar angle in radians. 329 @type phi: float 330 @param Dx_unit: The Dx unit vector. 331 @type Dx_unit: numpy array 332 @param Dy_unit: The Dy unit vector. 333 @type Dy_unit: numpy array 334 @param Dz_unit: The Dz unit vector. 335 @type Dz_unit: numpy array 336 @return: The rotation matrix. 337 @rtype: numpy 3x3 array 338 """ 339 340 # The rotation matrix for the sphere. 341 if diff_type == 'sphere': 342 return identity(3, float64) 343 344 # The rotation matrix for the spheroid. 345 elif diff_type == 'spheroid': 346 # Unpack the arguments. 347 spheroid_type, theta, phi = args 348 349 # Initialise the rotation matrix. 350 R = zeros((3, 3), float64) 351 352 # The unique axis in the diffusion frame. 353 if spheroid_type == 'prolate': 354 axis = array([0, 0, 1], float64) 355 else: 356 axis = array([1, 0, 0], float64) 357 358 # The spherical coordinate vector. 359 spher_vect = array([1, theta, phi], float64) 360 361 # The diffusion tensor axis in the PDB frame. 362 diff_axis = zeros(3, float64) 363 spherical_to_cartesian(spher_vect, diff_axis) 364 365 # The rotation matrix. 366 two_vect_to_R(diff_axis, axis, R) 367 368 # Return the rotation. 369 return R 370 371 # The rotation matrix for the ellipsoid. 372 elif diff_type == 'ellipsoid': 373 # Unpack the arguments. 374 Dx_unit, Dy_unit, Dz_unit = args 375 376 # Initialise the rotation matrix. 377 rotation = identity(3, float64) 378 379 # First column of the rotation matrix. 380 rotation[:, 0] = Dx_unit 381 382 # Second column of the rotation matrix. 383 rotation[:, 1] = Dy_unit 384 385 # Third column of the rotation matrix. 386 rotation[:, 2] = Dz_unit 387 388 # Return the tensor. 389 return rotation 390 391 # Raise an error. 392 else: 393 raise RelaxError('The diffusion tensor has not been specified')
394 395
396 -def calc_spheroid_type(Da, spheroid_type, flag):
397 """Determine the spheroid type. 398 399 @param Da: The diffusion tensor anisotropy. 400 @type Da: float 401 @param spheroid_type: The current value of spheroid_type. 402 @type spheroid_type: str 403 @param flag: A flag which if True will cause the current spheroid_type value to be returned. 404 @type flag: bool 405 @return: The spheroid type, either 'oblate' or 'prolate'. 406 @rtype: str 407 """ 408 409 # Do not change. 410 if flag: 411 return spheroid_type 412 413 # The spheroid type. 414 if Da > 0.0: 415 return 'prolate' 416 else: 417 return 'oblate'
418 419
420 -def calc_tensor(rotation, tensor_diag):
421 """Function for calculating the diffusion tensor (in the structural frame). 422 423 The diffusion tensor is calculated using the diagonalised tensor and the rotation matrix 424 through the equation:: 425 426 R . tensor_diag . R^T. 427 428 @keyword rotation: The rotation matrix. 429 @type rotation: numpy 3x3 array 430 @keyword tensor_diag: The diagonalised diffusion tensor. 431 @type tensor_diag: numpy 3x3 array 432 @return: The diffusion tensor (within the structural frame). 433 @rtype: numpy 3x3 array 434 """ 435 436 # Rotation (R . tensor_diag . R^T). 437 return dot(rotation, dot(tensor_diag, transpose(rotation)))
438 439
440 -def calc_tensor_diag(diff_type, *args):
441 """Function for calculating the diagonalised diffusion tensor. 442 443 The diagonalised spherical diffusion tensor is defined as:: 444 445 | Diso 0 0 | 446 tensor = | 0 Diso 0 |. 447 | 0 0 Diso | 448 449 The diagonalised spheroidal tensor is defined as:: 450 451 | Dper 0 0 | 452 tensor = | 0 Dper 0 |. 453 | 0 0 Dpar | 454 455 The diagonalised ellipsoidal diffusion tensor is defined as:: 456 457 | Dx 0 0 | 458 tensor = | 0 Dy 0 |. 459 | 0 0 Dz | 460 461 @param args: All the arguments. 462 @type args: tuple 463 @param Diso: The Diso parameter of the sphere. 464 @type Diso: float 465 @param Dpar: The Dpar parameter of the spheroid. 466 @type Dpar: float 467 @param Dper: The Dper parameter of the spheroid. 468 @type Dper: float 469 @param Dx: The Dx parameter of the ellipsoid. 470 @type Dx: float 471 @param Dy: The Dy parameter of the ellipsoid. 472 @type Dy: float 473 @param Dz: The Dz parameter of the ellipsoid. 474 @type Dz: float 475 @return: The diagonalised diffusion tensor. 476 @rtype: numpy 3x3 array 477 """ 478 479 # Spherical diffusion tensor. 480 if diff_type == 'sphere': 481 # Unpack the arguments. 482 Diso, = args 483 484 # Initialise the tensor. 485 tensor = zeros((3, 3), float64) 486 487 # Populate the diagonal elements. 488 tensor[0, 0] = Diso 489 tensor[1, 1] = Diso 490 tensor[2, 2] = Diso 491 492 # Return the tensor. 493 return tensor 494 495 # Spheroidal diffusion tensor. 496 elif diff_type == 'spheroid': 497 # Unpack the arguments. 498 Dpar, Dper = args 499 500 # Initialise the tensor. 501 tensor = zeros((3, 3), float64) 502 503 # Populate the diagonal elements. 504 if Dpar > Dper: 505 tensor[0, 0] = Dper 506 tensor[1, 1] = Dper 507 tensor[2, 2] = Dpar 508 else: 509 tensor[0, 0] = Dpar 510 tensor[1, 1] = Dper 511 tensor[2, 2] = Dper 512 513 # Return the tensor. 514 return tensor 515 516 # Ellipsoidal diffusion tensor. 517 elif diff_type == 'ellipsoid': 518 # Unpack the arguments. 519 Dx, Dy, Dz = args 520 521 # Initialise the tensor. 522 tensor = zeros((3, 3), float64) 523 524 # Populate the diagonal elements. 525 tensor[0, 0] = Dx 526 tensor[1, 1] = Dy 527 tensor[2, 2] = Dz 528 529 # Return the tensor. 530 return tensor
531 532
533 -def dependency_generator(diff_type):
534 """Generator for the automatic updating the diffusion tensor data structures. 535 536 The order of the yield statements is important! 537 538 @param diff_type: The type of Brownian rotational diffusion. 539 @type diff_type: str 540 @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. 541 """ 542 543 # Spherical diffusion. 544 if diff_type == 'sphere': 545 yield ('Diso', ['tm'], ['tm']) 546 yield ('tensor_diag', ['tm'], ['type', 'Diso']) 547 yield ('rotation', ['tm'], ['type']) 548 yield ('tensor', ['tm'], ['rotation', 'tensor_diag']) 549 550 # Spheroidal diffusion. 551 elif diff_type == 'spheroid': 552 yield ('Diso', ['tm'], ['tm']) 553 yield ('Dpar', ['tm', 'Da'], ['Diso', 'Da']) 554 yield ('Dper', ['tm', 'Da'], ['Diso', 'Da']) 555 yield ('Dratio', ['tm', 'Da'], ['Dpar', 'Dper']) 556 yield ('Dpar_unit', ['theta', 'phi'], ['theta', 'phi']) 557 yield ('tensor_diag', ['tm', 'Da'], ['type', 'Dpar', 'Dper']) 558 yield ('rotation', ['theta', 'phi'], ['type', 'spheroid_type', 'theta', 'phi']) 559 yield ('tensor', ['tm', 'Da', 'theta', 'phi'], ['rotation', 'tensor_diag']) 560 yield ('spheroid_type', ['Da'], ['Da', 'spheroid_type', '__spheroid_type']) 561 562 # Ellipsoidal diffusion. 563 elif diff_type == 'ellipsoid': 564 yield ('Diso', ['tm'], ['tm']) 565 yield ('Dx', ['tm', 'Da', 'Dr'], ['Diso', 'Da', 'Dr']) 566 yield ('Dy', ['tm', 'Da', 'Dr'], ['Diso', 'Da', 'Dr']) 567 yield ('Dz', ['tm', 'Da'], ['Diso', 'Da']) 568 yield ('Dx_unit', ['alpha', 'beta', 'gamma'], ['alpha', 'beta', 'gamma']) 569 yield ('Dy_unit', ['alpha', 'beta', 'gamma'], ['alpha', 'beta', 'gamma']) 570 yield ('Dz_unit', ['beta', 'gamma'], ['beta', 'gamma']) 571 yield ('tensor_diag', ['tm', 'Da', 'Dr'], ['type', 'Dx', 'Dy', 'Dz']) 572 yield ('rotation', ['alpha', 'beta', 'gamma'], ['type', 'Dx_unit', 'Dy_unit', 'Dz_unit']) 573 yield ('tensor', ['tm', 'Da', 'Dr', 'alpha', 'beta', 'gamma'], ['rotation', 'tensor_diag'])
574 575 576 577 # Diffusion tensor specific data. 578 ################################# 579
580 -class DiffTensorData(Element):
581 """An empty data container for the diffusion tensor elements.""" 582 583 # List of modifiable attributes. 584 __mod_attr__ = ['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 - def __deepcopy__(self, memo):
597 """Replacement deepcopy method.""" 598 599 # Make a new object. 600 new_obj = self.__class__.__new__(self.__class__) 601 602 # Loop over all modifiable objects in self and make deepcopies of them. 603 for name in self.__mod_attr__: 604 # Skip if missing from the object. 605 if not hasattr(self, name): 606 continue 607 608 # Get the object. 609 value = getattr(self, name) 610 611 612 # Replace the object with a deepcopy of it. 613 setattr(new_obj, name, deepcopy(value, memo)) 614 615 # Place the new class object into the namespace of DiffTensorSimList objects. 616 if isinstance(value, DiffTensorSimList): 617 # Get the new list. 618 new_value = getattr(new_obj, name) 619 620 # Place the new class object into the namespace of DiffTensorSimList objects. 621 new_value.diff_element = new_obj 622 623 # Recreate the list elements. 624 for i in range(len(value)): 625 new_value.append(value[i]) 626 627 # Return the new object. 628 return new_obj
629 630
631 - def __init__(self):
632 """Initialise a few instance variables.""" 633 634 # Set the initial diffusion type to None. 635 self.type = None 636 637 # Initialise the spheroid type flag. 638 self.__dict__['__spheroid_type'] = False
639 640
641 - def __setattr__(self, name, value):
642 """Function for calculating the parameters, unit vectors, and tensors on the fly. 643 644 The equations for the parameters Dper, Dpar, and Dratio are:: 645 646 Dratio = Dpar / Dper. 647 """ 648 649 # Get the base parameter name and determine the object category ('val', 'err', or 'sim'). 650 if search('_err$', name): 651 category = 'err' 652 param_name = name[:-4] 653 elif search('_sim$', name): 654 category = 'sim' 655 param_name = name[:-4] 656 else: 657 category = 'val' 658 param_name = name 659 660 # Test if the attribute that is trying to be set is modifiable. 661 if not param_name in self.__mod_attr__: 662 raise RelaxError("The object " + repr(name) + " is not a modifiable attribute.") 663 664 # Set the attribute normally. 665 self.__dict__[name] = value 666 667 # Flag for the spheroid type. 668 if name == 'spheroid_type' and value: 669 self.__dict__['__spheroid_type'] = True 670 671 # Skip the updating process for certain objects. 672 if name in ['type', 'fixed', 'spheroid_type']: 673 return 674 675 # Update the data structures. 676 for target, update_if_set, depends in dependency_generator(self.type): 677 self.__update_object(param_name, target, update_if_set, depends, category)
678 679
680 - def __update_sim_append(self, param_name, index):
681 """Update the Monte Carlo simulation data lists when a simulation value is appended. 682 683 @param param_name: The MC sim parameter name which is being appended to. 684 @type param_name: str 685 @param index: The index of the Monte Carlo simulation which was set. 686 @type index: int 687 """ 688 689 # Loop over the targets. 690 for target, update_if_set, depends in dependency_generator(self.type): 691 # Only update if the parameter name is within the 'update_if_set' list. 692 if not param_name in update_if_set: 693 continue 694 695 # Get the function for calculating the value. 696 fn = globals()['calc_'+target] 697 698 # Get all the dependencies if possible. 699 missing_dep = 0 700 deps = () 701 for dep_name in depends: 702 # Modify the dependency name. 703 if dep_name not in ['type', 'spheroid_type']: 704 dep_name = dep_name+'_sim' 705 706 # Test if the MC sim object exists. 707 if not hasattr(self, dep_name): 708 missing_dep = 1 709 break 710 711 # Get the MC dependency. 712 dep_obj = getattr(self, dep_name) 713 714 # The diffusion tensor type. 715 if dep_name in ['type', 'spheroid_type']: 716 deps = deps+(dep_obj,) 717 continue 718 719 # Test if the MC sim dependency is long enough. 720 if len(dep_obj) <= index: 721 missing_dep = 1 722 break 723 724 # Place the value corresponding to the index into the 'deps' array. 725 deps = deps+(dep_obj[index],) 726 727 # Only update the MC simulation object if its dependencies exist. 728 if not missing_dep: 729 # Initialise an empty array to store the MC simulation object elements (if it doesn't already exist). 730 if not target+'_sim' in self.__dict__: 731 self.__dict__[target+'_sim'] = DiffTensorSimList(target, self) 732 733 # Get the target object. 734 target_obj = getattr(self, target+'_sim') 735 736 # Calculate and set the value. 737 target_obj.append_untouchable_item(fn(*deps))
738 739
740 - def __update_sim_set(self, param_name, index):
741 """Update the Monte Carlo simulation data lists when a simulation value is set. 742 743 @param param_name: The MC sim parameter name which is being set. 744 @type param_name: str 745 @param index: The index of the Monte Carlo simulation which was set. 746 @type index: int 747 """ 748 749 # Loop over the targets. 750 for target, update_if_set, depends in dependency_generator(self.type): 751 # Only update if the parameter name is within the 'update_if_set' list. 752 if not param_name in update_if_set: 753 continue 754 755 # Get the function for calculating the value. 756 fn = globals()['calc_'+target] 757 758 # Get all the dependencies if possible. 759 missing_dep = 0 760 deps = () 761 for dep_name in depends: 762 # Modify the dependency name. 763 if dep_name not in ['type', 'spheroid_type']: 764 dep_name = dep_name+'_sim' 765 766 # Test if the MC sim object exists. 767 if not hasattr(self, dep_name): 768 missing_dep = 1 769 break 770 771 # Get the MC dependency. 772 dep_obj = getattr(self, dep_name) 773 774 # The diffusion tensor type. 775 if dep_name in ['type', 'spheroid_type']: 776 deps = deps+(dep_obj,) 777 continue 778 779 # Test if the MC sim dependency is long enough. 780 if len(dep_obj) <= index: 781 missing_dep = 1 782 break 783 784 # Place the value corresponding to the index into the 'deps' array. 785 deps = deps+(dep_obj[index],) 786 787 # Only update the MC simulation object if its dependencies exist. 788 if not missing_dep: 789 # Get the target object. 790 target_obj = getattr(self, target+'_sim') 791 792 # Missing data. 793 skip = False 794 for i in range(len(deps)): 795 if deps[i] == None: 796 skip = True 797 798 # Calculate and set the value. 799 if not skip: 800 target_obj.set_untouchable_item(index, fn(*deps))
801 802
803 - def __update_object(self, param_name, target, update_if_set, depends, category):
804 """Function for updating the target object, its error, and the MC simulations. 805 806 If the base name of the object is not within the 'update_if_set' list, this function returns 807 without doing anything (to avoid wasting time). Dependant upon the category the object 808 (target), its error (target+'_err'), or all Monte Carlo simulations (target+'_sim') are 809 updated. 810 811 @param param_name: The parameter name which is being set in the __setattr__() function. 812 @type param_name: str 813 @param target: The name of the object to update. 814 @type target: str 815 @param update_if_set: If the parameter being set by the __setattr__() function is not 816 within this list of parameters, don't waste time updating the 817 target. 818 @param depends: An array of names objects that the target is dependent upon. 819 @type depends: array of str 820 @param category: The category of the object to update (one of 'val', 'err', or 821 'sim'). 822 @type category: str 823 @return: None 824 """ 825 826 # Only update if the parameter name is within the 'update_if_set' list. 827 if not param_name in update_if_set: 828 return 829 830 # Get the function for calculating the value. 831 fn = globals()['calc_'+target] 832 833 834 # The value. 835 ############ 836 837 if category == 'val': 838 # Get all the dependencies if possible. 839 missing_dep = 0 840 deps = () 841 for dep_name in depends: 842 # Test if the object exists. 843 if not hasattr(self, dep_name): 844 missing_dep = 1 845 break 846 847 # Get the object and place it into the 'deps' tuple. 848 deps = deps+(getattr(self, dep_name),) 849 850 # Only update the object if its dependencies exist. 851 if not missing_dep: 852 # Calculate the value. 853 value = fn(*deps) 854 855 # Set the attribute. 856 self.__dict__[target] = value 857 858 859 # The error. 860 ############ 861 862 if category == 'err': 863 # Get all the dependencies if possible. 864 missing_dep = 0 865 deps = () 866 for dep_name in depends: 867 # Test if the error object exists. 868 if not hasattr(self, dep_name+'_err'): 869 missing_dep = 1 870 break 871 872 # Get the object and place it into the 'deps' tuple. 873 deps = deps+(getattr(self, dep_name+'_err'),) 874 875 # Only update the error object if its dependencies exist. 876 if not missing_dep: 877 # Calculate the value. 878 value = fn(*deps) 879 880 # Set the attribute. 881 self.__dict__[target+'_err'] = value 882 883 884 # The Monte Carlo simulations. 885 ############################## 886 887 if category == 'sim': 888 # Get all the dependencies if possible. 889 missing_dep = 0 890 deps = [] 891 for dep_name in depends: 892 # Modify the dependency name. 893 if dep_name not in ['type', 'spheroid_type']: 894 dep_name = dep_name+'_sim' 895 896 # Test if the MC sim object exists. 897 if not hasattr(self, dep_name) or getattr(self, dep_name) == None or not len(getattr(self, dep_name)): 898 missing_dep = 1 899 break 900 901 # Get the object and place it into the 'deps' tuple. 902 deps.append(getattr(self, dep_name)) 903 904 # Only create the MC simulation object if its dependencies exist. 905 if not missing_dep: 906 # The number of simulations. 907 num_sim = len(self.__dict__[update_if_set[0]+'_sim']) 908 909 # Initialise an empty array to store the MC simulation object elements (if it doesn't already exist). 910 if not target+'_sim' in self.__dict__: 911 self.__dict__[target+'_sim'] = DiffTensorSimList(target, self, elements=num_sim) 912 913 # Repackage the deps structure. 914 args = [] 915 skip = False 916 for i in range(num_sim): 917 args.append(()) 918 919 # Loop over the dependent structures. 920 for j in range(len(deps)): 921 # None, so skip. 922 if deps[j] == None or deps[j][i] == None: 923 skip = True 924 925 # String data type. 926 if isinstance(deps[j], str): 927 args[-1] = args[-1] + (deps[j],) 928 929 # List data type. 930 else: 931 args[-1] = args[-1] + (deps[j][i],) 932 933 # Loop over the sims and set the values. 934 if not skip: 935 for i in range(num_sim): 936 # Calculate the value. 937 value = fn(*args[i]) 938 939 # Set the attribute. 940 self.__dict__[target+'_sim'][i] = value
941 942
943 - def from_xml(self, diff_tensor_node, file_version=1):
944 """Recreate the diffusion tensor data structure from the XML diffusion tensor node. 945 946 @param diff_tensor_node: The diffusion tensor XML node. 947 @type diff_tensor_node: xml.dom.minicompat.Element instance 948 @keyword file_version: The relax XML version of the XML file. 949 @type file_version: int 950 """ 951 952 # First set the diffusion type. Doing this first is essential for the proper reconstruction of the object. 953 setattr(self, 'type', str(diff_tensor_node.getAttribute('type'))) 954 955 # Recreate all the other data structures. 956 xml_to_object(diff_tensor_node, self, file_version=file_version)
957 958
959 - def to_xml(self, doc, element):
960 """Create an XML element for the diffusion tensor. 961 962 @param doc: The XML document object. 963 @type doc: xml.dom.minidom.Document instance 964 @param element: The element to add the diffusion tensor element to. 965 @type element: XML element object 966 """ 967 968 # Create the diffusion tensor element and add it to the higher level element. 969 tensor_element = doc.createElement('diff_tensor') 970 element.appendChild(tensor_element) 971 972 # Set the diffusion tensor attributes. 973 tensor_element.setAttribute('desc', 'Diffusion tensor') 974 tensor_element.setAttribute('type', self.type) 975 976 # Add all simple python objects within the PipeContainer to the pipe element. 977 fill_object_contents(doc, tensor_element, object=self, blacklist=['type'] + list(self.__class__.__dict__.keys()))
978 979 980
981 -class DiffTensorSimList(ListType):
982 """Empty data container for Monte Carlo simulation diffusion tensor data.""" 983
984 - def __deepcopy__(self, memo):
985 """Replacement deepcopy method.""" 986 987 # Make a new object. 988 new_obj = self.__class__.__new__(self.__class__) 989 990 # Loop over all objects in self and make deepcopies of them. 991 for name in dir(self): 992 # Skip all names begining with '_'. 993 if search('^_', name): 994 continue 995 996 # Skip the class methods. 997 if name in list(self.__class__.__dict__.keys()) or name in dir(ListType): 998 continue 999 1000 # Skip the diff_element object. 1001 if name == 'diff_element': 1002 continue 1003 1004 # Get the object. 1005 value = getattr(self, name) 1006 1007 # Replace the object with a deepcopy of it. 1008 setattr(new_obj, name, deepcopy(value, memo)) 1009 1010 # Return the new object. 1011 return new_obj
1012 1013
1014 - def __init__(self, param_name, diff_element, elements=None):
1015 """Initialise the Monte Carlo simulation parameter list. 1016 1017 This function makes the parameter name and parent object accessible to the functions of this 1018 list object. 1019 1020 @param param_name: The name of the parameter. 1021 @type param_name: str 1022 @param diff_element: The parent class. 1023 @type diff_element: DiffTensorData element 1024 @keyword elements: The optional number of elements to initialise the length of the list 1025 to. 1026 @type elements: None or int 1027 """ 1028 1029 # Initialise. 1030 self.param_name = param_name 1031 self.diff_element = diff_element 1032 1033 # Initialise a length. 1034 if elements: 1035 for i in range(elements): 1036 self.append(None)
1037 1038
1039 - def __setitem__(self, index, value):
1040 """Set the value.""" 1041 1042 # Set the value. 1043 ListType.__setitem__(self, index, value) 1044 1045 # Then update the other lists. 1046 self.diff_element._DiffTensorData__update_sim_set(self.param_name, index)
1047 1048
1049 - def append(self, value):
1050 """Replacement function for the normal self.append() method.""" 1051 1052 # Append the value to the list. 1053 self[len(self):len(self)] = [value] 1054 1055 # Update the other MC lists. 1056 self.diff_element._DiffTensorData__update_sim_append(self.param_name, len(self)-1)
1057 1058
1059 - def append_untouchable_item(self, value):
1060 """Append the value for an untouchable MC data structure.""" 1061 1062 # Append the value to the list. 1063 self[len(self):len(self)] = [value]
1064 1065
1066 - def set_untouchable_item(self, index, value):
1067 """Set the value for an untouchable MC data structure.""" 1068 1069 # Set the value. 1070 ListType.__setitem__(self, index, value)
1071