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

Source Code for Module user_functions.structure

   1  ############################################################################### 
   2  #                                                                             # 
   3  # Copyright (C) 2003-2016 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  from pipe_control.pipes import pipe_names 
  38  import pipe_control.structure.geometric 
  39  import pipe_control.structure.main 
  40  from user_functions.data import Uf_info; uf_info = Uf_info() 
  41  from user_functions.data import Uf_tables; uf_tables = Uf_tables() 
  42  from user_functions.objects import Desc_container 
  43  from user_functions.wildcards import WILDCARD_STRUCT_GAUSSIAN_ALL, WILDCARD_STRUCT_PDB_ALL, WILDCARD_STRUCT_XYZ_ALL 
  44   
  45   
  46  # Text for the multi-structure paragraph. 
  47  paragraph_multi_struct = "Support for multiple structures is provided by the data pipes, model numbers and molecule names arguments.  Each data pipe, model and molecule combination will be treated as a separate structure.  As only atomic coordinates with the same residue name and number and atom name will be assembled, structures with slightly different atomic structures can be compared.  If the list of models is not supplied, then all models of all data pipes will be used.  If the optional molecules list is supplied, each molecule in the list will be considered as a separate structure for comparison between each other." 
  48  paragraph_atom_id = "The atom ID string, which uses the same notation as the spin ID, can be used to restrict the coordinates compared to a subset of molecules, residues, or atoms.  For example to only use backbone heavy atoms in a protein, set the atom ID to '@N,C,CA,O', assuming those are the names of the atoms in the 3D structural file." 
  49  paragraph_displace_id = "The displacement ID string, which is similar to the atom ID, gives finer control over which atoms are translated and rotated by the algorithm.  When not set this allows, for example, to align structures based on a set of backbone heavy atoms and the backbone protons and side-chains are displaced by default.  Or if set to the same as the atom ID, if a single domain is aligned, then just that domain will be displaced." 
  50   
  51   
  52  # The user function class. 
  53  uf_class = uf_info.add_class('structure') 
  54  uf_class.title = "Class containing the structural related functions." 
  55  uf_class.menu_text = "&structure" 
  56  uf_class.gui_icon = "relax.structure" 
  57   
  58   
  59  # The structure.add_atom user function. 
  60  uf = uf_info.add_uf('structure.add_atom') 
  61  uf.title = "Add an atom." 
  62  uf.title_short = "Atom creation." 
  63  uf.add_keyarg( 
  64      name = "mol_name", 
  65      py_type = "str", 
  66      desc_short = "molecule name", 
  67      desc = "The name of molecule container to create or add the atom to.", 
  68      can_be_none = True 
  69  ) 
  70  uf.add_keyarg( 
  71      name = "atom_name", 
  72      py_type = "str", 
  73      desc_short = "atom name", 
  74      desc = "The atom name." 
  75  ) 
  76  uf.add_keyarg( 
  77      name = "res_name", 
  78      py_type = "str", 
  79      desc_short = "residue name", 
  80      desc = "The residue name." 
  81  ) 
  82  uf.add_keyarg( 
  83      name = "res_num", 
  84      py_type = "int", 
  85      min = -10000, 
  86      max = 10000, 
  87      desc_short = "residue number", 
  88      desc = "The residue number." 
  89  ) 
  90  uf.add_keyarg( 
  91      name = "pos", 
  92      py_type = "float_object", 
  93      desc_short = "atomic position", 
  94      desc = "The atomic coordinates.  For specifying different coordinates for each model of the ensemble, a list of lists can be supplied.", 
  95      list_titles = ['X coordinate', 'Y coordinate', 'Z coordinate'] 
  96  ) 
  97  uf.add_keyarg( 
  98      name = "element", 
  99      py_type = "str", 
 100      desc_short = "element", 
 101      desc = "The element name.", 
 102      wiz_element_type = "combo", 
 103      wiz_combo_choices = ["N", "C", "H", "O", "P"], 
 104      can_be_none = True 
 105  ) 
 106  uf.add_keyarg( 
 107      name = "atom_num", 
 108      py_type = "int", 
 109      desc_short = "atom number", 
 110      desc = "The optional atom number.", 
 111      can_be_none = True 
 112  ) 
 113  uf.add_keyarg( 
 114      name = "chain_id", 
 115      py_type = "str", 
 116      desc_short = "optional chain ID", 
 117      desc = "The optional chain ID string.", 
 118      can_be_none = True 
 119  ) 
 120  uf.add_keyarg( 
 121      name = "segment_id", 
 122      py_type = "str", 
 123      desc_short = "optional segment ID", 
 124      desc = "The optional segment ID string.", 
 125      can_be_none = True 
 126  ) 
 127  uf.add_keyarg( 
 128      name = "pdb_record", 
 129      py_type = "str", 
 130      desc_short = "optional PDB record name", 
 131      desc = "The optional PDB record name, e.g. 'ATOM' or 'HETATM'.", 
 132      can_be_none = True 
 133  ) 
 134  # Description. 
 135  uf.desc.append(Desc_container()) 
 136  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.") 
 137  uf.backend = pipe_control.structure.main.add_atom 
 138  uf.menu_text = "&add_atom" 
 139  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 140  uf.wizard_size = (900, 700) 
 141  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 142   
 143   
 144  # The structure.add_model user function. 
 145  uf = uf_info.add_uf('structure.add_model') 
 146  uf.title = "Add a new model." 
 147  uf.title_short = "Model creation." 
 148  uf.add_keyarg( 
 149      name = "model_num", 
 150      py_type = "int", 
 151      desc_short = "model number", 
 152      desc = "The number of the new model." 
 153  ) 
 154  # Description. 
 155  uf.desc.append(Desc_container()) 
 156  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.") 
 157  uf.backend = pipe_control.structure.main.add_model 
 158  uf.menu_text = "&add_model" 
 159  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 160  uf.wizard_size = (700, 400) 
 161  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 162   
 163   
 164  # The structure.atomic_fluctuations user function. 
 165  uf = uf_info.add_uf('structure.atomic_fluctuations') 
 166  uf.title = "Create an interatomic distance fluctuation correlation matrix." 
 167  uf.title_short = "Interatomic distance fluctuation correlation matrix." 
 168  uf.add_keyarg( 
 169      name = "pipes", 
 170      py_type = "str_list", 
 171      desc_short = "data pipes", 
 172      desc = "The data pipes to generate the interatomic distance fluctuation correlation matrix for.", 
 173      wiz_combo_iter = pipe_names, 
 174      wiz_read_only = False, 
 175      can_be_none = True 
 176  ) 
 177  uf.add_keyarg( 
 178      name = "models", 
 179      py_type = "int_list_of_lists", 
 180      desc_short = "model list for each data pipe", 
 181      desc = "The list of models for each data pipe to generate the interatomic distance fluctuation correlation matrix for.  The number of elements must match the pipes argument.  If no models are given, then all will be used.", 
 182      can_be_none = True 
 183  ) 
 184  uf.add_keyarg( 
 185      name = "molecules", 
 186      py_type = "str_list_of_lists", 
 187      desc_short = "molecule list for each data pipe", 
 188      desc = "The list of molecules for each data pipe to generate the interatomic distance fluctuation correlation matrix for.  This allows differently named molecules in the same or different data pipes to be superimposed.  The number of elements must match the pipes argument.  If no molecules are given, then all will be used.", 
 189      can_be_none = True 
 190  ) 
 191  uf.add_keyarg( 
 192      name = "atom_id", 
 193      py_type = "str", 
 194      desc_short = "atom identification string", 
 195      desc = "The atom identification string of the coordinates of interest.  This can be used to restrict the correlation matrix to one atom per residue, for example.", 
 196      can_be_none = True 
 197  ) 
 198  uf.add_keyarg( 
 199      name = "measure", 
 200      py_type = "str", 
 201      default = "distance", 
 202      desc_short = "measure", 
 203      desc = "The type of fluctuation to investigate.  This allows for both interatomic distance and vector angle fluctuations to be calculated.", 
 204      wiz_element_type = "combo", 
 205      wiz_combo_choices = ["Interatomic distance fluctuations", "Interatomic vector angle fluctuations", "Interatomic parallax shift fluctuations"], 
 206      wiz_combo_data = ["distance", "angle", "parallax shift"] 
 207  ) 
 208  uf.add_keyarg( 
 209      name = "file", 
 210      py_type = "str_or_inst", 
 211      arg_type = "file sel", 
 212      desc_short = "file name", 
 213      desc = "The name of the text file to create.", 
 214      wiz_filesel_style = FD_SAVE 
 215  ) 
 216  uf.add_keyarg( 
 217      name = "format", 
 218      py_type = "str", 
 219      default = "text", 
 220      desc_short = "output format", 
 221      desc = "The output format.  For all formats other than the text file, a second file will be created with the same name as the text file but with the appropriate file extension added.", 
 222      wiz_element_type = "combo", 
 223      wiz_combo_choices = ["Text file", "Gnuplot script"], 
 224      wiz_combo_data = ["text", "gnuplot"] 
 225  ) 
 226  uf.add_keyarg( 
 227      name = "dir", 
 228      py_type = "str", 
 229      arg_type = "dir", 
 230      desc_short = "directory name", 
 231      desc = "The directory to save the file to.", 
 232      can_be_none = True 
 233  ) 
 234  uf.add_keyarg( 
 235      name = "force", 
 236      default = False, 
 237      py_type = "bool", 
 238      desc_short = "force flag", 
 239      desc = "A flag which if set to True will cause any pre-existing files to be overwritten." 
 240  ) 
 241  # Description. 
 242  uf.desc.append(Desc_container()) 
 243  uf.desc[-1].add_paragraph("This is used to visualise the interatomic fluctuations between different structures.  By setting the measure argument, different categories of fluctuations can seen:") 
 244  uf.desc[-1].add_item_list_element("'distance'", "The interatomic distance fluctuations is the default option.  The corrected sample standard deviation (SD) is calculated for the distances between all atom pairs, resulting in a pairwise matrix of SD values.  This is frame independent and hence is superimposition independent.") 
 245  uf.desc[-1].add_item_list_element("'angle'", "The interatomic vector angle fluctuations.  The corrected sample standard deviation (SD) is calculated for the angles between the inter atom vectors all atom pairs to an average vector.  This also produces a pairwise matrix of SD values.") 
 246  uf.desc[-1].add_item_list_element("'parallax shift'", "The interatomic parallax shift fluctuations.  The corrected sample standard deviation (SD) is calculated for the parallax shift between the inter atom vectors all atom pairs to an average vector.  This also produces a pairwise matrix of SD values.  The parallax shift is calculated as the dot product of the interatomic vector and the unit average vector, times the unit average vector.  It is a frame and superimposition dependent measure close to orthogonal to the interatomic distance fluctuations.  It is similar to the angle measure however, importantly, it is independent of the distance between the two atoms.") 
 247  uf.desc[-1].add_paragraph("For the output file, the currently supported formats are:") 
 248  uf.desc[-1].add_item_list_element("'text'", "This is the default value and will result in a single text file being created.") 
 249  uf.desc[-1].add_item_list_element("'gnuplot'", "This will create a both a text file with the data and a script for visualising the correlation matrix using gnuplot.  The script will have the same name as the text file, however the file extension will be changed to *.gnu.") 
 250  uf.desc[-1].add_paragraph(paragraph_multi_struct) 
 251  uf.desc[-1].add_paragraph(paragraph_atom_id) 
 252  # Prompt examples. 
 253  uf.desc.append(Desc_container("Prompt examples")) 
 254  uf.desc[-1].add_paragraph("To create the interatomic distance fluctuation correlation matrix for the models 1, 3, and 5, type:") 
 255  uf.desc[-1].add_prompt("relax> structure.atomic_fluctuations(models=[[1, 3, 5]], file='atomic_fluctuation_matrix')") 
 256  uf.desc[-1].add_paragraph("To create the interatomic distance fluctuation correlation matrix for the molecules 'A', 'B', 'C', and 'D', type:") 
 257  uf.desc[-1].add_prompt("relax> structure.atomic_fluctuations(molecules=[['A', 'B', 'C', 'D']], file='atomic_fluctuation_matrix')") 
 258  uf.backend = pipe_control.structure.main.atomic_fluctuations 
 259  uf.menu_text = "&atomic_fluctuations" 
 260  uf.wizard_height_desc = 370 
 261  uf.wizard_size = (1000, 750) 
 262  uf.wizard_apply_button = False 
 263  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 264   
 265   
 266  # The structure.com user function. 
 267  uf = uf_info.add_uf('structure.com') 
 268  uf.title = "Calculate the centre of mass (CoM) for all structures." 
 269  uf.title_short = "Centre of mass calculation." 
 270  uf.add_keyarg( 
 271      name = "model", 
 272      py_type = "int", 
 273      desc_short = "model", 
 274      desc = "The optional structural model number to restrict the calculation of the centre of mass to.", 
 275      can_be_none = True 
 276  ) 
 277  uf.add_keyarg( 
 278      name = "atom_id", 
 279      py_type = "str", 
 280      desc_short = "atom ID string", 
 281      desc = "The atom identification string to restrict the CoM calculation to.", 
 282      can_be_none = True 
 283  ) 
 284  # Description. 
 285  uf.desc.append(Desc_container()) 
 286  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.") 
 287  # Prompt examples. 
 288  uf.desc.append(Desc_container("Prompt examples")) 
 289  uf.desc[-1].add_paragraph("To determine the centre of mass of all structure, simply type:") 
 290  uf.desc[-1].add_prompt("relax> structure.com()") 
 291  uf.backend = pipe_control.structure.main.com 
 292  uf.menu_text = "co&m" 
 293  uf.wizard_size = (600, 400) 
 294  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 295   
 296   
 297  # The structure.connect_atom user function. 
 298  uf = uf_info.add_uf('structure.connect_atom') 
 299  uf.title = "Connect two atoms." 
 300  uf.title_short = "Atom connection." 
 301  uf.add_keyarg( 
 302      name = "index1", 
 303      py_type = "int", 
 304      max = 10000, 
 305      desc_short = "index 1", 
 306      desc = "The global index of the first atom." 
 307  ) 
 308  uf.add_keyarg( 
 309      name = "index2", 
 310      py_type = "int", 
 311      max = 10000, 
 312      desc_short = "index 2", 
 313      desc = "The global index of the second atom." 
 314  ) 
 315  # Description. 
 316  uf.desc.append(Desc_container()) 
 317  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.") 
 318  uf.backend = pipe_control.structure.main.connect_atom 
 319  uf.menu_text = "co&nnect_atom" 
 320  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 321   
 322   
 323  # The structure.create_diff_tensor_pdb user function. 
 324  uf = uf_info.add_uf('structure.create_diff_tensor_pdb') 
 325  uf.title = "Create a PDB file to represent the diffusion tensor." 
 326  uf.title_short = "Diffusion tensor PDB file creation." 
 327  uf.add_keyarg( 
 328      name = "scale", 
 329      default = 1.8e-6, 
 330      py_type = "num", 
 331      desc_short = "scaling factor", 
 332      desc = "Value for scaling the diffusion rates." 
 333  ) 
 334  uf.add_keyarg( 
 335      name = "file", 
 336      default = "tensor.pdb", 
 337      py_type = "str", 
 338      arg_type = "file sel", 
 339      desc_short = "file name", 
 340      desc = "The name of the PDB file.", 
 341      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
 342      wiz_filesel_style = FD_SAVE 
 343  ) 
 344  uf.add_keyarg( 
 345      name = "dir", 
 346      py_type = "str", 
 347      arg_type = "dir", 
 348      desc_short = "directory name", 
 349      desc = "The directory to place the file into.", 
 350      can_be_none = True 
 351  ) 
 352  uf.add_keyarg( 
 353      name = "force", 
 354      default = False, 
 355      py_type = "bool", 
 356      desc_short = "force flag", 
 357      desc = "A flag which, if set to True, will overwrite the any pre-existing file." 
 358  ) 
 359  # Description. 
 360  uf.desc.append(Desc_container()) 
 361  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.") 
 362  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.") 
 363  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.") 
 364  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.") 
 365  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:") 
 366  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.") 
 367  table.add_headings(["tm (ns)", "Diso (s^-1)", "Radius (Angstrom)"]) 
 368  table.add_row(["1", "1.67e8", "300"]) 
 369  table.add_row(["3", "5.56e7", "100"]) 
 370  table.add_row(["10", "1.67e7", "30"]) 
 371  table.add_row(["30", "5.56e6", "10"]) 
 372  uf.desc[-1].add_table(table.label) 
 373  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.") 
 374  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.") 
 375  uf.backend = pipe_control.structure.main.create_diff_tensor_pdb 
 376  uf.menu_text = "&create_diff_tensor_pdb" 
 377  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 378  uf.wizard_height_desc = 450 
 379  uf.wizard_size = (1000, 750) 
 380  uf.wizard_apply_button = False 
 381  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'create_diff_tensor_pdb.png' 
 382   
 383   
 384  # The structure.create_rotor_pdb user function. 
 385  uf = uf_info.add_uf('structure.create_rotor_pdb') 
 386  uf.title = "Create a PDB file representation of a rotor." 
 387  uf.title_short = "Rotor PDB representation." 
 388  uf.add_keyarg( 
 389      name = "file", 
 390      default = "rotor.pdb", 
 391      py_type = "str", 
 392      arg_type = "file sel", 
 393      desc_short = "file name", 
 394      desc = "The name of the PDB file.", 
 395      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
 396      wiz_filesel_style = FD_SAVE 
 397  ) 
 398  uf.add_keyarg( 
 399      name = "dir", 
 400      py_type = "str", 
 401      arg_type = "dir", 
 402      desc_short = "directory name", 
 403      desc = "The directory to place the file into.", 
 404      can_be_none = True 
 405  ) 
 406  uf.add_keyarg( 
 407      name = "rotor_angle", 
 408      default = 0.0, 
 409      py_type = "float", 
 410      desc_short = "rotor angle", 
 411      desc = "The angle of the rotor motion in degrees." 
 412  ) 
 413  uf.add_keyarg( 
 414      name = "axis", 
 415      py_type = "float_array", 
 416      dim = 3, 
 417      desc_short = "rotor axis vector", 
 418      desc = "The vector defining the rotor axis." 
 419  ) 
 420  uf.add_keyarg( 
 421      name = "axis_pt", 
 422      py_type = "float_array", 
 423      dim = 3, 
 424      desc_short = "rotor axis point", 
 425      desc = "A point lying anywhere on the rotor axis.  This is used to define the position of the axis in 3D space." 
 426  ) 
 427  uf.add_keyarg( 
 428      name = "centre", 
 429      py_type = "float_array", 
 430      dim = 3, 
 431      desc_short = "central point", 
 432      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." 
 433  ) 
 434  uf.add_keyarg( 
 435      name = "span", 
 436      default = 2e-9, 
 437      py_type = "num", 
 438      desc_short = "representation span", 
 439      desc = "The distance from the central point to the rotor blades (meters)." 
 440  ) 
 441  uf.add_keyarg( 
 442      name = "blade_length", 
 443      default = 5e-10, 
 444      py_type = "num", 
 445      desc_short = "blade length", 
 446      desc = "The length of the representative rotor blades." 
 447  ) 
 448  uf.add_keyarg( 
 449      name = "force", 
 450      default = False, 
 451      py_type = "bool", 
 452      desc_short = "force flag", 
 453      desc = "A flag which if True will overwrite the file if it already exists." 
 454  ) 
 455  uf.add_keyarg( 
 456      name = "staggered", 
 457      default = False, 
 458      py_type = "bool", 
 459      desc_short = "staggered flag", 
 460      desc = "A flag which if True will cause the rotor blades to be staggered.  This is used to avoid blade overlap." 
 461  ) 
 462  # Description. 
 463  uf.desc.append(Desc_container()) 
 464  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.") 
 465  # Prompt examples. 
 466  uf.desc.append(Desc_container("Prompt examples")) 
 467  uf.desc[-1].add_paragraph("The following is a synthetic example:") 
 468  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)") 
 469  uf.backend = pipe_control.structure.geometric.create_rotor_pdb 
 470  uf.menu_text = "create_&rotor_pdb" 
 471  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 472  uf.wizard_height_desc = 400 
 473  uf.wizard_size = (900, 700) 
 474  uf.wizard_apply_button = False 
 475  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 476   
 477   
 478  # The structure.create_vector_dist user function. 
 479  uf = uf_info.add_uf('structure.create_vector_dist') 
 480  uf.title = "Create a PDB file representation of the distribution of XH bond vectors." 
 481  uf.title_short = "XH vector distribution PDB representation." 
 482  uf.add_keyarg( 
 483      name = "length", 
 484      default = 2e-9, 
 485      py_type = "num", 
 486      desc_short = "vector length", 
 487      desc = "The length of the vectors in the PDB representation (meters)." 
 488  ) 
 489  uf.add_keyarg( 
 490      name = "file", 
 491      default = "XH_dist.pdb", 
 492      py_type = "str", 
 493      arg_type = "file sel", 
 494      desc_short = "file name", 
 495      desc = "The name of the PDB file.", 
 496      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
 497      wiz_filesel_style = FD_SAVE 
 498  ) 
 499  uf.add_keyarg( 
 500      name = "dir", 
 501      py_type = "str", 
 502      arg_type = "dir", 
 503      desc_short = "directory name", 
 504      desc = "The directory to place the file into.", 
 505      can_be_none = True 
 506  ) 
 507  uf.add_keyarg( 
 508      name = "symmetry", 
 509      default = True, 
 510      py_type = "bool", 
 511      desc_short = "symmetry flag", 
 512      desc = "A flag which if True will create a second chain with reversed XH bond orientations." 
 513  ) 
 514  uf.add_keyarg( 
 515      name = "force", 
 516      default = False, 
 517      py_type = "bool", 
 518      desc_short = "force flag", 
 519      desc = "A flag which if True will overwrite the file if it already exists." 
 520  ) 
 521  # Description. 
 522  uf.desc.append(Desc_container()) 
 523  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.") 
 524  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.") 
 525  uf.backend = pipe_control.structure.geometric.create_vector_dist 
 526  uf.menu_text = "cr&eate_vector_dist" 
 527  uf.gui_icon = "oxygen.actions.list-add-relax-blue" 
 528  uf.wizard_height_desc = 400 
 529  uf.wizard_size = (900, 700) 
 530  uf.wizard_apply_button = False 
 531  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'create_vector_dist.png' 
 532   
 533   
 534  # The structure.get_pos user function. 
 535  uf = uf_info.add_uf('structure.get_pos') 
 536  uf.title = "Extract the atomic positions from the loaded structures for the given spins." 
 537  uf.title_short = "Atomic position extraction." 
 538  uf.add_keyarg( 
 539      name = "spin_id", 
 540      py_type = "str", 
 541      desc_short = "spin ID string", 
 542      desc = "The spin identification string.", 
 543      can_be_none = True 
 544  ) 
 545  uf.add_keyarg( 
 546      name = "ave_pos", 
 547      default = True, 
 548      py_type = "bool", 
 549      desc_short = "average position flag", 
 550      desc = "A flag specifying if the position of the atom is to be averaged across models." 
 551  ) 
 552  # Description. 
 553  uf.desc.append(Desc_container()) 
 554  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.") 
 555  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.") 
 556  # Prompt examples. 
 557  uf.desc.append(Desc_container("Prompt examples")) 
 558  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:") 
 559  uf.desc[-1].add_prompt("relax> structure.read_pdb('1F3Y.pdb')") 
 560  uf.desc[-1].add_prompt("relax> structure.get_pos(spin_id='@N')") 
 561  uf.backend = pipe_control.structure.main.get_pos 
 562  uf.menu_text = "&get_pos" 
 563  uf.wizard_height_desc = 300 
 564  uf.wizard_size = (800, 600) 
 565  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 566   
 567   
 568  # The structure.delete user function. 
 569  uf = uf_info.add_uf('structure.delete') 
 570  uf.title = "Delete structural information." 
 571  uf.title_short = "Structure deletion." 
 572  uf.add_keyarg( 
 573      name = "atom_id", 
 574      py_type = "str", 
 575      desc_short = "atom ID string", 
 576      desc = "The atom identification string.", 
 577      can_be_none = True 
 578  ) 
 579  uf.add_keyarg( 
 580      name = "model", 
 581      py_type = "int", 
 582      desc_short = "structural model", 
 583      desc = "Individual structural models from a loaded ensemble can be deleted by specifying the model number.", 
 584      can_be_none = True 
 585  ) 
 586  uf.add_keyarg( 
 587      name = "verbosity", 
 588      default = 1, 
 589      py_type = "int", 
 590      desc_short = "verbosity level", 
 591      desc = "The amount of information to print out.  Set to zero to silence the user function, or one to see all messages." 
 592  ) 
 593  uf.add_keyarg( 
 594      name = "spin_info", 
 595      default = True, 
 596      py_type = "bool", 
 597      desc_short = "spin information flag", 
 598      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." 
 599  ) 
 600  # Description. 
 601  uf.desc.append(Desc_container()) 
 602  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, or the model argument can be used to delete individual structural models from an ensemble.") 
 603  # Prompt examples. 
 604  uf.desc.append(Desc_container("Prompt examples")) 
 605  uf.desc[-1].add_paragraph("To delete everything, simply type:") 
 606  uf.desc[-1].add_prompt("relax> structure.delete()") 
 607  uf.desc[-1].add_paragraph("To delete residues 50 to 100 of the molecule called 'Ap4Aase', type one of:") 
 608  uf.desc[-1].add_prompt("relax> structure.delete(':50-100')") 
 609  uf.desc[-1].add_prompt("relax> structure.delete(atom_id=':50-100')") 
 610  uf.backend = pipe_control.structure.main.delete 
 611  uf.menu_text = "&delete" 
 612  uf.gui_icon = "oxygen.actions.list-remove" 
 613  uf.wizard_size = (800, 550) 
 614  uf.wizard_apply_button = False 
 615  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 616   
 617   
 618  # The structure.delete_ss user function. 
 619  uf = uf_info.add_uf('structure.delete_ss') 
 620  uf.title = "Delete secondary structure information." 
 621  uf.title_short = "Secondary structure deletion." 
 622  # Description. 
 623  uf.desc.append(Desc_container()) 
 624  uf.desc[-1].add_paragraph("This will delete all secondary structure information from the current data pipe.") 
 625  # Prompt examples. 
 626  uf.desc.append(Desc_container("Prompt examples")) 
 627  uf.desc[-1].add_paragraph("To delete all secondary structure, simply type:") 
 628  uf.desc[-1].add_prompt("relax> structure.delete_ss()") 
 629  uf.backend = pipe_control.structure.main.delete_ss 
 630  uf.menu_text = "&delete_ss" 
 631  uf.gui_icon = "oxygen.actions.list-remove" 
 632  uf.wizard_size = (600, 400) 
 633  uf.wizard_apply_button = False 
 634  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 635   
 636   
 637  # The structure.displacement user function. 
 638  uf = uf_info.add_uf('structure.displacement') 
 639  uf.title = "Determine the rotational and translational displacement between a set of models or molecules." 
 640  uf.title_short = "Rotational and translational displacement." 
 641  uf.add_keyarg( 
 642      name = "pipes", 
 643      py_type = "str_list", 
 644      desc_short = "data pipes", 
 645      desc = "The data pipes to determine the displacements for.", 
 646      wiz_combo_iter = pipe_names, 
 647      wiz_read_only = False, 
 648      can_be_none = True 
 649  ) 
 650  uf.add_keyarg( 
 651      name = "models", 
 652      py_type = "int_list_of_lists", 
 653      desc_short = "model list for each data pipe", 
 654      desc = "The list of models for each data pipe to determine the displacements for.  The number of elements must match the pipes argument.  If no models are given, then all will be used.", 
 655      can_be_none = True 
 656  ) 
 657  uf.add_keyarg( 
 658      name = "molecules", 
 659      py_type = "str_list_of_lists", 
 660      desc_short = "molecule list for each data pipe", 
 661      desc = "The list of molecules for each data pipe to determine the displacements for.  This allows differently named molecules in the same or different data pipes to be superimposed.  The number of elements must match the pipes argument.  If no molecules are given, then all will be used.", 
 662      can_be_none = True 
 663  ) 
 664  uf.add_keyarg( 
 665      name = "atom_id", 
 666      py_type = "str", 
 667      desc_short = "atom identification string", 
 668      desc = "The atom identification string of the coordinates of interest.", 
 669      can_be_none = True 
 670  ) 
 671  uf.add_keyarg( 
 672      name = "centroid", 
 673      py_type = "float_array", 
 674      desc_short = "centroid position", 
 675      desc = "The alternative position of the centroid.", 
 676      can_be_none = True 
 677  ) 
 678  # Description. 
 679  uf.desc.append(Desc_container()) 
 680  uf.desc[-1].add_paragraph("This user function allows the rotational and translational displacement between different models or molecules 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.  Therefore the displacements in all directions between all models and molecules will be calculated.") 
 681  uf.desc[-1].add_paragraph(paragraph_multi_struct) 
 682  uf.desc[-1].add_paragraph(paragraph_atom_id) 
 683  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.") 
 684  # Prompt examples. 
 685  uf.desc.append(Desc_container("Prompt examples")) 
 686  uf.desc[-1].add_paragraph("To determine the rotational and translational displacements between all sets of models, type:") 
 687  uf.desc[-1].add_prompt("relax> structure.displacement()") 
 688  uf.backend = pipe_control.structure.main.displacement 
 689  uf.menu_text = "displace&ment" 
 690  uf.wizard_height_desc = 450 
 691  uf.wizard_size = (1000, 750) 
 692  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 693   
 694   
 695  # The structure.find_pivot user function. 
 696  uf = uf_info.add_uf('structure.find_pivot') 
 697  uf.title = "Find the pivot point of the motion of a set of structures." 
 698  uf.title_short = "Pivot search." 
 699  uf.add_keyarg( 
 700      name = "pipes", 
 701      py_type = "str_list", 
 702      desc_short = "data pipes", 
 703      desc = "The data pipes to use in the motional pivot algorithm.", 
 704      wiz_combo_iter = pipe_names, 
 705      wiz_read_only = False, 
 706      can_be_none = True 
 707  ) 
 708  uf.add_keyarg( 
 709      name = "models", 
 710      py_type = "int_list_of_lists", 
 711      desc_short = "model list for each data pipe", 
 712      desc = "The list of models for each data pipe to use in the motional pivot algorithm.  The number of elements must match the pipes argument.  If no models are given, then all will be used.", 
 713      can_be_none = True 
 714  ) 
 715  uf.add_keyarg( 
 716      name = "molecules", 
 717      py_type = "str_list_of_lists", 
 718      desc_short = "molecule list for each data pipe", 
 719      desc = "The list of molecules for each data pipe to use in the motional pivot algorithm.  This allows differently named molecules in the same or different data pipes to be used.  The number of elements must match the pipes argument.  If no molecules are given, then all will be used.", 
 720      can_be_none = True 
 721  ) 
 722  uf.add_keyarg( 
 723      name = "atom_id", 
 724      py_type = "str", 
 725      desc_short = "atom ID string", 
 726      desc = "The atom identification string of the coordinates of interest.", 
 727      can_be_none = True 
 728  ) 
 729  uf.add_keyarg( 
 730      name = "init_pos", 
 731      py_type = "float_array", 
 732      desc_short = "initial pivot position", 
 733      desc = "The initial position of the pivot.", 
 734      can_be_none = True 
 735  ) 
 736  uf.add_keyarg( 
 737      name = "func_tol", 
 738      default = 1e-5, 
 739      py_type = "num", 
 740      desc_short = "function tolerance", 
 741      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." 
 742  ) 
 743  uf.add_keyarg( 
 744      name = "box_limit", 
 745      default = 200, 
 746      py_type = "int", 
 747      desc_short = "box constraint limit", 
 748      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." 
 749  ) 
 750  # Description. 
 751  uf.desc.append(Desc_container()) 
 752  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.") 
 753  uf.desc[-1].add_paragraph(paragraph_multi_struct) 
 754  uf.desc[-1].add_paragraph(paragraph_atom_id) 
 755  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.") 
 756  uf.backend = pipe_control.structure.main.find_pivot 
 757  uf.menu_text = "&find_pivot" 
 758  uf.wizard_height_desc = 450 
 759  uf.wizard_size = (1000, 750) 
 760  uf.wizard_apply_button = False 
 761  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 762   
 763   
 764  # The structure.load_spins user function. 
 765  uf = uf_info.add_uf('structure.load_spins') 
 766  uf.title = "Load spins from the structure into the relax data store." 
 767  uf.title_short = "Loading spins from structure." 
 768  uf.add_keyarg( 
 769      name = "spin_id", 
 770      py_type = "str", 
 771      arg_type = "spin ID", 
 772      desc_short = "spin ID string", 
 773      desc = "The spin identification string for the selective loading of certain spins into the relax data store.", 
 774      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"], 
 775      can_be_none = True 
 776  ) 
 777  uf.add_keyarg( 
 778      name = "from_mols", 
 779      py_type = "str_list", 
 780      desc_short = "molecules to load spins from", 
 781      desc = "The list of similar, but not necessarily identical molecules to load spin information from.", 
 782      wiz_read_only = False, 
 783      can_be_none = True 
 784  ) 
 785  uf.add_keyarg( 
 786      name = "mol_name_target", 
 787      py_type = "str", 
 788      desc_short = "target molecule name", 
 789      desc = "The name of target molecule container, overriding the name of the loaded structures.", 
 790      can_be_none = True 
 791  ) 
 792  uf.add_keyarg( 
 793      name = "ave_pos", 
 794      default = True, 
 795      py_type = "bool", 
 796      desc_short = "average position flag", 
 797      desc = "A flag specifying if the position of the atom is to be averaged across models." 
 798  ) 
 799  uf.add_keyarg( 
 800      name = "spin_num", 
 801      default = True, 
 802      py_type = "bool", 
 803      desc_short = "spin number loading flag", 
 804      desc = "A flag specifying if the spin number should be loaded." 
 805  ) 
 806  # Description. 
 807  uf.desc.append(Desc_container()) 
 808  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).") 
 809  uf.desc[-1].add_paragraph("As an alternative to using structural models, by specifying the list of molecules to load spins from similar though not necessarily identical molecules will be combined.  In this case, the target molecule name must be supplied to create a single combined molecule.  And only a single model can be loaded in the current data pipe.  The spin numbering will be dropped to allow for sequential atom numbering in the PDB and other formats.  Therefore only the residue number and name and atom name will be preserved for creating the spin containers.  If the spin is only present in a subset of the structures, then the positional information will only be taken from that subset and hence the number of positions might be different for different spins.") 
 810  uf.desc[-1].add_paragraph("If averaging the atomic positions, then average position of all models or molecules will be loaded into the spin container.  Otherwise the positions from all models or molecules will be loaded separately.") 
 811  # Prompt examples. 
 812  uf.desc.append(Desc_container("Prompt examples")) 
 813  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:") 
 814  uf.desc[-1].add_prompt("relax> structure.read_pdb('1F3Y.pdb')") 
 815  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id='@N')") 
 816  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):") 
 817  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":A@C8\")") 
 818  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":A@C2\")") 
 819  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":G@C8\")") 
 820  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":G@N1\")") 
 821  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":C@C5\")") 
 822  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":C@C6\")") 
 823  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":U@N3\")") 
 824  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":U@C5\")") 
 825  uf.desc[-1].add_prompt("relax> structure.load_spins(spin_id=\":U@C6\")") 
 826  uf.desc[-1].add_paragraph("Alternatively using some Python programming:") 
 827  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\"]:") 
 828  uf.desc[-1].add_prompt("relax>     structure.load_spins(spin_id=id)") 
 829  uf.backend = pipe_control.structure.main.load_spins 
 830  uf.menu_text = "&load_spins" 
 831  uf.gui_icon = "relax.spin" 
 832  uf.wizard_height_desc = 500 
 833  uf.wizard_size = (900, 700) 
 834  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'load_spins.png' 
 835   
 836   
 837  # The structure.mean user function. 
 838  uf = uf_info.add_uf('structure.mean') 
 839  uf.title = "Calculate the mean structure from all loaded models." 
 840  uf.title_short = "Mean structure." 
 841  uf.add_keyarg( 
 842      name = "pipes", 
 843      py_type = "str_list", 
 844      desc_short = "data pipes", 
 845      desc = "The data pipes containing structures to average.", 
 846      wiz_combo_iter = pipe_names, 
 847      wiz_read_only = False, 
 848      can_be_none = True 
 849  ) 
 850  uf.add_keyarg( 
 851      name = "models", 
 852      py_type = "int_list_of_lists", 
 853      desc_short = "model list for each data pipe", 
 854      desc = "The list of models for each data pipe containing structures to average.  The number of elements must match the pipes argument.  If no models are given, then all will be used.", 
 855      can_be_none = True 
 856  ) 
 857  uf.add_keyarg( 
 858      name = "molecules", 
 859      py_type = "str_list_of_lists", 
 860      desc_short = "molecule list for each data pipe", 
 861      desc = "The list of molecules for each data pipe to average.  This allows differently named molecules in the same or different data pipes to be averaged.  The number of elements must match the pipes argument.  If no molecules are given, then all will be used.", 
 862      can_be_none = True 
 863  ) 
 864  uf.add_keyarg( 
 865      name = "atom_id", 
 866      py_type = "str", 
 867      desc_short = "atom identification string", 
 868      desc = "The atom identification string of the coordinates of interest.  This can be used to restrict the averaged structure to one atom per residue, for example.", 
 869      can_be_none = True 
 870  ) 
 871  uf.add_keyarg( 
 872      name = "set_mol_name", 
 873      py_type = "str", 
 874      desc_short = "averaged molecule name", 
 875      desc = "Set the optional name of the averaged molecule.", 
 876      can_be_none = True 
 877  ) 
 878  uf.add_keyarg( 
 879      name = "set_model_num", 
 880      py_type = "int", 
 881      desc_short = "averaged model number", 
 882      desc = "Set the optional model number of the averaged molecule.", 
 883      can_be_none = True 
 884  ) 
 885  # Description. 
 886  uf.desc.append(Desc_container()) 
 887  uf.desc[-1].add_paragraph("This will calculate and store the mean structure from a collection of related molecules.  If a new molecule name or model number is not supplied, the mean structure will replace all the models in the internal structural object.  This is provided as a structural aid, specifically for superimposition purposes.") 
 888  uf.backend = pipe_control.structure.main.average_structure 
 889  uf.menu_text = "&mean" 
 890  uf.gui_icon = "oxygen.categories.applications-education" 
 891  uf.wizard_size = (800, 600) 
 892  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
 893   
 894   
 895  # The structure.pca user function. 
 896  uf = uf_info.add_uf('structure.pca') 
 897  uf.title = "Principle component analysis (PCA) of the motions in an ensemble of structures." 
 898  uf.title_short = "Structural PCA." 
 899  uf.add_keyarg( 
 900      name = "pipes", 
 901      py_type = "str_list", 
 902      desc_short = "data pipes", 
 903      desc = "The data pipes to perform the PC analysis on.", 
 904      wiz_combo_iter = pipe_names, 
 905      wiz_read_only = False, 
 906      can_be_none = True 
 907  ) 
 908  uf.add_keyarg( 
 909      name = "models", 
 910      py_type = "int_list_of_lists", 
 911      desc_short = "model list for each data pipe", 
 912      desc = "The list of models for each data pipe to perform the PC analysis on.  The number of elements must match the pipes argument.  If no models are given, then all will be used.", 
 913      can_be_none = True 
 914  ) 
 915  uf.add_keyarg( 
 916      name = "molecules", 
 917      py_type = "str_list_of_lists", 
 918      desc_short = "molecule list for each data pipe", 
 919      desc = "The list of molecules for each data pipe to perform the PC analysis on.  The PCA will only be calculated for atoms with identical residue name and number and atom name.  The number of elements must match the pipes argument.  If no molecules are given, then all will be used.", 
 920      can_be_none = True 
 921  ) 
 922  uf.add_keyarg( 
 923      name = "obs_pipes", 
 924      py_type = "str_list", 
 925      desc_short = "observing data pipes", 
 926      desc = "The data pipes in the PC analysis which will have zero weight.  These structures are for comparison.", 
 927      wiz_combo_iter = pipe_names, 
 928      wiz_read_only = False, 
 929      can_be_none = True 
 930  ) 
 931  uf.add_keyarg( 
 932      name = "obs_models", 
 933      py_type = "int_list_of_lists", 
 934      desc_short = "observing model list for each data pipe", 
 935      desc = "The list of models for each data pipe in the PC analysis which will have zero weight.  These structures are for comparison.  The number of elements must match the pipes argument.  If no models are given, then all will be used.", 
 936      can_be_none = True 
 937  ) 
 938  uf.add_keyarg( 
 939      name = "obs_molecules", 
 940      py_type = "str_list_of_lists", 
 941      desc_short = "observing molecule list for each data pipe", 
 942      desc = "The list of molecules for each data pipe in the PC analysis which will have zero weight.  These structures are for comparison.  The PCA will only be calculated for atoms with identical residue name and number and atom name.  The number of elements must match the pipes argument.  If no molecules are given, then all will be used.", 
 943      can_be_none = True 
 944  ) 
 945  uf.add_keyarg( 
 946      name = "atom_id", 
 947      py_type = "str", 
 948      desc_short = "atom identification string", 
 949      desc = "The atom identification string of the coordinates of interest.", 
 950      can_be_none = True 
 951  ) 
 952  uf.add_keyarg( 
 953      name = "algorithm", 
 954      default = "eigen", 
 955      py_type = "str", 
 956      desc_short = "PCA algorithm", 
 957      desc = "The PCA algorithm used to find the principle components of.  This can be either 'eigen' for an eigenvalue/eigenvector decomposition, or 'svd' for a singular value decomposition.", 
 958      wiz_element_type = "combo", 
 959      wiz_combo_choices = ["eigen", "svd"], 
 960      wiz_read_only = True 
 961  ) 
 962  uf.add_keyarg( 
 963      name = "num_modes", 
 964      py_type = "int", 
 965      default = 4, 
 966      min = 1, 
 967      max = 1000, 
 968      desc_short = "number of modes", 
 969      desc = "The number of PCA modes to calculate." 
 970  ) 
 971  uf.add_keyarg( 
 972      name = "format", 
 973      default = "grace", 
 974      py_type = "str", 
 975      desc_short = "graph format", 
 976      desc = "The format of the plot data.", 
 977      wiz_element_type = "combo", 
 978      wiz_combo_choices = ["grace"], 
 979      wiz_read_only = True, 
 980      can_be_none = True 
 981  ) 
 982  uf.add_keyarg( 
 983      name = "dir", 
 984      py_type = "str", 
 985      arg_type = "dir sel", 
 986      desc_short = "directory name", 
 987      desc = "The directory to save the graphs into.", 
 988      can_be_none = True 
 989  ) 
 990  # Description. 
 991  uf.desc.append(Desc_container()) 
 992  uf.desc[-1].add_paragraph("Perform a principle component analysis (PCA) for all the chosen structures.  2D graphs of the PC projections will be generated and placed in the specified directory.") 
 993  uf.desc[-1].add_paragraph(paragraph_multi_struct) 
 994  uf.desc[-1].add_paragraph("A subset of the structures can be set as 'observing'.  This means that they will have a weight of zero when constructing the covariance matrix and determining its eigenvectors.  Therefore the structures will not contribute to the principle components, but will be present and compared to structures used in the analysis.") 
 995  uf.desc[-1].add_paragraph(paragraph_atom_id) 
 996  # Prompt examples. 
 997  uf.desc.append(Desc_container("Prompt examples")) 
 998  uf.desc[-1].add_paragraph("To determine the PCA modes of all models in the current data pipe, simply type:") 
 999  uf.desc[-1].add_prompt("relax> structure.pca()") 
1000  uf.backend = pipe_control.structure.main.pca 
1001  uf.menu_text = "&pca" 
1002  uf.wizard_height_desc = 300 
1003  uf.wizard_size = (1000, 750) 
1004  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1005   
1006   
1007  # The structure.read_gaussian user function. 
1008  uf = uf_info.add_uf('structure.read_gaussian') 
1009  uf.title = "Reading structures from Gaussian log files." 
1010  uf.title_short = "Gaussian log structure reading." 
1011  uf.add_keyarg( 
1012      name = "file", 
1013      py_type = "str", 
1014      arg_type = "file sel", 
1015      desc_short = "file name", 
1016      desc = "The name of the Gaussian log file.", 
1017      wiz_filesel_wildcard = WILDCARD_STRUCT_GAUSSIAN_ALL, 
1018      wiz_filesel_style = FD_OPEN 
1019  ) 
1020  uf.add_keyarg( 
1021      name = "dir", 
1022      py_type = "str", 
1023      arg_type = "dir", 
1024      desc_short = "directory name", 
1025      desc = "The directory where the file is located.", 
1026      can_be_none = True 
1027  ) 
1028  uf.add_keyarg( 
1029      name = "set_mol_name", 
1030      py_type = "str_or_str_list", 
1031      desc_short = "setting of molecule names", 
1032      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.", 
1033      can_be_none = True 
1034  ) 
1035  uf.add_keyarg( 
1036      name = "set_model_num", 
1037      py_type = "int_or_int_list", 
1038      desc_short = "setting of model numbers", 
1039      desc = "Set the model numbers of the loaded molecules.  This can be a single number or list of numbers.", 
1040      can_be_none = True 
1041  ) 
1042  uf.add_keyarg( 
1043      name = "verbosity", 
1044      default = 1, 
1045      py_type = "int", 
1046      desc_short = "verbosity level", 
1047      desc = "The amount of information to print out.  Set to zero to silence the user function, or one to see all messages." 
1048  ) 
1049  # Description. 
1050  uf.desc.append(Desc_container()) 
1051  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.") 
1052  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.") 
1053  # Prompt examples. 
1054  uf.desc.append(Desc_container("Prompt examples")) 
1055  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:") 
1056  uf.desc[-1].add_prompt("relax> structure.read_gaussian('taxol.log', '~/logs')") 
1057  uf.desc[-1].add_prompt("relax> structure.read_gaussian(file='taxol.log', dir=logs')") 
1058  uf.backend = pipe_control.structure.main.read_gaussian 
1059  uf.menu_text = "read_&gaussian" 
1060  uf.gui_icon = "oxygen.actions.document-open" 
1061  uf.wizard_height_desc = 400 
1062  uf.wizard_size = (900, 600) 
1063  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'read_xyz.png' 
1064   
1065   
1066  # The structure.read_pdb user function. 
1067  uf = uf_info.add_uf('structure.read_pdb') 
1068  uf.title = "Reading structures from PDB files." 
1069  uf.title_short = "PDB reading." 
1070  uf.add_keyarg( 
1071      name = "file", 
1072      py_type = "str", 
1073      arg_type = "file sel", 
1074      desc_short = "file name", 
1075      desc = "The name of the PDB file.", 
1076      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
1077      wiz_filesel_style = FD_OPEN 
1078  ) 
1079  uf.add_keyarg( 
1080      name = "dir", 
1081      py_type = "str", 
1082      arg_type = "dir", 
1083      desc_short = "directory name", 
1084      desc = "The directory where the file is located.", 
1085      can_be_none = True 
1086  ) 
1087  uf.add_keyarg( 
1088      name = "read_mol", 
1089      py_type = "int_or_int_list", 
1090      desc_short = "molecule number to read", 
1091      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.", 
1092      can_be_none = True 
1093  ) 
1094  uf.add_keyarg( 
1095      name = "set_mol_name", 
1096      py_type = "str_or_str_list", 
1097      desc_short = "setting of molecule names", 
1098      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.", 
1099      can_be_none = True 
1100  ) 
1101  uf.add_keyarg( 
1102      name = "read_model", 
1103      py_type = "int_or_int_list", 
1104      desc_short = "model to read", 
1105      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.", 
1106      can_be_none = True 
1107  ) 
1108  uf.add_keyarg( 
1109      name = "set_model_num", 
1110      py_type = "int_or_int_list", 
1111      desc_short = "setting of model numbers", 
1112      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.", 
1113      can_be_none = True 
1114  ) 
1115  uf.add_keyarg( 
1116      name = "alt_loc", 
1117      py_type = "str", 
1118      desc_short = "alternate location indicator", 
1119      desc = "The PDB ATOM record 'Alternate location indicator' field value.", 
1120      can_be_none = True 
1121  ) 
1122  uf.add_keyarg( 
1123      name = "verbosity", 
1124      default = 1, 
1125      py_type = "int", 
1126      desc_short = "verbosity level", 
1127      desc = "The amount of information to print out.  Set to zero to silence the user function, or one to see all messages." 
1128  ) 
1129  uf.add_keyarg( 
1130      name = "merge", 
1131      default = False, 
1132      py_type = "bool", 
1133      desc_short = "merge structure flag", 
1134      desc = "A flag which if set to True will try to merge the PDB structure into the currently loaded structures." 
1135  ) 
1136  # Description. 
1137  uf.desc.append(Desc_container()) 
1138  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.") 
1139  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.") 
1140  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.") 
1141  uf.desc[-1].add_paragraph("Note that relax will complain if it cannot work out what to do.") 
1142  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.") 
1143  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 selected.") 
1144  # Prompt examples. 
1145  uf.desc.append(Desc_container("Prompt examples")) 
1146  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:") 
1147  uf.desc[-1].add_prompt("relax> structure.read_pdb('test.pdb', '~/pdb')") 
1148  uf.desc[-1].add_prompt("relax> structure.read_pdb(file='test.pdb', dir='pdb')") 
1149  uf.desc[-1].add_paragraph("To load the 10th model from the file 'test.pdb' and naming it 'CaM', use one of:") 
1150  uf.desc[-1].add_prompt("relax> structure.read_pdb('test.pdb', read_model=10, set_mol_name='CaM')") 
1151  uf.desc[-1].add_prompt("relax> structure.read_pdb(file='test.pdb', read_model=10, set_mol_name='CaM')") 
1152  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:") 
1153  uf.desc[-1].add_prompt("relax> structure.read_pdb('test.pdb', read_model=[1, 5], set_model_num=[1, 1])") 
1154  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])") 
1155  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:") 
1156  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_1.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=1)") 
1157  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_2.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=2)") 
1158  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_3.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=3)") 
1159  uf.desc[-1].add_prompt("relax> structure.read_pdb('lactose_MCMM4_S1_4.pdb', set_mol_name='lactose_MCMM4_S1', set_model_num=4)") 
1160  uf.backend = pipe_control.structure.main.read_pdb 
1161  uf.menu_text = "read_&pdb" 
1162  uf.gui_icon = "oxygen.actions.document-open" 
1163  uf.wizard_height_desc = 360 
1164  uf.wizard_size = (1000, 750) 
1165  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'read_pdb.png' 
1166   
1167   
1168  # The structure.read_xyz user function. 
1169  uf = uf_info.add_uf('structure.read_xyz') 
1170  uf.title = "Reading structures from XYZ files." 
1171  uf.title_short = "XYZ reading." 
1172  uf.add_keyarg( 
1173      name = "file", 
1174      py_type = "str", 
1175      arg_type = "file sel", 
1176      desc_short = "file name", 
1177      desc = "The name of the XYZ file.", 
1178      wiz_filesel_wildcard = WILDCARD_STRUCT_XYZ_ALL, 
1179      wiz_filesel_style = FD_OPEN 
1180  ) 
1181  uf.add_keyarg( 
1182      name = "dir", 
1183      py_type = "str", 
1184      arg_type = "dir", 
1185      desc_short = "directory name", 
1186      desc = "The directory where the file is located.", 
1187      can_be_none = True 
1188  ) 
1189  uf.add_keyarg( 
1190      name = "read_mol", 
1191      py_type = "int_or_int_list", 
1192      desc_short = "molecule number to read", 
1193      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.", 
1194      can_be_none = True 
1195  ) 
1196  uf.add_keyarg( 
1197      name = "set_mol_name", 
1198      py_type = "str_or_str_list", 
1199      desc_short = "setting of molecule names", 
1200      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.", 
1201      can_be_none = True 
1202  ) 
1203  uf.add_keyarg( 
1204      name = "read_model", 
1205      py_type = "int_or_int_list", 
1206      desc_short = "model to read", 
1207      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.", 
1208      can_be_none = True 
1209  ) 
1210  uf.add_keyarg( 
1211      name = "set_model_num", 
1212      py_type = "int_or_int_list", 
1213      desc_short = "setting of model numbers", 
1214      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.", 
1215      can_be_none = True 
1216  ) 
1217  uf.add_keyarg( 
1218      name = "verbosity", 
1219      default = 1, 
1220      py_type = "int", 
1221      desc_short = "verbosity level", 
1222      desc = "The amount of information to print out.  Set to zero to silence the user function, or one to see all messages." 
1223  ) 
1224  # Description. 
1225  uf.desc.append(Desc_container()) 
1226  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.") 
1227  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.") 
1228  uf.desc[-1].add_paragraph("Note that relax will complain if it cannot work out what to do.") 
1229  # Prompt examples. 
1230  uf.desc.append(Desc_container("Prompt examples")) 
1231  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:") 
1232  uf.desc[-1].add_prompt("relax> structure.read_xyz('test.xyz', '~/xyz')") 
1233  uf.desc[-1].add_prompt("relax> structure.read_xyz(file='test.xyz', dir='xyz')") 
1234  uf.desc[-1].add_paragraph("To load the 10th model from the file 'test.xyz' and naming it 'CaM', use one of:") 
1235  uf.desc[-1].add_prompt("relax> structure.read_xyz('test.xyz', read_model=10, set_mol_name='CaM')") 
1236  uf.desc[-1].add_prompt("relax> structure.read_xyz(file='test.xyz', read_model=10, set_mol_name='CaM')") 
1237  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:") 
1238  uf.desc[-1].add_prompt("relax> structure.read_xyz('test.xyz', read_model=[1, 5], set_model_num=[1, 1])") 
1239  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])") 
1240  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:") 
1241  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_1.xyz', set_mol_name='test_1', set_model_num=1)") 
1242  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_2.xyz', set_mol_name='test_2', set_model_num=2)") 
1243  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_3.xyz', set_mol_name='test_3', set_model_num=3)") 
1244  uf.desc[-1].add_prompt("relax> structure.read_xyz('test_4.xyz', set_mol_name='test_4', set_model_num=4)") 
1245  uf.backend = pipe_control.structure.main.read_xyz 
1246  uf.menu_text = "read_&xyz" 
1247  uf.gui_icon = "oxygen.actions.document-open" 
1248  uf.wizard_height_desc = 400 
1249  uf.wizard_size = (900, 700) 
1250  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'read_xyz.png' 
1251   
1252   
1253  # The structure.rmsd user function. 
1254  uf = uf_info.add_uf('structure.rmsd') 
1255  uf.title = "Determine the RMSD between structures." 
1256  uf.title_short = "Structural RMSD." 
1257  uf.add_keyarg( 
1258      name = "pipes", 
1259      py_type = "str_list", 
1260      desc_short = "data pipes", 
1261      desc = "The data pipes to determine the RMSD for.", 
1262      wiz_combo_iter = pipe_names, 
1263      wiz_read_only = False, 
1264      can_be_none = True 
1265  ) 
1266  uf.add_keyarg( 
1267      name = "models", 
1268      py_type = "int_list_of_lists", 
1269      desc_short = "model list for each data pipe", 
1270      desc = "The list of models for each data pipe to determine the RMSD for.  The number of elements must match the pipes argument.  If no models are given, then all will be used.", 
1271      can_be_none = True 
1272  ) 
1273  uf.add_keyarg( 
1274      name = "molecules", 
1275      py_type = "str_list_of_lists", 
1276      desc_short = "molecule list for each data pipe", 
1277      desc = "The list of molecules for each data pipe to determine the RMSD for.  The RMSD will only be calculated for atoms with identical residue name and number and atom name.  The number of elements must match the pipes argument.  If no molecules are given, then all will be used.", 
1278      can_be_none = True 
1279  ) 
1280  uf.add_keyarg( 
1281      name = "atom_id", 
1282      py_type = "str", 
1283      desc_short = "atom identification string", 
1284      desc = "The atom identification string of the coordinates of interest.", 
1285      can_be_none = True 
1286  ) 
1287  uf.add_keyarg( 
1288      name = "atomic", 
1289      default = False, 
1290      py_type = "bool", 
1291      desc_short = "atomic-level RMSD flag", 
1292      desc = "A flag which if if True will allow for per-atom RMSDs to be additionally calculated." 
1293  ) 
1294  # Description. 
1295  uf.desc.append(Desc_container()) 
1296  uf.desc[-1].add_paragraph("This allows the root mean squared deviation (RMSD) between all structures to be calculated.  The RMSDs for individual structures to the mean structure will be calculated and reported.  These values averaged to produce a global RMSD stored in the structural object of the current data pipe.  If the 'atomic' argument is set, per-atom RMSDs will additionally be calculated stored in spin containers.") 
1297  uf.desc[-1].add_paragraph(paragraph_multi_struct) 
1298  uf.desc[-1].add_paragraph(paragraph_atom_id) 
1299  # Prompt examples. 
1300  uf.desc.append(Desc_container("Prompt examples")) 
1301  uf.desc[-1].add_paragraph("To determine the RMSD of all models in the current data pipe, simply type:") 
1302  uf.desc[-1].add_prompt("relax> structure.rmsd()") 
1303  uf.desc[-1].add_paragraph("For the backbone heavy atom RMSD of all models in the current data pipe, simply type:") 
1304  uf.desc[-1].add_prompt("relax> structure.rmsd(atom_id='@N,C,CA,O')") 
1305  uf.desc[-1].add_paragraph("To calculate the C-alpha backbone RMSDs of all models in the current data pipe, type:") 
1306  uf.desc[-1].add_prompt("relax> structure.rmsd(atom_id='CA', atomic=True)") 
1307  uf.backend = pipe_control.structure.main.rmsd 
1308  uf.menu_text = "&rmsd" 
1309  uf.wizard_height_desc = 400 
1310  uf.wizard_size = (900, 700) 
1311  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1312   
1313   
1314  # The structure.rotate user function. 
1315  uf = uf_info.add_uf('structure.rotate') 
1316  uf.title = "Rotate the internal structural object about the given origin by the rotation matrix." 
1317  uf.title_short = "Structure rotation." 
1318  uf.add_keyarg( 
1319      name = "R", 
1320      py_type = "float_matrix", 
1321      default = eye(3), 
1322      dim = (3, 3), 
1323      desc_short = "rotation matrix", 
1324      desc = "The rotation matrix in forwards rotation notation." 
1325  ) 
1326  uf.add_keyarg( 
1327      name = "origin", 
1328      py_type = "float_array", 
1329      dim = 3, 
1330      desc_short = "origin of rotation", 
1331      desc = "The origin or pivot of the rotation.", 
1332      can_be_none = True 
1333  ) 
1334  uf.add_keyarg( 
1335      name = "model", 
1336      py_type = "int", 
1337      desc_short = "model", 
1338      desc = "The model to rotate (which if not set will cause all models to be rotated).", 
1339      can_be_none = True 
1340  ) 
1341  uf.add_keyarg( 
1342      name = "atom_id", 
1343      py_type = "str", 
1344      desc_short = "atom ID string", 
1345      desc = "The atom identification string.", 
1346      can_be_none = True 
1347  ) 
1348  # Description. 
1349  uf.desc.append(Desc_container()) 
1350  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.") 
1351  uf.backend = pipe_control.structure.main.rotate 
1352  uf.menu_text = "&rotate" 
1353  uf.wizard_height_desc = 300 
1354  uf.wizard_size = (800, 600) 
1355  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1356   
1357   
1358  # The structure.sequence_alignment user function. 
1359  uf = uf_info.add_uf('structure.sequence_alignment') 
1360  uf.title = "Multiple sequence alignment (MSA) of structural data." 
1361  uf.title_short = "Multiple sequence alignment." 
1362  uf.add_keyarg( 
1363      name = "pipes", 
1364      py_type = "str_list", 
1365      desc_short = "data pipes", 
1366      desc = "The data pipes to use in the sequence alignment.", 
1367      wiz_combo_iter = pipe_names, 
1368      wiz_read_only = False, 
1369      can_be_none = True 
1370  ) 
1371  uf.add_keyarg( 
1372      name = "models", 
1373      py_type = "int_list_of_lists", 
1374      desc_short = "model list for each data pipe", 
1375      desc = "The list of models for each data pipe to use in the sequence alignment.  The number of elements must match the pipes argument.  If no models are given, then all will be used.", 
1376      can_be_none = True 
1377  ) 
1378  uf.add_keyarg( 
1379      name = "molecules", 
1380      py_type = "str_list_of_lists", 
1381      desc_short = "molecule list for each data pipe", 
1382      desc = "The list of molecules for each data pipe to use in the sequence alignment.  This allows differently named molecules in the same or different data pipes to be superimposed.  The number of elements must match the pipes argument.  If no molecules are given, then all will be used.", 
1383      can_be_none = True 
1384  ) 
1385  uf.add_keyarg( 
1386      name = "msa_algorithm", 
1387      default = "Central Star", 
1388      py_type = "str", 
1389      desc_short = "multiple sequence alignment (MSA) algorithm", 
1390      desc = "The multiple sequence alignment (MSA) algorithm used to align all the primary sequence of all structures of interest.", 
1391      wiz_element_type = "combo", 
1392      wiz_combo_choices = ["Central Star", "residue number"], 
1393      wiz_read_only = True 
1394  ) 
1395  uf.add_keyarg( 
1396      name = "pairwise_algorithm", 
1397      default = None, 
1398      py_type = "str", 
1399      desc_short = "pairwise alignment algorithm", 
1400      desc = "The pairwise alignment algorithm to align each pair of sequences.", 
1401      wiz_element_type = "combo", 
1402      wiz_combo_choices = ["NW70"], 
1403      wiz_read_only = True, 
1404      can_be_none = True 
1405  ) 
1406  uf.add_keyarg( 
1407      name = "matrix", 
1408      default = None, 
1409      py_type = "str", 
1410      desc_short = "substitution matrix", 
1411      desc = "The substitution matrix to use in the pairwise sequence alignment algorithm.", 
1412      wiz_element_type = "combo", 
1413      wiz_combo_choices = ["BLOSUM62", "PAM250", "NUC 4.4"], 
1414      wiz_read_only = True, 
1415      can_be_none = True 
1416  ) 
1417  uf.add_keyarg( 
1418      name = "gap_open_penalty", 
1419      default = 10.0, 
1420      py_type = "float", 
1421      desc_short = "gap opening penalty", 
1422      desc = "The penalty for introducing gaps, as a positive number." 
1423  ) 
1424  uf.add_keyarg( 
1425      name = "gap_extend_penalty", 
1426      default = 1.0, 
1427      py_type = "float", 
1428      desc_short = "gap extension penalty", 
1429      desc = "The penalty for extending a gap, as a positive number." 
1430  ) 
1431  uf.add_keyarg( 
1432      name = "end_gap_open_penalty", 
1433      default = 0.0, 
1434      py_type = "float", 
1435      desc_short = "end gap opening penalty", 
1436      desc = "The optional penalty for opening a gap at the end of a sequence." 
1437  ) 
1438  uf.add_keyarg( 
1439      name = "end_gap_extend_penalty", 
1440      default = 0.0, 
1441      py_type = "float", 
1442      desc_short = "end gap extension penalty", 
1443      desc = "The optional penalty for extending a gap at the end of a sequence." 
1444  ) 
1445  # Description. 
1446  uf.desc.append(Desc_container()) 
1447  uf.desc[-1].add_paragraph("To find the atoms in common between different molecules, a MSA of the primary sequence of the molecules is required.  This sequence alignment will then subsequently be used by any other user function which operates on multiple molecules.  The following MSA algorithms can be selected:") 
1448  uf.desc[-1].add_item_list_element("'Central Star'", "This is a heuristic, progressive alignment method using pairwise alignments to construct a MSA.  It consists of four major steps - pairwise alignment between all sequence pairs, finding the central sequence, iteratively aligning the sequences to the gapped central sequence, and introducing gaps in previous alignments during the iterative alignment.") 
1449  uf.desc[-1].add_item_list_element("'residue number'", "This will simply align the molecules based on residue number.") 
1450  uf.desc[-1].add_paragraph("For the MSA algorithms which require pairwise alignments, the following subalgorithms can be used:") 
1451  uf.desc[-1].add_item_list_element("'NW70'", "The Needleman-Wunsch alignment algorithm.  This has been modified to use the logic of the EMBOSS software for handling gap opening and extension penalties, as well as end penalties.") 
1452  uf.desc[-1].add_paragraph("For the MSAs or pairwise alignments which require a substitution matrix, one of the following can be used:") 
1453  uf.desc[-1].add_item_list_element("'BLOSUM62'", "The BLOcks SUbstitution Matrix for proteins with a cluster percentage >= 62%.") 
1454  uf.desc[-1].add_item_list_element("'PAM250'", "The point accepted mutation matrix for proteins with n = 250 evolutionary distance.") 
1455  uf.desc[-1].add_item_list_element("'NUC 4.4'", "The nucleotide 4.4 matrix for DNA/RNA.") 
1456  uf.desc[-1].add_paragraph(paragraph_multi_struct) 
1457  # Prompt examples. 
1458  uf.desc.append(Desc_container("Prompt examples")) 
1459  uf.desc[-1].add_paragraph("To superimpose the structures in the 'A' data pipe onto the structures of the 'B' data pipe using backbone heavy atoms, type:") 
1460  uf.desc[-1].add_prompt("relax> structure.sequence_alignment(pipes=['B', 'A'], atom_id='@N,C,CA,O')") 
1461  uf.backend = pipe_control.structure.main.sequence_alignment 
1462  uf.menu_text = "&sequence_alignment" 
1463  uf.wizard_apply_button = False 
1464  uf.wizard_height_desc = 320 
1465  uf.wizard_size = (1000, 750) 
1466  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1467   
1468   
1469  # The structure.superimpose user function. 
1470  uf = uf_info.add_uf('structure.superimpose') 
1471  uf.title = "Superimpose a set of structures." 
1472  uf.title_short = "Structural superimposition." 
1473  uf.add_keyarg( 
1474      name = "pipes", 
1475      py_type = "str_list", 
1476      desc_short = "data pipes", 
1477      desc = "The data pipes to use in the superimposition.", 
1478      wiz_combo_iter = pipe_names, 
1479      wiz_read_only = False, 
1480      can_be_none = True 
1481  ) 
1482  uf.add_keyarg( 
1483      name = "models", 
1484      py_type = "int_list_of_lists", 
1485      desc_short = "model list for each data pipe", 
1486      desc = "The list of models for each data pipe to use in the superimposition.  The number of elements must match the pipes argument.  If no models are given, then all will be used.", 
1487      can_be_none = True 
1488  ) 
1489  uf.add_keyarg( 
1490      name = "molecules", 
1491      py_type = "str_list_of_lists", 
1492      desc_short = "molecule list for each data pipe", 
1493      desc = "The list of molecules for each data pipe to use in the superimposition.  This allows differently named molecules in the same or different data pipes to be superimposed.  The number of elements must match the pipes argument.  If no molecules are given, then all will be used.", 
1494      can_be_none = True 
1495  ) 
1496  uf.add_keyarg( 
1497      name = "atom_id", 
1498      py_type = "str", 
1499      desc_short = "atom ID string", 
1500      desc = "The atom identification string of the coordinates of interest.  This allows a subset of all residues or atoms to be used in the superimposition.  For example for protein backbone heavy atoms, this can be set to '@N,C,CA,O'.", 
1501      can_be_none = True 
1502  ) 
1503  uf.add_keyarg( 
1504      name = "displace_id", 
1505      py_type = "str_or_str_list", 
1506      desc_short = "displacement ID string(s)", 
1507      desc = "The atom identification string for restricting the displacement to a subset of all atoms.  If not set, then all atoms will be translated and rotated.  If supplied as a list of IDs, then the number of items must match the number of structures.", 
1508      can_be_none = True 
1509  ) 
1510  uf.add_keyarg( 
1511      name = "method", 
1512      default = "fit to mean", 
1513      py_type = "str", 
1514      desc_short = "superimposition method", 
1515      desc = "The superimposition method.", 
1516      wiz_element_type = "combo", 
1517      wiz_combo_choices = ["fit to mean", "fit to first"], 
1518      wiz_read_only = True 
1519  ) 
1520  uf.add_keyarg( 
1521      name = "centre_type", 
1522      py_type = "str", 
1523      default = "centroid", 
1524      desc_short = "centre type", 
1525      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).", 
1526      wiz_element_type = "combo", 
1527      wiz_combo_choices = ["The centroid", "The centre of mass (CoM)"], 
1528      wiz_combo_data = ["centroid", "CoM"] 
1529  ) 
1530  uf.add_keyarg( 
1531      name = "centroid", 
1532      py_type = "float_array", 
1533      desc_short = "centroid position", 
1534      desc = "The alternative position of the centroid.", 
1535      can_be_none = True 
1536  ) 
1537  # Description. 
1538  uf.desc.append(Desc_container()) 
1539  uf.desc[-1].add_paragraph("This allows a set of related structures to be superimposed to each other.  If a multiple sequence alignment (MSA) of the molecules has already been performed with the structure.sequence_alignment user function, this will allow residues with different numbering to be superimposed.  Otherwise only residues with the same numbering will be used in the superimposition.  Two superimposition methods are currently supported:") 
1540  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.") 
1541  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 of the first data pipe.") 
1542  uf.desc[-1].add_paragraph(paragraph_multi_struct) 
1543  uf.desc[-1].add_paragraph(paragraph_atom_id) 
1544  uf.desc[-1].add_paragraph(paragraph_displace_id) 
1545  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.") 
1546  # Prompt examples. 
1547  uf.desc.append(Desc_container("Prompt examples")) 
1548  uf.desc[-1].add_paragraph("To superimpose all sets of models, type one of:") 
1549  uf.desc[-1].add_prompt("relax> structure.superimpose()") 
1550  uf.desc[-1].add_prompt("relax> structure.superimpose(method='fit to mean')") 
1551  uf.desc[-1].add_paragraph("To superimpose the models 1, 2, 3, 5 onto model 4, type:") 
1552  uf.desc[-1].add_prompt("relax> structure.superimpose(models=[[4, 1, 2, 3, 5]], method='fit to first')") 
1553  uf.desc[-1].add_paragraph("To superimpose an ensemble of protein structures using only the backbone heavy atoms, type one of:") 
1554  uf.desc[-1].add_prompt("relax> structure.superimpose(atom_id='@N,C,CA,O')") 
1555  uf.desc[-1].add_prompt("relax> structure.superimpose(method='fit to mean', atom_id='@N,C,CA,O')") 
1556  uf.desc[-1].add_paragraph("To superimpose the structures in the 'A' data pipe onto the structures of the 'B' data pipe using backbone heavy atoms, type one of:") 
1557  uf.desc[-1].add_prompt("relax> structure.superimpose(['B', 'A'], None, 'fit to first', '@N,C,CA,O')") 
1558  uf.desc[-1].add_prompt("relax> structure.superimpose(pipes=['B', 'A'], method='fit to first', atom_id='@N,C,CA,O')") 
1559  uf.backend = pipe_control.structure.main.superimpose 
1560  uf.menu_text = "&superimpose" 
1561  uf.wizard_apply_button = False 
1562  uf.wizard_height_desc = 370 
1563  uf.wizard_size = (1000, 750) 
1564  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1565   
1566   
1567  # The structure.translate user function. 
1568  uf = uf_info.add_uf('structure.translate') 
1569  uf.title = "Laterally displace the internal structural object by the translation vector." 
1570  uf.title_short = "Structure translation." 
1571  uf.add_keyarg( 
1572      name = "T", 
1573      py_type = "float_array", 
1574      dim = 3, 
1575      desc_short = "translation vector", 
1576      desc = "The translation vector." 
1577  ) 
1578  uf.add_keyarg( 
1579      name = "model", 
1580      py_type = "int", 
1581      desc_short = "model", 
1582      desc = "The model to translate (which if not set will cause all models to be translate).", 
1583      can_be_none = True 
1584  ) 
1585  uf.add_keyarg( 
1586      name = "atom_id", 
1587      py_type = "str", 
1588      desc_short = "atom ID string", 
1589      desc = "The atom identification string.", 
1590      can_be_none = True 
1591  ) 
1592  # Description. 
1593  uf.desc.append(Desc_container()) 
1594  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.") 
1595  uf.backend = pipe_control.structure.main.translate 
1596  uf.menu_text = "&translate" 
1597  uf.wizard_size = (750, 500) 
1598  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1599   
1600   
1601  # The structure.web_of_motion user function. 
1602  uf = uf_info.add_uf('structure.web_of_motion') 
1603  uf.title = "Create a PDB representation of motion between structures using a web of interconnecting lines." 
1604  uf.title_short = "Web of motion between models." 
1605  uf.add_keyarg( 
1606      name = "pipes", 
1607      py_type = "str_list", 
1608      desc_short = "data pipes", 
1609      desc = "The data pipes to generate the web between.", 
1610      wiz_combo_iter = pipe_names, 
1611      wiz_read_only = False, 
1612      can_be_none = True 
1613  ) 
1614  uf.add_keyarg( 
1615      name = "models", 
1616      py_type = "int_list_of_lists", 
1617      desc_short = "model list for each data pipe", 
1618      desc = "The list of models for each data pipe to generate the web between.  The number of elements must match the pipes argument.  If no models are given, then all will be used.", 
1619      can_be_none = True 
1620  ) 
1621  uf.add_keyarg( 
1622      name = "molecules", 
1623      py_type = "str_list_of_lists", 
1624      desc_short = "molecule list for each data pipe", 
1625      desc = "The list of molecules for each data pipe to generate the web between.  This allows differently named molecules in the same or different data pipes to be superimposed.  The number of elements must match the pipes argument.  If no molecules are given, then all will be used.", 
1626      can_be_none = True 
1627  ) 
1628  uf.add_keyarg( 
1629      name = "atom_id", 
1630      py_type = "str", 
1631      desc_short = "atom identification string", 
1632      desc = "The atom identification string of the coordinates of interest.", 
1633      can_be_none = True 
1634  ) 
1635  uf.add_keyarg( 
1636      name = "file", 
1637      py_type = "str_or_inst", 
1638      arg_type = "file sel", 
1639      desc_short = "file name", 
1640      desc = "The name of the PDB file.", 
1641      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
1642      wiz_filesel_style = FD_SAVE 
1643  ) 
1644  uf.add_keyarg( 
1645      name = "dir", 
1646      py_type = "str", 
1647      arg_type = "dir", 
1648      desc_short = "directory name", 
1649      desc = "The directory to save the file to.", 
1650      can_be_none = True 
1651  ) 
1652  uf.add_keyarg( 
1653      name = "force", 
1654      default = False, 
1655      py_type = "bool", 
1656      desc_short = "force flag", 
1657      desc = "A flag which if set to True will cause any pre-existing files to be overwritten." 
1658  ) 
1659  # Description. 
1660  uf.desc.append(Desc_container()) 
1661  uf.desc[-1].add_paragraph("This will create a PDB representation of the motion between the atoms of a given set of structures.  Identical atoms of the structures are concatenated into one model, within a temporary internal structural object, linked together using PDB CONECT records, and then written to the PDB file.") 
1662  uf.desc[-1].add_paragraph(paragraph_multi_struct) 
1663  uf.desc[-1].add_paragraph(paragraph_atom_id) 
1664  # Prompt examples. 
1665  uf.desc.append(Desc_container("Prompt examples")) 
1666  uf.desc[-1].add_paragraph("To create a web of motion for the models 1, 3, and 5, type:") 
1667  uf.desc[-1].add_prompt("relax> structure.web_of_motion(models=[[1, 3, 5]], file='web.pdb')") 
1668  uf.desc[-1].add_paragraph("To create a web of motion for the molecules 'A', 'B', 'C', and 'D', type:") 
1669  uf.desc[-1].add_prompt("relax> structure.web_of_motion(molecules=[['A', 'B', 'C', 'D']], file='web.pdb')") 
1670  uf.backend = pipe_control.structure.main.web_of_motion 
1671  uf.menu_text = "&web_of_motion" 
1672  uf.wizard_height_desc = 450 
1673  uf.wizard_size = (1000, 750) 
1674  uf.wizard_apply_button = False 
1675  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + '2JK4.png' 
1676   
1677   
1678  # The structure.write_pdb user function. 
1679  uf = uf_info.add_uf('structure.write_pdb') 
1680  uf.title = "Writing structures to a PDB file." 
1681  uf.title_short = "PDB writing." 
1682  uf.add_keyarg( 
1683      name = "file", 
1684      py_type = "str_or_inst", 
1685      arg_type = "file sel", 
1686      desc_short = "file name", 
1687      desc = "The name of the PDB file.", 
1688      wiz_filesel_wildcard = WILDCARD_STRUCT_PDB_ALL, 
1689      wiz_filesel_style = FD_SAVE 
1690  ) 
1691  uf.add_keyarg( 
1692      name = "dir", 
1693      py_type = "str", 
1694      arg_type = "dir", 
1695      desc_short = "directory name", 
1696      desc = "The directory where the file is located.", 
1697      can_be_none = True 
1698  ) 
1699  uf.add_keyarg( 
1700      name = "model_num", 
1701      py_type = "int", 
1702      desc_short = "model number", 
1703      desc = "Restrict the writing of structural data to a single model in the PDB file.", 
1704      can_be_none = True 
1705  ) 
1706  uf.add_keyarg( 
1707      name = "compress_type", 
1708      default = 0, 
1709      py_type = "int", 
1710      desc_short = "compression type", 
1711      desc = "The type of compression to use when creating the file.", 
1712      wiz_element_type = "combo", 
1713      wiz_combo_choices = [ 
1714          "No compression", 
1715          "bzip2 compression", 
1716          "gzip compression" 
1717      ], 
1718      wiz_combo_data = [ 
1719          0, 
1720          1, 
1721          2 
1722      ], 
1723      wiz_read_only = True 
1724  ) 
1725  uf.add_keyarg( 
1726      name = "force", 
1727      default = False, 
1728      py_type = "bool", 
1729      desc_short = "force flag", 
1730      desc = "A flag which if set to True will cause any pre-existing files to be overwritten." 
1731  ) 
1732  # Description. 
1733  uf.desc.append(Desc_container()) 
1734  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.") 
1735  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") 
1736  uf.desc[-1].add_item_list_element("0", "No compression (no file extension).") 
1737  uf.desc[-1].add_item_list_element("1", "bzip2 compression ('.bz2' file extension).") 
1738  uf.desc[-1].add_item_list_element("2", "gzip compression ('.gz' file extension).") 
1739  # Prompt examples. 
1740  uf.desc.append(Desc_container("Prompt examples")) 
1741  uf.desc[-1].add_paragraph("To write all models and molecules to the PDB file 'ensemble.pdb' within the directory '~/pdb', type one of:") 
1742  uf.desc[-1].add_prompt("relax> structure.write_pdb('ensemble.pdb', '~/pdb')") 
1743  uf.desc[-1].add_prompt("relax> structure.write_pdb(file='ensemble.pdb', dir='pdb')") 
1744  uf.desc[-1].add_paragraph("To write model number 3 into the new file 'test.pdb', use one of:") 
1745  uf.desc[-1].add_prompt("relax> structure.write_pdb('test.pdb', model_num=3)") 
1746  uf.desc[-1].add_prompt("relax> structure.write_pdb(file='test.pdb', model_num=3)") 
1747  uf.backend = pipe_control.structure.main.write_pdb 
1748  uf.menu_text = "&write_pdb" 
1749  uf.gui_icon = "oxygen.actions.document-save" 
1750  uf.wizard_height_desc = 400 
1751  uf.wizard_size = (900, 700) 
1752  uf.wizard_apply_button = False 
1753  uf.wizard_image = WIZARD_IMAGE_PATH + 'structure' + sep + 'write_pdb.png' 
1754