1   
   2   
   3   
   4   
   5   
   6   
   7   
   8   
   9   
  10   
  11   
  12   
  13   
  14   
  15   
  16   
  17   
  18   
  19   
  20   
  21   
  22   
  23   
  24  """Module containing the introductory text container.""" 
  25   
  26   
  27  import dep_check 
  28   
  29   
  30  if dep_check.ctypes_module: 
  31      import ctypes 
  32      if hasattr(ctypes, 'windll'): 
  33          import ctypes.wintypes 
  34  else: 
  35      ctypes = None 
  36  if dep_check.ctypes_structure_module: 
  37      from ctypes import Structure 
  38  else: 
  39      Structure = object 
  40  from os import environ, pathsep, waitpid 
  41  import platform 
  42  from re import search, sub 
  43  PIPE, Popen = None, None 
  44  if dep_check.subprocess_module: 
  45      from subprocess import PIPE, Popen 
  46  import sys 
  47  from textwrap import wrap 
  48   
  49   
  50  from lib.compat import linux_distribution 
  51  from status import Status; status = Status() 
  52  from version import repo_head, repo_type, repo_url, version, version_full 
  53   
  54   
  63   
  64   
  65   
  67      """A container storing information about relax.""" 
  68   
  69       
  70      instance = None 
  71   
  73          """Create the program introduction text stings. 
  74   
  75          This class generates a container with the following objects: 
  76              - title:  The program title 'relax' 
  77              - version:  For example 'repository commit' or '1.3.8'. 
  78              - desc:  The short program description. 
  79              - copyright:  A list of copyright statements. 
  80              - licence:  Text pertaining to the licencing. 
  81              - errors:  A list of import errors. 
  82          """ 
  83   
  84           
  85          self.title = "relax" 
  86          self.version = version 
  87   
  88           
  89          self.website = "http://www.nmr-relax.com" 
  90   
  91           
  92          self.desc = "Molecular dynamics by NMR data analysis" 
  93   
  94           
  95          self.desc_long = "The program relax is designed for the study of the dynamics of proteins or other macromolecules though the analysis of experimental NMR data. It is a community driven project created by NMR spectroscopists for NMR spectroscopists. It supports exponential curve fitting for the calculation of the R1 and R2 relaxation rates, calculation of the NOE, reduced spectral density mapping, and the Lipari and Szabo model-free analysis." 
  96   
  97           
  98          self.copyright_final_year = 2024 
  99          self.copyright = [] 
 100          self.copyright.append("Copyright (C) 2001-2006 Edward d'Auvergne") 
 101          self.copyright.append("Copyright (C) 2006-%s the relax development team" % self.copyright_final_year) 
 102          self.copyright_short = "Copyright (C) 2001-%s the relax development team" % self.copyright_final_year 
 103          self.copyright_latex = r"Copyright \copyright\ 2001-%s the relax development team" % self.copyright_final_year 
 104   
 105           
 106          self.licence = "This is free software which you are welcome to modify and redistribute under the conditions of the GNU General Public License (GPL), Version 3 or any later version published by the Free Software Foundation.  This program, including all modules, is licensed under the GPL and comes with absolutely no warranty.  For details type 'GPL' within the relax prompt." 
 107   
 108           
 109          self.errors = [] 
 110          if not dep_check.C_module_exp_fn: 
 111              self.errors.append(dep_check.C_module_exp_fn_mesg) 
 112   
 113           
 114          self._setup_references() 
  115   
 116   
 117 -    def __new__(self, *args, **kargs): 
  118          """Replacement function for implementing the singleton design pattern.""" 
 119   
 120           
 121          if self.instance is None: 
 122              self.instance = object.__new__(self, *args, **kargs) 
 123   
 124           
 125          return self.instance 
  126   
 127   
 147   
 148   
 149 -    def centre(self, string, width=100): 
  150          """Format the string to be centred to a certain number of spaces. 
 151   
 152          @param string:  The string to centre. 
 153          @type string:   str 
 154          @keyword width: The number of characters to centre to. 
 155          @type width:    int 
 156          @return:        The centred string with leading whitespace added. 
 157          @rtype:         str 
 158          """ 
 159   
 160           
 161          spaces = int((width - len(string)) / 2) 
 162   
 163           
 164          string = spaces * ' ' + string 
 165   
 166           
 167          return string 
  168   
 169   
 171          """Return a string representation of the file type. 
 172   
 173          @param path:    The full path of the file to return information about. 
 174          @type path:     str 
 175          @return:        The single line file type information string. 
 176          @rtype:         str 
 177          """ 
 178   
 179           
 180          if Popen == None: 
 181              return '' 
 182   
 183           
 184          pipe = Popen('file --help', shell=True, stdout=PIPE, stderr=PIPE, close_fds=False) 
 185          err = pipe.stderr.readlines() 
 186          if err: 
 187              return '' 
 188   
 189           
 190          cmd = "file -b '%s'" % path 
 191   
 192           
 193          pipe = Popen(cmd, shell=True, stdout=PIPE, close_fds=False) 
 194          if not hasattr(ctypes, 'windll'): 
 195              waitpid(pipe.pid, 0) 
 196   
 197           
 198          data = pipe.stdout.readlines() 
 199   
 200           
 201          if data[0][:-1] == 'Mach-O universal binary with 3 architectures': 
 202               
 203              arch = [None, None, None] 
 204              for i in range(3): 
 205                  row = data[i+1].split('\t') 
 206                  arch[i] = row[1][:-1] 
 207              arch.sort() 
 208   
 209               
 210              if arch == ['Mach-O 64-bit executable x86_64', 'Mach-O executable i386', 'Mach-O executable ppc']: 
 211                  file_type = '3-way exec (i386, ppc, x86_64)' 
 212              elif arch == ['Mach-O 64-bit bundle x86_64', 'Mach-O bundle i386', 'Mach-O bundle ppc']: 
 213                  file_type = '3-way bundle (i386, ppc, x86_64)' 
 214              elif arch == ['Mach-O 64-bit dynamically linked shared library x86_64', 'Mach-O dynamically linked shared library i386', 'Mach-O dynamically linked shared library ppc']: 
 215                  file_type = '3-way lib (i386, ppc, x86_64)' 
 216              elif arch == ['Mach-O 64-bit object x86_64', 'Mach-O object i386', 'Mach-O object ppc']: 
 217                  file_type = '3-way obj (i386, ppc, x86_64)' 
 218              else: 
 219                  file_type = '3-way %s' % arch 
 220   
 221           
 222          elif data[0][:-1] == 'Mach-O universal binary with 2 architectures': 
 223               
 224              arch = [None, None] 
 225              for i in range(2): 
 226                  row = data[i+1].split('\t') 
 227                  arch[i] = row[1][:-1] 
 228              arch.sort() 
 229   
 230               
 231              if arch == ['Mach-O executable i386', 'Mach-O executable ppc']: 
 232                  file_type = '2-way exec (i386, ppc)' 
 233              elif arch == ['Mach-O bundle i386', 'Mach-O bundle ppc']: 
 234                  file_type = '2-way bundle (i386, ppc)' 
 235              elif arch == ['Mach-O dynamically linked shared library i386', 'Mach-O dynamically linked shared library ppc']: 
 236                  file_type = '2-way lib (i386, ppc)' 
 237              elif arch == ['Mach-O object i386', 'Mach-O object ppc']: 
 238                  file_type = '2-way obj (i386, ppc)' 
 239              else: 
 240                  file_type = '2-way %s' % arch 
 241   
 242           
 243          else: 
 244              file_type = data[0][:-1] 
 245              if hasattr(file_type, 'decode'): 
 246                  file_type = file_type.decode() 
 247              for i in range(1, len(data)): 
 248                  row = data[i].split('\t') 
 249                  arch[i] = row[1][:-1] 
 250                  file_type += " %s" % arch 
 251   
 252           
 253          if file_type == None: 
 254              return '' 
 255          return file_type 
  256   
 257   
 281   
 282   
 283 -    def intro_text(self): 
  284          """Create the introductory string for STDOUT printing. 
 285   
 286          This text is word-wrapped to a fixed width of 100 characters (or 80 on MS Windows). 
 287   
 288   
 289          @return:    The introductory string. 
 290          @rtype:     str 
 291          """ 
 292   
 293           
 294          intro_string = '\n\n\n' 
 295   
 296           
 297          if version == 'repository commit': 
 298              if repo_type == 'git': 
 299                  text = "%s %s" % (self.title, self.version) 
 300                  text2 = "%s" % repo_head 
 301              else: 
 302                  text = "%s %s r%s" % (self.title, self.version, repo_head) 
 303                  text2 = "%s" % repo_url 
 304              intro_string += self.centre(text, status.text_width) + '\n' + self.centre(text2, status.text_width) + '\n' 
 305              if repo_type == 'git': 
 306                  for url in repo_url.split('\n'): 
 307                      intro_string += self.centre(url, status.text_width) + '\n' 
 308              intro_string += '\n' 
 309   
 310           
 311          else: 
 312              text = "%s %s" % (self.title, self.version) 
 313              intro_string = intro_string + self.centre(text, status.text_width) + '\n\n' 
 314   
 315           
 316          intro_string = intro_string + self.centre(self.desc, status.text_width) + '\n\n' 
 317   
 318           
 319          for i in range(len(self.copyright)): 
 320              intro_string = intro_string + self.centre(self.copyright[i], status.text_width) + '\n' 
 321          intro_string = intro_string + '\n' 
 322   
 323           
 324          for line in wrap(self.licence, status.text_width): 
 325              intro_string = intro_string + line + '\n' 
 326          intro_string = intro_string + '\n' 
 327    
 328           
 329          help = "Assistance in using the relax prompt and scripting interface can be accessed by typing 'help' within the prompt." 
 330          for line in wrap(help, status.text_width): 
 331              intro_string = intro_string + line + '\n' 
 332   
 333           
 334          for i in range(len(self.errors)): 
 335              intro_string = intro_string + '\n' + self.errors[i] + '\n' 
 336          intro_string = intro_string + '\n' 
 337   
 338           
 339          if hasattr(self, 'multi_processor_string'): 
 340              for line in wrap('Processor fabric:  %s\n' % self.multi_processor_string, status.text_width): 
 341                  intro_string = intro_string + line + '\n' 
 342   
 343           
 344          return intro_string 
  345   
 346   
 557   
 558   
 560          """Return a string for the processor name. 
 561   
 562          @return:    The processor name, in much more detail than platform.processor(). 
 563          @rtype:     str 
 564          """ 
 565   
 566           
 567          if Popen == None: 
 568              return "" 
 569   
 570           
 571          if not dep_check.subprocess_module: 
 572              return "" 
 573   
 574           
 575          system = platform.system() 
 576   
 577           
 578          if system == 'Linux': 
 579               
 580              cmd = "cat /proc/cpuinfo" 
 581   
 582               
 583              pipe = Popen(cmd, shell=True, stdout=PIPE, close_fds=False) 
 584              waitpid(pipe.pid, 0) 
 585   
 586               
 587              data = pipe.stdout.readlines() 
 588   
 589               
 590              for line in data: 
 591                   
 592                  if hasattr(line, 'decode'): 
 593                      line = line.decode() 
 594   
 595                   
 596                  if search("model name", line): 
 597                       
 598                      name = sub(".*model name.*:", "", line, 1) 
 599                      name = name.strip() 
 600   
 601                       
 602                      return name 
 603   
 604           
 605          if system == 'Windows' or system == 'Microsoft': 
 606              return platform.processor() 
 607   
 608           
 609          if system == 'Darwin': 
 610               
 611              environ['PATH'] += pathsep + '/usr/sbin' 
 612   
 613               
 614              cmd = "sysctl -n machdep.cpu.brand_string" 
 615   
 616               
 617              try: 
 618                   
 619                  pipe = Popen(cmd, shell=True, stdout=PIPE, close_fds=False) 
 620                  waitpid(pipe.pid, 0) 
 621   
 622                   
 623                  data = pipe.stdout.readlines() 
 624   
 625                   
 626                  string = data[0] 
 627                  if hasattr(string, 'decode'): 
 628                      string = string.decode() 
 629   
 630                   
 631                   
 632                  return string.strip() 
 633   
 634               
 635              except: 
 636                  return "" 
 637   
 638           
 639          return "" 
  640   
 641   
 642 -    def ram_info(self, format="    %-25s%s\n"): 
  643          """Return a string for printing to STDOUT with info from the Python packages used by relax. 
 644   
 645          @keyword format:    The formatting string. 
 646          @type format:       str 
 647          @return:            The info string. 
 648          @rtype:             str 
 649          """ 
 650   
 651           
 652          if Popen == None: 
 653              return '' 
 654   
 655           
 656          text = '' 
 657   
 658           
 659          system = platform.system() 
 660   
 661           
 662          if system == 'Linux': 
 663              pipe = Popen('free -m', shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=False) 
 664              free_lines = pipe.stdout.readlines() 
 665              if free_lines: 
 666                   
 667                  for line in free_lines: 
 668                       
 669                      row = line.split() 
 670   
 671                       
 672                      if row[0] == 'Mem:': 
 673                          text += format % ("Total RAM size: ", row[1], "Mb") 
 674   
 675                       
 676                      if row[0] == 'Swap:': 
 677                          text += format % ("Total swap size: ", row[1], "Mb") 
 678   
 679           
 680          if system == 'Windows' or system == 'Microsoft': 
 681               
 682              mem = MemoryStatusEx() 
 683   
 684               
 685              text += format % ("Total RAM size: ", mem.ullTotalPhys / 1024.**2, "Mb") 
 686   
 687               
 688              text += format % ("Total swap size: ", mem.ullTotalVirtual / 1024.**2, "Mb") 
 689   
 690           
 691          if system == 'Darwin': 
 692               
 693              environ['PATH'] += pathsep + '/usr/sbin' 
 694   
 695               
 696              cmd = "sysctl -n hw.physmem" 
 697              cmd2 = "sysctl -n hw.memsize" 
 698   
 699               
 700              try: 
 701                   
 702                  pipe = Popen(cmd, shell=True, stdout=PIPE, close_fds=False) 
 703                  waitpid(pipe.pid, 0) 
 704   
 705                   
 706                  data = pipe.stdout.readlines() 
 707   
 708                   
 709                  pipe = Popen(cmd2, shell=True, stdout=PIPE, close_fds=False) 
 710                  waitpid(pipe.pid, 0) 
 711   
 712                   
 713                  data2 = pipe.stdout.readlines() 
 714   
 715                   
 716                  ram = int(data[0].strip()) 
 717                  total = int(data2[0].strip()) 
 718                  swap = total - ram 
 719   
 720                   
 721                  text += format % ("Total RAM size: ", ram / 1024.**2, "Mb") 
 722   
 723                   
 724                  text += format % ("Total swap size: ", swap / 1024.**2, "Mb") 
 725   
 726               
 727              except: 
 728                  pass 
 729   
 730           
 731          if not text: 
 732              text += format % ("Total RAM size: ", "?", "Mb") 
 733              text += format % ("Total swap size: ", "?", "Mb") 
 734   
 735           
 736          return text 
  737   
 738   
 788   
 789   
 791          """Return a string for printing to STDOUT with info about the current relax instance. 
 792   
 793          @return:    The info string. 
 794          @rtype:     str 
 795          """ 
 796   
 797           
 798          text = '' 
 799   
 800           
 801          format  = "    %-25s%s\n" 
 802          format2 = "    %-25s%s %s\n" 
 803   
 804           
 805          text = text + ("\nHardware information:\n") 
 806          if hasattr(platform, 'machine'): 
 807              text = text + (format % ("Machine: ", platform.machine())) 
 808          if hasattr(platform, 'processor'): 
 809              text = text + (format % ("Processor: ", platform.processor())) 
 810          text = text + (format % ("Processor name: ", self.processor_name())) 
 811          text = text + (format % ("Endianness: ", sys.byteorder)) 
 812          text = text + self.ram_info(format=format2) 
 813   
 814           
 815          text = text + ("\nOperating system information:\n") 
 816          if hasattr(platform, 'system'): 
 817              text = text + (format % ("System: ", platform.system())) 
 818          if hasattr(platform, 'release'): 
 819              text = text + (format % ("Release: ", platform.release())) 
 820          if hasattr(platform, 'version'): 
 821              text = text + (format % ("Version: ", platform.version())) 
 822          if hasattr(platform, 'win32_ver') and platform.win32_ver()[0]: 
 823              text = text + (format % ("Win32 version: ", (platform.win32_ver()[0] + " " + platform.win32_ver()[1] + " " + platform.win32_ver()[2] + " " + platform.win32_ver()[3]))) 
 824          if linux_distribution()[0]: 
 825              text = text + (format % ("GNU/Linux version: ", (linux_distribution()[0] + " " + linux_distribution()[1] + " " + linux_distribution()[2]))) 
 826          if hasattr(platform, 'mac_ver') and platform.mac_ver()[0]: 
 827              text = text + (format % ("Mac version: ", (platform.mac_ver()[0] + " (" + platform.mac_ver()[1][0] + ", " + platform.mac_ver()[1][1] + ", " + platform.mac_ver()[1][2] + ") " + platform.mac_ver()[2]))) 
 828          if hasattr(platform, 'dist'): 
 829              text = text + (format % ("Distribution: ", (platform.dist()[0] + " " + platform.dist()[1] + " " + platform.dist()[2]))) 
 830          if hasattr(platform, 'platform'): 
 831              text = text + (format % ("Full platform string: ", (platform.platform()))) 
 832          if hasattr(ctypes, 'windll'): 
 833              text = text + (format % ("Windows architecture: ", (self.win_arch()))) 
 834   
 835           
 836          text = text + ("\nPython information:\n") 
 837          if hasattr(platform, 'architecture'): 
 838              text = text + (format % ("Architecture: ", (platform.architecture()[0] + " " + platform.architecture()[1]))) 
 839          if hasattr(platform, 'python_version'): 
 840              text = text + (format % ("Python version: ", platform.python_version())) 
 841          if hasattr(platform, 'python_branch'): 
 842              text = text + (format % ("Python branch: ", platform.python_branch())) 
 843          if hasattr(platform, 'python_build'): 
 844              text = text + ((format[:-1]+', %s\n') % ("Python build: ", platform.python_build()[0], platform.python_build()[1])) 
 845          if hasattr(platform, 'python_compiler'): 
 846              text = text + (format % ("Python compiler: ", platform.python_compiler())) 
 847          if hasattr(platform, 'libc_ver'): 
 848              text = text + (format % ("Libc version: ", (platform.libc_ver()[0] + " " + platform.libc_ver()[1]))) 
 849          if hasattr(platform, 'python_implementation'): 
 850              text = text + (format % ("Python implementation: ", platform.python_implementation())) 
 851          if hasattr(platform, 'python_revision'): 
 852              text = text + (format % ("Python revision: ", platform.python_revision())) 
 853          if sys.executable: 
 854              text = text + (format % ("Python executable: ", sys.executable)) 
 855          if hasattr(sys, 'flags'): 
 856              text = text + (format % ("Python flags: ", sys.flags)) 
 857          if hasattr(sys, 'float_info'): 
 858              text = text + (format % ("Python float info: ", sys.float_info)) 
 859          text = text + (format % ("Python module path: ", sys.path)) 
 860   
 861           
 862          text = text + self.package_info() 
 863   
 864           
 865          text = text + "\nrelax information:\n" 
 866          text = text + (format % ("Version: ", version_full())) 
 867          if hasattr(self, "multi_processor_string"): 
 868              text += format % ("Processor fabric: ", self.multi_processor_string) 
 869   
 870           
 871          text = text + self.relax_module_info() 
 872   
 873           
 874          text = text + ("\n") 
 875   
 876           
 877          return text 
  878   
 879   
 881          """Determine the MS Windows architecture. 
 882   
 883          @return:    The architecture string. 
 884          @rtype:     str 
 885          """ 
 886   
 887           
 888          if 'PROCESSOR_ARCHITEW6432' in environ: 
 889              arch = environ['PROCESSOR_ARCHITEW6432'] 
 890   
 891           
 892          else: 
 893              arch = environ['PROCESSOR_ARCHITECTURE'] 
 894   
 895           
 896          return arch 
   897   
 898   
 899   
 901      """Special object for obtaining hardware info in MS Windows.""" 
 902   
 903      if hasattr(ctypes, 'windll'): 
 904          _fields_ = [ 
 905              ('dwLength', ctypes.wintypes.DWORD), 
 906              ('dwMemoryLoad', ctypes.wintypes.DWORD), 
 907              ('ullTotalPhys', ctypes.c_ulonglong), 
 908              ('ullAvailPhys', ctypes.c_ulonglong), 
 909              ('ullTotalPageFile', ctypes.c_ulonglong), 
 910              ('ullAvailPageFile', ctypes.c_ulonglong), 
 911              ('ullTotalVirtual', ctypes.c_ulonglong), 
 912              ('ullAvailVirtual', ctypes.c_ulonglong), 
 913              ('ullExtendedVirtual', ctypes.c_ulonglong), 
 914          ] 
 915   
 917          """Set up the information and handle non MS Windows systems.""" 
 918   
 919           
 920          if hasattr(ctypes, 'windll'): 
 921              self.dwLength = ctypes.sizeof(self) 
 922              ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(self)) 
   923   
 924   
 925   
 927      """Reference base class.""" 
 928   
 929       
 930      type = None 
 931      author = None 
 932      author2 = None 
 933      title = None 
 934      status = None 
 935      journal = None 
 936      journal_full = None 
 937      volume = None 
 938      number = None 
 939      doi = None 
 940      pubmed_id = None 
 941      url = None 
 942      pages = None 
 943      year = None 
 944   
 945   
 947          """Generate some variables on the fly. 
 948   
 949          This is only called for objects not found in the class. 
 950   
 951          @param name:            The name of the object. 
 952          @type name:             str 
 953          @raises AttributeError: If the object cannot be created. 
 954          @returns:               The generated object. 
 955          @rtype:                 anything 
 956          """ 
 957   
 958           
 959          if name in ['page_first', 'page_last']: 
 960               
 961              if not self.pages: 
 962                  return None 
 963   
 964               
 965              vals = self.pages.split('-') 
 966   
 967               
 968              if len(vals) == 1: 
 969                  return vals[0] 
 970   
 971               
 972              if name == 'page_first': 
 973                  return vals[0] 
 974   
 975               
 976              if name == 'page_last': 
 977                  return vals[1] 
 978   
 979          raise AttributeError(name) 
  980   
 981   
 982 -    def cite_short(self, author=True, title=True, journal=True, volume=True, number=True, pages=True, year=True, doi=True, url=True, status=True): 
  983          """Compile a short citation. 
 984           
 985          The returned text will have the form of: 
 986   
 987              - d'Auvergne, E.J. and Gooley, P.R. (2008). Optimisation of NMR dynamic models I. Minimisation algorithms and their performance within the model-free and Brownian rotational diffusion spaces. J. Biomol. NMR, 40(2), 107-119. 
 988   
 989   
 990          @keyword author:    The author flag. 
 991          @type author:       bool 
 992          @keyword title:     The title flag. 
 993          @type title:        bool 
 994          @keyword journal:   The journal flag. 
 995          @type journal:      bool 
 996          @keyword volume:    The volume flag. 
 997          @type volume:       bool 
 998          @keyword number:    The number flag. 
 999          @type number:       bool 
1000          @keyword pages:     The pages flag. 
1001          @type pages:        bool 
1002          @keyword year:      The year flag. 
1003          @type year:         bool 
1004          @keyword doi:       The doi flag. 
1005          @type doi:          bool 
1006          @keyword url:       The url flag. 
1007          @type url:          bool 
1008          @keyword status:    The status flag.  This will only be shown if not 'published'. 
1009          @type status:       bool 
1010          @return:            The full citation. 
1011          @rtype:             str 
1012          """ 
1013   
1014           
1015          cite = '' 
1016          if author and self.author and hasattr(self, 'author'): 
1017              cite = cite + self.author 
1018          if year and self.year and hasattr(self, 'year'): 
1019              cite = cite + ' (' + repr(self.year) + ').' 
1020          if title and self.title and hasattr(self, 'title'): 
1021              cite = cite + ' ' + self.title 
1022          if journal and self.journal and hasattr(self, 'journal'): 
1023              cite = cite + ' ' + self.journal + ',' 
1024          if volume and self.volume and hasattr(self, 'volume'): 
1025              cite = cite + ' ' + self.volume 
1026          if number and self.number and hasattr(self, 'number'): 
1027              cite = cite + '(' + self.number + '),' 
1028          if pages and self.pages and hasattr(self, 'pages'): 
1029              cite = cite + ' ' + self.pages 
1030          if doi and self.doi and hasattr(self, 'doi'): 
1031              cite = cite + ' (http://dx.doi.org/'+self.doi + ')' 
1032          if url and self.url and hasattr(self, 'url'): 
1033              cite = cite + ' (' + self.url + ')' 
1034          if status and hasattr(self, 'status') and self.status != 'published': 
1035              cite = cite + ' (' + self.status + ')' 
1036   
1037           
1038          if cite[-1] != '.': 
1039              cite = cite + '.' 
1040   
1041           
1042          return cite 
 1043   
1044   
1045 -    def cite_html(self, author=True, title=True, journal=True, volume=True, number=True, pages=True, year=True, doi=True, url=True, status=True): 
 1046          """Compile a citation for HTML display. 
1047   
1048          @keyword author:    The author flag. 
1049          @type author:       bool 
1050          @keyword title:     The title flag. 
1051          @type title:        bool 
1052          @keyword journal:   The journal flag. 
1053          @type journal:      bool 
1054          @keyword volume:    The volume flag. 
1055          @type volume:       bool 
1056          @keyword number:    The number flag. 
1057          @type number:       bool 
1058          @keyword pages:     The pages flag. 
1059          @type pages:        bool 
1060          @keyword year:      The year flag. 
1061          @type year:         bool 
1062          @keyword doi:       The doi flag. 
1063          @type doi:          bool 
1064          @keyword url:       The url flag. 
1065          @type url:          bool 
1066          @keyword status:    The status flag.  This will only be shown if not 'published'. 
1067          @type status:       bool 
1068          @return:            The full citation. 
1069          @rtype:             str 
1070          """ 
1071   
1072           
1073          cite = '' 
1074          if author and hasattr(self, 'author') and self.author: 
1075              cite = cite + self.author 
1076          if year and hasattr(self, 'year') and self.year: 
1077              cite = cite + ' (' + repr(self.year) + ').' 
1078          if title and hasattr(self, 'title') and self.title: 
1079              cite = cite + ' ' + self.title 
1080          if journal and hasattr(self, 'journal') and self.journal: 
1081              cite = cite + ' <em>' + self.journal + '</em>,' 
1082          if volume and hasattr(self, 'volume') and self.volume: 
1083              cite = cite + ' <strong>' + self.volume + '</strong>' 
1084          if number and hasattr(self, 'number') and self.number: 
1085              cite = cite + '(' + self.number + '),' 
1086          if pages and hasattr(self, 'pages') and self.pages: 
1087              cite = cite + ' ' + self.pages 
1088          if doi and hasattr(self, 'doi') and self.doi: 
1089              cite = cite + ' (<a href="http://dx.doi.org/%s">abstract</a>)' % self.doi 
1090          if url and hasattr(self, 'url') and self.url: 
1091              cite = cite + ' (<a href="%s">url</a>)' % self.url 
1092          if status and hasattr(self, 'status') and self.status != 'published': 
1093              cite = cite + ' (<i>%s</i>)' % self.status 
1094   
1095           
1096          if cite[-1] != '.': 
1097              cite = cite + '.' 
1098   
1099           
1100          return cite 
  1101   
1102   
1103   
1105      """Bibliography container.""" 
1106   
1107      type           = "journal" 
1108      author         = "Bieri, M., d'Auvergne, E. J. and Gooley, P. R." 
1109      author2        = [["Michael", "Bieri", "M.", ""], ["Edward", "d'Auvergne", "E.", "J."], ["Paul", "Gooley", "P.", "R."]] 
1110      title          = "relaxGUI: a new software for fast and simple NMR relaxation data analysis and calculation of ps-ns and micro-s motion of proteins" 
1111      journal        = "J. Biomol. NMR" 
1112      journal_full   = "Journal of Biomolecular NMR" 
1113      abstract       = "Investigation of protein dynamics on the ps-ns and mus-ms timeframes provides detailed insight into the mechanisms of enzymes and the binding properties of proteins. Nuclear magnetic resonance (NMR) is an excellent tool for studying protein dynamics at atomic resolution. Analysis of relaxation data using model-free analysis can be a tedious and time consuming process, which requires good knowledge of scripting procedures. The software relaxGUI was developed for fast and simple model-free analysis and is fully integrated into the software package relax. It is written in Python and uses wxPython to build the graphical user interface (GUI) for maximum performance and multi-platform use. This software allows the analysis of NMR relaxation data with ease and the generation of publication quality graphs as well as color coded images of molecular structures. The interface is designed for simple data analysis and management. The software was tested and validated against the command line version of relax." 
1114      authoraddress  = "Department of Biochemistry and Molecular Biology, University of Melbourne, Melbourne, Victoria 3010, Australia." 
1115      doi            = "10.1007/s10858-011-9509-1" 
1116      pubmed_id      = 21618018 
1117      status         = "published" 
1118      year           = 2011 
 1119   
1120   
1121   
1123      """Bibliography container.""" 
1124   
1125      type           = "journal" 
1126      author         = "Clore, G. M. and Szabo, A. and Bax, A. and Kay, L. E. and Driscoll, P. C. and Gronenborn, A. M." 
1127      title          = "Deviations from the simple 2-parameter model-free approach to the interpretation of N-15 nuclear magnetic-relaxation of proteins" 
1128      journal        = "J. Am. Chem. Soc." 
1129      journal_full   = "Journal of the American Chemical Society" 
1130      volume         = "112" 
1131      number         = "12" 
1132      pages          = "4989-4991" 
1133      address        = "1155 16th St, NW, Washington, DC 20036" 
1134      sourceid       = "ISI:A1990DH27700070" 
1135      status         = "published" 
1136      year           = 1990 
 1137   
1138   
1139   
1141      """Bibliography container.""" 
1142   
1143      type           = "thesis" 
1144      author         = "d'Auvergne, E. J." 
1145      author2        = [["Edward", "d'Auvergne", "E.", "J."]] 
1146      title          = "Protein dynamics: a study of the model-free analysis of NMR relaxation data." 
1147      school         = "Biochemistry and Molecular Biology, University of Melbourne." 
1148      url            = "http://eprints.infodiv.unimelb.edu.au/archive/00002799/" 
1149      status         = "published" 
1150      year           = 2006 
 1151   
1152   
1153   
1155      """Bibliography container.""" 
1156   
1157      type           = "journal" 
1158      author         = "d'Auvergne, E. J. and Gooley, P. R." 
1159      author2        = [["Edward", "d'Auvergne", "E.", "J."], ["Paul", "Gooley", "P.", "R."]] 
1160      title          = "The use of model selection in the model-free analysis of protein dynamics." 
1161      journal        = "J. Biomol. NMR" 
1162      journal_full   = "Journal of Biomolecular NMR" 
1163      volume         = "25" 
1164      number         = "1" 
1165      pages          = "25-39" 
1166      abstract       = "Model-free analysis of NMR relaxation data, which is widely used for the study of protein dynamics, consists of the separation of the global rotational diffusion from internal motions relative to the diffusion frame and the description of these internal motions by amplitude and timescale. Five model-free models exist, each of which describes a different type of motion. Model-free analysis requires the selection of the model which best describes the dynamics of the NH bond. It will be demonstrated that the model selection technique currently used has two significant flaws, under-fitting, and not selecting a model when one ought to be selected. Under-fitting breaks the principle of parsimony causing bias in the final model-free results, visible as an overestimation of S2 and an underestimation of taue and Rex. As a consequence the protein falsely appears to be more rigid than it actually is. Model selection has been extensively developed in other fields. The techniques known as Akaike's Information Criteria (AIC), small sample size corrected AIC (AICc), Bayesian Information Criteria (BIC), bootstrap methods, and cross-validation will be compared to the currently used technique. To analyse the variety of techniques, synthetic noisy data covering all model-free motions was created. The data consists of two types of three-dimensional grid, the Rex grids covering single motions with chemical exchange [S2,taue,Rex], and the Double Motion grids covering two internal motions [S f 2,S s 2,tau s ]. The conclusion of the comparison is that for accurate model-free results, AIC model selection is essential. As the method neither under, nor over-fits, AIC is the best tool for applying Occam's razor and has the additional benefits of simplifying and speeding up model-free analysis." 
1167      authoraddress  = "Department of Biochemistry and Molecular Biology, University of Melbourne, Melbourne, Victoria 3010, Australia." 
1168      keywords       = "Amines ; Diffusion ; *Models, Molecular ; Motion ; Nuclear Magnetic Resonance, Biomolecular/*methods ; Proteins/*chemistry ; Research Support, Non-U.S. Gov't ; Rotation" 
1169      doi            = "10.1023/A:1021902006114" 
1170      pubmed_id      = 12566997 
1171      status         = "published" 
1172      year           = 2003 
 1173   
1174   
1175   
1177      """Bibliography container.""" 
1178   
1179      type           = "journal" 
1180      author         = "d'Auvergne, E. J. and Gooley, P. R." 
1181      author2        = [["Edward", "d'Auvergne", "E.", "J."], ["Paul", "Gooley", "P.", "R."]] 
1182      title          = "Model-free model elimination: A new step in the model-free dynamic analysis of NMR relaxation data." 
1183      journal        = "J. Biomol. NMR" 
1184      journal_full   = "Journal of Biomolecular NMR" 
1185      volume         = "35" 
1186      number         = "2" 
1187      pages          = "117-135" 
1188      abstract       = "Model-free analysis is a technique commonly used within the field of NMR spectroscopy to extract atomic resolution, interpretable dynamic information on multiple timescales from the R (1), R (2), and steady state NOE. Model-free approaches employ two disparate areas of data analysis, the discipline of mathematical optimisation, specifically the minimisation of a chi(2) function, and the statistical field of model selection. By searching through a large number of model-free minimisations, which were setup using synthetic relaxation data whereby the true underlying dynamics is known, certain model-free models have been identified to, at times, fail. This has been characterised as either the internal correlation times, tau( e ), tau( f ), or tau( s ), or the global correlation time parameter, local tau( m ), heading towards infinity, the result being that the final parameter values are far from the true values. In a number of cases the minimised chi(2) value of the failed model is significantly lower than that of all other models and, hence, will be the model which is chosen by model selection techniques. If these models are not removed prior to model selection the final model-free results could be far from the truth. By implementing a series of empirical rules involving inequalities these models can be specifically isolated and removed. Model-free analysis should therefore consist of three distinct steps: model-free minimisation, model-free model elimination, and finally model-free model selection. Failure has also been identified to affect the individual Monte Carlo simulations used within error analysis. Each simulation involves an independent randomised relaxation data set and model-free minimisation, thus simulations suffer from exactly the same types of failure as model-free models. Therefore, to prevent these outliers from causing a significant overestimation of the errors the failed Monte Carlo simulations need to be culled prior to calculating the parameter standard deviations." 
1189      authoraddress  = "Department of Biochemistry and Molecular Biology, Bio21 Institute of Biotechnology and Molecular Science, University of Melbourne, Parkville, Victoria, 3010, Australia" 
1190      doi            = "10.1007/s10858-006-9007-z" 
1191      pubmed_id      = 16791734 
1192      status         = "published" 
1193      year           = 2006 
 1194   
1195   
1196   
1198      """Bibliography container.""" 
1199   
1200      type           = "journal" 
1201      author         = "d'Auvergne, E. J. and Gooley, P. R." 
1202      author2        = [["Edward", "d'Auvergne", "E.", "J."], ["Paul", "Gooley", "P.", "R."]] 
1203      title          = "Set theory formulation of the model-free problem and the diffusion seeded model-free paradigm." 
1204      journal        = "Mol. Biosys." 
1205      journal_full   = "Molecular BioSystems" 
1206      volume         = "3" 
1207      number         = "7" 
1208      pages          = "483-494" 
1209      abstract       = "Model-free analysis of NMR relaxation data, which describes the motion of individual atoms, is a problem intricately linked to the Brownian rotational diffusion of the macromolecule. The diffusion tensor parameters strongly influence the optimisation of the various model-free models and the subsequent model selection between them. Finding the optimal model of the dynamics of the system among the numerous diffusion and model-free models is hence quite complex. Using set theory, the entirety of this global problem has been encapsulated by the universal set Ll, and its resolution mathematically formulated as the universal solution Ll. Ever since the original Lipari and Szabo papers the model-free dynamics of a molecule has most often been solved by initially estimating the diffusion tensor. The model-free models which depend on the diffusion parameter values are then optimised and the best model is chosen to represent the dynamics of the residue. Finally, the global model of all diffusion and model-free parameters is optimised. These steps are repeated until convergence. For simplicity this approach to Ll will be labelled the diffusion seeded model-free paradigm. Although this technique suffers from a number of problems many have been solved. All aspects of the diffusion seeded paradigm and its consequences, together with a few alternatives to the paradigm, will be reviewed through the use of set notation." 
1210      authoraddress  = "Department of Biochemistry and Molecular Biology, Bio21 Institute of Biotechnology and Molecular Science, University of Melbourne, Parkville, Melbourne, Victoria 3010, Australia." 
1211      keywords       = "Magnetic Resonance Spectroscopy/*methods ; *Models, Theoretical ; Proteins/chemistry ; Thermodynamics" 
1212      doi            = "10.1039/b702202f" 
1213      pubmed_id      = 17579774 
1214      status         = "published" 
1215      year           = 2007 
 1216   
1217   
1218   
1220      """Bibliography container.""" 
1221   
1222      type           = "journal" 
1223      author         = "d'Auvergne, E. J. and Gooley, P. R." 
1224      author2        = [["Edward", "d'Auvergne", "E.", "J."], ["Paul", "Gooley", "P.", "R."]] 
1225      title          = "Optimisation of NMR dynamic models I. Minimisation algorithms and their performance within the model-free and Brownian rotational diffusion spaces." 
1226      journal        = "J. Biomol. NMR" 
1227      journal_full   = "Journal of Biomolecular NMR" 
1228      volume         = "40" 
1229      number         = "2" 
1230      pages          = "107-119" 
1231      abstract       = "The key to obtaining the model-free description of the dynamics of a macromolecule is the optimisation of the model-free and Brownian rotational diffusion parameters using the collected R (1), R (2) and steady-state NOE relaxation data. The problem of optimising the chi-squared value is often assumed to be trivial, however, the long chain of dependencies required for its calculation complicates the model-free chi-squared space. Convolutions are induced by the Lorentzian form of the spectral density functions, the linear recombinations of certain spectral density values to obtain the relaxation rates, the calculation of the NOE using the ratio of two of these rates, and finally the quadratic form of the chi-squared equation itself. Two major topological features of the model-free space complicate optimisation. The first is a long, shallow valley which commences at infinite correlation times and gradually approaches the minimum. The most severe convolution occurs for motions on two timescales in which the minimum is often located at the end of a long, deep, curved tunnel or multidimensional valley through the space. A large number of optimisation algorithms will be investigated and their performance compared to determine which techniques are suitable for use in model-free analysis. Local optimisation algorithms will be shown to be sufficient for minimisation not only within the model-free space but also for the minimisation of the Brownian rotational diffusion tensor. In addition the performance of the programs Modelfree and Dasha are investigated. A number of model-free optimisation failures were identified: the inability to slide along the limits, the singular matrix failure of the Levenberg-Marquardt minimisation algorithm, the low precision of both programs, and a bug in Modelfree. Significantly, the singular matrix failure of the Levenberg-Marquardt algorithm occurs when internal correlation times are undefined and is greatly amplified in model-free analysis by both the grid search and constraint algorithms. The program relax ( http://www.nmr-relax.com ) is also presented as a new software package designed for the analysis of macromolecular dynamics through the use of NMR relaxation data and which alleviates all of the problems inherent within model-free analysis." 
1232      authoraddress  = "Department of NMR-based Structural Biology, Max Planck Institute for Biophysical Chemistry, Am Fassberg 11, D-37077, Goettingen, Germany" 
1233      keywords       = "*Algorithms ; Cytochromes c2/chemistry ; Diffusion ; *Models, Molecular ; Nuclear Magnetic Resonance, Biomolecular/*methods ; Rhodobacter capsulatus/chemistry ; *Rotation" 
1234      doi            = "10.1007/s10858-007-9214-2" 
1235      pubmed_id      = 18085410 
1236      status         = "published" 
1237      year           = 2008 
 1238   
1239   
1240   
1242      """Bibliography container.""" 
1243   
1244      type           = "journal" 
1245      author         = "d'Auvergne, E. J. and Gooley, P. R." 
1246      author2        = [["Edward", "d'Auvergne", "E.", "J."], ["Paul", "Gooley", "P.", "R."]] 
1247      title          = "Optimisation of NMR dynamic models II. A new methodology for the dual optimisation of the model-free parameters and the Brownian rotational diffusion tensor." 
1248      journal        = "J. Biomol. NMR" 
1249      journal_full   = "Journal of Biomolecular NMR" 
1250      volume         = "40" 
1251      number         = "2" 
1252      pages          = "121-133" 
1253      abstract       = "Finding the dynamics of an entire macromolecule is a complex problem as the model-free parameter values are intricately linked to the Brownian rotational diffusion of the molecule, mathematically through the autocorrelation function of the motion and statistically through model selection. The solution to this problem was formulated using set theory as an element of the universal set [formula: see text]-the union of all model-free spaces (d'Auvergne EJ and Gooley PR (2007) Mol. BioSyst. 3(7), 483-494). The current procedure commonly used to find the universal solution is to initially estimate the diffusion tensor parameters, to optimise the model-free parameters of numerous models, and then to choose the best model via model selection. The global model is then optimised and the procedure repeated until convergence. In this paper a new methodology is presented which takes a different approach to this diffusion seeded model-free paradigm. Rather than starting with the diffusion tensor this iterative protocol begins by optimising the model-free parameters in the absence of any global model parameters, selecting between all the model-free models, and finally optimising the diffusion tensor. The new model-free optimisation protocol will be validated using synthetic data from Schurr JM et al. (1994) J. Magn. Reson. B 105(3), 211-224 and the relaxation data of the bacteriorhodopsin (1-36)BR fragment from Orekhov VY (1999) J. Biomol. NMR 14(4), 345-356. To demonstrate the importance of this new procedure the NMR relaxation data of the Olfactory Marker Protein (OMP) of Gitti R et al. (2005) Biochem. 44(28), 9673-9679 is reanalysed. The result is that the dynamics for certain secondary structural elements is very different from those originally reported." 
1254      authoraddress  = "Department of NMR-based Structural Biology, Max Planck Institute for Biophysical Chemistry, Am Fassberg 11, Goettingen, D-37077, Germany" 
1255      keywords       = "Algorithms ; Amides/chemistry ; Bacteriorhodopsins/chemistry ; Crystallography, X-Ray ; Diffusion ; *Models, Molecular ; Nuclear Magnetic Resonance, Biomolecular/*methods ; Olfactory Marker Protein/chemistry ; Peptide Fragments/chemistry ; Protein Structure, Secondary ; *Rotation" 
1256      language       = "eng" 
1257      doi            = "10.1007/s10858-007-9213-3" 
1258      pubmed_id      = 18085411 
1259      status         = "published" 
1260      year           = 2008 
 1261   
1262   
1263   
1265      """Bibliography container.""" 
1266   
1267      type            = "journal" 
1268      author          = "Delaglio, F., Grzesiek, S., Vuister, G.W., Zhu, G., Pfeifer, J. and Bax, A." 
1269      author2         = [["Frank", "Delaglio", "F.", None], ["Stephan", "Grzesiek", "S.", None], ["Geerten", "Vuister", "G.", "W."], ["Guang", "Zhu", "G.", None], ["John", "Pfeifer", "J.", None], ["Ad", "Bax", "A.", None]] 
1270      title           = "NMRPipe: a multidimensional spectral processing system based on UNIX pipes." 
1271      journal         = "J. Biomol. NMR" 
1272      journal_full    = "Journal of Biomolecular NMR" 
1273      volume          = "6" 
1274      number          = "3" 
1275      pages           = "277-293" 
1276      abstract        = "The NMRPipe system is a UNIX software environment of processing, graphics, and analysis tools designed to meet current routine and research-oriented multidimensional processing requirements, and to anticipate and accommodate future demands and developments. The system is based on UNIX pipes, which allow programs running simultaneously to exchange streams of data under user control. In an NMRPipe processing scheme, a stream of spectral data flows through a pipeline of processing programs, each of which performs one component of the overall scheme, such as Fourier transformation or linear prediction. Complete multidimensional processing schemes are constructed as simple UNIX shell scripts. The processing modules themselves maintain and exploit accurate records of data sizes, detection modes, and calibration information in all dimensions, so that schemes can be constructed without the need to explicitly define or anticipate data sizes or storage details of real and imaginary channels during processing. The asynchronous pipeline scheme provides other substantial advantages, including high flexibility, favorable processing speeds, choice of both all-in-memory and disk-bound processing, easy adaptation to different data formats, simpler software development and maintenance, and the ability to distribute processing tasks on multi-CPU computers and computer networks." 
1277      authoraddress   = "Laboratory of Chemical Physics, National Institute of Diabetes and Digestive and Kidney Diseases, National Institutes of Health, Bethesda, MD 20892, USA." 
1278      keywords        = "Magnetic Resonance Spectroscopy/*instrumentation ; *Software" 
1279      language        = "eng" 
1280      doi             = "10.1007/BF00197809" 
1281      pubmed_id       = 8520220 
1282      status         = "published" 
1283      year            = 1995 
 1284   
1285   
1286   
1288      """Bibliography container.""" 
1289   
1290      author          = "Goddard, T.D. and Kneller, D.G." 
1291      author2         = [["Tom", "Goddard", "T.", "D."], ["Donald", "Kneller", "D.", "G."]] 
1292      journal         = "University of California, San Francisco." 
1293      title           = "Sparky 3." 
1294      status          = "unpublished" 
1295      type            = "internet" 
 1296   
1297   
1298   
1300      """Bibliography container.""" 
1301   
1302      type           = "journal" 
1303      author         = "Lipari, G. and Szabo, A." 
1304      title          = "Model-free approach to the interpretation of nuclear magnetic-resonance relaxation in macromolecules I. Theory and range of validity" 
1305      journal        = "J. Am. Chem. Soc." 
1306      journal_full   = "Journal of the American Chemical Society" 
1307      volume         = "104" 
1308      number         = "17" 
1309      pages          = "4546-4559" 
1310      authoraddress  = "NIADDKD,Chem Phys Lab,Bethesda,MD 20205." 
1311      sourceid       = "ISI:A1982PC82900009" 
1312      status         = "published" 
1313      year           = 1982 
 1314   
1315   
1316   
1318      """Bibliography container.""" 
1319   
1320      type           = "journal" 
1321      author         = "Lipari, G. and Szabo, A." 
1322      title          = "Model-free approach to the interpretation of nuclear magnetic-resonance relaxation in macromolecules II. Analysis of experimental results" 
1323      journal        = "J. Am. Chem. Soc." 
1324      journal_full   = "Journal of the American Chemical Society" 
1325      volume         = "104" 
1326      number         = "17" 
1327      pages          = "4559-4570" 
1328      abstract       = "For pt.I see ibid., vol.104, p.4546 (1982). In the preceding paper it has been shown that the unique dynamic information on fast internal motions in an NMR relaxation experiment on macromolecules in solution is specified by a generalized order parameter, S , and an effective correlation time, tau /sub e/. The authors now deal with the extraction and interpretation of this information. The procedure used to obtain S /sup 2/ and tau /sub e/ from experimental data by using a least-squares method and, in certain favorable circumstances, by using an analytical formula is described. A variety of experiments are then analyzed to yield information on the time scale and spatial restriction of internal motions of isoleucines in myoglobin, methionines in dihydrofolate reductase and myoglobin, a number of aliphatic residues in basic pancreatic trypsin inhibitor, and ethyl isocyanide bound to myoglobin, hemoglobin, and aliphatic side chains in three random-coil polymers. The numerical values of S /sup 2/ and tau /sub e / can be readily interpreted within the framework of a variety of models." 
1329      authoraddress  = "NIADDKD,Chem Phys Lab,Bethesda,MD 20205." 
1330      sourceid       = "ISI:A1982PC82900010" 
1331      status         = "published" 
1332      year           = 1982 
 1333