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

Source Code for Module user_functions.structure

   1  ############################################################################### 
   2  #                                                                             # 
   3  # Copyright (C) 2003-2014 Edward d'Auvergne                                   # 
   4  #                                                                             # 
   5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
   6  #                                                                             # 
   7  # This program is free software: you can redistribute it and/or modify        # 
   8  # it under the terms of the GNU General Public License as published by        # 
   9  # the Free Software Foundation, either version 3 of the License, or           # 
  10  # (at your option) any later version.                                         # 
  11  #                                                                             # 
  12  # This program is distributed in the hope that it will be useful,             # 
  13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
  14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
  15  # GNU General Public License for more details.                                # 
  16  #                                                                             # 
  17  # You should have received a copy of the GNU General Public License           # 
  18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
  19  #                                                                             # 
  20  ############################################################################### 
  21   
  22  # Module docstring. 
  23  """The 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  from user_functions.wildcards import WILDCARD_STRUCT_GAUSSIAN_ALL, WILDCARD_STRUCT_PDB_ALL, WILDCARD_STRUCT_XYZ_ALL 
  43   
  44   
  45  # The user function class. 
  46  uf_class = uf_info.add_class('structure') 
  47  uf_class.title = "Class containing the structural related functions." 
  48  uf_class.menu_text = "&structure" 
  49  uf_class.gui_icon = "relax.structure" 
  50   
  51   
  52  # The structure.add_atom user function. 
  53  uf = uf_info.add_uf('structure.add_atom') 
  54  uf.title = "Add an atom." 
  55  uf.title_short = "Atom creation." 
  56  uf.add_keyarg( 
  57      name = "atom_name", 
  58      py_type = "str", 
  59      desc_short = "atom name", 
  60      desc = "The atom name." 
  61  ) 
  62  uf.add_keyarg( 
  63      name = "res_name", 
  64      py_type = "str", 
  65      desc_short = "residue name", 
  66      desc = "The residue name." 
  67  ) 
  68  uf.add_keyarg( 
  69      name = "res_num", 
  70      py_type = "int", 
  71      min = -10000, 
  72      max = 10000, 
  73      desc_short = "residue number", 
  74      desc = "The residue number." 
  75  ) 
  76  uf.add_keyarg( 
  77      name = "pos", 
  78      py_type = "float_object", 
  79      dim = 3, 
  80      desc_short = "atomic position", 
  81      desc = "The atomic coordinates.", 
  82      list_titles = ['X coordinate', 'Y coordinate', 'Z coordinate'] 
  83  ) 
  84  uf.add_keyarg( 
  85      name = "element", 
  86      py_type = "str", 
  87      desc_short = "element", 
  88      desc = "The element name.", 
  89      wiz_element_type = "combo", 
  90      wiz_combo_choices = ["N", "C", "H", "O", "P"], 
  91      can_be_none = True 
  92  ) 
  93  uf.add_keyarg( 
  94      name = "atom_num", 
  95      py_type = "int", 
  96      desc_short = "atom number", 
  97      desc = "The optional atom number.", 
  98      can_be_none = True 
  99  ) 
 100  uf.add_keyarg( 
 101      name = "chain_id", 
 102      py_type = "str", 
 103      desc_short = "optional chain ID", 
 104      desc = "The optional chain ID string.", 
 105      can_be_none = True 
 106  ) 
 107  uf.add_keyarg( 
 108      name = "segment_id", 
 109      py_type = "str", 
 110      desc_short = "optional segment ID", 
 111      desc = "The optional segment ID string.", 
 112      can_be_none = True 
 113  ) 
 114  uf.add_keyarg( 
 115      name = "pdb_record", 
 116      py_type = "str", 
 117      desc_short = "optional PDB record name", 
 118      desc = "The optional PDB record name, e.g. 'ATOM' or 'HETATM'.", 
 119      can_be_none = True 
 120  ) 
 121  # Description. 
 122  uf.desc.append(Desc_container()) 
 123  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.") 
 124  uf.backend = pipe_control.structure.main.add_atom 
 125  uf.menu_text = "&add_atom" 
 126  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 127  uf.wizard_size = (900, 700) 
 128  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 129   
 130   
 131  # The structure.add_model user function. 
 132  uf = uf_info.add_uf('structure.add_model') 
 133  uf.title = "Add a new model." 
 134  uf.title_short = "Model creation." 
 135  uf.add_keyarg( 
 136      name = "model_num", 
 137      py_type = "int", 
 138      desc_short = "model number", 
 139      desc = "The number of the new model." 
 140  ) 
 141  # Description. 
 142  uf.desc.append(Desc_container()) 
 143  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") 
 144  uf.backend = pipe_control.structure.main.add_model 
 145  uf.menu_text = "&add_model" 
 146  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 147  uf.wizard_size = (700, 400) 
 148  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 149   
 150   
 151  # The structure.com user function. 
 152  uf = uf_info.add_uf('structure.com') 
 153  uf.title = "Calculate the centre of mass for all structures." 
 154  uf.title_short = "Centre of mass calculation." 
 155  uf.add_keyarg( 
 156      name = "model", 
 157      py_type = "int", 
 158      desc_short = "model", 
 159      desc = "The optional structural model number to restrict the calculation of the centre of mass to.", 
 160      can_be_none = True 
 161  ) 
 162  # Description. 
 163  uf.desc.append(Desc_container()) 
 164  uf.desc[-1].add_paragraph("This user function will calculate the centre of mass (CoM) for all loaded structures, printing out the position and storing it in the current data pipe.") 
 165  # Prompt examples. 
 166  uf.desc.append(Desc_container("Prompt examples")) 
 167  uf.desc[-1].add_paragraph("To determine the centre of mass of all structure, simply type:") 
 168  uf.desc[-1].add_prompt("relax> structure.com()") 
 169  uf.backend = pipe_control.structure.main.com 
 170  uf.menu_text = "co&m" 
 171  uf.wizard_size = (600, 400) 
 172  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 173   
 174   
 175  # The structure.connect_atom user function. 
 176  uf = uf_info.add_uf('structure.connect_atom') 
 177  uf.title = "Connect two atoms." 
 178  uf.title_short = "Atom connection." 
 179  uf.add_keyarg( 
 180      name = "index1", 
 181      py_type = "int", 
 182      max = 10000, 
 183      desc_short = "index 1", 
 184      desc = "The global index of the first atom." 
 185  ) 
 186  uf.add_keyarg( 
 187      name = "index2", 
 188      py_type = "int", 
 189      max = 10000, 
 190      desc_short = "index 2", 
 191      desc = "The global index of the second atom." 
 192  ) 
 193  # Description. 
 194  uf.desc.append(Desc_container()) 
 195  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.") 
 196  uf.backend = pipe_control.structure.main.connect_atom 
 197  uf.menu_text = "co&nnect_atom" 
 198  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 199   
 200   
 201  # The structure.create_diff_tensor_pdb user function. 
 202  uf = uf_info.add_uf('structure.create_diff_tensor_pdb') 
 203  uf.title = "Create a PDB file to represent the diffusion tensor." 
 204  uf.title_short = "Diffusion tensor PDB file creation." 
 205  uf.add_keyarg( 
 206      name = "scale", 
 207      default = 1.8e-6, 
 208      py_type = "num", 
 209      desc_short = "scaling factor", 
 210      desc = "Value for scaling the diffusion rates." 
 211  ) 
 212  uf.add_keyarg( 
 213      name = "file", 
 214      default = "tensor.pdb", 
 215      py_type = "str", 
 216      arg_type = "file sel", 
 217      desc_short = "file name", 
 218      desc = "The name of the PDB file.", 
 219      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
 220      wiz_filesel_style = FD_SAVE 
 221  ) 
 222  uf.add_keyarg( 
 223      name = "dir", 
 224      py_type = "str", 
 225      arg_type = "dir", 
 226      desc_short = "directory name", 
 227      desc = "The directory to place the file into.", 
 228      can_be_none = True 
 229  ) 
 230  uf.add_keyarg( 
 231      name = "force", 
 232      default = False, 
 233      py_type = "bool", 
 234      desc_short = "force flag", 
 235      desc = "A flag which, if set to True, will overwrite the any pre-existing file." 
 236  ) 
 237  # Description. 
 238  uf.desc.append(Desc_container()) 
 239  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.") 
 240  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.") 
 241  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.") 
 242  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.") 
 243  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:") 
 244  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.") 
 245  table.add_headings(["tm (ns)", "Diso (s^-1)", "Radius (Angstrom)"]) 
 246  table.add_row(["1", "1.67e8", "300"]) 
 247  table.add_row(["3", "5.56e7", "100"]) 
 248  table.add_row(["10", "1.67e7", "30"]) 
 249  table.add_row(["30", "5.56e6", "10"]) 
 250  uf.desc[-1].add_table(table.label) 
 251  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.") 
 252  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.") 
 253  uf.backend = pipe_control.structure.main.create_diff_tensor_pdb 
 254  uf.menu_text = "&create_diff_tensor_pdb" 
 255  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 256  uf.wizard_height_desc = 450 
 257  uf.wizard_size = (1000, 750) 
 258  uf.wizard_apply_button = False 
 259  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'create_diff_tensor_pdb.png' 
 260   
 261   
 262  # The structure.create_rotor_pdb user function. 
 263  uf = uf_info.add_uf('structure.create_rotor_pdb') 
 264  uf.title = "Create a PDB file representation of a rotor." 
 265  uf.title_short = "Rotor PDB representation." 
 266  uf.add_keyarg( 
 267      name = "file", 
 268      default = "rotor.pdb", 
 269      py_type = "str", 
 270      arg_type = "file sel", 
 271      desc_short = "file name", 
 272      desc = "The name of the PDB file.", 
 273      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
 274      wiz_filesel_style = FD_SAVE 
 275  ) 
 276  uf.add_keyarg( 
 277      name = "dir", 
 278      py_type = "str", 
 279      arg_type = "dir", 
 280      desc_short = "directory name", 
 281      desc = "The directory to place the file into.", 
 282      can_be_none = True 
 283  ) 
 284  uf.add_keyarg( 
 285      name = "rotor_angle", 
 286      default = 0.0, 
 287      py_type = "float", 
 288      desc_short = "rotor angle", 
 289      desc = "The angle of the rotor motion in degrees." 
 290  ) 
 291  uf.add_keyarg( 
 292      name = "axis", 
 293      py_type = "float_array", 
 294      dim = 3, 
 295      desc_short = "rotor axis vector", 
 296      desc = "The vector defining the rotor axis." 
 297  ) 
 298  uf.add_keyarg( 
 299      name = "axis_pt", 
 300      py_type = "float_array", 
 301      dim = 3, 
 302      desc_short = "rotor axis point", 
 303      desc = "A point lying anywhere on the rotor axis.  This is used to define the position of the axis in 3D space." 
 304  ) 
 305  uf.add_keyarg( 
 306      name = "centre", 
 307      py_type = "float_array", 
 308      dim = 3, 
 309      desc_short = "central point", 
 310      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." 
 311  ) 
 312  uf.add_keyarg( 
 313      name = "span", 
 314      default = 2e-9, 
 315      py_type = "num", 
 316      desc_short = "representation span", 
 317      desc = "The distance from the central point to the rotor blades (meters)." 
 318  ) 
 319  uf.add_keyarg( 
 320      name = "blade_length", 
 321      default = 5e-10, 
 322      py_type = "num", 
 323      desc_short = "blade length", 
 324      desc = "The length of the representative rotor blades." 
 325  ) 
 326  uf.add_keyarg( 
 327      name = "force", 
 328      default = False, 
 329      py_type = "bool", 
 330      desc_short = "force flag", 
 331      desc = "A flag which if True will overwrite the file if it already exists." 
 332  ) 
 333  uf.add_keyarg( 
 334      name = "staggered", 
 335      default = False, 
 336      py_type = "bool", 
 337      desc_short = "staggered flag", 
 338      desc = "A flag which if True will cause the rotor blades to be staggered.  This is used to avoid blade overlap." 
 339  ) 
 340  # Description. 
 341  uf.desc.append(Desc_container()) 
 342  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.") 
 343  # Prompt examples. 
 344  uf.desc.append(Desc_container("Prompt examples")) 
 345  uf.desc[-1].add_paragraph("The following is a synthetic example:") 
 346  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)") 
 347  uf.backend = pipe_control.structure.geometric.create_rotor_pdb 
 348  uf.menu_text = "create_&rotor_pdb" 
 349  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 350  uf.wizard_height_desc = 400 
 351  uf.wizard_size = (900, 700) 
 352  uf.wizard_apply_button = False 
 353  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 354   
 355   
 356  # The structure.create_vector_dist user function. 
 357  uf = uf_info.add_uf('structure.create_vector_dist') 
 358  uf.title = "Create a PDB file representation of the distribution of XH bond vectors." 
 359  uf.title_short = "XH vector distribution PDB representation." 
 360  uf.add_keyarg( 
 361      name = "length", 
 362      default = 2e-9, 
 363      py_type = "num", 
 364      desc_short = "vector length", 
 365      desc = "The length of the vectors in the PDB representation (meters)." 
 366  ) 
 367  uf.add_keyarg( 
 368      name = "file", 
 369      default = "XH_dist.pdb", 
 370      py_type = "str", 
 371      arg_type = "file sel", 
 372      desc_short = "file name", 
 373      desc = "The name of the PDB file.", 
 374      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
 375      wiz_filesel_style = FD_SAVE 
 376  ) 
 377  uf.add_keyarg( 
 378      name = "dir", 
 379      py_type = "str", 
 380      arg_type = "dir", 
 381      desc_short = "directory name", 
 382      desc = "The directory to place the file into.", 
 383      can_be_none = True 
 384  ) 
 385  uf.add_keyarg( 
 386      name = "symmetry", 
 387      default = True, 
 388      py_type = "bool", 
 389      desc_short = "symmetry flag", 
 390      desc = "A flag which if True will create a second chain with reversed XH bond orientations." 
 391  ) 
 392  uf.add_keyarg( 
 393      name = "force", 
 394      default = False, 
 395      py_type = "bool", 
 396      desc_short = "force flag", 
 397      desc = "A flag which if True will overwrite the file if it already exists." 
 398  ) 
 399  # Description. 
 400  uf.desc.append(Desc_container()) 
 401  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.") 
 402  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.") 
 403  uf.backend = pipe_control.structure.geometric.create_vector_dist 
 404  uf.menu_text = "cr&eate_vector_dist" 
 405  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 406  uf.wizard_height_desc = 400 
 407  uf.wizard_size = (900, 700) 
 408  uf.wizard_apply_button = False 
 409  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'create_vector_dist.png' 
 410   
 411   
 412  # The structure.get_pos user function. 
 413  uf = uf_info.add_uf('structure.get_pos') 
 414  uf.title = "Extract the atomic positions from the loaded structures for the given spins." 
 415  uf.title_short = "Atomic position extraction." 
 416  uf.add_keyarg( 
 417      name = "spin_id", 
 418      py_type = "str", 
 419      desc_short = "spin ID string", 
 420      desc = "The spin identification string.", 
 421      can_be_none = True 
 422  ) 
 423  uf.add_keyarg( 
 424      name = "ave_pos", 
 425      default = True, 
 426      py_type = "bool", 
 427      desc_short = "average position flag", 
 428      desc = "A flag specifying if the position of the atom is to be averaged across models." 
 429  ) 
 430  # Description. 
 431  uf.desc.append(Desc_container()) 
 432  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.") 
 433  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.") 
 434  # Prompt examples. 
 435  uf.desc.append(Desc_container("Prompt examples")) 
 436  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:") 
 437  uf.desc[-1].add_prompt("relax> structure.read_pdb('1F3Y.pdb')") 
 438  uf.desc[-1].add_prompt("relax> structure.get_pos(spin_id='@N')") 
 439  uf.backend = pipe_control.structure.main.get_pos 
 440  uf.menu_text = "&get_pos" 
 441  uf.wizard_height_desc = 300 
 442  uf.wizard_size = (800, 600) 
 443  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 444   
 445   
 446  # The structure.delete user function. 
 447  uf = uf_info.add_uf('structure.delete') 
 448  uf.title = "Delete structural information." 
 449  uf.title_short = "Structure deletion." 
 450  uf.add_keyarg( 
 451      name = "atom_id", 
 452      py_type = "str", 
 453      desc_short = "atom ID string", 
 454      desc = "The atom identification string.", 
 455      can_be_none = True 
 456  ) 
 457  uf.add_keyarg( 
 458      name = "verbosity", 
 459      default = 1, 
 460      py_type = "int", 
 461      desc_short = "verbosity level", 
 462      desc = "The amount of information to print out.  Set to zero to silence the user function, or one to see all messages." 
 463  ) 
 464  uf.add_keyarg( 
 465      name = "spin_info", 
 466      default = True, 
 467      py_type = "bool", 
 468      desc_short = "spin information flag", 
 469      desc = "A flag which if True will cause all structural information in the spin containers and interatomic data containers to be deleted as well.  If False, then only the 3D structural data will be deleted." 
 470  ) 
 471  # Description. 
 472  uf.desc.append(Desc_container()) 
 473  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.") 
 474  # Prompt examples. 
 475  uf.desc.append(Desc_container("Prompt examples")) 
 476  uf.desc[-1].add_paragraph("To delete everything, simply type:") 
 477  uf.desc[-1].add_prompt("relax> structure.delete()") 
 478  uf.desc[-1].add_paragraph("To delete residues 50 to 100 of the molecule called 'Ap4Aase', type one of:") 
 479  uf.desc[-1].add_prompt("relax> structure.delete(':50-100')") 
 480  uf.desc[-1].add_prompt("relax> structure.delete(atom_id=':50-100')") 
 481  uf.backend = pipe_control.structure.main.delete 
 482  uf.menu_text = "&delete" 
 483  uf.gui_icon = "oxygen.actions.list-remove" 
 484  uf.wizard_size = (700, 500) 
 485  uf.wizard_apply_button = False 
 486  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 487   
 488   
 489  # The structure.displacement user function. 
 490  uf = uf_info.add_uf('structure.displacement') 
 491  uf.title = "Determine the rotational and translational displacement between a set of models." 
 492  uf.title_short = "Rotational and translational displacement." 
 493  uf.add_keyarg( 
 494      name = "model_from", 
 495      py_type = "int", 
 496      desc_short = "model from", 
 497      desc = "The optional model number for the starting position of the displacement.", 
 498      can_be_none = True 
 499  ) 
 500  uf.add_keyarg( 
 501      name = "model_to", 
 502      py_type = "int", 
 503      desc_short = "model to", 
 504      desc = "The optional model number for the ending position of the displacement.", 
 505      can_be_none = True 
 506  ) 
 507  uf.add_keyarg( 
 508      name = "atom_id", 
 509      py_type = "str", 
 510      desc_short = "atom identification string", 
 511      desc = "The atom identification string.", 
 512      can_be_none = True 
 513  ) 
 514  uf.add_keyarg( 
 515      name = "centroid", 
 516      py_type = "float_array", 
 517      desc_short = "centroid position", 
 518      desc = "The alternative position of the centroid.", 
 519      can_be_none = True 
 520  ) 
 521  # Description. 
 522  uf.desc.append(Desc_container()) 
 523  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.") 
 524  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.") 
 525  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.") 
 526  # Prompt examples. 
 527  uf.desc.append(Desc_container("Prompt examples")) 
 528  uf.desc[-1].add_paragraph("To determine the rotational and translational displacements between all sets of models, type:") 
 529  uf.desc[-1].add_prompt("relax> structure.displacement()") 
 530  uf.desc[-1].add_paragraph("To determine the displacement from model 5 to all other models, type:") 
 531  uf.desc[-1].add_prompt("relax> structure.displacement(model_from=5)") 
 532  uf.desc[-1].add_paragraph("To determine the displacement of all models to model 5, type:") 
 533  uf.desc[-1].add_prompt("relax> structure.displacement(model_to=5)") 
 534  uf.desc[-1].add_paragraph("To determine the displacement of model 2 to model 3, type one of:") 
 535  uf.desc[-1].add_prompt("relax> structure.displacement(2, 3)") 
 536  uf.desc[-1].add_prompt("relax> structure.displacement(model_from=2, model_to=3)") 
 537  uf.backend = pipe_control.structure.main.displacement 
 538  uf.menu_text = "displace&ment" 
 539  uf.wizard_height_desc = 400 
 540  uf.wizard_size = (900, 700) 
 541  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 542   
 543   
 544  # The structure.find_pivot user function. 
 545  uf = uf_info.add_uf('structure.find_pivot') 
 546  uf.title = "Find the pivot point of the motion of a set of structures." 
 547  uf.title_short = "Pivot search." 
 548  uf.add_keyarg( 
 549      name = "models", 
 550      py_type = "int_list", 
 551      desc_short = "model list", 
 552      desc = "The list of models to use.", 
 553      can_be_none = True 
 554  ) 
 555  uf.add_keyarg( 
 556      name = "atom_id", 
 557      py_type = "str", 
 558      desc_short = "atom ID string", 
 559      desc = "The atom identification string.", 
 560      can_be_none = True 
 561  ) 
 562  uf.add_keyarg( 
 563      name = "init_pos", 
 564      py_type = "float_array", 
 565      desc_short = "initial pivot position", 
 566      desc = "The initial position of the pivot.", 
 567      can_be_none = True 
 568  ) 
 569  uf.add_keyarg( 
 570      name = "func_tol", 
 571      default = 1e-5, 
 572      py_type = "num", 
 573      desc_short = "function tolerance", 
 574      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." 
 575  ) 
 576  uf.add_keyarg( 
 577      name = "box_limit", 
 578      default = 200, 
 579      py_type = "int", 
 580      desc_short = "box constraint limit", 
 581      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." 
 582  ) 
 583  # Description. 
 584  uf.desc.append(Desc_container()) 
 585  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.") 
 586  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.") 
 587  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.") 
 588  uf.backend = pipe_control.structure.main.find_pivot 
 589  uf.menu_text = "&find_pivot" 
 590  uf.wizard_height_desc = 400 
 591  uf.wizard_size = (900, 700) 
 592  uf.wizard_apply_button = False 
 593  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 594   
 595   
 596  # The structure.load_spins user function. 
 597  uf = uf_info.add_uf('structure.load_spins') 
 598  uf.title = "Load spins from the structure into the relax data store." 
 599  uf.title_short = "Loading spins from structure." 
 600  uf.add_keyarg( 
 601      name = "spin_id", 
 602      py_type = "str", 
 603      arg_type = "spin ID", 
 604      desc_short = "spin ID string", 
 605      desc = "The spin identification string for the selective loading of certain spins into the relax data store.", 
 606      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"], 
 607      can_be_none = True 
 608  ) 
 609  uf.add_keyarg( 
 610      name = "mol_name_target", 
 611      py_type = "str", 
 612      desc_short = "target molecule name", 
 613      desc = "The name of target molecule container, overriding the name of the loaded structures.", 
 614      can_be_none = True 
 615  ) 
 616  uf.add_keyarg( 
 617      name = "ave_pos", 
 618      default = True, 
 619      py_type = "bool", 
 620      desc_short = "average position flag", 
 621      desc = "A flag specifying if the position of the atom is to be averaged across models." 
 622  ) 
 623  # Description. 
 624  uf.desc.append(Desc_container()) 
 625  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).") 
 626  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.") 
 627  # Prompt examples. 
 628  uf.desc.append(Desc_container("Prompt examples")) 
 629  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:") 
 630  uf.desc[-1].add_prompt("relax> structure.read_pdb('1F3Y.pdb')") 
 631  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id='@N')") 
 632  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):") 
 633  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":A@C8\")") 
 634  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":A@C2\")") 
 635  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":G@C8\")") 
 636  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":G@N1\")") 
 637  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":C@C5\")") 
 638  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":C@C6\")") 
 639  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":U@N3\")") 
 640  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":U@C5\")") 
 641  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":U@C6\")") 
 642  uf.desc[-1].add_paragraph("Alternatively using some Python programming:") 
 643  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\"]:") 
 644  uf.desc[-1].add_prompt("relax>     structure.load_spins(spin_id=id)") 
 645  uf.backend = pipe_control.structure.main.load_spins 
 646  uf.menu_text = "&load_spins" 
 647  uf.gui_icon = "relax.spin" 
 648  uf.wizard_height_desc = 300 
 649  uf.wizard_size = (800, 600) 
 650  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'load_spins.png' 
 651   
 652   
 653  # The structure.read_gaussian user function. 
 654  uf = uf_info.add_uf('structure.read_gaussian') 
 655  uf.title = "Reading structures from Gaussian log files." 
 656  uf.title_short = "Gaussian log structure reading." 
 657  uf.add_keyarg( 
 658      name = "file", 
 659      py_type = "str", 
 660      arg_type = "file sel", 
 661      desc_short = "file name", 
 662      desc = "The name of the Gaussian log file.", 
 663      wiz_filesel_wildcard = WILDCARD_STRUCT_GAUSSIAN_ALL, 
 664      wiz_filesel_style = FD_OPEN 
 665  ) 
 666  uf.add_keyarg( 
 667      name = "dir", 
 668      py_type = "str", 
 669      arg_type = "dir", 
 670      desc_short = "directory name", 
 671      desc = "The directory where the file is located.", 
 672      can_be_none = True 
 673  ) 
 674  uf.add_keyarg( 
 675      name = "set_mol_name", 
 676      py_type = "str_or_str_list", 
 677      desc_short = "setting of molecule names", 
 678      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.", 
 679      can_be_none = True 
 680  ) 
 681  uf.add_keyarg( 
 682      name = "set_model_num", 
 683      py_type = "int_or_int_list", 
 684      desc_short = "setting of model numbers", 
 685      desc = "Set the model numbers of the loaded molecules.  This can be a single number or list of numbers.", 
 686      can_be_none = True 
 687  ) 
 688  uf.add_keyarg( 
 689      name = "verbosity", 
 690      default = 1, 
 691      py_type = "int", 
 692      desc_short = "verbosity level", 
 693      desc = "The amount of information to print out.  Set to zero to silence the user function, or one to see all messages." 
 694  ) 
 695  # Description. 
 696  uf.desc.append(Desc_container()) 
 697  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.") 
 698  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.") 
 699  # Prompt examples. 
 700  uf.desc.append(Desc_container("Prompt examples")) 
 701  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:") 
 702  uf.desc[-1].add_prompt("relax> structure.read_gaussian('taxol.log', '~/logs')") 
 703  uf.desc[-1].add_prompt("relax> structure.read_gaussian(file='taxol.log', dir=logs')") 
 704  uf.backend = pipe_control.structure.main.read_gaussian 
 705  uf.menu_text = "read_&gaussian" 
 706  uf.gui_icon = "oxygen.actions.document-open" 
 707  uf.wizard_height_desc = 400 
 708  uf.wizard_size = (900, 600) 
 709  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'read_xyz.png' 
 710   
 711   
 712  # The structure.read_pdb user function. 
 713  uf = uf_info.add_uf('structure.read_pdb') 
 714  uf.title = "Reading structures from PDB files." 
 715  uf.title_short = "PDB reading." 
 716  uf.add_keyarg( 
 717      name = "file", 
 718      py_type = "str", 
 719      arg_type = "file sel", 
 720      desc_short = "file name", 
 721      desc = "The name of the PDB file.", 
 722      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
 723      wiz_filesel_style = FD_OPEN 
 724  ) 
 725  uf.add_keyarg( 
 726      name = "dir", 
 727      py_type = "str", 
 728      arg_type = "dir", 
 729      desc_short = "directory name", 
 730      desc = "The directory where the file is located.", 
 731      can_be_none = True 
 732  ) 
 733  uf.add_keyarg( 
 734      name = "read_mol", 
 735      py_type = "int_or_int_list", 
 736      desc_short = "molecule number to read", 
 737      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.", 
 738      can_be_none = True 
 739  ) 
 740  uf.add_keyarg( 
 741      name = "set_mol_name", 
 742      py_type = "str_or_str_list", 
 743      desc_short = "setting of molecule names", 
 744      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.", 
 745      can_be_none = True 
 746  ) 
 747  uf.add_keyarg( 
 748      name = "read_model", 
 749      py_type = "int_or_int_list", 
 750      desc_short = "model to read", 
 751      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.", 
 752      can_be_none = True 
 753  ) 
 754  uf.add_keyarg( 
 755      name = "set_model_num", 
 756      py_type = "int_or_int_list", 
 757      desc_short = "setting of model numbers", 
 758      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.", 
 759      can_be_none = True 
 760  ) 
 761  uf.add_keyarg( 
 762      name = "alt_loc", 
 763      py_type = "str", 
 764      desc_short = "alternate location indicator", 
 765      desc = "The PDB ATOM record 'Alternate location indicator' field value.", 
 766      can_be_none = True 
 767  ) 
 768  uf.add_keyarg( 
 769      name = "verbosity", 
 770      default = 1, 
 771      py_type = "int", 
 772      desc_short = "verbosity level", 
 773      desc = "The amount of information to print out.  Set to zero to silence the user function, or one to see all messages." 
 774  ) 
 775  uf.add_keyarg( 
 776      name = "merge", 
 777      default = False, 
 778      py_type = "bool", 
 779      desc_short = "merge structure flag", 
 780      desc = "A flag which if set to True will try to merge the PDB structure into the currently loaded structures." 
 781  ) 
 782  # Description. 
 783  uf.desc.append(Desc_container()) 
 784  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.") 
 785  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.") 
 786  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.") 
 787  uf.desc[-1].add_paragraph("Note that relax will complain if it cannot work out what to do.") 
 788  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.") 
 789  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.") 
 790  # Prompt examples. 
 791  uf.desc.append(Desc_container("Prompt examples")) 
 792  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:") 
 793  uf.desc[-1].add_prompt("relax> structure.read_pdb('test.pdb', '~/pdb')") 
 794  uf.desc[-1].add_prompt("relax> structure.read_pdb(file='test.pdb', dir='pdb')") 
 795  uf.desc[-1].add_paragraph("To load the 10th model from the file 'test.pdb' and naming it 'CaM', use one of:") 
 796  uf.desc[-1].add_prompt("relax> structure.read_pdb('test.pdb', read_model=10, set_mol_name='CaM')") 
 797  uf.desc[-1].add_prompt("relax> structure.read_pdb(file='test.pdb', read_model=10, set_mol_name='CaM')") 
 798  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:") 
 799  uf.desc[-1].add_prompt("relax> structure.read_pdb('test.pdb', read_model=[1, 5], set_model_num=[1, 1])") 
 800  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])") 
 801  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:") 
 802  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_1.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=1)") 
 803  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_2.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=2)") 
 804  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_3.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=3)") 
 805  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_4.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=4)") 
 806  uf.backend = pipe_control.structure.main.read_pdb 
 807  uf.menu_text = "read_&pdb" 
 808  uf.gui_icon = "oxygen.actions.document-open" 
 809  uf.wizard_height_desc = 360 
 810  uf.wizard_size = (1000, 750) 
 811  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'read_pdb.png' 
 812   
 813   
 814  # The structure.read_xyz user function. 
 815  uf = uf_info.add_uf('structure.read_xyz') 
 816  uf.title = "Reading structures from XYZ files." 
 817  uf.title_short = "XYZ reading." 
 818  uf.add_keyarg( 
 819      name = "file", 
 820      py_type = "str", 
 821      arg_type = "file sel", 
 822      desc_short = "file name", 
 823      desc = "The name of the XYZ file.", 
 824      wiz_filesel_wildcard = WILDCARD_STRUCT_XYZ_ALL, 
 825      wiz_filesel_style = FD_OPEN 
 826  ) 
 827  uf.add_keyarg( 
 828      name = "dir", 
 829      py_type = "str", 
 830      arg_type = "dir", 
 831      desc_short = "directory name", 
 832      desc = "The directory where the file is located.", 
 833      can_be_none = True 
 834  ) 
 835  uf.add_keyarg( 
 836      name = "read_mol", 
 837      py_type = "int_or_int_list", 
 838      desc_short = "molecule number to read", 
 839      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.", 
 840      can_be_none = True 
 841  ) 
 842  uf.add_keyarg( 
 843      name = "set_mol_name", 
 844      py_type = "str_or_str_list", 
 845      desc_short = "setting of molecule names", 
 846      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.", 
 847      can_be_none = True 
 848  ) 
 849  uf.add_keyarg( 
 850      name = "read_model", 
 851      py_type = "int_or_int_list", 
 852      desc_short = "model to read", 
 853      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.", 
 854      can_be_none = True 
 855  ) 
 856  uf.add_keyarg( 
 857      name = "set_model_num", 
 858      py_type = "int_or_int_list", 
 859      desc_short = "setting of model numbers", 
 860      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.", 
 861      can_be_none = True 
 862  ) 
 863  uf.add_keyarg( 
 864      name = "verbosity", 
 865      default = 1, 
 866      py_type = "int", 
 867      desc_short = "verbosity level", 
 868      desc = "The amount of information to print out.  Set to zero to silence the user function, or one to see all messages." 
 869  ) 
 870  # Description. 
 871  uf.desc.append(Desc_container()) 
 872  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.") 
 873  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.") 
 874  uf.desc[-1].add_paragraph("Note that relax will complain if it cannot work out what to do.") 
 875  # Prompt examples. 
 876  uf.desc.append(Desc_container("Prompt examples")) 
 877  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:") 
 878  uf.desc[-1].add_prompt("relax> structure.read_xyz('test.xyz', '~/xyz')") 
 879  uf.desc[-1].add_prompt("relax> structure.read_xyz(file='test.xyz', dir='xyz')") 
 880  uf.desc[-1].add_paragraph("To load the 10th model from the file 'test.xyz' and naming it 'CaM', use one of:") 
 881  uf.desc[-1].add_prompt("relax> structure.read_xyz('test.xyz', read_model=10, set_mol_name='CaM')") 
 882  uf.desc[-1].add_prompt("relax> structure.read_xyz(file='test.xyz', read_model=10, set_mol_name='CaM')") 
 883  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:") 
 884  uf.desc[-1].add_prompt("relax> structure.read_xyz('test.xyz', read_model=[1, 5], set_model_num=[1, 1])") 
 885  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])") 
 886  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:") 
 887  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_1.xyz', set_mol_name='test_1', set_model_num=1)") 
 888  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_2.xyz', set_mol_name='test_2', set_model_num=2)") 
 889  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_3.xyz', set_mol_name='test_3', set_model_num=3)") 
 890  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_4.xyz', set_mol_name='test_4', set_model_num=4)") 
 891  uf.backend = pipe_control.structure.main.read_xyz 
 892  uf.menu_text = "read_&xyz" 
 893  uf.gui_icon = "oxygen.actions.document-open" 
 894  uf.wizard_height_desc = 400 
 895  uf.wizard_size = (900, 700) 
 896  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'read_xyz.png' 
 897   
 898   
 899  # The structure.rmsd user function. 
 900  uf = uf_info.add_uf('structure.rmsd') 
 901  uf.title = "Determine the RMSD between the models." 
 902  uf.title_short = "Structural RMSD." 
 903  uf.add_keyarg( 
 904      name = "atom_id", 
 905      py_type = "str", 
 906      desc_short = "atom identification string", 
 907      desc = "The atom identification string.", 
 908      can_be_none = True 
 909  ) 
 910  # Description. 
 911  uf.desc.append(Desc_container()) 
 912  uf.desc[-1].add_paragraph("This allows the root mean squared deviation (RMSD) between all models to be calculated.") 
 913  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.") 
 914  # Prompt examples. 
 915  uf.desc.append(Desc_container("Prompt examples")) 
 916  uf.desc[-1].add_paragraph("To determine the RMSD, simply type:") 
 917  uf.desc[-1].add_prompt("relax> structure.rmsd()") 
 918  uf.backend = pipe_control.structure.main.rmsd 
 919  uf.menu_text = "&rmsd" 
 920  uf.wizard_size = (700, 500) 
 921  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 922   
 923   
 924  # The structure.rotate user function. 
 925  uf = uf_info.add_uf('structure.rotate') 
 926  uf.title = "Rotate the internal structural object about the given origin by the rotation matrix." 
 927  uf.title_short = "Structure rotation." 
 928  uf.add_keyarg( 
 929      name = "R", 
 930      py_type = "float_matrix", 
 931      default = eye(3), 
 932      dim = (3, 3), 
 933      desc_short = "rotation matrix", 
 934      desc = "The rotation matrix in forwards rotation notation." 
 935  ) 
 936  uf.add_keyarg( 
 937      name = "origin", 
 938      py_type = "float_array", 
 939      dim = 3, 
 940      desc_short = "origin of rotation", 
 941      desc = "The origin or pivot of the rotation.", 
 942      can_be_none = True 
 943  ) 
 944  uf.add_keyarg( 
 945      name = "model", 
 946      py_type = "int", 
 947      desc_short = "model", 
 948      desc = "The model to rotate (which if not set will cause all models to be rotated).", 
 949      can_be_none = True 
 950  ) 
 951  uf.add_keyarg( 
 952      name = "atom_id", 
 953      py_type = "str", 
 954      desc_short = "atom ID string", 
 955      desc = "The atom identification string.", 
 956      can_be_none = True 
 957  ) 
 958  # Description. 
 959  uf.desc.append(Desc_container()) 
 960  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.") 
 961  uf.backend = pipe_control.structure.main.rotate 
 962  uf.menu_text = "&rotate" 
 963  uf.wizard_height_desc = 300 
 964  uf.wizard_size = (800, 600) 
 965  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 966   
 967   
 968  # The structure.superimpose user function. 
 969  uf = uf_info.add_uf('structure.superimpose') 
 970  uf.title = "Superimpose a set of models of the same structure." 
 971  uf.title_short = "Structural superimposition." 
 972  uf.add_keyarg( 
 973      name = "models", 
 974      py_type = "int_list", 
 975      desc_short = "model list", 
 976      desc = "The list of models to superimpose.", 
 977      can_be_none = True 
 978  ) 
 979  uf.add_keyarg( 
 980      name = "method", 
 981      default = "fit to mean", 
 982      py_type = "str", 
 983      desc_short = "superimposition method", 
 984      desc = "The superimposition method.", 
 985      wiz_element_type = "combo", 
 986      wiz_combo_choices = ["fit to mean", "fit to first"], 
 987      wiz_read_only = True 
 988  ) 
 989  uf.add_keyarg( 
 990      name = "atom_id", 
 991      py_type = "str", 
 992      desc_short = "atom ID string", 
 993      desc = "The atom identification string.", 
 994      can_be_none = True 
 995  ) 
 996  uf.add_keyarg( 
 997      name = "centre_type", 
 998      py_type = "str", 
 999      default = "centroid", 
1000      desc_short = "centre type", 
1001      desc = "The type of centre to user for the superimposition, i.e. either the standard centroid superimposition or a superimposition using the centre of mass (CoM).", 
1002      wiz_element_type = "combo", 
1003      wiz_combo_choices = ["The centroid", "The centre of mass (CoM)"], 
1004      wiz_combo_data = ["centroid", "CoM"] 
1005  ) 
1006  uf.add_keyarg( 
1007      name = "centroid", 
1008      py_type = "float_array", 
1009      desc_short = "centroid position", 
1010      desc = "The alternative position of the centroid.", 
1011      can_be_none = True 
1012  ) 
1013  # Description. 
1014  uf.desc.append(Desc_container()) 
1015  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:") 
1016  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.") 
1017  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.") 
1018  uf.desc[-1].add_paragraph("If the list of models is not supplied, then all models will be superimposed.") 
1019  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.") 
1020  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.") 
1021  # Prompt examples. 
1022  uf.desc.append(Desc_container("Prompt examples")) 
1023  uf.desc[-1].add_paragraph("To superimpose all sets of models, type one of:") 
1024  uf.desc[-1].add_prompt("relax> structure.superimpose()") 
1025  uf.desc[-1].add_prompt("relax> structure.superimpose(method='fit to mean')") 
1026  uf.desc[-1].add_paragraph("To superimpose the models 1, 2, 3, 5 onto model 4, type:") 
1027  uf.desc[-1].add_prompt("relax> structure.superimpose(models=[4, 1, 2, 3, 5], method='fit to first')") 
1028  uf.desc[-1].add_paragraph("To superimpose an ensemble of protein structures using only the backbone heavy atoms, type one of:") 
1029  uf.desc[-1].add_prompt("relax> structure.superimpose(atom_id='@N,C,CA,O')") 
1030  uf.desc[-1].add_prompt("relax> structure.superimpose(method='fit to mean', atom_id='@N,C,CA,O')") 
1031  uf.desc[-1].add_paragraph("To superimpose model 2 onto model 3 using backbone heavy atoms, type one of:") 
1032  uf.desc[-1].add_prompt("relax> structure.superimpose([3, 2], 'fit to first', '@N,C,CA,O')") 
1033  uf.desc[-1].add_prompt("relax> structure.superimpose(models=[3, 2], method='fit to first', atom_id='@N,C,CA,O')") 
1034  uf.backend = pipe_control.structure.main.superimpose 
1035  uf.menu_text = "&superimpose" 
1036  uf.wizard_apply_button = False 
1037  uf.wizard_height_desc = 450 
1038  uf.wizard_size = (1000, 750) 
1039  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1040   
1041   
1042  # The structure.translate user function. 
1043  uf = uf_info.add_uf('structure.translate') 
1044  uf.title = "Laterally displace the internal structural object by the translation vector." 
1045  uf.title_short = "Structure translation." 
1046  uf.add_keyarg( 
1047      name = "T", 
1048      py_type = "float_array", 
1049      dim = 3, 
1050      desc_short = "translation vector", 
1051      desc = "The translation vector." 
1052  ) 
1053  uf.add_keyarg( 
1054      name = "model", 
1055      py_type = "int", 
1056      desc_short = "model", 
1057      desc = "The model to translate (which if not set will cause all models to be translate).", 
1058      can_be_none = True 
1059  ) 
1060  uf.add_keyarg( 
1061      name = "atom_id", 
1062      py_type = "str", 
1063      desc_short = "atom ID string", 
1064      desc = "The atom identification string.", 
1065      can_be_none = True 
1066  ) 
1067  # Description. 
1068  uf.desc.append(Desc_container()) 
1069  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.") 
1070  uf.backend = pipe_control.structure.main.translate 
1071  uf.menu_text = "&translate" 
1072  uf.wizard_size = (750, 500) 
1073  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1074   
1075   
1076  # The structure.web_of_motion user function. 
1077  uf = uf_info.add_uf('structure.web_of_motion') 
1078  uf.title = "Create a PDB representation of motion between models using a web of interconnecting lines." 
1079  uf.title_short = "Web of motion between models." 
1080  uf.add_keyarg( 
1081      name = "file", 
1082      py_type = "str_or_inst", 
1083      arg_type = "file sel", 
1084      desc_short = "file name", 
1085      desc = "The name of the PDB file.", 
1086      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
1087      wiz_filesel_style = FD_SAVE 
1088  ) 
1089  uf.add_keyarg( 
1090      name = "dir", 
1091      py_type = "str", 
1092      arg_type = "dir", 
1093      desc_short = "directory name", 
1094      desc = "The directory to save the file to.", 
1095      can_be_none = True 
1096  ) 
1097  uf.add_keyarg( 
1098      name = "models", 
1099      py_type = "int_list", 
1100      desc_short = "model numbers", 
1101      desc = "Restrict the web to a subset of models.", 
1102      can_be_none = True 
1103  ) 
1104  uf.add_keyarg( 
1105      name = "force", 
1106      default = False, 
1107      py_type = "bool", 
1108      desc_short = "force flag", 
1109      desc = "A flag which if set to True will cause any pre-existing files to be overwritten." 
1110  ) 
1111  # Description. 
1112  uf.desc.append(Desc_container()) 
1113  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.") 
1114  # Prompt examples. 
1115  uf.desc.append(Desc_container("Prompt examples")) 
1116  uf.desc[-1].add_paragraph("To create a web of motion for the models 1, 3, and 5, type one of:") 
1117  uf.desc[-1].add_prompt("relax> structure.web_of_motion('web.pdb', '.', [1, 3, 5])") 
1118  uf.desc[-1].add_prompt("relax> structure.web_of_motion(file='web.pdb', models=[1, 3, 5])") 
1119  uf.desc[-1].add_prompt("relax> structure.web_of_motion(file='web.pdb', dir='.', models=[1, 3, 5])") 
1120  uf.backend = pipe_control.structure.main.web_of_motion 
1121  uf.menu_text = "&web_of_motion" 
1122  uf.wizard_size = (900, 600) 
1123  uf.wizard_apply_button = False 
1124  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1125   
1126   
1127  # The structure.write_pdb user function. 
1128  uf = uf_info.add_uf('structure.write_pdb') 
1129  uf.title = "Writing structures to a PDB file." 
1130  uf.title_short = "PDB writing." 
1131  uf.add_keyarg( 
1132      name = "file", 
1133      py_type = "str_or_inst", 
1134      arg_type = "file sel", 
1135      desc_short = "file name", 
1136      desc = "The name of the PDB file.", 
1137      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
1138      wiz_filesel_style = FD_SAVE 
1139  ) 
1140  uf.add_keyarg( 
1141      name = "dir", 
1142      py_type = "str", 
1143      arg_type = "dir", 
1144      desc_short = "directory name", 
1145      desc = "The directory where the file is located.", 
1146      can_be_none = True 
1147  ) 
1148  uf.add_keyarg( 
1149      name = "model_num", 
1150      py_type = "int", 
1151      desc_short = "model number", 
1152      desc = "Restrict the writing of structural data to a single model in the PDB file.", 
1153      can_be_none = True 
1154  ) 
1155  uf.add_keyarg( 
1156      name = "compress_type", 
1157      default = 0, 
1158      py_type = "int", 
1159      desc_short = "compression type", 
1160      desc = "The type of compression to use when creating the file.", 
1161      wiz_element_type = "combo", 
1162      wiz_combo_choices = [ 
1163          "No compression", 
1164          "bzip2 compression", 
1165          "gzip compression" 
1166      ], 
1167      wiz_combo_data = [ 
1168          0, 
1169          1, 
1170          2 
1171      ], 
1172      wiz_read_only = True 
1173  ) 
1174  uf.add_keyarg( 
1175      name = "force", 
1176      default = False, 
1177      py_type = "bool", 
1178      desc_short = "force flag", 
1179      desc = "A flag which if set to True will cause any pre-existing files to be overwritten." 
1180  ) 
1181  # Description. 
1182  uf.desc.append(Desc_container()) 
1183  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.") 
1184  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") 
1185  uf.desc[-1].add_item_list_element("0", "No compression (no file extension).") 
1186  uf.desc[-1].add_item_list_element("1", "bzip2 compression ('.bz2' file extension).") 
1187  uf.desc[-1].add_item_list_element("2", "gzip compression ('.gz' file extension).") 
1188  # Prompt examples. 
1189  uf.desc.append(Desc_container("Prompt examples")) 
1190  uf.desc[-1].add_paragraph("To write all models and molecules to the PDB file 'ensemble.pdb' within the directory '~/pdb', type one of:") 
1191  uf.desc[-1].add_prompt("relax> structure.write_pdb('ensemble.pdb', '~/pdb')") 
1192  uf.desc[-1].add_prompt("relax> structure.write_pdb(file='ensemble.pdb', dir='pdb')") 
1193  uf.desc[-1].add_paragraph("To write model number 3 into the new file 'test.pdb', use one of:") 
1194  uf.desc[-1].add_prompt("relax> structure.write_pdb('test.pdb', model_num=3)") 
1195  uf.desc[-1].add_prompt("relax> structure.write_pdb(file='test.pdb', model_num=3)") 
1196  uf.backend = pipe_control.structure.main.write_pdb 
1197  uf.menu_text = "&write_pdb" 
1198  uf.gui_icon = "oxygen.actions.document-save" 
1199  uf.wizard_height_desc = 400 
1200  uf.wizard_size = (900, 700) 
1201  uf.wizard_apply_button = False 
1202  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'write_pdb.png' 
1203