Package user_functions :: Module structure
[hide private]
[frames] | no frames]

Source Code for Module user_functions.structure

   1  ############################################################################### 
   2  #                                                                             # 
   3  # Copyright (C) 2003-2013 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 structure user function definitions.""" 
  24   
  25  # Python module imports. 
  26  from numpy import eye 
  27  from os import sep 
  28  import dep_check 
  29  if dep_check.wx_module: 
  30      from wx import FD_OPEN, FD_SAVE 
  31  else: 
  32      FD_OPEN = -1 
  33      FD_SAVE = -1 
  34   
  35  # relax module imports. 
  36  from graphics import WIZARD_IMAGE_PATH 
  37  import pipe_control.structure.geometric 
  38  import pipe_control.structure.main 
  39  from user_functions.data import Uf_info; uf_info = Uf_info() 
  40  from user_functions.data import Uf_tables; uf_tables = Uf_tables() 
  41  from user_functions.objects import Desc_container 
  42   
  43   
  44  # The user function class. 
  45  uf_class = uf_info.add_class('structure') 
  46  uf_class.title = "Class containing the structural related functions." 
  47  uf_class.menu_text = "&structure" 
  48  uf_class.gui_icon = "relax.structure" 
  49   
  50   
  51  # The structure.add_atom user function. 
  52  uf = uf_info.add_uf('structure.add_atom') 
  53  uf.title = "Add an atom." 
  54  uf.title_short = "Atom creation." 
  55  uf.add_keyarg( 
  56      name = "atom_name", 
  57      py_type = "str", 
  58      desc_short = "atom name", 
  59      desc = "The atom name." 
  60  ) 
  61  uf.add_keyarg( 
  62      name = "res_name", 
  63      py_type = "str", 
  64      desc_short = "residue name", 
  65      desc = "The residue name." 
  66  ) 
  67  uf.add_keyarg( 
  68      name = "res_num", 
  69      py_type = "int", 
  70      min = -10000, 
  71      max = 10000, 
  72      desc_short = "residue number", 
  73      desc = "The residue number." 
  74  ) 
  75  uf.add_keyarg( 
  76      name = "pos", 
  77      py_type = "float_object", 
  78      desc_short = "atomic position", 
  79      desc = "The atomic coordinates." 
  80  ) 
  81  uf.add_keyarg( 
  82      name = "element", 
  83      py_type = "str", 
  84      desc_short = "element", 
  85      desc = "The element name.", 
  86      wiz_element_type = "combo", 
  87      wiz_combo_choices = ["N", "C", "H", "O", "P"], 
  88      can_be_none = True 
  89  ) 
  90  uf.add_keyarg( 
  91      name = "atom_num", 
  92      py_type = "int", 
  93      desc_short = "atom number", 
  94      desc = "The optional atom number.", 
  95      can_be_none = True 
  96  ) 
  97  uf.add_keyarg( 
  98      name = "chain_id", 
  99      py_type = "str", 
 100      desc_short = "optional chain ID", 
 101      desc = "The optional chain ID string.", 
 102      can_be_none = True 
 103  ) 
 104  uf.add_keyarg( 
 105      name = "segment_id", 
 106      py_type = "str", 
 107      desc_short = "optional segment ID", 
 108      desc = "The optional segment ID string.", 
 109      can_be_none = True 
 110  ) 
 111  uf.add_keyarg( 
 112      name = "pdb_record", 
 113      py_type = "str", 
 114      desc_short = "optional PDB record name", 
 115      desc = "The optional PDB record name, e.g. 'ATOM' or 'HETATM'.", 
 116      can_be_none = True 
 117  ) 
 118  # Description. 
 119  uf.desc.append(Desc_container()) 
 120  uf.desc[-1].add_paragraph("This allows atoms to be added to the internal structural object.  To use the same atomic coordinates for all models, the atomic position can be an array of 3 values.  Alternatively different coordinates can be used for each model if the atomic position is a rank-2 array where the first dimension matches the number of models currently present.") 
 121  uf.backend = pipe_control.structure.main.add_atom 
 122  uf.menu_text = "&add_atom" 
 123  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 124  uf.wizard_size = (900, 700) 
 125  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 126   
 127   
 128  # The structure.add_model user function. 
 129  uf = uf_info.add_uf('structure.add_model') 
 130  uf.title = "Add a new model." 
 131  uf.title_short = "Model creation." 
 132  uf.add_keyarg( 
 133      name = "model_num", 
 134      py_type = "int", 
 135      desc_short = "model number", 
 136      desc = "The number of the new model." 
 137  ) 
 138  # Description. 
 139  uf.desc.append(Desc_container()) 
 140  uf.desc[-1].add_paragraph("This allows new models to be added to the internal structural object.  Note that no structural information is allowed to be present") 
 141  uf.backend = pipe_control.structure.main.add_model 
 142  uf.menu_text = "&add_model" 
 143  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 144  uf.wizard_size = (700, 400) 
 145  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 146   
 147   
 148  # The structure.connect_atom user function. 
 149  uf = uf_info.add_uf('structure.connect_atom') 
 150  uf.title = "Connect two atoms." 
 151  uf.title_short = "Atom connection." 
 152  uf.add_keyarg( 
 153      name = "index1", 
 154      py_type = "int", 
 155      max = 10000, 
 156      desc_short = "index 1", 
 157      desc = "The global index of the first atom." 
 158  ) 
 159  uf.add_keyarg( 
 160      name = "index2", 
 161      py_type = "int", 
 162      max = 10000, 
 163      desc_short = "index 2", 
 164      desc = "The global index of the second atom." 
 165  ) 
 166  # Description. 
 167  uf.desc.append(Desc_container()) 
 168  uf.desc[-1].add_paragraph("This allows atoms to be connected in the internal structural object.  The global index is normally equal to the PDB atom number minus 1.") 
 169  uf.backend = pipe_control.structure.main.connect_atom 
 170  uf.menu_text = "co&nnect_atom" 
 171  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 172   
 173   
 174  # The structure.create_diff_tensor_pdb user function. 
 175  uf = uf_info.add_uf('structure.create_diff_tensor_pdb') 
 176  uf.title = "Create a PDB file to represent the diffusion tensor." 
 177  uf.title_short = "Diffusion tensor PDB file creation." 
 178  uf.add_keyarg( 
 179      name = "scale", 
 180      default = 1.8e-6, 
 181      py_type = "num", 
 182      desc_short = "scaling factor", 
 183      desc = "Value for scaling the diffusion rates." 
 184  ) 
 185  uf.add_keyarg( 
 186      name = "file", 
 187      default = "tensor.pdb", 
 188      py_type = "str", 
 189      arg_type = "file sel", 
 190      desc_short = "file name", 
 191      desc = "The name of the PDB file.", 
 192      wiz_filesel_wildcard = "PDB files (*.pdb)|*.pdb;*.PDB", 
 193      wiz_filesel_style = FD_SAVE 
 194  ) 
 195  uf.add_keyarg( 
 196      name = "dir", 
 197      py_type = "str", 
 198      arg_type = "dir", 
 199      desc_short = "directory name", 
 200      desc = "The directory to place the file into.", 
 201      can_be_none = True 
 202  ) 
 203  uf.add_keyarg( 
 204      name = "force", 
 205      default = False, 
 206      py_type = "bool", 
 207      desc_short = "force flag", 
 208      desc = "A flag which, if set to True, will overwrite the any pre-existing file." 
 209  ) 
 210  # Description. 
 211  uf.desc.append(Desc_container()) 
 212  uf.desc[-1].add_paragraph("This creates a PDB file containing an artificial geometric structure to represent the diffusion tensor.  A structure must have previously been read into relax.  The diffusion tensor is represented by an ellipsoidal, spheroidal, or spherical geometric object with its origin located at the centre of mass (of the selected residues).  This diffusion tensor PDB file can subsequently read into any molecular viewer.") 
 213  uf.desc[-1].add_paragraph("There are four different types of residue within the PDB.  The centre of mass of the selected residues is represented as a single carbon atom of the residue 'COM'.  The ellipsoidal geometric shape consists of numerous H atoms of the residue 'TNS'.  The axes of the tensor, when defined, are presented as the residue 'AXS' and consist of carbon atoms: one at the centre of mass and one at the end of each eigenvector.  Finally, if Monte Carlo simulations were run and the diffusion tensor parameters were allowed to vary then there will be multiple 'SIM' residues, one for each simulation.  These are essentially the same as the 'AXS' residue, representing the axes of the simulated tensors, and they will appear as a distribution.") 
 214  uf.desc[-1].add_paragraph("As the Brownian rotational diffusion tensor is a measure of the rate of rotation about different axes - the larger the geometric object, the faster the diffusion of a molecule.  For example the diffusion tensor of a water molecule is much larger than that of a macromolecule.") 
 215  uf.desc[-1].add_paragraph("The effective global correlation time experienced by an XH bond vector, not to be confused with the Lipari and Szabo parameter tau_e, will be approximately proportional to the component of the diffusion tensor parallel to it.  The approximation is not exact due to the multiexponential form of the correlation function of Brownian rotational diffusion.  If an XH bond vector is parallel to the longest axis of the tensor, it will be unaffected by rotations about that axis, which are the fastest rotations of the molecule, and therefore its effective global correlation time will be maximal.") 
 216  uf.desc[-1].add_paragraph("To set the size of the diffusion tensor within the PDB frame the unit vectors used to generate the geometric object are first multiplied by the diffusion tensor (which has the units of inverse seconds) then by the scaling factor (which has the units of second Angstroms and has the default value of 1.8e-6 s.Angstrom).  Therefore the rotational diffusion rate per Angstrom is equal the inverse of the scale value (which defaults to 5.56e5 s^-1.Angstrom^-1).  Using the default scaling value for spherical diffusion, the correspondence between global correlation time, Diso diffusion rate, and the radius of the sphere for a number of discrete cases will be:") 
 217  table = uf_tables.add_table(label="table: diff tensor PDB scaling", caption="Diffusion tensor PDB representation sizes using the default scaling for different diffusion tensors", caption_short="Diffusion tensor PDB scaling.") 
 218  table.add_headings(["tm (ns)", "Diso (s^-1)", "Radius (Angstrom)"]) 
 219  table.add_row(["1", "1.67e8", "300"]) 
 220  table.add_row(["3", "5.56e7", "100"]) 
 221  table.add_row(["10", "1.67e7", "30"]) 
 222  table.add_row(["30", "5.56e6", "10"]) 
 223  uf.desc[-1].add_table(table.label) 
 224  uf.desc[-1].add_paragraph("The scaling value has been fixed to facilitate comparisons within or between publications, but can be changed to vary the size of the tensor geometric object if necessary.  Reporting the rotational diffusion rate per Angstrom within figure legends would be useful.") 
 225  uf.desc[-1].add_paragraph("To create the tensor PDB representation, a number of algorithms are utilised.  Firstly the centre of mass is calculated for the selected residues and is represented in the PDB by a C atom.  Then the axes of the diffusion are calculated, as unit vectors scaled to the appropriate length (multiplied by the eigenvalue Dx, Dy, Dz, Dpar, Dper, or Diso as well as the scale value), and a C atom placed at the position of this vector plus the centre of mass.  Finally a uniform distribution of vectors on a sphere is generated using spherical coordinates.  By incrementing the polar angle using an arccos distribution, a radial array of vectors representing latitude are created while incrementing the azimuthal angle evenly creates the longitudinal vectors.  These unit vectors, which are distributed within the PDB frame and are of 1 Angstrom in length, are first rotated into the diffusion frame using a rotation matrix (the spherical diffusion tensor is not rotated).  Then they are multiplied by the diffusion tensor matrix to extend the vector out to the correct length, and finally multiplied by the scale value so that the vectors reasonably superimpose onto the macromolecular structure.  The last set of algorithms place all this information into a PDB file.  The distribution of vectors are represented by H atoms and are all connected using PDB CONECT records.  Each H atom is connected to its two neighbours on the both the longitude and latitude.  This creates a geometric PDB object with longitudinal and latitudinal lines.") 
 226  uf.backend = pipe_control.structure.main.create_diff_tensor_pdb 
 227  uf.menu_text = "&create_diff_tensor_pdb" 
 228  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 229  uf.wizard_height_desc = 450 
 230  uf.wizard_size = (1000, 750) 
 231  uf.wizard_apply_button = False 
 232  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'create_diff_tensor_pdb.png' 
 233   
 234   
 235  # The structure.create_rotor_pdb user function. 
 236  uf = uf_info.add_uf('structure.create_rotor_pdb') 
 237  uf.title = "Create a PDB file representation of a rotor." 
 238  uf.title_short = "Rotor PDB representation." 
 239  uf.add_keyarg( 
 240      name = "file", 
 241      default = "rotor.pdb", 
 242      py_type = "str", 
 243      arg_type = "file sel", 
 244      desc_short = "file name", 
 245      desc = "The name of the PDB file.", 
 246      wiz_filesel_wildcard = "PDB files (*.pdb)|*.pdb;*.PDB", 
 247      wiz_filesel_style = FD_SAVE 
 248  ) 
 249  uf.add_keyarg( 
 250      name = "dir", 
 251      py_type = "str", 
 252      arg_type = "dir", 
 253      desc_short = "directory name", 
 254      desc = "The directory to place the file into.", 
 255      can_be_none = True 
 256  ) 
 257  uf.add_keyarg( 
 258      name = "rotor_angle", 
 259      default = 0.0, 
 260      py_type = "float", 
 261      desc_short = "rotor angle", 
 262      desc = "The angle of the rotor motion in degrees." 
 263  ) 
 264  uf.add_keyarg( 
 265      name = "axis", 
 266      py_type = "float_array", 
 267      dim = 3, 
 268      desc_short = "rotor axis vector", 
 269      desc = "The vector defining the rotor axis." 
 270  ) 
 271  uf.add_keyarg( 
 272      name = "axis_pt", 
 273      py_type = "float_array", 
 274      dim = 3, 
 275      desc_short = "rotor axis point", 
 276      desc = "A point lying anywhere on the rotor axis.  This is used to define the position of the axis in 3D space." 
 277  ) 
 278  uf.add_keyarg( 
 279      name = "centre", 
 280      py_type = "float_array", 
 281      dim = 3, 
 282      desc_short = "central point", 
 283      desc = "The central point of the representation.  If this point is not on the rotor axis, then the closest point on the axis will be used for the centre." 
 284  ) 
 285  uf.add_keyarg( 
 286      name = "span", 
 287      default = 2e-9, 
 288      py_type = "num", 
 289      desc_short = "representation span", 
 290      desc = "The distance from the central point to the rotor blades (meters)." 
 291  ) 
 292  uf.add_keyarg( 
 293      name = "blade_length", 
 294      default = 5e-10, 
 295      py_type = "num", 
 296      desc_short = "blade length", 
 297      desc = "The length of the representative rotor blades." 
 298  ) 
 299  uf.add_keyarg( 
 300      name = "force", 
 301      default = False, 
 302      py_type = "bool", 
 303      desc_short = "force flag", 
 304      desc = "A flag which if True will overwrite the file if it already exists." 
 305  ) 
 306  uf.add_keyarg( 
 307      name = "staggered", 
 308      default = False, 
 309      py_type = "bool", 
 310      desc_short = "staggered flag", 
 311      desc = "A flag which if True will cause the rotor blades to be staggered.  This is used to avoid blade overlap." 
 312  ) 
 313  # Description. 
 314  uf.desc.append(Desc_container()) 
 315  uf.desc[-1].add_paragraph("This creates a PDB file representation of a rotor motional model.  The model axis is defined by a vector and a single point on the axis.  The centre of the representation will be taken as the point on the rotor axis closest to the given centre position.  The size of the representation is defined by the span, which is the distance from the central point to the rotors, and the length of the blades.") 
 316  # Prompt examples. 
 317  uf.desc.append(Desc_container("Prompt examples")) 
 318  uf.desc[-1].add_paragraph("The following is a synthetic example:") 
 319  uf.desc[-1].add_prompt("relax> structure.create_rotor_pdb(file='rotor.pdb', rotor_angle=20.0, axis=[0., 0., 1.], axis_pt=[1., 1., 0.], centre=[0., 0., 2.], span=2e-9, blade_length=1e-9)") 
 320  uf.backend = pipe_control.structure.geometric.create_rotor_pdb 
 321  uf.menu_text = "create_&rotor_pdb" 
 322  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 323  uf.wizard_height_desc = 400 
 324  uf.wizard_size = (900, 700) 
 325  uf.wizard_apply_button = False 
 326  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 327   
 328   
 329  # The structure.create_vector_dist user function. 
 330  uf = uf_info.add_uf('structure.create_vector_dist') 
 331  uf.title = "Create a PDB file representation of the distribution of XH bond vectors." 
 332  uf.title_short = "XH vector distribution PDB representation." 
 333  uf.add_keyarg( 
 334      name = "length", 
 335      default = 2e-9, 
 336      py_type = "num", 
 337      desc_short = "vector length", 
 338      desc = "The length of the vectors in the PDB representation (meters)." 
 339  ) 
 340  uf.add_keyarg( 
 341      name = "file", 
 342      default = "XH_dist.pdb", 
 343      py_type = "str", 
 344      arg_type = "file sel", 
 345      desc_short = "file name", 
 346      desc = "The name of the PDB file.", 
 347      wiz_filesel_wildcard = "PDB files (*.pdb)|*.pdb;*.PDB", 
 348      wiz_filesel_style = FD_SAVE 
 349  ) 
 350  uf.add_keyarg( 
 351      name = "dir", 
 352      py_type = "str", 
 353      arg_type = "dir", 
 354      desc_short = "directory name", 
 355      desc = "The directory to place the file into.", 
 356      can_be_none = True 
 357  ) 
 358  uf.add_keyarg( 
 359      name = "symmetry", 
 360      default = True, 
 361      py_type = "bool", 
 362      desc_short = "symmetry flag", 
 363      desc = "A flag which if True will create a second chain with reversed XH bond orientations." 
 364  ) 
 365  uf.add_keyarg( 
 366      name = "force", 
 367      default = False, 
 368      py_type = "bool", 
 369      desc_short = "force flag", 
 370      desc = "A flag which if True will overwrite the file if it already exists." 
 371  ) 
 372  # Description. 
 373  uf.desc.append(Desc_container()) 
 374  uf.desc[-1].add_paragraph("This creates a PDB file containing an artificial vectors, the length of which default to 20 Angstrom.  A structure must have previously been read into relax.  The origin of the vector distribution is located at the centre of mass (of the selected residues).  This vector distribution PDB file can subsequently be read into any molecular viewer.") 
 375  uf.desc[-1].add_paragraph("Because of the symmetry of the diffusion tensor reversing the orientation of the XH bond vector has no effect.  Therefore by setting the symmetry flag two chains 'A' and 'B' will be added to the PDB file whereby chain 'B' is chain 'A' with the XH bonds reversed.") 
 376  uf.backend = pipe_control.structure.geometric.create_vector_dist 
 377  uf.menu_text = "cr&eate_vector_dist" 
 378  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 379  uf.wizard_height_desc = 400 
 380  uf.wizard_size = (900, 700) 
 381  uf.wizard_apply_button = False 
 382  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'create_vector_dist.png' 
 383   
 384   
 385  # The structure.get_pos user function. 
 386  uf = uf_info.add_uf('structure.get_pos') 
 387  uf.title = "Extract the atomic positions from the loaded structures for the given spins." 
 388  uf.title_short = "Atomic position extraction." 
 389  uf.add_keyarg( 
 390      name = "spin_id", 
 391      py_type = "str", 
 392      desc_short = "spin ID string", 
 393      desc = "The spin identification string.", 
 394      can_be_none = True 
 395  ) 
 396  uf.add_keyarg( 
 397      name = "ave_pos", 
 398      default = True, 
 399      py_type = "bool", 
 400      desc_short = "average position flag", 
 401      desc = "A flag specifying if the position of the atom is to be averaged across models." 
 402  ) 
 403  # Description. 
 404  uf.desc.append(Desc_container()) 
 405  uf.desc[-1].add_paragraph("This allows the atomic positions of the spins to be extracted from the loaded structures.  This is automatically performed by the structure.load_spins user function, but if the sequence information is generated in other ways, this user function allows the structural information to be obtained.") 
 406  uf.desc[-1].add_paragraph("If averaging the atomic positions, then average position of all models will be loaded into the spin container.  Otherwise the positions from all models will be loaded separately.") 
 407  # Prompt examples. 
 408  uf.desc.append(Desc_container("Prompt examples")) 
 409  uf.desc[-1].add_paragraph("For a model-free backbone amide nitrogen analysis whereby the N spins have already been created, to obtain the backbone N positions from the file '1F3Y.pdb' (which is a single protein), type the following two user functions:") 
 410  uf.desc[-1].add_prompt("relax> structure.read_pdb('1F3Y.pdb')") 
 411  uf.desc[-1].add_prompt("relax> structure.get_pos(spin_id='@N')") 
 412  uf.backend = pipe_control.structure.main.get_pos 
 413  uf.menu_text = "&get_pos" 
 414  uf.wizard_height_desc = 300 
 415  uf.wizard_size = (800, 600) 
 416  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 417   
 418   
 419  # The structure.delete user function. 
 420  uf = uf_info.add_uf('structure.delete') 
 421  uf.title = "Delete structural information." 
 422  uf.title_short = "Structure deletion." 
 423  uf.add_keyarg( 
 424      name = "atom_id", 
 425      py_type = "str", 
 426      desc_short = "atom ID string", 
 427      desc = "The atom identification string.", 
 428      can_be_none = True 
 429  ) 
 430  # Description. 
 431  uf.desc.append(Desc_container()) 
 432  uf.desc[-1].add_paragraph("This will delete structural information from the current data pipe.  All spin and sequence information loaded from these structures will be preserved - this only affects the structural data.  The atom ID argument can be used to restrict deletion to parts of the loaded molecules.") 
 433  # Prompt examples. 
 434  uf.desc.append(Desc_container("Prompt examples")) 
 435  uf.desc[-1].add_paragraph("To delete everything, simply type:") 
 436  uf.desc[-1].add_prompt("relax> structure.delete()") 
 437  uf.desc[-1].add_paragraph("To delete residues 50 to 100 of the molecule called 'Ap4Aase', type one of:") 
 438  uf.desc[-1].add_prompt("relax> structure.delete(':50-100')") 
 439  uf.desc[-1].add_prompt("relax> structure.delete(atom_id=':50-100')") 
 440  uf.backend = pipe_control.structure.main.delete 
 441  uf.menu_text = "&delete" 
 442  uf.gui_icon = "oxygen.actions.list-remove" 
 443  uf.wizard_size = (700, 500) 
 444  uf.wizard_apply_button = False 
 445  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 446   
 447   
 448  # The structure.displacement user function. 
 449  uf = uf_info.add_uf('structure.displacement') 
 450  uf.title = "Determine the rotational and translational displacement between a set of models." 
 451  uf.title_short = "Rotational and translational displacement." 
 452  uf.add_keyarg( 
 453      name = "model_from", 
 454      py_type = "int", 
 455      desc_short = "model from", 
 456      desc = "The optional model number for the starting position of the displacement.", 
 457      can_be_none = True 
 458  ) 
 459  uf.add_keyarg( 
 460      name = "model_to", 
 461      py_type = "int", 
 462      desc_short = "model to", 
 463      desc = "The optional model number for the ending position of the displacement.", 
 464      can_be_none = True 
 465  ) 
 466  uf.add_keyarg( 
 467      name = "atom_id", 
 468      py_type = "str", 
 469      desc_short = "atom identification string", 
 470      desc = "The atom identification string.", 
 471      can_be_none = True 
 472  ) 
 473  uf.add_keyarg( 
 474      name = "centroid", 
 475      py_type = "float_array", 
 476      desc_short = "centroid position", 
 477      desc = "The alternative position of the centroid.", 
 478      can_be_none = True 
 479  ) 
 480  # Description. 
 481  uf.desc.append(Desc_container()) 
 482  uf.desc[-1].add_paragraph("This user function allows the rotational and translational displacement between two models of the same structure to be calculated.  The information will be printed out in various formats and held in the relax data store.  This is directional, so there is a starting and ending position for each displacement.  If the starting and ending models are not specified, then the displacements in all directions between all models will be calculated.") 
 483  uf.desc[-1].add_paragraph("The atom ID, which uses the same notation as the spin ID strings, can be used to restrict the displacement calculation to certain molecules, residues, or atoms.  This is useful if studying domain motions, secondary structure rearrangements, amino acid side chain rotations, etc.") 
 484  uf.desc[-1].add_paragraph("By supplying the position of the centroid, an alternative position than the standard rigid body centre is used as the focal point of the motion.  The allows, for example, a pivot of a rotational domain motion to be specified.  This is not a formally correct algorithm, all translations will be zero, but does give an indication to the amplitude of the pivoting angle.") 
 485  # Prompt examples. 
 486  uf.desc.append(Desc_container("Prompt examples")) 
 487  uf.desc[-1].add_paragraph("To determine the rotational and translational displacements between all sets of models, type:") 
 488  uf.desc[-1].add_prompt("relax> structure.displacement()") 
 489  uf.desc[-1].add_paragraph("To determine the displacement from model 5 to all other models, type:") 
 490  uf.desc[-1].add_prompt("relax> structure.displacement(model_from=5)") 
 491  uf.desc[-1].add_paragraph("To determine the displacement of all models to model 5, type:") 
 492  uf.desc[-1].add_prompt("relax> structure.displacement(model_to=5)") 
 493  uf.desc[-1].add_paragraph("To determine the displacement of model 2 to model 3, type one of:") 
 494  uf.desc[-1].add_prompt("relax> structure.displacement(2, 3)") 
 495  uf.desc[-1].add_prompt("relax> structure.displacement(model_from=2, model_to=3)") 
 496  uf.backend = pipe_control.structure.main.displacement 
 497  uf.menu_text = "displace&ment" 
 498  uf.wizard_height_desc = 400 
 499  uf.wizard_size = (900, 700) 
 500  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 501   
 502   
 503  # The structure.find_pivot user function. 
 504  uf = uf_info.add_uf('structure.find_pivot') 
 505  uf.title = "Find the pivot point of the motion of a set of structures." 
 506  uf.title_short = "Pivot search." 
 507  uf.add_keyarg( 
 508      name = "models", 
 509      py_type = "int_list", 
 510      desc_short = "model list", 
 511      desc = "The list of models to use.", 
 512      can_be_none = True 
 513  ) 
 514  uf.add_keyarg( 
 515      name = "atom_id", 
 516      py_type = "str", 
 517      desc_short = "atom ID string", 
 518      desc = "The atom identification string.", 
 519      can_be_none = True 
 520  ) 
 521  uf.add_keyarg( 
 522      name = "init_pos", 
 523      py_type = "float_array", 
 524      desc_short = "initial pivot position", 
 525      desc = "The initial position of the pivot.", 
 526      can_be_none = True 
 527  ) 
 528  uf.add_keyarg( 
 529      name = "func_tol", 
 530      default = 1e-5, 
 531      py_type = "num", 
 532      desc_short = "function tolerance", 
 533      desc = "The function tolerance.  This is used to terminate minimisation once the function value between iterations is less than the tolerance.  The default value is 1e-5." 
 534  ) 
 535  uf.add_keyarg( 
 536      name = "box_limit", 
 537      default = 200, 
 538      py_type = "int", 
 539      desc_short = "box constraint limit", 
 540      desc = "The pivot point is constrained withing a box of +/- x Angstrom the using the logarithmic barrier function together with simplex optimisation.  This argument is the value of x." 
 541  ) 
 542  # Description. 
 543  uf.desc.append(Desc_container()) 
 544  uf.desc[-1].add_paragraph("This is used to find pivot point of motion between a set of structural models.  If the list of models is not supplied, then all models will be used.") 
 545  uf.desc[-1].add_paragraph("The atom ID, which uses the same notation as the spin ID strings, can be used to restrict the search to certain molecules, residues, or atoms.  For example to only use backbone heavy atoms in a protein, use the atom ID of '@N,C,CA,O', assuming those are the names of the atoms from the structural file.") 
 546  uf.desc[-1].add_paragraph("By supplying the position of the centroid, an alternative position than the standard rigid body centre is used as the focal point of the superimposition.  The allows, for example, the superimposition about a pivot point.") 
 547  uf.backend = pipe_control.structure.main.find_pivot 
 548  uf.menu_text = "&find_pivot" 
 549  uf.wizard_height_desc = 400 
 550  uf.wizard_size = (900, 700) 
 551  uf.wizard_apply_button = False 
 552  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 553   
 554   
 555  # The structure.load_spins user function. 
 556  uf = uf_info.add_uf('structure.load_spins') 
 557  uf.title = "Load spins from the structure into the relax data store." 
 558  uf.title_short = "Loading spins from structure." 
 559  uf.add_keyarg( 
 560      name = "spin_id", 
 561      py_type = "str", 
 562      arg_type = "spin ID", 
 563      desc_short = "spin ID string", 
 564      desc = "The spin identification string for the selective loading of certain spins into the relax data store.", 
 565      wiz_combo_choices = ["@N", "@C", "@H", "@O", "@P", "@NE1", "@HE1", ":A@C2", ":A@C8", ":G@N1", ":G@C8", ":C@C5", ":C@C5", ":U@N3", ":U@C5", ":U@C6"], 
 566      can_be_none = True 
 567  ) 
 568  uf.add_keyarg( 
 569      name = "mol_name_target", 
 570      py_type = "str", 
 571      desc_short = "target molecule name", 
 572      desc = "The name of target molecule container, overriding the name of the loaded structures.", 
 573      can_be_none = True 
 574  ) 
 575  uf.add_keyarg( 
 576      name = "ave_pos", 
 577      default = True, 
 578      py_type = "bool", 
 579      desc_short = "average position flag", 
 580      desc = "A flag specifying if the position of the atom is to be averaged across models." 
 581  ) 
 582  # Description. 
 583  uf.desc.append(Desc_container()) 
 584  uf.desc[-1].add_paragraph("This allows a sequence to be generated within the relax data store using the atomic information from the structure already associated with this data pipe.  The spin ID string is used to select which molecules, which residues, and which atoms will be recognised as spin systems within relax.  If the spin ID is left unspecified, then all molecules, residues, and atoms will be placed within the data store (and all atoms will be treated as spins).") 
 585  uf.desc[-1].add_paragraph("If averaging the atomic positions, then average position of all models will be loaded into the spin container.  Otherwise the positions from all models will be loaded separately.") 
 586  # Prompt examples. 
 587  uf.desc.append(Desc_container("Prompt examples")) 
 588  uf.desc[-1].add_paragraph("For a model-free backbone amide nitrogen analysis, to load just the backbone N sequence from the file '1F3Y.pdb' (which is a single protein), type the following two user functions:") 
 589  uf.desc[-1].add_prompt("relax> structure.read_pdb('1F3Y.pdb')") 
 590  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id='@N')") 
 591  uf.desc[-1].add_paragraph("For an RNA analysis of adenine C8 and C2, guanine C8 and N1, cytidine C5 and C6, and uracil N3, C5, and C6, type the following series of commands (assuming that the PDB file with this atom naming has already been read):") 
 592  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":A@C8\")") 
 593  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":A@C2\")") 
 594  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":G@C8\")") 
 595  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":G@N1\")") 
 596  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":C@C5\")") 
 597  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":C@C6\")") 
 598  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":U@N3\")") 
 599  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":U@C5\")") 
 600  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":U@C6\")") 
 601  uf.desc[-1].add_paragraph("Alternatively using some Python programming:") 
 602  uf.desc[-1].add_prompt("relax> for id in [\":A@C8\", \":A@C2\", \":G@C8\", \":G@N1\", \":C@C5\", \":C@C6\", \":U@N3\", \":U@C5\", \":U@C6\"]:") 
 603  uf.desc[-1].add_prompt("relax>     structure.load_spins(spin_id=id)") 
 604  uf.backend = pipe_control.structure.main.load_spins 
 605  uf.menu_text = "&load_spins" 
 606  uf.gui_icon = "relax.spin" 
 607  uf.wizard_height_desc = 300 
 608  uf.wizard_size = (800, 600) 
 609  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'load_spins.png' 
 610   
 611   
 612  # The structure.read_gaussian user function. 
 613  uf = uf_info.add_uf('structure.read_gaussian') 
 614  uf.title = "Reading structures from Gaussian log files." 
 615  uf.title_short = "Gaussian log structure reading." 
 616  uf.add_keyarg( 
 617      name = "file", 
 618      py_type = "str", 
 619      arg_type = "file sel", 
 620      desc_short = "file name", 
 621      desc = "The name of the Gaussian log file.", 
 622      wiz_filesel_wildcard = "Gaussian log files (*.log)|*.log;*.log.gz;*.log.bz2", 
 623      wiz_filesel_style = FD_OPEN 
 624  ) 
 625  uf.add_keyarg( 
 626      name = "dir", 
 627      py_type = "str", 
 628      arg_type = "dir", 
 629      desc_short = "directory name", 
 630      desc = "The directory where the file is located.", 
 631      can_be_none = True 
 632  ) 
 633  uf.add_keyarg( 
 634      name = "set_mol_name", 
 635      py_type = "str_or_str_list", 
 636      desc_short = "setting of molecule names", 
 637      desc = "Set the names of the read molecules.  If unset, then the molecules will be automatically labelled based on the file name or other information.  This can either be a single name or a list of names.", 
 638      can_be_none = True 
 639  ) 
 640  uf.add_keyarg( 
 641      name = "set_model_num", 
 642      py_type = "int_or_int_list", 
 643      desc_short = "setting of model numbers", 
 644      desc = "Set the model numbers of the loaded molecules.  This can be a single number or list of numbers.", 
 645      can_be_none = True 
 646  ) 
 647  # Description. 
 648  uf.desc.append(Desc_container()) 
 649  uf.desc[-1].add_paragraph("The atomic positions from a Gaussian log file can be read into relax.  If optimisation has been preformed, the last set of atomic coordinates from the log will be read to obtain the final structure.  The log file can be Gzip or Bzip2 compressed.") 
 650  uf.desc[-1].add_paragraph("The setting of molecule names is used to name the molecules within the Gaussian file.  If not set, then the molecules will be named after the file name, with the molecule number appended if more than one exists.  By setting the molecule name or setting the model number, the loaded structure can be stored as a specific model or as a different molecule.") 
 651  # Prompt examples. 
 652  uf.desc.append(Desc_container("Prompt examples")) 
 653  uf.desc[-1].add_paragraph("To load all structures from the Gaussian file 'taxol.log' in the directory '~/logs', including all models and all molecules, type one of:") 
 654  uf.desc[-1].add_prompt("relax> structure.read_gaussian('taxol.log', '~/logs')") 
 655  uf.desc[-1].add_prompt("relax> structure.read_gaussian(file='taxol.log', dir=logs')") 
 656  uf.backend = pipe_control.structure.main.read_gaussian 
 657  uf.menu_text = "read_&gaussian" 
 658  uf.gui_icon = "oxygen.actions.document-open" 
 659  uf.wizard_height_desc = 400 
 660  uf.wizard_size = (900, 600) 
 661  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'read_xyz.png' 
 662   
 663   
 664  # The structure.read_pdb user function. 
 665  uf = uf_info.add_uf('structure.read_pdb') 
 666  uf.title = "Reading structures from PDB files." 
 667  uf.title_short = "PDB reading." 
 668  uf.add_keyarg( 
 669      name = "file", 
 670      py_type = "str", 
 671      arg_type = "file sel", 
 672      desc_short = "file name", 
 673      desc = "The name of the PDB file.", 
 674      wiz_filesel_wildcard = "PDB files (*.pdb)|*.pdb;*.PDB", 
 675      wiz_filesel_style = FD_OPEN 
 676  ) 
 677  uf.add_keyarg( 
 678      name = "dir", 
 679      py_type = "str", 
 680      arg_type = "dir", 
 681      desc_short = "directory name", 
 682      desc = "The directory where the file is located.", 
 683      can_be_none = True 
 684  ) 
 685  uf.add_keyarg( 
 686      name = "read_mol", 
 687      py_type = "int_or_int_list", 
 688      desc_short = "molecule number to read", 
 689      desc = "If set, only the given molecule(s) will be read.  The molecules are numbered consecutively from 1.  If unset, then all molecules will be loaded.  By providing a list of numbers such as [1, 2], multiple molecules will be read.", 
 690      can_be_none = True 
 691  ) 
 692  uf.add_keyarg( 
 693      name = "set_mol_name", 
 694      py_type = "str_or_str_list", 
 695      desc_short = "setting of molecule names", 
 696      desc = "Set the names of the read molecules.  If unset, then the molecules will be automatically labelled based on the file name or other information.  This can either be a single name or a list of names.", 
 697      can_be_none = True 
 698  ) 
 699  uf.add_keyarg( 
 700      name = "read_model", 
 701      py_type = "int_or_int_list", 
 702      desc_short = "model to read", 
 703      desc = "If set, only the given model number(s) from the PDB file will be read.  Otherwise all models will be read.  This can be a single number or list of numbers.", 
 704      can_be_none = True 
 705  ) 
 706  uf.add_keyarg( 
 707      name = "set_model_num", 
 708      py_type = "int_or_int_list", 
 709      desc_short = "setting of model numbers", 
 710      desc = "Set the model numbers of the loaded molecules.  If unset, then the PDB model numbers will be preserved if they exist.  This can be a single number or list of numbers.", 
 711      can_be_none = True 
 712  ) 
 713  uf.add_keyarg( 
 714      name = "alt_loc", 
 715      py_type = "str", 
 716      desc_short = "alternate location indicator", 
 717      desc = "The PDB ATOM record 'Alternate location indicator' field value.", 
 718      can_be_none = True 
 719  ) 
 720  uf.add_keyarg( 
 721      name = "merge", 
 722      default = False, 
 723      py_type = "bool", 
 724      desc_short = "merge structure flag", 
 725      desc = "A flag which if set to True will try to merge the PDB structure into the currently loaded structures." 
 726  ) 
 727  # Description. 
 728  uf.desc.append(Desc_container()) 
 729  uf.desc[-1].add_paragraph("The reading of PDB files into relax is quite a flexible procedure allowing for both models, defined as an ensemble of the same molecule but with different atomic positions, and different molecules within the same model.  One of more molecules can exist in one or more models.  The flexibility allows PDB models to be converted into different molecules and different PDB files loaded as the same molecule but as different models.") 
 730  uf.desc[-1].add_paragraph("In a PDB file, the models are specified by the MODEL PDB record.  All the supported PDB readers in relax recognise this.  The internal reader defines molecules using the TER PDB record.  In both cases, the molecules will be numbered consecutively from 1.") 
 731  uf.desc[-1].add_paragraph("Setting the molecule name allows the molecule within the PDB (within one model) to have a custom name.  If not set, then the molecules will be named after the file name, with the molecule number appended if more than one exists.") 
 732  uf.desc[-1].add_paragraph("Note that relax will complain if it cannot work out what to do.") 
 733  uf.desc[-1].add_paragraph("This is able to handle uncompressed, bzip2 compressed files, or gzip compressed files automatically.  The full file name including extension can be supplied, however, if the file cannot be found, this function will search for the file name with '.bz2' appended followed by the file name with '.gz' appended.") 
 734  uf.desc[-1].add_paragraph("If a PDB file contains alternative atomic locations, then the alternate location indicator must be specified to allow one of the multiple coordinate sets to be select.") 
 735  # Prompt examples. 
 736  uf.desc.append(Desc_container("Prompt examples")) 
 737  uf.desc[-1].add_paragraph("To load all structures from the PDB file 'test.pdb' in the directory '~/pdb', including all models and all molecules, type one of:") 
 738  uf.desc[-1].add_prompt("relax> structure.read_pdb('test.pdb', '~/pdb')") 
 739  uf.desc[-1].add_prompt("relax> structure.read_pdb(file='test.pdb', dir='pdb')") 
 740  uf.desc[-1].add_paragraph("To load the 10th model from the file 'test.pdb' and naming it 'CaM', use one of:") 
 741  uf.desc[-1].add_prompt("relax> structure.read_pdb('test.pdb', read_model=10, set_mol_name='CaM')") 
 742  uf.desc[-1].add_prompt("relax> structure.read_pdb(file='test.pdb', read_model=10, set_mol_name='CaM')") 
 743  uf.desc[-1].add_paragraph("To load models 1 and 5 from the file 'test.pdb' as two different structures of the same model, type one of:") 
 744  uf.desc[-1].add_prompt("relax> structure.read_pdb('test.pdb', read_model=[1, 5], set_model_num=[1, 1])") 
 745  uf.desc[-1].add_prompt("relax> structure.read_pdb('test.pdb', set_mol_name=['CaM_1', 'CaM_2'], read_model=[1, 5], set_model_num=[1, 1])") 
 746  uf.desc[-1].add_paragraph("To load the files 'lactose_MCMM4_S1_1.pdb', 'lactose_MCMM4_S1_2.pdb', 'lactose_MCMM4_S1_3.pdb' and 'lactose_MCMM4_S1_4.pdb' as models, type the following sequence of commands:") 
 747  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_1.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=1)") 
 748  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_2.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=2)") 
 749  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_3.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=3)") 
 750  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_4.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=4)") 
 751  uf.backend = pipe_control.structure.main.read_pdb 
 752  uf.menu_text = "read_&pdb" 
 753  uf.gui_icon = "oxygen.actions.document-open" 
 754  uf.wizard_height_desc = 360 
 755  uf.wizard_size = (1000, 750) 
 756  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'read_pdb.png' 
 757   
 758   
 759  # The structure.read_xyz user function. 
 760  uf = uf_info.add_uf('structure.read_xyz') 
 761  uf.title = "Reading structures from XYZ files." 
 762  uf.title_short = "XYZ reading." 
 763  uf.add_keyarg( 
 764      name = "file", 
 765      py_type = "str", 
 766      arg_type = "file sel", 
 767      desc_short = "file name", 
 768      desc = "The name of the XYZ file.", 
 769      wiz_filesel_wildcard = "XYZ files (*.xyz)|*.xyz;*.XYZ", 
 770      wiz_filesel_style = FD_OPEN 
 771  ) 
 772  uf.add_keyarg( 
 773      name = "dir", 
 774      py_type = "str", 
 775      arg_type = "dir", 
 776      desc_short = "directory name", 
 777      desc = "The directory where the file is located.", 
 778      can_be_none = True 
 779  ) 
 780  uf.add_keyarg( 
 781      name = "read_mol", 
 782      py_type = "int_or_int_list", 
 783      desc_short = "molecule number to read", 
 784      desc = "If set, only the given molecule(s) will be read.  The molecules are numbered consecutively from 1.  If unset, then all molecules will be loaded.  By providing a list of numbers such as [1, 2], multiple molecules will be read.", 
 785      can_be_none = True 
 786  ) 
 787  uf.add_keyarg( 
 788      name = "set_mol_name", 
 789      py_type = "str_or_str_list", 
 790      desc_short = "setting of molecule names", 
 791      desc = "Set the names of the read molecules.  If unset, then the molecules will be automatically labelled based on the file name or other information.  This can either be a single name or a list of names.", 
 792      can_be_none = True 
 793  ) 
 794  uf.add_keyarg( 
 795      name = "read_model", 
 796      py_type = "int_or_int_list", 
 797      desc_short = "model to read", 
 798      desc = "If set, only the given model number(s) from the PDB file will be read.  Otherwise all models will be read.  This can be a single number or list of numbers.", 
 799      can_be_none = True 
 800  ) 
 801  uf.add_keyarg( 
 802      name = "set_model_num", 
 803      py_type = "int_or_int_list", 
 804      desc_short = "setting of model numbers", 
 805      desc = "Set the model numbers of the loaded molecules.  If unset, then the PDB model numbers will be preserved if they exist.  This can be a single number or list of numbers.", 
 806      can_be_none = True 
 807  ) 
 808  # Description. 
 809  uf.desc.append(Desc_container()) 
 810  uf.desc[-1].add_paragraph("The XYZ files with different models, which defined as an ensemble of the same molecule but with different atomic positions, can be read into relax.  If there are several molecules in one xyz file, please separate them into different files and then load them individually.  Loading different models and different molecules is controlled by specifying the molecule number read, setting the molecule names, specifying which model to read, and setting the model numbers.") 
 811  uf.desc[-1].add_paragraph("The setting of molecule names is used to name the molecules within the XYZ (within one model).  If not set, then the molecules will be named after the file name, with the molecule number appended if more than one exists.") 
 812  uf.desc[-1].add_paragraph("Note that relax will complain if it cannot work out what to do.") 
 813  # Prompt examples. 
 814  uf.desc.append(Desc_container("Prompt examples")) 
 815  uf.desc[-1].add_paragraph("To load all structures from the XYZ file 'test.xyz' in the directory '~/xyz', including all models and all molecules, type one of:") 
 816  uf.desc[-1].add_prompt("relax> structure.read_xyz('test.xyz', '~/xyz')") 
 817  uf.desc[-1].add_prompt("relax> structure.read_xyz(file='test.xyz', dir='xyz')") 
 818  uf.desc[-1].add_paragraph("To load the 10th model from the file 'test.xyz' and naming it 'CaM', use one of:") 
 819  uf.desc[-1].add_prompt("relax> structure.read_xyz('test.xyz', read_model=10, set_mol_name='CaM')") 
 820  uf.desc[-1].add_prompt("relax> structure.read_xyz(file='test.xyz', read_model=10, set_mol_name='CaM')") 
 821  uf.desc[-1].add_paragraph("To load models 1 and 5 from the file 'test.xyz' as two different structures of the same model, type one of:") 
 822  uf.desc[-1].add_prompt("relax> structure.read_xyz('test.xyz', read_model=[1, 5], set_model_num=[1, 1])") 
 823  uf.desc[-1].add_prompt("relax> structure.read_xyz('test.xyz', set_mol_name=['CaM_1', 'CaM_2'], read_model=[1, 5], set_model_num=[1, 1])") 
 824  uf.desc[-1].add_paragraph("To load the files 'test_1.xyz', 'test_2.xyz', 'test_3.xyz' and 'test_4.xyz' as models, type the  following sequence of commands:") 
 825  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_1.xyz', set_mol_name='test_1', set_model_num=1)") 
 826  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_2.xyz', set_mol_name='test_2', set_model_num=2)") 
 827  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_3.xyz', set_mol_name='test_3', set_model_num=3)") 
 828  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_4.xyz', set_mol_name='test_4', set_model_num=4)") 
 829  uf.backend = pipe_control.structure.main.read_xyz 
 830  uf.menu_text = "read_&xyz" 
 831  uf.gui_icon = "oxygen.actions.document-open" 
 832  uf.wizard_height_desc = 400 
 833  uf.wizard_size = (900, 700) 
 834  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'read_xyz.png' 
 835   
 836   
 837  # The structure.rmsd user function. 
 838  uf = uf_info.add_uf('structure.rmsd') 
 839  uf.title = "Determine the RMSD between the models." 
 840  uf.title_short = "Structural RMSD." 
 841  uf.add_keyarg( 
 842      name = "atom_id", 
 843      py_type = "str", 
 844      desc_short = "atom identification string", 
 845      desc = "The atom identification string.", 
 846      can_be_none = True 
 847  ) 
 848  # Description. 
 849  uf.desc.append(Desc_container()) 
 850  uf.desc[-1].add_paragraph("This allows the root mean squared deviation (RMSD) between all models to be calculated.") 
 851  uf.desc[-1].add_paragraph("The atom ID, which uses the same notation as the spin ID strings, can be used to restrict the RMSD calculation to certain molecules, residues, or atoms.") 
 852  # Prompt examples. 
 853  uf.desc.append(Desc_container("Prompt examples")) 
 854  uf.desc[-1].add_paragraph("To determine the RMSD, simply type:") 
 855  uf.desc[-1].add_prompt("relax> structure.rmsd()") 
 856  uf.backend = pipe_control.structure.main.rmsd 
 857  uf.menu_text = "&rmsd" 
 858  uf.wizard_size = (700, 500) 
 859  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 860   
 861   
 862  # The structure.rotate user function. 
 863  uf = uf_info.add_uf('structure.rotate') 
 864  uf.title = "Rotate the internal structural object about the given origin by the rotation matrix." 
 865  uf.title_short = "Structure rotation." 
 866  uf.add_keyarg( 
 867      name = "R", 
 868      py_type = "float_matrix", 
 869      default = eye(3), 
 870      dim = (3, 3), 
 871      desc_short = "rotation matrix", 
 872      desc = "The rotation matrix in forwards rotation notation." 
 873  ) 
 874  uf.add_keyarg( 
 875      name = "origin", 
 876      py_type = "float_array", 
 877      dim = 3, 
 878      desc_short = "origin of rotation", 
 879      desc = "The origin or pivot of the rotation.", 
 880      can_be_none = True 
 881  ) 
 882  uf.add_keyarg( 
 883      name = "model", 
 884      py_type = "int", 
 885      desc_short = "model", 
 886      desc = "The model to rotate (which if not set will cause all models to be rotated).", 
 887      can_be_none = True 
 888  ) 
 889  uf.add_keyarg( 
 890      name = "atom_id", 
 891      py_type = "str", 
 892      desc_short = "atom ID string", 
 893      desc = "The atom identification string.", 
 894      can_be_none = True 
 895  ) 
 896  # Description. 
 897  uf.desc.append(Desc_container()) 
 898  uf.desc[-1].add_paragraph("This is used to rotate the internal structural data by the given rotation matrix.  If the origin is supplied, then this will act as the pivot of the rotation.  Otherwise, all structural data will be rotated about the point [0, 0, 0].  The rotation can be restricted to one specific model.") 
 899  uf.backend = pipe_control.structure.main.rotate 
 900  uf.menu_text = "&rotate" 
 901  uf.wizard_height_desc = 300 
 902  uf.wizard_size = (800, 600) 
 903  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 904   
 905   
 906  # The structure.superimpose user function. 
 907  uf = uf_info.add_uf('structure.superimpose') 
 908  uf.title = "Superimpose a set of models of the same structure." 
 909  uf.title_short = "Structural superimposition." 
 910  uf.add_keyarg( 
 911      name = "models", 
 912      py_type = "int_list", 
 913      desc_short = "model list", 
 914      desc = "The list of models to superimpose.", 
 915      can_be_none = True 
 916  ) 
 917  uf.add_keyarg( 
 918      name = "method", 
 919      default = "fit to mean", 
 920      py_type = "str", 
 921      desc_short = "superimposition method", 
 922      desc = "The superimposition method.", 
 923      wiz_element_type = "combo", 
 924      wiz_combo_choices = ["fit to mean", "fit to first"], 
 925      wiz_read_only = True 
 926  ) 
 927  uf.add_keyarg( 
 928      name = "atom_id", 
 929      py_type = "str", 
 930      desc_short = "atom ID string", 
 931      desc = "The atom identification string.", 
 932      can_be_none = True 
 933  ) 
 934  uf.add_keyarg( 
 935      name = "centroid", 
 936      py_type = "float_array", 
 937      desc_short = "centroid position", 
 938      desc = "The alternative position of the centroid.", 
 939      can_be_none = True 
 940  ) 
 941  # Description. 
 942  uf.desc.append(Desc_container()) 
 943  uf.desc[-1].add_paragraph("This allows a set of models of the same structure to be superimposed to each other.  Two superimposition methods are currently supported:") 
 944  uf.desc[-1].add_item_list_element("'fit to mean'", "All models are fit to the mean structure.  This is the default and most accurate method for an ensemble description.  It is an iterative method which first calculates a mean structure and then fits each model to the mean structure using the Kabsch algorithm.  This is repeated until convergence.") 
 945  uf.desc[-1].add_item_list_element("'fit to first'", "This is quicker but is not as accurate for an ensemble description.  The Kabsch algorithm is used to rotate and translate each model to be superimposed onto the first model.") 
 946  uf.desc[-1].add_paragraph("If the list of models is not supplied, then all models will be superimposed.") 
 947  uf.desc[-1].add_paragraph("The atom ID, which uses the same notation as the spin ID strings, can be used to restrict the superimpose calculation to certain molecules, residues, or atoms.  For example to only superimpose backbone heavy atoms in a protein, use the atom ID of '@N,C,CA,O', assuming those are the names of the atoms from the structural file.") 
 948  uf.desc[-1].add_paragraph("By supplying the position of the centroid, an alternative position than the standard rigid body centre is used as the focal point of the superimposition.  The allows, for example, the superimposition about a pivot point.") 
 949  # Prompt examples. 
 950  uf.desc.append(Desc_container("Prompt examples")) 
 951  uf.desc[-1].add_paragraph("To superimpose all sets of models, type one of:") 
 952  uf.desc[-1].add_prompt("relax> structure.superimpose()") 
 953  uf.desc[-1].add_prompt("relax> structure.superimpose(method='fit to mean')") 
 954  uf.desc[-1].add_paragraph("To superimpose the models 1, 2, 3, 5 onto model 4, type:") 
 955  uf.desc[-1].add_prompt("relax> structure.superimpose(models=[4, 1, 2, 3, 5], method='fit to first')") 
 956  uf.desc[-1].add_paragraph("To superimpose an ensemble of protein structures using only the backbone heavy atoms, type one of:") 
 957  uf.desc[-1].add_prompt("relax> structure.superimpose(atom_id='@N,C,CA,O')") 
 958  uf.desc[-1].add_prompt("relax> structure.superimpose(method='fit to mean', atom_id='@N,C,CA,O')") 
 959  uf.desc[-1].add_paragraph("To superimpose model 2 onto model 3 using backbone heavy atoms, type one of:") 
 960  uf.desc[-1].add_prompt("relax> structure.superimpose([3, 2], 'fit to first', '@N,C,CA,O')") 
 961  uf.desc[-1].add_prompt("relax> structure.superimpose(models=[3, 2], method='fit to first', atom_id='@N,C,CA,O')") 
 962  uf.backend = pipe_control.structure.main.superimpose 
 963  uf.menu_text = "&superimpose" 
 964  uf.wizard_apply_button = False 
 965  uf.wizard_height_desc = 450 
 966  uf.wizard_size = (1000, 750) 
 967  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 968   
 969   
 970  # The structure.translate user function. 
 971  uf = uf_info.add_uf('structure.translate') 
 972  uf.title = "Laterally displace the internal structural object by the translation vector." 
 973  uf.title_short = "Structure translation." 
 974  uf.add_keyarg( 
 975      name = "T", 
 976      py_type = "float_array", 
 977      dim = 3, 
 978      desc_short = "translation vector", 
 979      desc = "The translation vector." 
 980  ) 
 981  uf.add_keyarg( 
 982      name = "model", 
 983      py_type = "int", 
 984      desc_short = "model", 
 985      desc = "The model to translate (which if not set will cause all models to be translate).", 
 986      can_be_none = True 
 987  ) 
 988  uf.add_keyarg( 
 989      name = "atom_id", 
 990      py_type = "str", 
 991      desc_short = "atom ID string", 
 992      desc = "The atom identification string.", 
 993      can_be_none = True 
 994  ) 
 995  # Description. 
 996  uf.desc.append(Desc_container()) 
 997  uf.desc[-1].add_paragraph("This is used to translate the internal structural data by the given translation vector.  The translation can be restricted to one specific model.") 
 998  uf.backend = pipe_control.structure.main.translate 
 999  uf.menu_text = "&translate" 
1000  uf.wizard_size = (750, 500) 
1001  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1002   
1003   
1004  # The structure.web_of_motion user function. 
1005  uf = uf_info.add_uf('structure.web_of_motion') 
1006  uf.title = "Create a PDB representation of motion between models using a web of interconnecting lines." 
1007  uf.title_short = "Web of motion between models." 
1008  uf.add_keyarg( 
1009      name = "file", 
1010      py_type = "str_or_inst", 
1011      arg_type = "file sel", 
1012      desc_short = "file name", 
1013      desc = "The name of the PDB file.", 
1014      wiz_filesel_wildcard = "PDB files (*.pdb)|*.pdb;*.PDB", 
1015      wiz_filesel_style = FD_SAVE 
1016  ) 
1017  uf.add_keyarg( 
1018      name = "dir", 
1019      py_type = "str", 
1020      arg_type = "dir", 
1021      desc_short = "directory name", 
1022      desc = "The directory to save the file to.", 
1023      can_be_none = True 
1024  ) 
1025  uf.add_keyarg( 
1026      name = "models", 
1027      py_type = "int_list", 
1028      desc_short = "model numbers", 
1029      desc = "Restrict the web to a subset of models.", 
1030      can_be_none = True 
1031  ) 
1032  uf.add_keyarg( 
1033      name = "force", 
1034      default = False, 
1035      py_type = "bool", 
1036      desc_short = "force flag", 
1037      desc = "A flag which if set to True will cause any pre-existing files to be overwritten." 
1038  ) 
1039  # Description. 
1040  uf.desc.append(Desc_container()) 
1041  uf.desc[-1].add_paragraph("This will create a PDB representation of the motion between the atoms of a given set of structural models.  Identical atoms of the selected models are concatenated into one model, within a temporary internal structural object, and linked together using PDB CONECT records.") 
1042  # Prompt examples. 
1043  uf.desc.append(Desc_container("Prompt examples")) 
1044  uf.desc[-1].add_paragraph("To create a web of motion for the models 1, 3, and 5, type one of:") 
1045  uf.desc[-1].add_prompt("relax> structure.web_of_motion('web.pdb', '.', [1, 3, 5])") 
1046  uf.desc[-1].add_prompt("relax> structure.web_of_motion(file='web.pdb', models=[1, 3, 5])") 
1047  uf.desc[-1].add_prompt("relax> structure.web_of_motion(file='web.pdb', dir='.', models=[1, 3, 5])") 
1048  uf.backend = pipe_control.structure.main.web_of_motion 
1049  uf.menu_text = "&web_of_motion" 
1050  uf.wizard_size = (900, 600) 
1051  uf.wizard_apply_button = False 
1052  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1053   
1054   
1055  # The structure.write_pdb user function. 
1056  uf = uf_info.add_uf('structure.write_pdb') 
1057  uf.title = "Writing structures to a PDB file." 
1058  uf.title_short = "PDB writing." 
1059  uf.add_keyarg( 
1060      name = "file", 
1061      py_type = "str_or_inst", 
1062      arg_type = "file sel", 
1063      desc_short = "file name", 
1064      desc = "The name of the PDB file.", 
1065      wiz_filesel_wildcard = "PDB files (*.pdb)|*.pdb;*.PDB", 
1066      wiz_filesel_style = FD_SAVE 
1067  ) 
1068  uf.add_keyarg( 
1069      name = "dir", 
1070      py_type = "str", 
1071      arg_type = "dir", 
1072      desc_short = "directory name", 
1073      desc = "The directory where the file is located.", 
1074      can_be_none = True 
1075  ) 
1076  uf.add_keyarg( 
1077      name = "model_num", 
1078      py_type = "int", 
1079      desc_short = "model number", 
1080      desc = "Restrict the writing of structural data to a single model in the PDB file.", 
1081      can_be_none = True 
1082  ) 
1083  uf.add_keyarg( 
1084      name = "compress_type", 
1085      default = 0, 
1086      py_type = "int", 
1087      desc_short = "compression type", 
1088      desc = "The type of compression to use when creating the file.", 
1089      wiz_element_type = "combo", 
1090      wiz_combo_choices = [ 
1091          "No compression", 
1092          "bzip2 compression", 
1093          "gzip compression" 
1094      ], 
1095      wiz_combo_data = [ 
1096          0, 
1097          1, 
1098          2 
1099      ], 
1100      wiz_read_only = True 
1101  ) 
1102  uf.add_keyarg( 
1103      name = "force", 
1104      default = False, 
1105      py_type = "bool", 
1106      desc_short = "force flag", 
1107      desc = "A flag which if set to True will cause any pre-existing files to be overwritten." 
1108  ) 
1109  # Description. 
1110  uf.desc.append(Desc_container()) 
1111  uf.desc[-1].add_paragraph("This will write all of the structural data loaded in the current data pipe to be converted to the PDB format and written to file.  Specifying the model number allows single models to be output.") 
1112  uf.desc[-1].add_paragraph("The default behaviour of this function is to not compress the file.  The compression can, however, be changed to either bzip2 or gzip compression.  If the '.bz2' or '.gz' extension is not included in the file name, it will be added.  This behaviour is controlled by the compression type which can be set to") 
1113  uf.desc[-1].add_item_list_element("0", "No compression (no file extension).") 
1114  uf.desc[-1].add_item_list_element("1", "bzip2 compression ('.bz2' file extension).") 
1115  uf.desc[-1].add_item_list_element("2", "gzip compression ('.gz' file extension).") 
1116  # Prompt examples. 
1117  uf.desc.append(Desc_container("Prompt examples")) 
1118  uf.desc[-1].add_paragraph("To write all models and molecules to the PDB file 'ensemble.pdb' within the directory '~/pdb', type one of:") 
1119  uf.desc[-1].add_prompt("relax> structure.write_pdb('ensemble.pdb', '~/pdb')") 
1120  uf.desc[-1].add_prompt("relax> structure.write_pdb(file='ensemble.pdb', dir='pdb')") 
1121  uf.desc[-1].add_paragraph("To write model number 3 into the new file 'test.pdb', use one of:") 
1122  uf.desc[-1].add_prompt("relax> structure.write_pdb('test.pdb', model_num=3)") 
1123  uf.desc[-1].add_prompt("relax> structure.write_pdb(file='test.pdb', model_num=3)") 
1124  uf.backend = pipe_control.structure.main.write_pdb 
1125  uf.menu_text = "&write_pdb" 
1126  uf.gui_icon = "oxygen.actions.document-save" 
1127  uf.wizard_height_desc = 400 
1128  uf.wizard_size = (900, 700) 
1129  uf.wizard_apply_button = False 
1130  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'write_pdb.png' 
1131