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

Source Code for Module user_functions.structure

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