1   
   2   
   3   
   4   
   5   
   6   
   7   
   8   
   9   
  10   
  11   
  12   
  13   
  14   
  15   
  16   
  17   
  18   
  19   
  20   
  21   
  22   
  23  """The diffusion tensor objects of the relax data store.""" 
  24   
  25   
  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   
  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   
  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       
  53      return 1.0 / (6.0 * tm) 
   54   
  55   
  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       
  72      return Diso + 2.0/3.0 * Da 
   73   
  74   
  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       
  93      Dpar_unit = zeros(3, float64) 
  94   
  95       
  96      Dpar_unit[0] = sin(theta) * cos(phi) 
  97      Dpar_unit[1] = sin(theta) * sin(phi) 
  98      Dpar_unit[2] = cos(theta) 
  99   
 100       
 101      return Dpar_unit 
  102   
 103   
 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       
 120      return Diso - 1.0/3.0 * Da 
  121   
 122   
 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       
 139      return Dpar / Dper 
  140   
 141   
 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       
 160      return Diso - 1.0/3.0 * Da * (1.0 + 3.0*Dr) 
  161   
 162   
 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       
 183      Dx_unit = zeros(3, float64) 
 184   
 185       
 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       
 191      return Dx_unit 
  192   
 193   
 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       
 212      return Diso - 1.0/3.0 * Da * (1.0 - 3.0*Dr) 
  213   
 214   
 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       
 235      Dy_unit = zeros(3, float64) 
 236   
 237       
 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       
 243      return Dy_unit 
  244   
 245   
 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       
 262      return Diso + 2.0/3.0 * Da 
  263   
 264   
 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       
 283      Dz_unit = zeros(3, float64) 
 284   
 285       
 286      Dz_unit[0] = -sin(beta) * cos(gamma) 
 287      Dz_unit[1] = sin(beta) * sin(gamma) 
 288      Dz_unit[2] = cos(beta) 
 289   
 290       
 291      return Dz_unit 
  292   
 293   
 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       
 331      if diff_type == 'sphere': 
 332          return identity(3, float64) 
 333   
 334       
 335      elif diff_type == 'spheroid': 
 336           
 337          spheroid_type, theta, phi = args 
 338   
 339           
 340          R = zeros((3, 3), float64) 
 341   
 342           
 343          if spheroid_type == 'prolate': 
 344              axis = array([0, 0, 1], float64) 
 345          else: 
 346              axis = array([1, 0, 0], float64) 
 347   
 348           
 349          spher_vect = array([1, theta, phi], float64) 
 350   
 351           
 352          diff_axis = zeros(3, float64) 
 353          spherical_to_cartesian(spher_vect, diff_axis) 
 354   
 355           
 356          two_vect_to_R(diff_axis, axis, R) 
 357   
 358           
 359          return R 
 360   
 361       
 362      elif diff_type == 'ellipsoid': 
 363           
 364          Dx_unit, Dy_unit, Dz_unit = args 
 365   
 366           
 367          rotation = identity(3, float64) 
 368   
 369           
 370          rotation[:, 0] = Dx_unit 
 371   
 372           
 373          rotation[:, 1] = Dy_unit 
 374   
 375           
 376          rotation[:, 2] = Dz_unit 
 377   
 378           
 379          return rotation 
 380   
 381       
 382      else: 
 383          raise RelaxError('The diffusion tensor has not been specified') 
  384   
 385   
 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       
 400      if flag: 
 401          return spheroid_type 
 402   
 403       
 404      if Da > 0.0: 
 405          return 'prolate' 
 406      else: 
 407          return 'oblate' 
  408   
 409   
 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       
 427      return dot(rotation, dot(tensor_diag, transpose(rotation))) 
  428   
 429   
 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       
 458      if diff_type == 'sphere': 
 459           
 460          Diso, = args 
 461   
 462           
 463          tensor = zeros((3, 3), float64) 
 464   
 465           
 466          tensor[0, 0] = Diso 
 467          tensor[1, 1] = Diso 
 468          tensor[2, 2] = Diso 
 469   
 470           
 471          return tensor 
 472   
 473       
 474      elif diff_type == 'spheroid': 
 475           
 476          Dpar, Dper = args 
 477   
 478           
 479          tensor = zeros((3, 3), float64) 
 480   
 481           
 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           
 492          return tensor 
 493   
 494       
 495      elif diff_type == 'ellipsoid': 
 496           
 497          Dx, Dy, Dz = args 
 498   
 499           
 500          tensor = zeros((3, 3), float64) 
 501   
 502           
 503          tensor[0, 0] = Dx 
 504          tensor[1, 1] = Dy 
 505          tensor[2, 2] = Dz 
 506   
 507           
 508          return tensor 
  509   
 510   
 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       
 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       
 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       
 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   
 556   
 557   
 559      """An empty data container for the diffusion tensor elements.""" 
 560   
 561       
 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   
 577          """Replacement deepcopy method.""" 
 578   
 579           
 580          new_obj = self.__class__.__new__(self.__class__) 
 581   
 582           
 583          new_obj.__init__() 
 584   
 585           
 586          new_obj.__dict__['_sim_num'] = self._sim_num 
 587   
 588           
 589          for name in self._mod_attr: 
 590               
 591              if not hasattr(self, name): 
 592                  continue 
 593   
 594               
 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               
 606              value = getattr(self, name) 
 607   
 608               
 609              if category == 'val': 
 610                  new_obj.set(param=param, value=deepcopy(value, memo)) 
 611   
 612               
 613              elif category == 'err': 
 614                  new_obj.set(param=param, value=deepcopy(value, memo), category='err') 
 615   
 616               
 617              else: 
 618                   
 619                  for i in range(len(value)): 
 620                      new_obj.set(param=param, value=value[i], category='sim', sim_index=i) 
 621   
 622           
 623          return new_obj 
  624   
 625   
 627          """Initialise a few instance variables.""" 
 628   
 629           
 630          self.__dict__['type'] = None 
 631   
 632           
 633          self.__dict__['_spheroid_type'] = False 
 634   
 635           
 636          self.__dict__['_sim_num'] = None 
  637   
 638   
 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           
 669          if not param_name in update_if_set: 
 670              return 
 671   
 672           
 673          fn = globals()['calc_'+target] 
 674   
 675   
 676           
 677           
 678   
 679          if category == 'val': 
 680               
 681              missing_dep = 0 
 682              deps = () 
 683              for dep_name in depends: 
 684                   
 685                  if not hasattr(self, dep_name): 
 686                      missing_dep = 1 
 687                      break 
 688   
 689                   
 690                  deps = deps+(getattr(self, dep_name),) 
 691   
 692               
 693              if not missing_dep: 
 694                   
 695                  value = fn(*deps) 
 696   
 697                   
 698                  self.__dict__[target] = value 
 699   
 700   
 701           
 702           
 703   
 704          if category == 'err': 
 705               
 706              missing_dep = 0 
 707              deps = () 
 708              for dep_name in depends: 
 709                   
 710                  if not hasattr(self, dep_name+'_err'): 
 711                      missing_dep = 1 
 712                      break 
 713   
 714                   
 715                  deps = deps+(getattr(self, dep_name+'_err'),) 
 716   
 717               
 718              if not missing_dep: 
 719                   
 720                  value = fn(*deps) 
 721   
 722                   
 723                  self.__dict__[target+'_err'] = value 
 724   
 725   
 726           
 727           
 728   
 729          if category == 'sim': 
 730               
 731              missing_dep = 0 
 732              deps = [] 
 733              for dep_name in depends: 
 734                   
 735                  if dep_name not in ['type', 'spheroid_type']: 
 736                      dep_name = dep_name+'_sim' 
 737   
 738                   
 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                   
 744                  deps.append(getattr(self, dep_name)) 
 745   
 746               
 747              if not missing_dep: 
 748                   
 749                  if not target+'_sim' in self.__dict__: 
 750                      self.__dict__[target+'_sim'] = DiffTensorSimList(elements=self._sim_num) 
 751   
 752                   
 753                  args = [] 
 754                  skip = False 
 755                  for i in range(self._sim_num): 
 756                      args.append(()) 
 757   
 758                       
 759                      for j in range(len(deps)): 
 760                           
 761                          if deps[j] is None or deps[j][i] is None: 
 762                              skip = True 
 763   
 764                           
 765                          if isinstance(deps[j], str): 
 766                              args[-1] = args[-1] + (deps[j],) 
 767   
 768                           
 769                          else: 
 770                              args[-1] = args[-1] + (deps[j][i],) 
 771   
 772                   
 773                  if not skip: 
 774                      for i in range(self._sim_num): 
 775                           
 776                          value = fn(*args[i]) 
 777   
 778                           
 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           
 792          self.__dict__['type'] = str(diff_tensor_node.getAttribute('type')) 
 793   
 794           
 795          temp_obj = Element() 
 796   
 797           
 798          xml_to_object(diff_tensor_node, temp_obj, file_version=file_version) 
 799   
 800           
 801          for name in self._mod_attr: 
 802               
 803              if not hasattr(temp_obj, name): 
 804                  continue 
 805   
 806               
 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               
 818              value = getattr(temp_obj, name) 
 819   
 820               
 821              if category == 'val': 
 822                  self.set(param=param, value=value) 
 823   
 824               
 825              elif category == 'err': 
 826                  self.set(param=param, value=value, category='err') 
 827   
 828               
 829              else: 
 830                   
 831                  for i in range(len(value)): 
 832                      self.set(param=param, value=value[i], category='sim', sim_index=i) 
 833   
 834           
 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           
 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           
 856          if not param in self._mod_attr: 
 857              raise RelaxError("The object '%s' is not a modifiable attribute." % param) 
 858   
 859           
 860          if category == 'val': 
 861              self.__dict__[param] = value 
 862   
 863           
 864          elif category == 'err': 
 865              self.__dict__[param+'_err'] = value 
 866   
 867           
 868          else: 
 869               
 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               
 874              sim_param = param+'_sim' 
 875   
 876               
 877              if not hasattr(self, sim_param): 
 878                  self.__dict__[sim_param] = DiffTensorSimList(elements=self._sim_num) 
 879   
 880               
 881              obj = getattr(self, sim_param) 
 882   
 883               
 884              obj._set(value=value, sim_index=sim_index) 
 885   
 886           
 887          if param == 'spheroid_type' and value: 
 888              self.__dict__['_spheroid_type'] = True 
 889   
 890           
 891          if param in ['type', 'fixed', 'spheroid_type']: 
 892              return 
 893   
 894           
 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   
 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   
 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           
 917          if self._sim_num != None: 
 918              raise RelaxError("The number of simulations has already been set.") 
 919   
 920           
 921          self.__dict__['_sim_num'] = sim_number 
  922   
 923   
 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           
 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           
 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           
 950          tensor_element = doc.createElement('diff_tensor') 
 951          element.appendChild(tensor_element) 
 952   
 953           
 954          tensor_element.setAttribute('desc', 'Diffusion tensor') 
 955          tensor_element.setAttribute('type', self.type) 
 956   
 957           
 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           
 964          fill_object_contents(doc, tensor_element, object=self, blacklist=blacklist) 
   965   
 966   
 967   
 969      """Empty data container for Monte Carlo simulation diffusion tensor data.""" 
 970   
 972          """Replacement deepcopy method.""" 
 973   
 974           
 975          new_obj = self.__class__.__new__(self.__class__) 
 976   
 977           
 978          for name in dir(self): 
 979               
 980              if search('^_', name): 
 981                  continue 
 982   
 983               
 984              if name in self.__class__.__dict__ or name in dir(list): 
 985                  continue 
 986   
 987               
 988              value = getattr(self, name) 
 989   
 990               
 991              setattr(new_obj, name, deepcopy(value, memo)) 
 992   
 993           
 994          return new_obj 
  995   
 996   
 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           
1005          for i in range(elements): 
1006              self._append(None) 
 1007   
1008   
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   
1016          """The secret append method. 
1017   
1018          @param value:   The value to append to the list. 
1019          @type value:    anything 
1020          """ 
1021   
1022           
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           
1036          super(DiffTensorSimList, self).__setitem__(sim_index, value) 
 1037   
1038   
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