Package gromacs :: Module tools
[hide private]
[frames] | no frames]

Source Code for Module gromacs.tools

  1  # $Id$ 
  2  # Copyright (c) 2009 Oliver Beckstein <orbeckst@gmail.com> 
  3  # Released under the GNU Public License 3 (or higher, your choice) 
  4  # See the file COPYING for details. 
  5   
  6  """ 
  7  :mod:`gromacs.tools` -- Gromacs commands classes 
  8  ================================================ 
  9   
 10  A Gromacs command class can be thought of as a factory function that 
 11  produces an instance of a gromacs command 
 12  (:class:`gromacs.core.GromacsCommand`) with initial default values. 
 13   
 14  By convention, a class has the capitalized name of the corresponding Gromacs 
 15  tool; dots are replaced by underscores to make it a valid python identifier. 
 16   
 17  The list of Gromacs tools to be loaded is configured in 
 18  :data:`gromacs.config.gmx_tool_groups`. 
 19   
 20  It is also possible to extend the basic commands and patch in additional 
 21  functionality. For example, the :class:`GromacsCommandMultiIndex` class makes a 
 22  command accept multiple index files and concatenates them on the fly; the 
 23  behaviour mimics Gromacs' "multi-file" input that has not yet been enabled for 
 24  all tools. 
 25   
 26  .. autoclass:: GromacsCommandMultiIndex 
 27     :members: run, _fake_multi_ndx, __del__ 
 28   
 29  Example 
 30  ------- 
 31   
 32  In this example we create two instances of the :class:`gromacs.tools.Trjconv` command (which 
 33  runs the Gromacs ``trjconv`` command):: 
 34   
 35    import gromacs.tools as tools 
 36   
 37    trjconv = tools.Trjconv() 
 38    trjconv_compact = tools.Trjconv(ur='compact', center=True, boxcenter='tric', pbc='mol', 
 39                                    input=('protein','system'), 
 40                                    doc="Returns a compact representation of the system centered on the protein") 
 41   
 42  The first one, ``trjconv``, behaves as the standard commandline tool but the 
 43  second one, ``trjconv_compact``, will by default create a compact 
 44  representation of the input data by taking into account the shape of the unit 
 45  cell. Of course, the same effect can be obtained by providing the corresponding 
 46  arguments to ``trjconv`` but by naming the more specific command differently 
 47  one can easily build up a library of small tools that will solve a specifi, 
 48  repeatedly encountered problem reliably. This is particularly helpful when doing 
 49  interactive work. 
 50   
 51  Gromacs tools 
 52  ------------- 
 53  .. The docs for the tool classes are auto generated. 
 54  """ 
 55   
 56  __docformat__ = "restructuredtext en" 
 57   
 58  import os.path 
 59  import tempfile 
 60   
 61  import config 
 62  from core import GromacsCommand, Command 
 63  import utilities 
 64   
 65   
 66  #: This dict holds all generated classes. 
 67  registry = {} 
 68   
 69  # Auto-generate classes such as: 
 70  # class g_dist(GromacsCommand): 
 71  #     command_name = 'g_dist' 
 72   
 73  for name in config.load_tools: 
 74      # make names valid python identifiers and use convention that class names are capitalized 
 75      clsname = name.replace('.','_').replace('-','_').capitalize()   
 76      cls = type(clsname, (GromacsCommand,), {'command_name':name, 
 77                                              '__doc__': "Gromacs tool %(name)r." % vars()}) 
 78      registry[clsname] = cls      # registry keeps track of all classes 
 79   
 80   
 81  # modify/fix classes as necessary 
 82  # Note:  
 83  # - check if class was defined in first place 
 84  # - replace class 
 85  # - update local context AND registry as done below 
 86   
87 -class GromacsCommandMultiIndex(GromacsCommand):
88 - def __init__(self, **kwargs):
89 """Initialize instance. 90 91 1) Sets up the combined index file. 92 2) Inititialize :class:`~gromacs.core.GromacsCommand` with the 93 new index file. 94 95 See the documentation for :class:`gromacs.core.GromacsCommand` for details. 96 """ 97 kwargs = self._fake_multi_ndx(**kwargs) 98 super(GromacsCommandMultiIndex, self).__init__(**kwargs)
99
100 - def run(self,*args,**kwargs):
101 """Run the command; make a combined multi-index file if necessary.""" 102 kwargs = self._fake_multi_ndx(**kwargs) 103 return super(GromacsCommandMultiIndex, self).run(*args, **kwargs)
104
105 - def _fake_multi_ndx(self, **kwargs):
106 """Combine multiple index file into a single one and return appropriate kwargs. 107 108 Calling the method combines multiple index files into a a single 109 temporary one so that Gromacs tools that do not (yet) support multi 110 file input for index files can be used transparently as if they did. 111 112 If a temporary index file is required then it is deleted once the 113 object is destroyed. 114 115 :Returns: 116 The method returns the input keyword arguments with the necessary 117 changes to use the temporary index files. 118 119 :Keywords: 120 Only the listed keywords have meaning for the method: 121 122 *n* : filename or list of filenames 123 possibly multiple index files; *n* is replaced by the name of 124 the temporary index file. 125 *s* : filename 126 structure file (tpr, pdb, ...) or ``None``; if a structure file is 127 supplied then the Gromacs default index groups are automatically added 128 to the temporary indexs file. 129 130 :Example: 131 Used in derived classes that replace the standard 132 :meth:`run` (or :meth:`__init__`) methods with something like:: 133 134 def run(self,*args,**kwargs): 135 kwargs = self._fake_multi_ndx(**kwargs) 136 return super(G_mindist, self).run(*args, **kwargs) 137 138 """ 139 ndx = kwargs.get('n') 140 if not (ndx is None or type(ndx) is str): 141 if len(ndx) > 1: 142 # g_mindist cannot deal with multiple ndx files (at least 4.0.5) 143 # so we combine them in a temporary file; it is unlinked in __del__. 144 # self.multi_ndx stores file name for __del__ 145 fd, self.multi_ndx = tempfile.mkstemp(suffix='.ndx', prefix='multi_') 146 make_ndx = Make_ndx(f=kwargs.get('s'), n=ndx) 147 rc,out,err = make_ndx(o=self.multi_ndx, input=['q'], # concatenate all index files 148 stdout=False, stderr=False) 149 self.orig_ndx = ndx 150 kwargs['n'] = self.multi_ndx 151 return kwargs
152
153 - def __del__(self):
154 """Clean up temporary multi-index files if they were used.""" 155 # XXX: does not seem to work when closing the interpreter?! 156 try: 157 # self.multi_ndx <-- _fake_multi_index() 158 utilities.unlink_gmx(self.multi_ndx) 159 except (AttributeError, OSError): 160 pass
161 # XXX: type error --- can't use super in __del__? 162 #super(GromacsCommandMultiIndex, self).__del__() 163 164 # patching up... 165 166 if 'G_mindist' in registry: 167 # let G_mindist handle multiple ndx files
168 - class G_mindist(GromacsCommandMultiIndex):
169 """Gromacs tool 'g_mindist' (with patch to handle multiple ndx files).""" 170 command_name = 'g_mindist'
171 registry['G_mindist'] = G_mindist 172 173 if 'G_dist' in registry: 174 # let G_dist handle multiple ndx files
175 - class G_dist(GromacsCommandMultiIndex):
176 """Gromacs tool 'g_dist' (with patch to handle multiple ndx files).""" 177 command_name = 'g_dist'
178 registry['G_dist'] = G_dist 179 180 # TODO: generate multi index classes via type(), not copy&paste as above... 181 182 183 # load additional scripts from config 184 for rec in config.load_scripts: 185 name, clsname, doc = rec 186 exec_name = os.path.basename(name) 187 registry[clsname] = type(clsname, (Command,), 188 {'command_name':name, 189 '__doc__': "External tool %(exec_name)r\n\n%(doc)s." % vars()}) 190 191 192 # finally, add everything 193 globals().update(registry) # add classes to module's scope 194 __all__ = registry.keys() 195 196 # and clean up the module scope 197 cls = clsname = name = rec = doc = None # make sure they exist, because the next line 198 del rec, name, cls, clsname, doc # would throw NameError if no tool was configured 199