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

Source Code for Module gromacs.run

  1  # GromacsWrapper: run.py 
  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.run` -- Running simulations 
  8  ========================================= 
  9   
 10  Helper functions and classes around :class:`gromacs.tools.Mdrun`. 
 11   
 12  .. autoclass:: MDrunner 
 13     :members: 
 14  .. autoclass:: MDrunnerOpenMP 
 15  .. autoclass:: MDrunnerOpenMP64 
 16  .. autoclass:: MDrunnerMpich2Smpd 
 17   
 18  .. autofunction:: check_mdrun_success 
 19   
 20  """ 
 21  from __future__ import with_statement 
 22  __docformat__ = "restructuredtext en" 
 23   
 24  import subprocess 
 25  import os.path 
 26   
 27  # logging 
 28  import logging 
 29  logger = logging.getLogger('gromacs.run') 
 30   
 31   
 32  # gromacs modules 
 33  import core 
 34  import utilities 
 35   
36 -class MDrunner(utilities.FileUtils):
37 """A class to manage running :program:`mdrun` in various ways. 38 39 In order to do complicated multiprocessor runs with mpiexec or 40 similar you need to derive from this class and override 41 42 - :attr:`MDrunner.mdrun` with the path to the ``mdrun`` executable 43 - :attr:`MDrunner.mpiexec` with the path to the MPI launcher 44 - :meth:`MDrunner.mpicommand` with a function that returns the mpi command as a list 45 46 In addition there are two methods named :meth:`prehook` and 47 :meth:`posthook` that are called right before and after the 48 process is started. If they are overriden appropriately then they 49 can be used to set up a mpi environment. 50 """ 51 52 #: path to the :program:`mdrun` executable (or the name if it can be found on :envvar:`PATH`) 53 mdrun = "mdrun" 54 #: path to the MPI launcher (e.g. :program:`mpiexec`) 55 mpiexec = None 56
57 - def __init__(self, dirname=os.path.curdir, **kwargs):
58 """Set up a simple run with ``mdrun``. 59 60 :Keywords: 61 *dirname* 62 Change to this directory before launching the job. Input 63 files must be supplied relative to this directory. 64 *keywords* 65 All other keword arguments are used to construct the 66 :class:`~gromacs.tools.mdrun` commandline. Note that only 67 keyword arguments are allowed. 68 69 """ 70 # run MD in this directory (input files must be relative to this dir!) 71 self.dirname = dirname 72 73 # use a GromacsCommand class for handling arguments 74 cls = type('MDRUN', (core.GromacsCommand,), 75 {'command_name': self.mdrun, 76 '__doc__': "MDRUN command %r" % self.mdrun}) 77 78 kwargs['failure'] = 'raise' # failure mode of class 79 self.MDRUN = cls(**kwargs) # might fail for mpi binaries? .. -h? 80 81 # analyze command line to deduce logfile name 82 logname = kwargs.get('g', None) # explicit 83 if logname in (True, None): # implicit 84 logname = 'md' # mdrun default 85 deffnm = kwargs.get('deffnm', None) 86 if not deffnm is None: 87 logname = deffnm 88 self.logname = os.path.realpath( 89 os.path.join(self.dirname, self.filename(logname, ext='log')))
90
91 - def commandline(self, **mpiargs):
92 """Returns simple command line to invoke mdrun. 93 94 If :attr:`mpiexec` is set then :meth:`mpicommand` provides the mpi 95 launcher command that prefixes the actual ``mdrun`` invocation: 96 97 :attr:`mpiexec` [*mpiargs*] :attr:`mdrun` [*mdrun-args*] 98 99 The *mdrun-args* are set on initializing the class. Override 100 :meth:`mpicommand` to fit your system if the simple default 101 OpenMP launcher is not appropriate. 102 """ 103 cmd = self.MDRUN.commandline() 104 if self.mpiexec: 105 cmd = self.mpicommand(**mpiargs) + cmd 106 return cmd
107
108 - def mpicommand(self, *args, **kwargs):
109 """Return a list of the mpi command portion of the commandline. 110 111 Only allows primitive mpi at the moment: 112 *mpiexec* -n *ncores* *mdrun* *mdrun-args* 113 114 (This is a primitive example for OpenMP. Override it for more 115 complicated cases.) 116 """ 117 if self.mpiexec is None: 118 raise NotImplementedError("Override mpiexec to enable the simple OpenMP launcher") 119 # example implementation 120 ncores = kwargs.pop('ncores', 8) 121 return [self.mpiexec, '-n', str(ncores)]
122
123 - def prehook(self, **kwargs):
124 """Called directly before launching the process.""" 125 return
126
127 - def posthook(self, **kwargs):
128 """Called directly after the process terminated (also if it failed).""" 129 return
130
131 - def run(self, pre=None, post=None, **mpiargs):
132 """Execute the mdrun command (possibly as a MPI command) and run the simulation. 133 134 :Keywords: 135 *pre* 136 a dictionary containing keyword arguments for the :meth:`prehook` 137 *post* 138 a dictionary containing keyword arguments for the :meth:`posthook` 139 *mpiargs* 140 keyword arguments that are processed by :meth:`mpicommand` 141 """ 142 143 if pre is None: 144 pre = {} 145 if post is None: 146 post = {} 147 148 cmd = self.commandline(**mpiargs) 149 150 with utilities.in_dir(self.dirname, create=False): 151 try: 152 self.prehook(**pre) 153 logger.info(" ".join(cmd)) 154 rc = subprocess.call(cmd) 155 except: 156 logger.exception("Failed MD run for unknown reasons.") 157 raise 158 finally: 159 self.posthook(**post) 160 if rc == 0: 161 logger.info("MDrun completed ok, returncode = %d" % rc) 162 else: 163 logger.critical("Failure in MDrun, returncode = %d" % rc) 164 return rc
165
166 - def run_check(self, **kwargs):
167 """Run :program:`mdrun` and check if run completed when it finishes. 168 169 This works by looking at the mdrun log file for 'Finished 170 mdrun on node'. It is useful to implement robust simulation 171 techniques. 172 173 :Arguments: 174 *kwargs* are keyword arguments that are passed on to 175 :meth:`run` (typically used for mpi things) 176 177 :Returns: 178 - ``True`` if run completed successfully 179 - ``False`` otherwise 180 """ 181 rc = None # set to something in case we ever want to look at it later (and bomb in the try block) 182 try: 183 rc = self.run(**kwargs) 184 except: 185 logger.exception("run_check: caught exception") 186 status = self.check_success() 187 if status: 188 logger.info("run_check: Hooray! mdrun finished successfully") 189 else: 190 logger.error("run_check: mdrun failed to complete run") 191 return status
192
193 - def check_success(self):
194 """Check if :program:`mdrun` finished successfully. 195 196 (See :func:`check_mdrun_success` for details) 197 """ 198 return check_mdrun_success(self.logname)
199
200 -class MDrunnerDoublePrecision(MDrunner):
201 """Manage running :program:`mdrun_d`. 202 """ 203 mdrun = "mdrun_d"
204
205 -class MDrunnerOpenMP(MDrunner):
206 """Manage running :program:`mdrun` as an OpenMP_ multiprocessor job. 207 208 .. _OpenMP: http://openmp.org/wp/ 209 """ 210 mdrun = "mdrun_openmp" 211 mpiexec = "mpiexec"
212
213 -class MDrunnerOpenMP64(MDrunner):
214 """Manage running :program:`mdrun` as an OpenMP_ multiprocessor job (64-bit executable). 215 216 .. _OpenMP: http://openmp.org/wp/ 217 """ 218 mdrun = "mdrun_openmp64" 219 mpiexec = "mpiexec"
220
221 -class MDrunnerMpich2Smpd(MDrunner):
222 """Manage running :program:`mdrun` as mpich2_ multiprocessor job with the SMPD mechanism. 223 224 .. _mpich2: http://www.mcs.anl.gov/research/projects/mpich2/ 225 """ 226 mdrun = "mdrun_mpich2" 227 mpiexec = "mpiexec" 228
229 - def prehook(self, **kwargs):
230 """Launch local smpd.""" 231 cmd = ['smpd', '-s'] 232 logger.info("Starting smpd: "+" ".join(cmd)) 233 rc = subprocess.call(cmd) 234 return rc
235
236 - def posthook(self, **kwargs):
237 """Shut down smpd""" 238 cmd = ['smpd', '-shutdown'] 239 logger.info("Shutting down smpd: "+" ".join(cmd)) 240 rc = subprocess.call(cmd) 241 return rc
242 243 244
245 -def check_mdrun_success(logfile):
246 """Check if ``mdrun`` finished successfully. 247 248 Analyses the output from ``mdrun`` in *logfile*. Right now we are 249 simply looking for the line "Finished mdrun on node" in the last 1kb of 250 the file. (The file must be seeakable.) 251 252 :Arguments: 253 logfile : filename 254 Logfile produced by ``mdrun``. 255 :Returns: boolean (``True`` if all ok, ``False`` otherwise) 256 """ 257 status = False 258 log = open(logfile) 259 try: 260 log.seek(-1024L, 2) 261 for line in log: 262 if line.startswith("Finished mdrun on node"): 263 status = True 264 break 265 finally: 266 log.close() 267 268 return status
269