signature:
def set_gmxrc_environment ( gmxrc ) :
    """Set the environment from ` ` GMXRC ` ` provided in * gmxrc * .
 Runs ` ` GMXRC ` ` in a subprocess and puts environment variables loaded by it
 into this Python environment .
 If * gmxrc * evaluates to ` ` False ` ` then nothing is done . If errors occur
 then only a warning will be logged . Thus , it should be safe to just call
 this function ."""

implementation:
# only v5 : ' GMXPREFIX ' , ' GROMACS _ DIR '
envvars = [ 'GMXBIN' , 'GMXLDLIB' , 'GMXMAN' , 'GMXDATA' , 'LD_LIBRARY_PATH' , 'MANPATH' , 'PKG_CONFIG_PATH' , 'PATH' , 'GMXPREFIX' , 'GROMACS_DIR' ]
# in order to keep empty values , add _ _ _ sentinels around result
# ( will be removed later )
cmdargs = [ 'bash' , '-c' , ". {0} && echo {1}" . format ( gmxrc , ' ' . join ( [ '___${{{0}}}___' . format ( v ) for v in envvars ] ) ) ]
if not gmxrc :
    logger . debug ( "set_gmxrc_environment(): no GMXRC, nothing done." )
    return
try :
    out = subprocess . check_output ( cmdargs )
    out = out . strip ( ) . split ( )
    for key , value in zip ( envvars , out ) :
        value = str ( value . decode ( 'ascii' ) . replace ( '___' , '' ) )
        # remove sentinels
        os . environ [ key ] = value
        logger . debug ( "set_gmxrc_environment(): %s = %r" , key , value )
except ( subprocess . CalledProcessError , OSError ) :
    logger . warning ( "Failed to automatically set the Gromacs environment" "from GMXRC=%r" , gmxrc )


signature:
def get_tool_names ( ) :
    """Get tool names from all configured groups .
 : return : list of tool names"""

implementation:
names = [ ]
for group in cfg . get ( 'Gromacs' , 'groups' ) . split ( ) :
    names . extend ( cfg . get ( 'Gromacs' , group ) . split ( ) )
return names


signature:
def configuration ( self ) :
    """Dict of variables that we make available as globals in the module .
 Can be used as : :
 globals ( ) . update ( GMXConfigParser . configuration ) # update configdir , templatesdir . . ."""

implementation:
configuration = { 'configfilename' : self . filename , 'logfilename' : self . getpath ( 'Logging' , 'logfilename' ) , 'loglevel_console' : self . getLogLevel ( 'Logging' , 'loglevel_console' ) , 'loglevel_file' : self . getLogLevel ( 'Logging' , 'loglevel_file' ) , 'configdir' : self . getpath ( 'DEFAULT' , 'configdir' ) , 'qscriptdir' : self . getpath ( 'DEFAULT' , 'qscriptdir' ) , 'templatesdir' : self . getpath ( 'DEFAULT' , 'templatesdir' ) , }
configuration [ 'path' ] = [ os . path . curdir , configuration [ 'qscriptdir' ] , configuration [ 'templatesdir' ] ]
return configuration


signature:
def getpath ( self , section , option ) :
    """Return option as an expanded path ."""

implementation: return os . path . expanduser ( os . path . expandvars ( self . get ( section , option ) ) )


signature:
def getLogLevel ( self , section , option ) :
    """Return the textual representation of logging level ' option ' or the number .
 Note that option is always interpreted as an UPPERCASE string
 and hence integer log levels will not be recognized .
 . . SeeAlso : : mod : ` logging ` and : func : ` logging . getLevelName `"""

implementation: return logging . getLevelName ( self . get ( section , option ) . upper ( ) )


signature:
def save ( self , filename ) :
    """Pickle the whole collection to * filename * .
 If no extension is provided , " . collection " is appended ."""

implementation: cPickle . dump ( self , open ( self . _canonicalize ( filename ) , 'wb' ) , protocol = cPickle . HIGHEST_PROTOCOL )


signature:
def load ( self , filename , append = False ) :
    """Load collection from pickled file * filename * .
 * append * determines if the saved collection is added to the current one
 or if it replaces the current content .
 If no extension is provided , " . collection " is appended ."""

implementation:
tmp = cPickle . load ( open ( self . _canonicalize ( filename ) , 'rb' ) )
if append :
    self . extend ( tmp )
else :
    self [ : ] = tmp [ : ]
del tmp


signature:
def _canonicalize ( self , filename ) :
    """Use . collection as extension unless provided"""

implementation:
path , ext = os . path . splitext ( filename )
if not ext :
    ext = ".collection"
return path + ext


signature:
def register ( self , flag ) :
    """Register a new : class : ` Flag ` instance with the Flags registry ."""

implementation: super ( Flags , self ) . __setitem__ ( flag . name , flag )


signature:
def update ( self , * flags ) :
    """Update Flags registry with a list of : class : ` Flag ` instances ."""

implementation: super ( Flags , self ) . update ( [ ( flag . name , flag ) for flag in flags ] )


signature:
def scale_dihedrals ( mol , dihedrals , scale , banned_lines = None ) :
    """Scale dihedral angles"""

implementation:
if banned_lines is None :
    banned_lines = [ ]
new_dihedrals = [ ]
for dh in mol . dihedrals :
    atypes = dh . atom1 . get_atomtype ( ) , dh . atom2 . get_atomtype ( ) , dh . atom3 . get_atomtype ( ) , dh . atom4 . get_atomtype ( )
    atypes = [ a . replace ( "_" , "" ) . replace ( "=" , "" ) for a in atypes ]
    # special - case : this is a [ dihedral ] override in molecule block , continue and don ' t match
    if dh . gromacs [ 'param' ] != [ ] :
        for p in dh . gromacs [ 'param' ] :
            p [ 'kch' ] *= scale
        new_dihedrals . append ( dh )
        continue
    for iswitch in range ( 32 ) :
        if ( iswitch % 2 == 0 ) :
            a1 = atypes [ 0 ] ;
            a2 = atypes [ 1 ] ;
            a3 = atypes [ 2 ] ;
            a4 = atypes [ 3 ]
        else :
            a1 = atypes [ 3 ] ;
            a2 = atypes [ 2 ] ;
            a3 = atypes [ 1 ] ;
            a4 = atypes [ 0 ]
        if ( ( iswitch // 2 ) % 2 == 1 ) :
            a1 = "X" ;
        if ( ( iswitch // 4 ) % 2 == 1 ) :
            a2 = "X" ;
        if ( ( iswitch // 8 ) % 2 == 1 ) :
            a3 = "X" ;
        if ( ( iswitch // 16 ) % 2 == 1 ) :
            a4 = "X" ;
        key = "{0}-{1}-{2}-{3}-{4}" . format ( a1 , a2 , a3 , a4 , dh . gromacs [ 'func' ] )
        if ( key in dihedrals ) :
            for i , dt in enumerate ( dihedrals [ key ] ) :
                dhA = copy . deepcopy ( dh )
                param = copy . deepcopy ( dt . gromacs [ 'param' ] )
                # Only check the first dihedral in a list
                if not dihedrals [ key ] [ 0 ] . line in banned_lines :
                    for p in param :
                        p [ 'kchi' ] *= scale
                dhA . gromacs [ 'param' ] = param
                # if key = = " CT3 - C - NH1 - CT1-9 " : print i , dt , key
                if i == 0 :
                    dhA . comment = "; banned lines {0} found={1}\n" . format ( " " . join ( map ( str , banned_lines ) ) , 1 if dt . line in banned_lines else 0 )
                    dhA . comment += "; parameters for types {}-{}-{}-{}-9 at LINE({})\n" . format ( dhA . atom1 . atomtype , dhA . atom2 . atomtype , dhA . atom3 . atomtype , dhA . atom4 . atomtype , dt . line ) . replace ( "_" , "" )
                name = "{}-{}-{}-{}-9" . format ( dhA . atom1 . atomtype , dhA . atom2 . atomtype , dhA . atom3 . atomtype , dhA . atom4 . atomtype ) . replace ( "_" , "" )
                # if name = = " CL - CTL2 - CTL2 - HAL2-9 " : print dihedrals [ key ] , key
                new_dihedrals . append ( dhA )
            break
mol . dihedrals = new_dihedrals
# assert ( len ( mol . dihedrals ) = = new _ dihedrals )
return mol


signature:
def scale_impropers ( mol , impropers , scale , banned_lines = None ) :
    """Scale improper dihedrals"""

implementation:
if banned_lines is None :
    banned_lines = [ ]
new_impropers = [ ]
for im in mol . impropers :
    atypes = ( im . atom1 . get_atomtype ( ) , im . atom2 . get_atomtype ( ) , im . atom3 . get_atomtype ( ) , im . atom4 . get_atomtype ( ) )
    atypes = [ a . replace ( "_" , "" ) . replace ( "=" , "" ) for a in atypes ]
    # special - case : this is a [ dihedral ] override in molecule block , continue and don ' t match
    if im . gromacs [ 'param' ] != [ ] :
        for p in im . gromacs [ 'param' ] :
            p [ 'kpsi' ] *= scale
        new_impropers . append ( im )
        continue
    for iswitch in range ( 32 ) :
        if ( iswitch % 2 == 0 ) :
            a1 = atypes [ 0 ] ;
            a2 = atypes [ 1 ] ;
            a3 = atypes [ 2 ] ;
            a4 = atypes [ 3 ] ;
        else :
            a1 = atypes [ 3 ] ;
            a2 = atypes [ 2 ] ;
            a3 = atypes [ 1 ] ;
            a4 = atypes [ 0 ] ;
        if ( ( iswitch // 2 ) % 2 == 1 ) :
            a1 = "X" ;
        if ( ( iswitch // 4 ) % 2 == 1 ) :
            a2 = "X" ;
        if ( ( iswitch // 8 ) % 2 == 1 ) :
            a3 = "X" ;
        if ( ( iswitch // 16 ) % 2 == 1 ) :
            a4 = "X" ;
        key = "{0}-{1}-{2}-{3}-{4}" . format ( a1 , a2 , a3 , a4 , im . gromacs [ 'func' ] )
        if ( key in impropers ) :
            for i , imt in enumerate ( impropers [ key ] ) :
                imA = copy . deepcopy ( im )
                param = copy . deepcopy ( imt . gromacs [ 'param' ] )
                # Only check the first dihedral in a list
                if not impropers [ key ] [ 0 ] . line in banned_lines :
                    for p in param :
                        p [ 'kpsi' ] *= scale
                imA . gromacs [ 'param' ] = param
                if i == 0 :
                    imA . comment = "; banned lines {0} found={1}\n ; parameters for types {2}-{3}-{4}-{5}-9 at LINE({6})\n" . format ( " " . join ( map ( str , banned_lines ) ) , 1 if imt . line in banned_lines else 0 , imt . atype1 , imt . atype2 , imt . atype3 , imt . atype4 , imt . line )
                new_impropers . append ( imA )
            break
# assert ( len ( mol . impropers ) = = new _ impropers )
mol . impropers = new_impropers
return mol


signature:
def partial_tempering ( topfile = "processed.top" , outfile = "scaled.top" , banned_lines = '' , scale_lipids = 1.0 , scale_protein = 1.0 ) :
    """Set up topology for partial tempering ( REST2 ) replica exchange .
 . . versionchanged : : 0.7.0
 Use keyword arguments instead of an ` args ` Namespace object ."""

implementation:
banned_lines = map ( int , banned_lines . split ( ) )
top = TOP ( topfile )
groups = [ ( "_" , float ( scale_protein ) ) , ( "=" , float ( scale_lipids ) ) ]
# CMAPTYPES
cmaptypes = [ ]
for ct in top . cmaptypes :
    cmaptypes . append ( ct )
    for gr , scale in groups :
        ctA = copy . deepcopy ( ct )
        ctA . atype1 += gr
        ctA . atype2 += gr
        ctA . atype3 += gr
        ctA . atype4 += gr
        ctA . atype8 += gr
        ctA . gromacs [ 'param' ] = [ v * scale for v in ct . gromacs [ 'param' ] ]
        cmaptypes . append ( ctA )
logger . debug ( "cmaptypes was {0}, is {1}" . format ( len ( top . cmaptypes ) , len ( cmaptypes ) ) )
top . cmaptypes = cmaptypes
# ATOMTYPES
atomtypes = [ ]
for at in top . atomtypes :
    atomtypes . append ( at )
    for gr , scale in groups :
        atA = copy . deepcopy ( at )
        atA . atnum = atA . atype
        atA . atype += gr
        atA . gromacs [ 'param' ] [ 'lje' ] *= scale
        atomtypes . append ( atA )
top . atomtypes = atomtypes
# PAIRTYPES
pairtypes = [ ]
for pt in top . pairtypes :
    pairtypes . append ( pt )
    for gr , scale in groups :
        ptA = copy . deepcopy ( pt )
        ptA . atype1 += gr
        ptA . atype2 += gr
        ptA . gromacs [ 'param' ] [ 'lje14' ] *= scale
        pairtypes . append ( ptA )
top . pairtypes = pairtypes
# BONDTYPES
bondtypes = [ ]
for bt in top . bondtypes :
    bondtypes . append ( bt )
    for gr , scale in groups :
        btA = copy . deepcopy ( bt )
        btA . atype1 += gr
        btA . atype2 += gr
        bondtypes . append ( btA )
top . bondtypes = bondtypes
# ANGLETYPES
angletypes = [ ]
for at in top . angletypes :
    angletypes . append ( at )
    for gr , scale in groups :
        atA = copy . deepcopy ( at )
        atA . atype1 += gr
        atA . atype2 += gr
        atA . atype3 += gr
        angletypes . append ( atA )
top . angletypes = angletypes
# Build dihedral dictionary
dihedraltypes = { }
for dt in top . dihedraltypes :
    dt . disabled = True
    dt . comment = "; type={0!s}-{1!s}-{2!s}-{3!s}-9\n; LINE({4:d}) " . format ( dt . atype1 , dt . atype2 , dt . atype3 , dt . atype4 , dt . line )
    dt . comment = dt . comment . replace ( "_" , "" )
    # if " X - CTL2 - CTL2 - X - 9 " in dt . comment : print dt
    name = "{0}-{1}-{2}-{3}-{4}" . format ( dt . atype1 , dt . atype2 , dt . atype3 , dt . atype4 , dt . gromacs [ 'func' ] )
    if not name in dihedraltypes :
        dihedraltypes [ name ] = [ ]
    dihedraltypes [ name ] . append ( dt )
logger . debug ( "Build dihedraltypes dictionary with {0} entries" . format ( len ( dihedraltypes ) ) )
# Build improper dictionary
impropertypes = { }
for it in top . impropertypes :
    it . disabled = True
    it . comment = "; LINE({0:d}) " . format ( it . line )
    name = "{0}-{1}-{2}-{3}-{4}" . format ( it . atype1 , it . atype2 , it . atype3 , it . atype4 , it . gromacs [ 'func' ] )
    if not name in impropertypes :
        impropertypes [ name ] = [ ]
    impropertypes [ name ] . append ( it )
logger . debug ( "Build impropertypes dictionary with {0} entries" . format ( len ( impropertypes ) ) )
for molname_mol in top . dict_molname_mol :
    if not 'Protein' in molname_mol :
        continue
    mol = top . dict_molname_mol [ molname_mol ]
    for at in mol . atoms :
        at . charge *= math . sqrt ( scale_protein )
    mol = scale_dihedrals ( mol , dihedraltypes , scale_protein , banned_lines )
    mol = scale_impropers ( mol , impropertypes , 1.0 , banned_lines )
top . write ( outfile )


signature:
def to_unicode ( obj ) :
    """Convert obj to unicode ( if it can be be converted ) .
 Conversion is only attempted if ` obj ` is a string type ( as
 determined by : data : ` six . string _ types ` ) .
 . . versionchanged : : 0.7.0
 removed ` encoding keyword argument"""

implementation:
if not isinstance ( obj , six . string_types ) :
    return obj
try :
    obj = six . text_type ( obj )
except TypeError :
    pass
return obj


signature:
def besttype ( x ) :
    """Convert string x to the most useful type , i . e . int , float or unicode string .
 If x is a quoted string ( single or double quotes ) then the quotes
 are stripped and the enclosed string returned .
 . . Note : :
 Strings will be returned as Unicode strings ( using : func : ` to _ unicode ` ) .
 . . versionchanged : : 0.7.0
 removed ` encoding keyword argument"""

implementation:
x = to_unicode ( x )
# make unicode as soon as possible
try :
    x = x . strip ( )
except AttributeError :
    pass
m = re . match ( r"""['"](?P<value>.*)["']$""" , x )
if m is None : # not a quoted string , try different types
    for converter in int , float , to_unicode : # try them in increasing order of lenience
        try :
            return converter ( x )
        except ValueError :
            pass
else : # quoted string
    x = to_unicode ( m . group ( 'value' ) )
return x


signature:
def to_int64 ( a ) :
    """Return view of the recarray with all int32 cast to int64."""

implementation:
# build new dtype and replace i4 - - > i8
def promote_i4 ( typestr ) :
    if typestr [ 1 : ] == 'i4' :
        typestr = typestr [ 0 ] + 'i8'
    return typestr
dtype = [ ( name , promote_i4 ( typestr ) ) for name , typestr in a . dtype . descr ]
return a . astype ( dtype )


signature:
def irecarray_to_py ( a ) :
    """Slow conversion of a recarray into a list of records with python types .
 Get the field names from : attr : ` a . dtype . names ` .
 : Returns : iterator so that one can handle big input arrays"""

implementation:
pytypes = [ pyify ( typestr ) for name , typestr in a . dtype . descr ]
def convert_record ( r ) :
    return tuple ( [ converter ( value ) for converter , value in zip ( pytypes , r ) ] )
return ( convert_record ( r ) for r in a )


signature:
def _convert_fancy ( self , field ) :
    """Convert to a list ( sep ! = None ) and convert list elements ."""

implementation:
if self . sep is False :
    x = self . _convert_singlet ( field )
else :
    x = tuple ( [ self . _convert_singlet ( s ) for s in field . split ( self . sep ) ] )
    if len ( x ) == 0 :
        x = ''
    elif len ( x ) == 1 :
        x = x [ 0 ]
# print " % r - - > % r " % ( field , x )
return x


signature:
def parse ( self ) :
    """Parse the xpm file and populate : attr : ` XPM . array ` ."""

implementation:
with utilities . openany ( self . real_filename ) as xpm : # Read in lines until we find the start of the array
    meta = [ xpm . readline ( ) ]
    while not meta [ - 1 ] . startswith ( "static char *gromacs_xpm[]" ) :
        meta . append ( xpm . readline ( ) )
    # The next line will contain the dimensions of the array
    dim = xpm . readline ( )
    # There are four integers surrounded by quotes
    # nx : points along x , ny : points along y , nc : ? , nb : stride x
    nx , ny , nc , nb = [ int ( i ) for i in self . unquote ( dim ) . split ( ) ]
    # The next dim [ 2 ] lines contain the color definitions
    # Each pixel is encoded by dim [ 3 ] bytes , and a comment
    # at the end of the line contains the corresponding value
    colors = dict ( [ self . col ( xpm . readline ( ) ) for i in range ( nc ) ] )
    if self . autoconvert :
        autoconverter = Autoconverter ( mode = "singlet" )
        for symbol , value in colors . items ( ) :
            colors [ symbol ] = autoconverter . convert ( value )
        self . logger . debug ( "Autoconverted colours: %r" , colors )
    # make an array containing all possible values and let numpy figure out the dtype
    dtype = numpy . array ( colors . values ( ) ) . dtype
    self . logger . debug ( "Guessed array type: %s" , dtype . name )
    # pre - allocate array
    data = numpy . zeros ( ( int ( nx / nb ) , ny ) , dtype = dtype )
    self . logger . debug ( "dimensions: NX=%d NY=%d strideX=%d (NC=%d) --> (%d, %d)" , nx , ny , nb , nc , nx / nb , ny )
    iy = 0
    xval = [ ]
    yval = [ ]
    autoconverter = Autoconverter ( mode = "singlet" )
    for line in xpm :
        if line . startswith ( "/*" ) : # lines ' / * x - axis : ' . . . and ' / * y - axis : ' contain the
        # values of x and y coordinates
            s = self . uncomment ( line ) . strip ( )
            if s . startswith ( 'x-axis:' ) :
                xval . extend ( [ autoconverter . convert ( x ) for x in s [ 7 : ] . split ( ) ] )
            elif s . startswith ( 'y-axis:' ) :
                yval . extend ( [ autoconverter . convert ( y ) for y in s [ 7 : ] . split ( ) ] )
            continue
        s = self . unquote ( line )
        # Joao M . Damas < jmdamas @ itqb . unl . pt > suggests on gmx - users ( 24 Oct 2014)
        # that the next line should read :
        # data [ : , iy ] = [ colors [ j [ k : k + nb ] ] for k in range ( 0 , nx * nb , nb ) ]
        # " if one is using higher - nlevels for the . xpm construction ( in g _ rms , for example ) "
        # However , without a test case I am not eager to change it right away so in
        # case some faulty behavior is discovered with the XPM reader then this comment
        # might be helpful . - - - Oliver 2014-10-25
        data [ : , iy ] = [ colors [ s [ k : k + nb ] ] for k in range ( 0 , nx , nb ) ]
        self . logger . debug ( "read row %d with %d columns: '%s....%s'" , iy , data . shape [ 0 ] , s [ : 4 ] , s [ - 4 : ] )
        iy += 1
# for next row
self . xvalues = numpy . array ( xval )
if self . reverse :
    self . logger . debug ( "reversed row order, reverse=%r" , self . reverse )
    self . __array = data [ : , : : - 1 ]
    self . yvalues = numpy . array ( yval )
else :
    self . __array = data
    self . yvalues = numpy . array ( yval ) [ : : - 1 ]


signature:
def col ( self , c ) :
    """Parse colour specification"""

implementation:
m = self . COLOUR . search ( c )
if not m :
    self . logger . fatal ( "Cannot parse colour specification %r." , c )
    raise ParseError ( "XPM reader: Cannot parse colour specification {0!r}." . format ( c ) )
value = m . group ( 'value' )
color = m . group ( 'symbol' )
self . logger . debug ( "%s: %s %s\n" , c . strip ( ) , color , value )
return color , value


signature:
def run ( self , * args , ** kwargs ) :
    """Run the command ; args / kwargs are added or replace the ones given to the constructor ."""

implementation:
_args , _kwargs = self . _combine_arglist ( args , kwargs )
results , p = self . _run_command ( * _args , ** _kwargs )
return results


signature:
def _combine_arglist ( self , args , kwargs ) :
    """Combine the default values and the supplied values ."""

implementation:
_args = self . args + args
_kwargs = self . kwargs . copy ( )
_kwargs . update ( kwargs )
return _args , _kwargs


signature:
def _run_command ( self , * args , ** kwargs ) :
    """Execute the command ; see the docs for _ _ call _ _ .
 : Returns : a tuple of the * results * tuple ` ` ( rc , stdout , stderr ) ` ` and
 the : class : ` Popen ` instance ."""

implementation:
# hack to run command WITHOUT input ( - h . . . ) even though user defined
# input ( should have named it " ignore _ input " with opposite values . . . )
use_input = kwargs . pop ( 'use_input' , True )
# logic for capturing output ( see docs on I / O and the flags )
capturefile = None
if environment . flags [ 'capture_output' ] is True : # capture into Python vars ( see subprocess . Popen . communicate ( ) )
    kwargs . setdefault ( 'stderr' , PIPE )
    kwargs . setdefault ( 'stdout' , PIPE )
elif environment . flags [ 'capture_output' ] == "file" :
    if 'stdout' in kwargs and 'stderr' in kwargs :
        pass
    else : # XXX : not race or thread proof ; potentially many commands write to the same file
        fn = environment . flags [ 'capture_output_filename' ]
        capturefile = file ( fn , "w" )
        # overwrite ( clobber ) capture file
        if 'stdout' in kwargs and 'stderr' not in kwargs : # special case of stdout used by code but stderr should be captured to file
            kwargs . setdefault ( 'stderr' , capturefile )
        else : # merge stderr with stdout and write stdout to file
        # ( stderr comes * before * stdout in capture file , could split . . . )
            kwargs . setdefault ( 'stderr' , STDOUT )
            kwargs . setdefault ( 'stdout' , capturefile )
try :
    p = self . Popen ( * args , ** kwargs )
    out , err = p . communicate ( use_input = use_input )
    # special Popen knows input !
except :
    if capturefile is not None :
        logger . error ( "Use captured command output in %r for diagnosis." , capturefile )
    raise
finally :
    if capturefile is not None :
        capturefile . close ( )
rc = p . returncode
return ( rc , out , err ) , p


signature:
def _commandline ( self , * args , ** kwargs ) :
    """Returns the command line ( without pipes ) as a list ."""

implementation:
# transform _ args ( ) is a hook ( used in GromacsCommand very differently ! )
return [ self . command_name ] + self . transform_args ( * args , ** kwargs )


signature:
def commandline ( self , * args , ** kwargs ) :
    """Returns the commandline that run ( ) uses ( without pipes ) ."""

implementation:
# this mirrors the setup in run ( )
_args , _kwargs = self . _combine_arglist ( args , kwargs )
return self . _commandline ( * _args , ** _kwargs )


signature:
def Popen ( self , * args , ** kwargs ) :
    """Returns a special Popen instance ( : class : ` PopenWithInput ` ) .
 The instance has its input pre - set so that calls to
 : meth : ` ~ PopenWithInput . communicate ` will not need to supply
 input . This is necessary if one wants to chain the output from
 one command to an input from another .
 : TODO :
 Write example ."""

implementation:
stderr = kwargs . pop ( 'stderr' , None )
# default : print to stderr ( if STDOUT then merge )
if stderr is False : # False : capture it
    stderr = PIPE
elif stderr is True :
    stderr = None
    # use stderr
stdout = kwargs . pop ( 'stdout' , None )
# either set to PIPE for capturing output
if stdout is False : # . . . or to False
    stdout = PIPE
elif stdout is True :
    stdout = None
    # for consistency , make True write to screen
stdin = kwargs . pop ( 'stdin' , None )
input = kwargs . pop ( 'input' , None )
use_shell = kwargs . pop ( 'use_shell' , False )
if input :
    stdin = PIPE
    if isinstance ( input , six . string_types ) and not input . endswith ( '\n' ) : # make sure that input is a simple string with \ n line endings
        input = six . text_type ( input ) + '\n'
    else :
        try : # make sure that input is a simple string with \ n line endings
            input = '\n' . join ( map ( six . text_type , input ) ) + '\n'
        except TypeError : # so maybe we are a file or something . . . and hope for the best
            pass
cmd = self . _commandline ( * args , ** kwargs )
# lots of magic happening here
# ( cannot move out of method because filtering of stdin etc )
try :
    p = PopenWithInput ( cmd , stdin = stdin , stderr = stderr , stdout = stdout , universal_newlines = True , input = input , shell = use_shell )
except OSError as err :
    logger . error ( " " . join ( cmd ) )
    # log command line
    if err . errno == errno . ENOENT :
        errmsg = "Failed to find Gromacs command {0!r}, maybe its not on PATH or GMXRC must be sourced?" . format ( self . command_name )
        logger . fatal ( errmsg )
        raise OSError ( errmsg )
    else :
        logger . exception ( "Setting up Gromacs command {0!r} raised an exception." . format ( self . command_name ) )
        raise
logger . debug ( p . command_string )
return p


signature:
def transform_args ( self , * args , ** kwargs ) :
    """Transform arguments and return them as a list suitable for Popen ."""

implementation:
options = [ ]
for option , value in kwargs . items ( ) :
    if not option . startswith ( '-' ) : # heuristic for turning key = val pairs into options
    # ( fails for commands such as ' find ' - - then just use args )
        if len ( option ) == 1 :
            option = '-' + option
            # POSIX style
        else :
            option = '--' + option
            # GNU option
    if value is True :
        options . append ( option )
        continue
    elif value is False :
        raise ValueError ( 'A False value is ambiguous for option {0!r}' . format ( option ) )
    if option [ : 2 ] == '--' :
        options . append ( option + '=' + str ( value ) )
        # GNU option
    else :
        options . extend ( ( option , str ( value ) ) )
        # POSIX style
return options + list ( args )


signature:
def help ( self , long = False ) :
    """Print help ; same as using ` ` ? ` ` in ` ` ipython ` ` . long = True also gives call signature ."""

implementation:
print ( "\ncommand: {0!s}\n\n" . format ( self . command_name ) )
print ( self . __doc__ )
if long :
    print ( "\ncall method: command():\n" )
    print ( self . __call__ . __doc__ )


implementation:
gmxargs = self . gmxargs . copy ( )
gmxargs . update ( self . _combineargs ( * args , ** kwargs ) )
return ( ) , gmxargs


signature:
def _combineargs ( self , * args , ** kwargs ) :
    """Add switches as ' options ' with value True to the options dict ."""

implementation:
d = { arg : True for arg in args }
# switches are kwargs with value True
d . update ( kwargs )
return d


signature:
def _build_arg_list ( self , ** kwargs ) :
    """Build list of arguments from the dict ; keys must be valid gromacs flags ."""

implementation:
arglist = [ ]
for flag , value in kwargs . items ( ) : # XXX : check flag against allowed values
    flag = str ( flag )
    if flag . startswith ( '_' ) :
        flag = flag [ 1 : ]
        # python - illegal keywords are ' _ ' - quoted
    if not flag . startswith ( '-' ) :
        flag = '-' + flag
        # now flag is guaranteed to start with ' - '
    if value is True :
        arglist . append ( flag )
        # simple command line flag
    elif value is False :
        if flag . startswith ( '-no' ) : # negate a negated flag ( ' noX = False ' - - > X = True - - > - X . . . but who uses that ? )
            arglist . append ( '-' + flag [ 3 : ] )
        else :
            arglist . append ( '-no' + flag [ 1 : ] )
            # gromacs switches booleans by prefixing ' no '
    elif value is None :
        pass
        # ignore flag = None
    else :
        try :
            arglist . extend ( [ flag ] + value )
            # option with value list
        except TypeError :
            arglist . extend ( [ flag , value ] )
            # option with single value
return list ( map ( str , arglist ) )


signature:
def _run_command ( self , * args , ** kwargs ) :
    """Execute the gromacs command ; see the docs for _ _ call _ _ ."""

implementation:
result , p = super ( GromacsCommand , self ) . _run_command ( * args , ** kwargs )
self . check_failure ( result , command_string = p . command_string )
return result , p


signature:
def _commandline ( self , * args , ** kwargs ) :
    """Returns the command line ( without pipes ) as a list . Inserts driver if present"""

implementation:
if ( self . driver is not None ) :
    return [ self . driver , self . command_name ] + self . transform_args ( * args , ** kwargs )
return [ self . command_name ] + self . transform_args ( * args , ** kwargs )


signature:
def transform_args ( self , * args , ** kwargs ) :
    """Combine arguments and turn them into gromacs tool arguments ."""

implementation:
newargs = self . _combineargs ( * args , ** kwargs )
return self . _build_arg_list ( ** newargs )


signature:
def _get_gmx_docs ( self ) :
    """Extract standard gromacs doc
 Extract by running the program and chopping the header to keep from
 ' DESCRIPTION ' onwards ."""

implementation:
if self . _doc_cache is not None :
    return self . _doc_cache
try :
    logging . disable ( logging . CRITICAL )
    rc , header , docs = self . run ( 'h' , stdout = PIPE , stderr = PIPE , use_input = False )
except :
    logging . critical ( "Invoking command {0} failed when determining its doc string. Proceed with caution" . format ( self . command_name ) )
    self . _doc_cache = "(No Gromacs documentation available)"
    return self . _doc_cache
finally : # ALWAYS restore logging . . .
    logging . disable ( logging . NOTSET )
# The header is on STDOUT and is ignored . The docs are read from STDERR in GMX 4.
m = re . match ( self . doc_pattern , docs , re . DOTALL )
if m is None : # In GMX 5 , the opposite is true ( Grrr )
    m = re . match ( self . doc_pattern , header , re . DOTALL )
    if m is None :
        self . _doc_cache = "(No Gromacs documentation available)"
        return self . _doc_cache
self . _doc_cache = m . group ( 'DOCS' )
return self . _doc_cache


signature:
def communicate ( self , use_input = True ) :
    """Run the command , using the input that was set up on _ _ init _ _ ( for * use _ input * = ` ` True ` ` )"""

implementation:
if use_input :
    return super ( PopenWithInput , self ) . communicate ( self . input )
else :
    return super ( PopenWithInput , self ) . communicate ( )


signature:
def autoconvert ( s ) :
    """Convert input to a numerical type if possible .
 1 . A non - string object is returned as it is
 2 . Try conversion to int , float , str ."""

implementation:
if type ( s ) is not str :
    return s
for converter in int , float , str : # try them in increasing order of lenience
    try :
        s = [ converter ( i ) for i in s . split ( ) ]
        if len ( s ) == 1 :
            return s [ 0 ]
        else :
            return numpy . array ( s )
    except ( ValueError , AttributeError ) :
        pass
raise ValueError ( "Failed to autoconvert {0!r}" . format ( s ) )


signature:
def openany ( datasource , mode = 'rt' , reset = True ) :
    """Context manager for : func : ` anyopen ` .
 Open the ` datasource ` and close it when the context of the : keyword : ` with `
 statement exits .
 ` datasource ` can be a filename or a stream ( see : func : ` isstream ` ) . A stream
 is reset to its start if possible ( via : meth : ` ~ io . IOBase . seek ` or
 : meth : ` ~ cString . StringIO . reset ` ) .
 The advantage of this function is that very different input sources
 ( " streams " ) can be used for a " file " , ranging from files on disk ( including
 compressed files ) to open file objects to sockets and strings - - - as long as
 they have a file - like interface .
 : Arguments :
 * datasource *
 a file or a stream
 * mode *
 { ' r ' , ' w ' } ( optional ) , open in r ( ead ) or w ( rite ) mode
 * reset *
 bool ( optional ) try to read ( ` mode ` ' r ' ) the stream from the
 start [ ` ` True ` ` ]
 * * Example * *
 Open a gzipped file and process it line by line : :
 with openany ( " input . pdb . gz " ) as pdb :
 for line in pdb :
 if line . startswith ( ' ATOM ' ) :
 print ( line )
 Open a URL and read it : :
 import urllib2
 with openany ( urllib2 . urlopen ( " https : / / www . mdanalysis . org / " ) ) as html :
 print ( html . read ( ) )
 . . SeeAlso : :
 : func : ` anyopen `"""

implementation:
stream = anyopen ( datasource , mode = mode , reset = reset )
try :
    yield stream
finally :
    stream . close ( )


signature:
def anyopen ( datasource , mode = 'rt' , reset = True ) :
    """Open datasource ( gzipped , bzipped , uncompressed ) and return a stream .
 ` datasource ` can be a filename or a stream ( see : func : ` isstream ` ) . By
 default , a stream is reset to its start if possible ( via
 : meth : ` ~ io . IOBase . seek ` or : meth : ` ~ cString . StringIO . reset ` ) .
 If possible , the attribute ` ` stream . name ` ` is set to the filename or
 " < stream > " if no filename could be associated with the * datasource * .
 : Arguments :
 * datasource *
 a file ( from : class : ` file ` or : func : ` open ` ) or a stream ( e . g . from
 : func : ` urllib2 . urlopen ` or : class : ` cStringIO . StringIO ` )
 * mode *
 { ' r ' , ' w ' , ' a ' } ( optional ) ,
 Open in r ( ead ) , w ( rite ) or a ( ppen ) mode . More complicated
 modes ( ' r + ' , ' w + ' , . . . ) are not supported ; only the first letter of
 ` mode ` is used and thus any additional modifiers are silently ignored .
 * reset *
 bool ( optional ) ,
 try to read ( ` mode ` ' r ' ) the stream from the start
 : Returns :
 file - like object
 . . SeeAlso : :
 : func : ` openany ` to be used with the : keyword : ` with ` statement ."""

implementation:
handlers = { 'bz2' : bz2_open , 'gz' : gzip . open , '' : open }
if mode . startswith ( 'r' ) :
    if isstream ( datasource ) :
        stream = datasource
        try :
            filename = str ( stream . name )
            # maybe that does not always work ?
        except AttributeError :
            filename = "<stream>"
        if reset :
            try :
                stream . reset ( )
            except ( AttributeError , IOError ) :
                try :
                    stream . seek ( 0 )
                except ( AttributeError , IOError ) :
                    warnings . warn ( "Stream {0}: not guaranteed to be at the beginning." "" . format ( filename ) , category = StreamWarning )
    else :
        stream = None
        filename = datasource
        for ext in ( 'bz2' , 'gz' , '' ) : # file = = ' ' should be last
            openfunc = handlers [ ext ]
            stream = _get_stream ( datasource , openfunc , mode = mode )
            if stream is not None :
                break
        if stream is None :
            raise IOError ( errno . EIO , "Cannot open file or stream in mode={mode!r}." . format ( ** vars ( ) ) , repr ( filename ) )
elif mode . startswith ( 'w' ) or mode . startswith ( 'a' ) : # append ' a ' not tested . . .
    if isstream ( datasource ) :
        stream = datasource
        try :
            filename = str ( stream . name )
            # maybe that does not always work ?
        except AttributeError :
            filename = "<stream>"
    else :
        stream = None
        filename = datasource
        name , ext = os . path . splitext ( filename )
        if ext . startswith ( '.' ) :
            ext = ext [ 1 : ]
        if not ext in ( 'bz2' , 'gz' ) :
            ext = ''
            # anything else but bz2 or gz is just a normal file
        openfunc = handlers [ ext ]
        stream = openfunc ( datasource , mode = mode )
        if stream is None :
            raise IOError ( errno . EIO , "Cannot open file or stream in mode={mode!r}." . format ( ** vars ( ) ) , repr ( filename ) )
else :
    raise NotImplementedError ( "Sorry, mode={mode!r} is not implemented for {datasource!r}" . format ( ** vars ( ) ) )
try :
    stream . name = filename
except ( AttributeError , TypeError ) :
    pass
    # can ' t set name ( e . g . cStringIO . StringIO )
return stream


signature:
def _get_stream ( filename , openfunction = open , mode = 'r' ) :
    """Return open stream if * filename * can be opened with * openfunction * or else ` ` None ` ` ."""

implementation:
try :
    stream = openfunction ( filename , mode = mode )
except ( IOError , OSError ) as err : # An exception might be raised due to two reasons , first the openfunction is unable to open the file , in this
# case we have to ignore the error and return None . Second is when openfunction can ' t open the file because
# either the file isn ' t there or the permissions don ' t allow access .
    if errno . errorcode [ err . errno ] in [ 'ENOENT' , 'EACCES' ] :
        six . reraise ( * sys . exc_info ( ) )
    return None
if mode . startswith ( 'r' ) : # additional check for reading ( eg can we uncompress ) - - - is this needed ?
    try :
        stream . readline ( )
    except IOError :
        stream . close ( )
        stream = None
    except :
        stream . close ( )
        raise
    else :
        stream . close ( )
        stream = openfunction ( filename , mode = mode )
return stream


signature:
def hasmethod ( obj , m ) :
    """Return ` ` True ` ` if object * obj * contains the method * m * .
 . . versionadded : : 0.7.1"""

implementation: return hasattr ( obj , m ) and callable ( getattr ( obj , m ) )


signature:
def isstream ( obj ) :
    """Detect if ` obj ` is a stream .
 We consider anything a stream that has the methods
 - ` ` close ( ) ` `
 and either set of the following
 - ` ` read ( ) ` ` , ` ` readline ( ) ` ` , ` ` readlines ( ) ` `
 - ` ` write ( ) ` ` , ` ` writeline ( ) ` ` , ` ` writelines ( ) ` `
 : Arguments :
 * obj *
 stream or str
 : Returns :
 * bool * , ` ` True ` ` if ` obj ` is a stream , ` ` False ` ` otherwise
 . . SeeAlso : :
 : mod : ` io `
 . . versionadded : : 0.7.1"""

implementation:
signature_methods = ( "close" , )
alternative_methods = ( ( "read" , "readline" , "readlines" ) , ( "write" , "writeline" , "writelines" ) )
# Must have ALL the signature methods
for m in signature_methods :
    if not hasmethod ( obj , m ) :
        return False
# Must have at least one complete set of alternative _ methods
alternative_results = [ numpy . all ( [ hasmethod ( obj , m ) for m in alternatives ] ) for alternatives in alternative_methods ]
return numpy . any ( alternative_results )


signature:
def convert_aa_code ( x ) :
    """Converts between 3 - letter and 1 - letter amino acid codes ."""

implementation:
if len ( x ) == 1 :
    return amino_acid_codes [ x . upper ( ) ]
elif len ( x ) == 3 :
    return inverse_aa_codes [ x . upper ( ) ]
else :
    raise ValueError ( "Can only convert 1-letter or 3-letter amino acid codes, " "not %r" % x )


signature:
def in_dir ( directory , create = True ) :
    """Context manager to execute a code block in a directory .
 * The directory is created if it does not exist ( unless
 create = False is set )
 * At the end or after an exception code always returns to
 the directory that was the current directory before entering
 the block ."""

implementation:
startdir = os . getcwd ( )
try :
    try :
        os . chdir ( directory )
        logger . debug ( "Working in {directory!r}..." . format ( ** vars ( ) ) )
    except OSError as err :
        if create and err . errno == errno . ENOENT :
            os . makedirs ( directory )
            os . chdir ( directory )
            logger . info ( "Working in {directory!r} (newly created)..." . format ( ** vars ( ) ) )
        else :
            logger . exception ( "Failed to start working in {directory!r}." . format ( ** vars ( ) ) )
            raise
    yield os . getcwd ( )
finally :
    os . chdir ( startdir )


signature:
def realpath ( * args ) :
    """Join all args and return the real path , rooted at / .
 Expands ` ` ~ ` ` and environment variables such as : envvar : ` $ HOME ` .
 Returns ` ` None ` ` if any of the args is none ."""

implementation:
if None in args :
    return None
return os . path . realpath ( os . path . expandvars ( os . path . expanduser ( os . path . join ( * args ) ) ) )


signature:
def find_first ( filename , suffices = None ) :
    """Find first * filename * with a suffix from * suffices * .
 : Arguments :
 * filename *
 base filename ; this file name is checked first
 * suffices *
 list of suffices that are tried in turn on the root of * filename * ; can contain the
 ext separator ( : data : ` os . path . extsep ` ) or not
 : Returns : The first match or ` ` None ` ` ."""

implementation:
# struct is not reliable as it depends on qscript so now we just try everything . . .
root , extension = os . path . splitext ( filename )
if suffices is None :
    suffices = [ ]
else :
    suffices = withextsep ( suffices )
extensions = [ extension ] + suffices
# native name is first
for ext in extensions :
    fn = root + ext
    if os . path . exists ( fn ) :
        return fn
return None


signature:
def withextsep ( extensions ) :
    """Return list in which each element is guaranteed to start with : data : ` os . path . extsep ` ."""

implementation:
def dottify ( x ) :
    if x . startswith ( os . path . extsep ) :
        return x
    return os . path . extsep + x
return [ dottify ( x ) for x in asiterable ( extensions ) ]


signature:
def iterable ( obj ) :
    """Returns ` ` True ` ` if * obj * can be iterated over and is * not * a string ."""

implementation:
if isinstance ( obj , string_types ) :
    return False
    # avoid iterating over characters of a string
if hasattr ( obj , 'next' ) :
    return True
    # any iterator will do
try :
    len ( obj )
    # anything else that might work
except TypeError :
    return False
return True


signature:
def unlink_f ( path ) :
    """Unlink path but do not complain if file does not exist ."""

implementation:
try :
    os . unlink ( path )
except OSError as err :
    if err . errno != errno . ENOENT :
        raise


signature:
def unlink_gmx_backups ( * args ) :
    """Unlink ( rm ) all backup files corresponding to the listed files ."""

implementation:
for path in args :
    dirname , filename = os . path . split ( path )
    fbaks = glob . glob ( os . path . join ( dirname , '#' + filename + '.*#' ) )
    for bak in fbaks :
        unlink_f ( bak )


signature:
def mkdir_p ( path ) :
    """Create a directory * path * with subdirs but do not complain if it exists .
 This is like GNU ` ` mkdir - p path ` ` ."""

implementation:
try :
    os . makedirs ( path )
except OSError as err :
    if err . errno != errno . EEXIST :
        raise


signature:
def cat ( f = None , o = None ) :
    """Concatenate files * f * = [ . . . ] and write to * o *"""

implementation:
# need f , o to be compatible with trjcat and eneconv
if f is None or o is None :
    return
target = o
infiles = asiterable ( f )
logger . debug ( "cat {0!s} > {1!s} " . format ( " " . join ( infiles ) , target ) )
with open ( target , 'w' ) as out :
    rc = subprocess . call ( [ 'cat' ] + infiles , stdout = out )
if rc != 0 :
    msg = "failed with return code {0:d}: cat {1!r} > {2!r} " . format ( rc , " " . join ( infiles ) , target )
    logger . exception ( msg )
    raise OSError ( errno . EIO , msg , target )


signature:
def activate_subplot ( numPlot ) :
    """Make subplot * numPlot * active on the canvas .
 Use this if a simple ` ` subplot ( numRows , numCols , numPlot ) ` `
 overwrites the subplot instead of activating it ."""

implementation:
# see http : / / www . mail - archive . com / matplotlib - users @ lists . sourceforge . net / msg07156 . html
from pylab import gcf , axes
numPlot -= 1
# index is 0 - based , plots are 1 - based
return axes ( gcf ( ) . get_axes ( ) [ numPlot ] )


signature:
def remove_legend ( ax = None ) :
    """Remove legend for axes or gca .
 See http : / / osdir . com / ml / python . matplotlib . general / 2005-07 / msg00285 . html"""

implementation:
from pylab import gca , draw
if ax is None :
    ax = gca ( )
ax . legend_ = None
draw ( )


signature:
def number_pdbs ( * args , ** kwargs ) :
    """Rename pdbs x1 . pdb . . . x345 . pdb - - > x0001 . pdb . . . x0345 . pdb
 : Arguments :
 - * args * : filenames or glob patterns ( such as " pdb / md * . pdb " )
 - * format * : format string including keyword * num * [ " % ( num ) 04d " ]"""

implementation:
format = kwargs . pop ( 'format' , "%(num)04d" )
name_format = "%(prefix)s" + format + ".%(suffix)s"
for f in itertools . chain . from_iterable ( map ( glob . glob , args ) ) :
    m = NUMBERED_PDB . search ( f )
    if m is None :
        continue
    num = int ( m . group ( 'NUMBER' ) )
    prefix = m . group ( 'PREFIX' )
    suffix = m . group ( 'SUFFIX' )
    newname = name_format % vars ( )
    logger . info ( "Renaming {f!r} --> {newname!r}" . format ( ** vars ( ) ) )
    try :
        os . rename ( f , newname )
    except OSError :
        logger . exception ( "renaming failed" )


signature:
def _init_filename ( self , filename = None , ext = None ) :
    """Initialize the current filename : attr : ` FileUtils . real _ filename ` of the object .
 Bit of a hack .
 - The first invocation must have ` ` filename ! = None ` ` ; this will set a
 default filename with suffix : attr : ` FileUtils . default _ extension `
 unless another one was supplied .
 - Subsequent invocations either change the filename accordingly or
 ensure that the default filename is set with the proper suffix ."""

implementation:
extension = ext or self . default_extension
filename = self . filename ( filename , ext = extension , use_my_ext = True , set_default = True )
# : Current full path of the object for reading and writing I / O .
self . real_filename = os . path . realpath ( filename )


signature:
def filename ( self , filename = None , ext = None , set_default = False , use_my_ext = False ) :
    """Supply a file name for the class object .
 Typical uses : :
 fn = filename ( ) - - - > < default _ filename >
 fn = filename ( ' name . ext ' ) - - - > ' name '
 fn = filename ( ext = ' pickle ' ) - - - > < default _ filename > ' . pickle '
 fn = filename ( ' name . inp ' , ' pdf ' ) - - > ' name . pdf '
 fn = filename ( ' foo . pdf ' , ext = ' png ' , use _ my _ ext = True ) - - > ' foo . pdf '
 The returned filename is stripped of the extension
 ( ` ` use _ my _ ext = False ` ` ) and if provided , another extension is
 appended . Chooses a default if no filename is given .
 Raises a ` ` ValueError ` ` exception if no default file name is known .
 If ` ` set _ default = True ` ` then the default filename is also set .
 ` ` use _ my _ ext = True ` ` lets the suffix of a provided filename take
 priority over a default ` ` ext ` ` tension .
 . . versionchanged : : 0.3.1
 An empty string as * ext * = " " will suppress appending an extension ."""

implementation:
if filename is None :
    if not hasattr ( self , '_filename' ) :
        self . _filename = None
        # add attribute to class
    if self . _filename :
        filename = self . _filename
    else :
        raise ValueError ( "A file name is required because no default file name was defined." )
    my_ext = None
else :
    filename , my_ext = os . path . splitext ( filename )
    if set_default : # replaces existing default file name
        self . _filename = filename
if my_ext and use_my_ext :
    ext = my_ext
if ext is not None :
    if ext . startswith ( os . extsep ) :
        ext = ext [ 1 : ]
        # strip a dot to avoid annoying mistakes
    if ext != "" :
        filename = filename + os . extsep + ext
return filename


signature:
def check_file_exists ( self , filename , resolve = 'exception' , force = None ) :
    """If a file exists then continue with the action specified in ` ` resolve ` ` .
 ` ` resolve ` ` must be one of
 " ignore "
 always return ` ` False ` `
 " indicate "
 return ` ` True ` ` if it exists
 " warn "
 indicate and issue a : exc : ` UserWarning `
 " exception "
 raise : exc : ` IOError ` if it exists
 Alternatively , set * force * for the following behaviour ( which
 ignores * resolve * ) :
 ` ` True ` `
 same as * resolve * = " ignore " ( will allow overwriting of files )
 ` ` False ` `
 same as * resolve * = " exception " ( will prevent overwriting of files )
 ` ` None ` `
 ignored , do whatever * resolve * says"""

implementation:
def _warn ( x ) :
    msg = "File {0!r} already exists." . format ( x )
    logger . warn ( msg )
    warnings . warn ( msg )
    return True
def _raise ( x ) :
    msg = "File {0!r} already exists." . format ( x )
    logger . error ( msg )
    raise IOError ( errno . EEXIST , x , msg )
solutions = { 'ignore' : lambda x : False , # file exists , but we pretend that it doesn ' t
'indicate' : lambda x : True , # yes , file exists
'warn' : _warn , 'warning' : _warn , 'exception' : _raise , 'raise' : _raise , }
if force is True :
    resolve = 'ignore'
elif force is False :
    resolve = 'exception'
if not os . path . isfile ( filename ) :
    return False
else :
    return solutions [ resolve ] ( filename )


signature:
def infix_filename ( self , name , default , infix , ext = None ) :
    """Unless * name * is provided , insert * infix * before the extension * ext * of * default * ."""

implementation:
if name is None :
    p , oldext = os . path . splitext ( default )
    if ext is None :
        ext = oldext
    if ext . startswith ( os . extsep ) :
        ext = ext [ 1 : ]
    name = self . filename ( p + infix , ext = ext )
return name


signature:
def strftime ( self , fmt = "%d:%H:%M:%S" ) :
    """Primitive string formatter .
 The only directives understood are the following :
 Directive meaning
 % d day as integer
 % H hour [ 00-23]
 % h hours including days
 % M minute as integer [ 00-59]
 % S second as integer [ 00-59]"""

implementation:
substitutions = { "%d" : str ( self . days ) , "%H" : "{0:02d}" . format ( self . dhours ) , "%h" : str ( 24 * self . days + self . dhours ) , "%M" : "{0:02d}" . format ( self . dminutes ) , "%S" : "{0:02d}" . format ( self . dseconds ) , }
s = fmt
for search , replacement in substitutions . items ( ) :
    s = s . replace ( search , replacement )
return s


signature:
def start_logging ( logfile = "gromacs.log" ) :
    """Start logging of messages to file and console .
 The default logfile is named ` ` gromacs . log ` ` and messages are
 logged with the tag * gromacs * ."""

implementation:
from . import log
log . create ( "gromacs" , logfile = logfile )
logging . getLogger ( "gromacs" ) . info ( "GromacsWrapper %s STARTED logging to %r" , __version__ , logfile )


signature:
def stop_logging ( ) :
    """Stop logging to logfile and console ."""

implementation:
from . import log
logger = logging . getLogger ( "gromacs" )
logger . info ( "GromacsWrapper %s STOPPED logging" , get_version ( ) )
log . clear_handlers ( logger )


signature:
def filter_gromacs_warnings ( action , categories = None ) :
    """Set the : meth : ` warnings . simplefilter ` to * action * .
 * categories * must be a list of warning classes or strings .
 ` ` None ` ` selects the defaults , : data : ` gromacs . less _ important _ warnings ` ."""

implementation:
if categories is None :
    categories = less_important_warnings
for c in categories :
    try :
        w = globals ( ) [ c ]
    except KeyError :
        w = c
    if not issubclass ( w , Warning ) :
        raise TypeError ( "{0!r} is neither a Warning nor the name of a Gromacs warning." . format ( c ) )
    warnings . simplefilter ( action , category = w )


signature:
def tool_factory ( clsname , name , driver , base = GromacsCommand ) :
    """Factory for GromacsCommand derived types ."""

implementation:
clsdict = { 'command_name' : name , 'driver' : driver , '__doc__' : property ( base . _get_gmx_docs ) }
return type ( clsname , ( base , ) , clsdict )


signature:
def find_executables ( path ) :
    """Find executables in a path .
 Searches executables in a directory excluding some know commands
 unusable with GromacsWrapper .
 : param path : dirname to search for
 : return : list of executables"""

implementation:
execs = [ ]
for exe in os . listdir ( path ) :
    fullexe = os . path . join ( path , exe )
    if ( os . access ( fullexe , os . X_OK ) and not os . path . isdir ( fullexe ) and exe not in [ 'GMXRC' , 'GMXRC.bash' , 'GMXRC.csh' , 'GMXRC.zsh' , 'demux.pl' , 'xplor2gmx.pl' ] ) :
        execs . append ( exe )
return execs


signature:
def load_v5_tools ( ) :
    """Load Gromacs 2018/2016/5 . x tools automatically using some heuristic .
 Tries to load tools ( 1 ) using the driver from configured groups ( 2 ) and
 falls back to automatic detection from ` ` GMXBIN ` ` ( 3 ) then to rough guesses .
 In all cases the command ` ` gmx help ` ` is ran to get all tools available .
 : return : dict mapping tool names to GromacsCommand classes"""

implementation:
logger . debug ( "Loading 2018/2016/5.x tools..." )
drivers = config . get_tool_names ( )
if len ( drivers ) == 0 and 'GMXBIN' in os . environ :
    drivers = find_executables ( os . environ [ 'GMXBIN' ] )
if len ( drivers ) == 0 or len ( drivers ) > 4 :
    drivers = [ 'gmx' , 'gmx_d' , 'gmx_mpi' , 'gmx_mpi_d' ]
append = config . cfg . getboolean ( 'Gromacs' , 'append_suffix' , fallback = True )
tools = { }
for driver in drivers :
    suffix = driver . partition ( '_' ) [ 2 ]
    try :
        out = subprocess . check_output ( [ driver , '-quiet' , 'help' , 'commands' ] )
        for line in out . splitlines ( ) [ 5 : - 1 ] :
            line = str ( line . decode ( 'ascii' ) )
            # Python 3 : byte string - > str , Python 2 : normal string
            if line [ 4 ] != ' ' :
                name = line [ 4 : line . index ( ' ' , 4 ) ]
                fancy = make_valid_identifier ( name )
                if suffix and append :
                    fancy = '{0!s}_{1!s}' . format ( fancy , suffix )
                tools [ fancy ] = tool_factory ( fancy , name , driver )
    except ( subprocess . CalledProcessError , OSError ) :
        pass
if not tools :
    errmsg = "Failed to load 2018/2016/5.x tools (tried drivers: {})" . format ( drivers )
    logger . debug ( errmsg )
    raise GromacsToolLoadingError ( errmsg )
logger . debug ( "Loaded {0} v5 tools successfully!" . format ( len ( tools ) ) )
return tools


signature:
def load_v4_tools ( ) :
    """Load Gromacs 4 . x tools automatically using some heuristic .
 Tries to load tools ( 1 ) in configured tool groups ( 2 ) and fails back to
 automatic detection from ` ` GMXBIN ` ` ( 3 ) then to a prefilled list .
 Also load any extra tool configured in ` ` ~ / . gromacswrapper . cfg ` `
 : return : dict mapping tool names to GromacsCommand classes"""

implementation:
logger . debug ( "Loading v4 tools..." )
names = config . get_tool_names ( )
if len ( names ) == 0 and 'GMXBIN' in os . environ :
    names = find_executables ( os . environ [ 'GMXBIN' ] )
if len ( names ) == 0 or len ( names ) > len ( V4TOOLS ) * 4 :
    names = list ( V4TOOLS )
names . extend ( config . get_extra_tool_names ( ) )
tools = { }
for name in names :
    fancy = make_valid_identifier ( name )
    tools [ fancy ] = tool_factory ( fancy , name , None )
if not tools :
    errmsg = "Failed to load v4 tools"
    logger . debug ( errmsg )
    raise GromacsToolLoadingError ( errmsg )
logger . debug ( "Loaded {0} v4 tools successfully!" . format ( len ( tools ) ) )
return tools


signature:
def merge_ndx ( * args ) :
    """Takes one or more index files and optionally one structure file and
 returns a path for a new merged index file .
 : param args : index files and zero or one structure file
 : return : path for the new merged index file"""

implementation:
ndxs = [ ]
struct = None
for fname in args :
    if fname . endswith ( '.ndx' ) :
        ndxs . append ( fname )
    else :
        if struct is not None :
            raise ValueError ( "only one structure file supported" )
        struct = fname
fd , multi_ndx = tempfile . mkstemp ( suffix = '.ndx' , prefix = 'multi_' )
os . close ( fd )
atexit . register ( os . unlink , multi_ndx )
if struct :
    make_ndx = registry [ 'Make_ndx' ] ( f = struct , n = ndxs , o = multi_ndx )
else :
    make_ndx = registry [ 'Make_ndx' ] ( n = ndxs , o = multi_ndx )
_ , _ , _ = make_ndx ( input = [ 'q' ] , stdout = False , stderr = False )
return multi_ndx


signature:
def read ( self , filename = None ) :
    """Read and parse index file * filename * ."""

implementation:
self . _init_filename ( filename )
data = odict ( )
with open ( self . real_filename ) as ndx :
    current_section = None
    for line in ndx :
        line = line . strip ( )
        if len ( line ) == 0 :
            continue
        m = self . SECTION . match ( line )
        if m :
            current_section = m . group ( 'name' )
            data [ current_section ] = [ ]
            # can fail if name not legal python key
            continue
        if current_section is not None :
            data [ current_section ] . extend ( map ( int , line . split ( ) ) )
super ( NDX , self ) . update ( odict ( [ ( name , self . _transform ( atomnumbers ) ) for name , atomnumbers in data . items ( ) ] ) )


signature:
def write ( self , filename = None , ncol = ncol , format = format ) :
    """Write index file to * filename * ( or overwrite the file that the index was read from )"""

implementation:
with open ( self . filename ( filename , ext = 'ndx' ) , 'w' ) as ndx :
    for name in self :
        atomnumbers = self . _getarray ( name )
        # allows overriding
        ndx . write ( '[ {0!s} ]\n' . format ( name ) )
        for k in range ( 0 , len ( atomnumbers ) , ncol ) :
            line = atomnumbers [ k : k + ncol ] . astype ( int )
            # nice formatting in ncol - blocks
            n = len ( line )
            ndx . write ( ( " " . join ( n * [ format ] ) + '\n' ) % tuple ( line ) )
        ndx . write ( '\n' )


signature:
def ndxlist ( self ) :
    """Return a list of groups in the same format as : func : ` gromacs . cbook . get _ ndx _ groups ` .
 Format :
 [ { ' name ' : group _ name , ' natoms ' : number _ atoms , ' nr ' : # group _ number } , . . . . ]"""

implementation: return [ { 'name' : name , 'natoms' : len ( atomnumbers ) , 'nr' : nr + 1 } for nr , ( name , atomnumbers ) in enumerate ( self . items ( ) ) ]


signature:
def join ( self , * groupnames ) :
    """Return an index group that contains atoms from all * groupnames * .
 The method will silently ignore any groups that are not in the
 index .
 * * Example * *
 Always make a solvent group from water and ions , even if not
 all ions are present in all simulations : :
 I [ ' SOLVENT ' ] = I . join ( ' SOL ' , ' NA + ' , ' K + ' , ' CL - ' )"""

implementation: return self . _sum ( [ self [ k ] for k in groupnames if k in self ] )


signature:
def break_array ( a , threshold = numpy . pi , other = None ) :
    """Create a array which masks jumps > = threshold .
 Extra points are inserted between two subsequent values whose
 absolute difference differs by more than threshold ( default is
 pi ) .
 Other can be a secondary array which is also masked according to
 Returns ( * a _ masked * , * other _ masked * ) ( where * other _ masked * can be
 ` ` None ` ` )"""

implementation:
assert len ( a . shape ) == 1 , "Only 1D arrays supported"
if other is not None and a . shape != other . shape :
    raise ValueError ( "arrays must be of identical shape" )
# jump occurs after the index in break
breaks = numpy . where ( numpy . abs ( numpy . diff ( a ) ) >= threshold ) [ 0 ]
# insert a blank after
breaks += 1
# is this needed ? ? - - no , but leave it here as a reminder
# f2 = numpy . diff ( a , 2)
# up = ( f2 [ breaks - 1 ] > = 0 ) # > 0 : up , < 0 : down
# sort into up and down breaks :
# breaks _ up = breaks [ up ]
# breaks _ down = breaks [ ~ up ]
# new array b including insertions for all the breaks
m = len ( breaks )
b = numpy . empty ( ( len ( a ) + m ) )
# calculate new indices for breaks in b , taking previous insertions into account
b_breaks = breaks + numpy . arange ( m )
mask = numpy . zeros_like ( b , dtype = numpy . bool )
mask [ b_breaks ] = True
b [ ~ mask ] = a
b [ mask ] = numpy . NAN
if other is not None :
    c = numpy . empty_like ( b )
    c [ ~ mask ] = other
    c [ mask ] = numpy . NAN
    ma_c = numpy . ma . array ( c , mask = mask )
else :
    ma_c = None
return numpy . ma . array ( b , mask = mask ) , ma_c


signature:
def write ( self , filename = None ) :
    """Write array to xvg file * filename * in NXY format .
 . . Note : : Only plain files working at the moment , not compressed ."""

implementation:
self . _init_filename ( filename )
with utilities . openany ( self . real_filename , 'w' ) as xvg :
    xvg . write ( "# xmgrace compatible NXY data file\n" "# Written by gromacs.formats.XVG()\n" )
    xvg . write ( "# :columns: {0!r}\n" . format ( self . names ) )
    for xyy in self . array . T :
        xyy . tofile ( xvg , sep = " " , format = "%-8s" )
        # quick and dirty ascii output . . . - - no compression !
        xvg . write ( '\n' )


signature:
def ma ( self ) :
    """Represent data as a masked array .
 The array is returned with column - first indexing , i . e . for a data file with
 columns X Y1 Y2 Y3 . . . the array a will be a [ 0 ] = X , a [ 1 ] = Y1 , . . . .
 inf and nan are filtered via : func : ` numpy . isfinite ` ."""

implementation:
a = self . array
return numpy . ma . MaskedArray ( a , mask = numpy . logical_not ( numpy . isfinite ( a ) ) )


signature:
def _tcorrel ( self , nstep = 100 , ** kwargs ) :
    """Correlation " time " of data .
 The 0 - th column of the data is interpreted as a time and the
 decay of the data is computed from the autocorrelation
 function ( using FFT ) .
 . . SeeAlso : : : func : ` numkit . timeseries . tcorrel `"""

implementation:
t = self . array [ 0 , : : nstep ]
r = gromacs . collections . Collection ( [ numkit . timeseries . tcorrel ( t , Y , nstep = 1 , ** kwargs ) for Y in self . array [ 1 : , : : nstep ] ] )
return r


signature:
def set_correlparameters ( self , ** kwargs ) :
    """Set and change the parameters for calculations with correlation functions .
 The parameters persist until explicitly changed .
 : Keywords :
 * nstep *
 only process every * nstep * data point to speed up the FFT ; if
 left empty a default is chosen that produces roughly 25,000 data
 points ( or whatever is set in * ncorrel * )
 * ncorrel *
 If no * nstep * is supplied , aim at using * ncorrel * data points for
 the FFT ; sets : attr : ` XVG . ncorrel ` [ 25000]
 * force *
 force recalculating correlation data even if cached values are
 available
 * kwargs *
 see : func : ` numkit . timeseries . tcorrel ` for other options
 . . SeeAlso : : attr : ` XVG . error ` for details and references ."""

implementation:
self . ncorrel = kwargs . pop ( 'ncorrel' , self . ncorrel ) or 25000
nstep = kwargs . pop ( 'nstep' , None )
if nstep is None : # good step size leads to ~ 25,000 data points
    nstep = len ( self . array [ 0 ] ) / float ( self . ncorrel )
    nstep = int ( numpy . ceil ( nstep ) )
    # catch small data sets
kwargs [ 'nstep' ] = nstep
self . __correlkwargs . update ( kwargs )
# only contains legal kw for numkit . timeseries . tcorrel or force
return self . __correlkwargs


signature:
def parse ( self , stride = None ) :
    """Read and cache the file as a numpy array .
 Store every * stride * line of data ; if ` ` None ` ` then the class default is used .
 The array is returned with column - first indexing , i . e . for a data file with
 columns X Y1 Y2 Y3 . . . the array a will be a [ 0 ] = X , a [ 1 ] = Y1 , . . . ."""

implementation:
if stride is None :
    stride = self . stride
self . corrupted_lineno = [ ]
irow = 0
# count rows of data
# cannot use numpy . loadtxt ( ) because xvg can have two types of ' comment ' lines
with utilities . openany ( self . real_filename ) as xvg :
    rows = [ ]
    ncol = None
    for lineno , line in enumerate ( xvg ) :
        line = line . strip ( )
        if len ( line ) == 0 :
            continue
        if "label" in line and "xaxis" in line :
            self . xaxis = line . split ( '"' ) [ - 2 ]
        if "label" in line and "yaxis" in line :
            self . yaxis = line . split ( '"' ) [ - 2 ]
        if line . startswith ( "@ legend" ) :
            if not "legend" in self . metadata :
                self . metadata [ "legend" ] = [ ]
            self . metadata [ "legend" ] . append ( line . split ( "legend " ) [ - 1 ] )
        if line . startswith ( "@ s" ) and "subtitle" not in line :
            name = line . split ( "legend " ) [ - 1 ] . replace ( '"' , '' ) . strip ( )
            self . names . append ( name )
        if line . startswith ( ( '#' , '@' ) ) :
            continue
        if line . startswith ( '&' ) :
            raise NotImplementedError ( '{0!s}: Multi-data not supported, only simple NXY format.' . format ( self . real_filename ) )
        # parse line as floats
        try :
            row = [ float ( el ) for el in line . split ( ) ]
        except :
            if self . permissive :
                self . logger . warn ( "%s: SKIPPING unparsable line %d: %r" , self . real_filename , lineno + 1 , line )
                self . corrupted_lineno . append ( lineno + 1 )
                continue
            self . logger . error ( "%s: Cannot parse line %d: %r" , self . real_filename , lineno + 1 , line )
            raise
        # check for same number of columns as in previous step
        if ncol is not None and len ( row ) != ncol :
            if self . permissive :
                self . logger . warn ( "%s: SKIPPING line %d with wrong number of columns: %r" , self . real_filename , lineno + 1 , line )
                self . corrupted_lineno . append ( lineno + 1 )
                continue
            errmsg = "{0!s}: Wrong number of columns in line {1:d}: {2!r}" . format ( self . real_filename , lineno + 1 , line )
            self . logger . error ( errmsg )
            raise IOError ( errno . ENODATA , errmsg , self . real_filename )
        # finally : a good line
        if irow % stride == 0 :
            ncol = len ( row )
            rows . append ( row )
        irow += 1
try :
    self . __array = numpy . array ( rows ) . transpose ( )
    # cache result
except :
    self . logger . error ( "%s: Failed reading XVG file, possibly data corrupted. " "Check the last line of the file..." , self . real_filename )
    raise
finally :
    del rows


signature:
def plot ( self , ** kwargs ) :
    """Plot xvg file data .
 The first column of the data is always taken as the abscissa
 X . Additional columns are plotted as ordinates Y1 , Y2 , . . .
 In the special case that there is only a single column then this column
 is plotted against the index , i . e . ( N , Y ) .
 : Keywords :
 * columns * : list
 Select the columns of the data to be plotted ; the list
 is used as a numpy . array extended slice . The default is
 to use all columns . Columns are selected * after * a transform .
 * transform * : function
 function ` ` transform ( array ) - > array ` ` which transforms
 the original array ; must return a 2D numpy array of
 shape [ X , Y1 , Y2 , . . . ] where X , Y1 , . . . are column
 vectors . By default the transformation is the
 identity [ ` ` lambda x : x ` ` ] .
 * maxpoints * : int
 limit the total number of data points ; matplotlib has issues processing
 png files with > 100,000 points and pdfs take forever to display . Set to
 ` ` None ` ` if really all data should be displayed . At the moment we simply
 decimate the data at regular intervals . [ 10000]
 * method *
 method to decimate the data to * maxpoints * , see : meth : ` XVG . decimate `
 for details
 * color *
 single color ( used for all plots ) ; sequence of colors
 ( will be repeated as necessary ) ; or a matplotlib
 colormap ( e . g . " jet " , see : mod : ` matplotlib . cm ` ) . The
 default is to use the : attr : ` XVG . default _ color _ cycle ` .
 * ax *
 plot into given axes or create new one if ` ` None ` ` [ ` ` None ` ` ]
 * kwargs *
 All other keyword arguments are passed on to : func : ` matplotlib . pyplot . plot ` .
 : Returns :
 * ax *
 axes instance"""

implementation:
columns = kwargs . pop ( 'columns' , Ellipsis )
# slice for everything
maxpoints = kwargs . pop ( 'maxpoints' , self . maxpoints_default )
transform = kwargs . pop ( 'transform' , lambda x : x )
# default is identity transformation
method = kwargs . pop ( 'method' , "mean" )
ax = kwargs . pop ( 'ax' , None )
if columns is Ellipsis or columns is None :
    columns = numpy . arange ( self . array . shape [ 0 ] )
if len ( columns ) == 0 :
    raise MissingDataError ( "plot() needs at least one column of data" )
if len ( self . array . shape ) == 1 or self . array . shape [ 0 ] == 1 : # special case : plot against index ; plot would do this automatically but
# we ' ll just produce our own xdata and pretend that this was X all along
    a = numpy . ravel ( self . array )
    X = numpy . arange ( len ( a ) )
    a = numpy . vstack ( ( X , a ) )
    columns = [ 0 ] + [ c + 1 for c in columns ]
else :
    a = self . array
color = kwargs . pop ( 'color' , self . default_color_cycle )
try :
    cmap = matplotlib . cm . get_cmap ( color )
    colors = cmap ( matplotlib . colors . Normalize ( ) ( numpy . arange ( len ( columns [ 1 : ] ) , dtype = float ) ) )
except TypeError :
    colors = cycle ( utilities . asiterable ( color ) )
if ax is None :
    ax = plt . gca ( )
# ( decimate / smooth o slice o transform ) ( array )
a = self . decimate ( method , numpy . asarray ( transform ( a ) ) [ columns ] , maxpoints = maxpoints )
# now deal with infs , nans etc AFTER all transformations ( needed for plotting across inf / nan )
ma = numpy . ma . MaskedArray ( a , mask = numpy . logical_not ( numpy . isfinite ( a ) ) )
# finally plot ( each column separately to catch empty sets )
for column , color in zip ( range ( 1 , len ( columns ) ) , colors ) :
    if len ( ma [ column ] ) == 0 :
        warnings . warn ( "No data to plot for column {column:d}" . format ( ** vars ( ) ) , category = MissingDataWarning )
    kwargs [ 'color' ] = color
    ax . plot ( ma [ 0 ] , ma [ column ] , ** kwargs )
    # plot all other columns in parallel
return ax


signature:
def plot_coarsened ( self , ** kwargs ) :
    """Plot data like : meth : ` XVG . plot ` with the range of * * all * * data shown .
 Data are reduced to * maxpoints * ( good results are obtained
 with low values such as 100 ) and the actual range of observed
 data is plotted as a translucent error band around the mean .
 Each column in * columns * ( except the abscissa , i . e . the first
 column ) is decimated ( with : meth : ` XVG . decimate ` ) and the range
 of data is plotted alongside the mean using
 : meth : ` XVG . errorbar ` ( see for arguments ) . Additional
 arguments :
 : Kewords :
 * maxpoints *
 number of points ( bins ) to coarsen over
 * color *
 single color ( used for all plots ) ; sequence of colors
 ( will be repeated as necessary ) ; or a matplotlib
 colormap ( e . g . " jet " , see : mod : ` matplotlib . cm ` ) . The
 default is to use the : attr : ` XVG . default _ color _ cycle ` .
 * method *
 Method to coarsen the data . See : meth : ` XVG . decimate `
 The * demean * keyword has no effect as it is required to be ` ` True ` ` .
 . . SeeAlso : : : meth : ` XVG . plot ` , : meth : ` XVG . errorbar ` and : meth : ` XVG . decimate `"""

implementation:
ax = kwargs . pop ( 'ax' , None )
columns = kwargs . pop ( 'columns' , Ellipsis )
# slice for everything
if columns is Ellipsis or columns is None :
    columns = numpy . arange ( self . array . shape [ 0 ] )
if len ( columns ) < 2 :
    raise MissingDataError ( "plot_coarsened() assumes that there is at least one column " "of data for the abscissa and one or more for the ordinate." )
color = kwargs . pop ( 'color' , self . default_color_cycle )
try :
    cmap = matplotlib . cm . get_cmap ( color )
    colors = cmap ( matplotlib . colors . Normalize ( ) ( numpy . arange ( len ( columns [ 1 : ] ) , dtype = float ) ) )
except TypeError :
    colors = cycle ( utilities . asiterable ( color ) )
if ax is None :
    ax = plt . gca ( )
t = columns [ 0 ]
kwargs [ 'demean' ] = True
kwargs [ 'ax' ] = ax
for column , color in zip ( columns [ 1 : ] , colors ) :
    kwargs [ 'color' ] = color
    self . errorbar ( columns = [ t , column , column ] , ** kwargs )
return ax


signature:
def errorbar ( self , ** kwargs ) :
    """errorbar plot for a single time series with errors .
 Set * columns * keyword to select [ x , y , dy ] or [ x , y , dx , dy ] ,
 e . g . ` ` columns = [ 0,1,2 ] ` ` . See : meth : ` XVG . plot ` for
 details . Only a single timeseries can be plotted and the user
 needs to select the appropriate columns with the * columns *
 keyword .
 By default , the data are decimated ( see : meth : ` XVG . plot ` ) for
 the default of * maxpoints * = 10000 by averaging data in
 * maxpoints * bins .
 x , y , dx , dy data can plotted with error bars in the x - and
 y - dimension ( use * filled * = ` ` False ` ` ) .
 For x , y , dy use * filled * = ` ` True ` ` to fill the region between
 y ± dy . * fill _ alpha * determines the transparency of the fill
 color . * filled * = ` ` False ` ` will draw lines for the error
 bars . Additional keywords are passed to
 : func : ` pylab . errorbar ` .
 By default , the errors are decimated by plotting the 5 % and
 95 % percentile of the data in each bin . The percentile can be
 changed with the * percentile * keyword ; e . g . * percentile * = 1
 will plot the 1 % and 99 % perentile ( as will * percentile * =
 99 ) .
 The * error _ method * keyword can be used to compute errors as
 the root mean square sum ( * error _ method * = " rms " ) across each
 bin instead of percentiles ( " percentile " ) . The value of the
 keyword * demean * is applied to the decimation of error data
 alone .
 . . SeeAlso : :
 : meth : ` XVG . plot ` lists keywords common to both methods ."""

implementation:
ax = kwargs . pop ( 'ax' , None )
color = kwargs . pop ( 'color' , 'black' )
filled = kwargs . pop ( 'filled' , True )
fill_alpha = kwargs . pop ( 'fill_alpha' , 0.2 )
kwargs . setdefault ( 'capsize' , 0 )
kwargs . setdefault ( 'elinewidth' , 1 )
kwargs . setdefault ( 'ecolor' , color )
kwargs . setdefault ( 'alpha' , 0.3 )
kwargs . setdefault ( 'fmt' , None )
columns = kwargs . pop ( 'columns' , Ellipsis )
# slice for everything
maxpoints = kwargs . pop ( 'maxpoints' , self . maxpoints_default )
transform = kwargs . pop ( 'transform' , lambda x : x )
# default is identity transformation
method = kwargs . pop ( 'method' , "mean" )
if method != "mean" :
    raise NotImplementedError ( "For errors only method == 'mean' is supported." )
error_method = kwargs . pop ( 'error_method' , "percentile" )
# can also use ' rms ' and ' error '
percentile = numpy . abs ( kwargs . pop ( 'percentile' , 95. ) )
demean = kwargs . pop ( 'demean' , False )
# order : ( decimate / smooth o slice o transform ) ( array )
try :
    data = numpy . asarray ( transform ( self . array ) ) [ columns ]
except IndexError :
    raise MissingDataError ( "columns {0!r} are not suitable to index the transformed array, possibly not eneough data" . format ( columns ) )
if data . shape [ - 1 ] == 0 :
    raise MissingDataError ( "There is no data to be plotted." )
a = numpy . zeros ( ( data . shape [ 0 ] , maxpoints ) , dtype = numpy . float64 )
a [ 0 : 2 ] = self . decimate ( "mean" , data [ 0 : 2 ] , maxpoints = maxpoints )
error_data = numpy . vstack ( ( data [ 0 ] , data [ 2 : ] ) )
if error_method == "percentile" :
    if percentile > 50 :
        upper_per = percentile
        lower_per = 100 - percentile
    else :
        upper_per = 100 - percentile
        lower_per = percentile
    # demean generally does not make sense with the percentiles ( but for analysing
    # the regularised data itself we use this as a flag - - - see below ! )
    upper = a [ 2 : ] = self . decimate ( "percentile" , error_data , maxpoints = maxpoints , per = upper_per , demean = False ) [ 1 : ]
    lower = self . decimate ( "percentile" , error_data , maxpoints = maxpoints , per = lower_per , demean = False ) [ 1 : ]
else :
    a [ 2 : ] = self . decimate ( error_method , error_data , maxpoints = maxpoints , demean = demean ) [ 1 : ]
    lower = None
# now deal with infs , nans etc AFTER all transformations ( needed for plotting across inf / nan )
ma = numpy . ma . MaskedArray ( a , mask = numpy . logical_not ( numpy . isfinite ( a ) ) )
if lower is not None :
    mlower = numpy . ma . MaskedArray ( lower , mask = numpy . logical_not ( numpy . isfinite ( lower ) ) )
# finally plot
X = ma [ 0 ]
# abscissa set separately
Y = ma [ 1 ]
try :
    kwargs [ 'yerr' ] = ma [ 3 ]
    kwargs [ 'xerr' ] = ma [ 2 ]
except IndexError :
    try :
        kwargs [ 'yerr' ] = ma [ 2 ]
    except IndexError :
        raise TypeError ( "Either too few columns selected or data does not have a error column" )
if ax is None :
    ax = plt . gca ( )
if filled : # can only plot dy
    if error_method == "percentile" :
        if demean : # signal that we are looking at percentiles of an observable and not error
            y1 = mlower [ - 1 ]
            y2 = kwargs [ 'yerr' ]
        else : # percentiles of real errors ( > 0)
            y1 = Y - mlower [ - 1 ]
            y2 = Y + kwargs [ 'yerr' ]
    else :
        y1 = Y - kwargs [ 'yerr' ]
        y2 = Y + kwargs [ 'yerr' ]
    ax . fill_between ( X , y1 , y2 , color = color , alpha = fill_alpha )
else :
    if error_method == "percentile" : # errorbars extend to different lengths ;
        if demean :
            kwargs [ 'yerr' ] = numpy . vstack ( ( mlower [ - 1 ] , kwargs [ 'yerr' ] ) )
        else :
            kwargs [ 'yerr' ] = numpy . vstack ( ( Y - mlower [ - 1 ] , Y + kwargs [ 'yerr' ] ) )
        try : # xerr only makes sense when the data is a real
        # error so we don ' t even bother with demean = ?
            kwargs [ 'xerr' ] = numpy . vstack ( ( X - mlower [ 0 ] , X + kwargs [ 'xerr' ] ) )
        except ( KeyError , IndexError ) :
            pass
    ax . errorbar ( X , Y , ** kwargs )
# clean up args for plot
for kw in "yerr" , "xerr" , "capsize" , "ecolor" , "elinewidth" , "fmt" :
    kwargs . pop ( kw , None )
kwargs [ 'alpha' ] = 1.0
ax . plot ( X , Y , color = color , ** kwargs )
return ax


signature:
def decimate ( self , method , a , maxpoints = 10000 , ** kwargs ) :
    """Decimate data * a * to * maxpoints * using * method * .
 If * a * is a 1D array then it is promoted to a ( 2 , N ) array
 where the first column simply contains the index .
 If the array contains fewer than * maxpoints * points or if
 * maxpoints * is ` ` None ` ` then it is returned as it is . The
 default for * maxpoints * is 10000.
 Valid values for the reduction * method * :
 * " mean " , uses : meth : ` XVG . decimate _ mean ` to coarse grain by
 averaging the data in bins along the time axis
 * " circmean " , uses : meth : ` XVG . decimate _ circmean ` to coarse
 grain by calculating the circular mean of the data in bins
 along the time axis . Use additional keywords * low * and
 * high * to set the limits . Assumes that the data are in
 degrees .
 * " min " and " max * select the extremum in each bin
 * " rms " , uses : meth : ` XVG . decimate _ rms ` to coarse grain by
 computing the root mean square sum of the data in bins
 along the time axis ( for averaging standard deviations and
 errors )
 * " percentile " with keyword * per * : : meth : ` XVG . decimate _ percentile `
 reduces data in each bin to the percentile * per *
 * " smooth " , uses : meth : ` XVG . decimate _ smooth ` to subsample
 from a smoothed function ( generated with a running average
 of the coarse graining step size derived from the original
 number of data points and * maxpoints * )
 : Returns : numpy array ` ` ( M ' , N ' ) ` ` from a ` ` ( M ' , N ) ` ` array
 with ` ` M ' = = M ` ` ( except when ` ` M = = 1 ` ` , see above )
 and ` ` N ' < = N ` ` ( ` ` N ' ` ` is * maxpoints * ) ."""

implementation:
methods = { 'mean' : self . decimate_mean , 'min' : self . decimate_min , 'max' : self . decimate_max , 'smooth' : self . decimate_smooth , 'rms' : self . decimate_rms , 'percentile' : self . decimate_percentile , 'error' : self . decimate_error , # undocumented , not working well
'circmean' : self . decimate_circmean , }
if len ( a . shape ) == 1 : # add first column as index
# ( probably should do this in class / init anyway . . . )
    X = numpy . arange ( len ( a ) )
    a = numpy . vstack ( [ X , a ] )
ny = a . shape [ - 1 ]
# assume 1D or 2D array with last dimension varying fastest
if maxpoints is None or ny <= maxpoints :
    return a
return methods [ method ] ( a , maxpoints , ** kwargs )


signature:
def decimate_mean ( self , a , maxpoints , ** kwargs ) :
    """Return data * a * mean - decimated on * maxpoints * .
 Histograms each column into * maxpoints * bins and calculates
 the weighted average in each bin as the decimated data , using
 : func : ` numkit . timeseries . mean _ histogrammed _ function ` . The coarse grained
 time in the first column contains the centers of the histogram
 time .
 If * a * contains < = * maxpoints * then * a * is simply returned ;
 otherwise a new array of the same dimensions but with a
 reduced number of * maxpoints * points is returned .
 . . Note : :
 Assumes that the first column is time ."""

implementation: return self . _decimate ( numkit . timeseries . mean_histogrammed_function , a , maxpoints , ** kwargs )


signature:
def decimate_circmean ( self , a , maxpoints , ** kwargs ) :
    """Return data * a * circmean - decimated on * maxpoints * .
 Histograms each column into * maxpoints * bins and calculates
 the weighted circular mean in each bin as the decimated data ,
 using
 : func : ` numkit . timeseries . circmean _ histogrammed _ function ` . The
 coarse grained time in the first column contains the centers
 of the histogram time .
 If * a * contains < = * maxpoints * then * a * is simply returned ;
 otherwise a new array of the same dimensions but with a
 reduced number of * maxpoints * points is returned .
 Keywords * low * and * high * can be used to set the
 boundaries . By default they are [ - pi , + pi ] .
 This method returns a * * masked * * array where jumps are flagged
 by an insertion of a masked point .
 . . Note : :
 Assumes that the first column is time and that the data are
 in * * degrees * * .
 . . Warning : :
 Breaking of arrays only works properly with a two - column
 array because breaks are only inserted in the x - column
 ( a [ 0 ] ) where y1 = a [ 1 ] has a break ."""

implementation:
a_rad = numpy . vstack ( ( a [ 0 ] , numpy . deg2rad ( a [ 1 : ] ) ) )
b = self . _decimate ( numkit . timeseries . circmean_histogrammed_function , a_rad , maxpoints , ** kwargs )
y_ma , x_ma = break_array ( b [ 1 ] , threshold = numpy . pi , other = b [ 0 ] )
v = [ y_ma ]
for y in b [ 2 : ] :
    v . append ( break_array ( y , threshold = numpy . pi ) [ 0 ] )
    if v [ - 1 ] . shape != v [ 0 ] . shape :
        raise ValueError ( "y dimensions have different breaks: you MUST deal with them separately" )
return numpy . vstack ( ( x_ma , numpy . rad2deg ( v ) ) )


signature:
def decimate_min ( self , a , maxpoints , ** kwargs ) :
    """Return data * a * min - decimated on * maxpoints * .
 Histograms each column into * maxpoints * bins and calculates
 the minimum in each bin as the decimated data , using
 : func : ` numkit . timeseries . min _ histogrammed _ function ` . The coarse grained
 time in the first column contains the centers of the histogram
 time .
 If * a * contains < = * maxpoints * then * a * is simply returned ;
 otherwise a new array of the same dimensions but with a
 reduced number of * maxpoints * points is returned .
 . . Note : :
 Assumes that the first column is time ."""

implementation: return self . _decimate ( numkit . timeseries . min_histogrammed_function , a , maxpoints , ** kwargs )


signature:
def decimate_max ( self , a , maxpoints , ** kwargs ) :
    """Return data * a * max - decimated on * maxpoints * .
 Histograms each column into * maxpoints * bins and calculates
 the maximum in each bin as the decimated data , using
 : func : ` numkit . timeseries . max _ histogrammed _ function ` . The coarse grained
 time in the first column contains the centers of the histogram
 time .
 If * a * contains < = * maxpoints * then * a * is simply returned ;
 otherwise a new array of the same dimensions but with a
 reduced number of * maxpoints * points is returned .
 . . Note : :
 Assumes that the first column is time ."""

implementation: return self . _decimate ( numkit . timeseries . max_histogrammed_function , a , maxpoints , ** kwargs )


signature:
def decimate_rms ( self , a , maxpoints , ** kwargs ) :
    """Return data * a * rms - decimated on * maxpoints * .
 Histograms each column into * maxpoints * bins and calculates
 the root mean square sum in each bin as the decimated data ,
 using : func : ` numkit . timeseries . rms _ histogrammed _ function ` . The coarse
 grained time in the first column contains the centers of the
 histogram time .
 If * a * contains < = * maxpoints * then * a * is simply returned ;
 otherwise a new array of the same dimensions but with a
 reduced number of * maxpoints * points is returned .
 . . Note : :
 Assumes that the first column is time ."""

implementation: return self . _decimate ( numkit . timeseries . rms_histogrammed_function , a , maxpoints , ** kwargs )


signature:
def decimate_percentile ( self , a , maxpoints , ** kwargs ) :
    """Return data * a * percentile - decimated on * maxpoints * .
 Histograms each column into * maxpoints * bins and calculates
 the percentile * per * in each bin as the decimated data , using
 : func : ` numkit . timeseries . percentile _ histogrammed _ function ` . The
 coarse grained time in the first column contains the centers
 of the histogram time .
 If * a * contains < = * maxpoints * then * a * is simply returned ;
 otherwise a new array of the same dimensions but with a
 reduced number of * maxpoints * points is returned .
 . . Note : :
 Assumes that the first column is time .
 : Keywords :
 * per *
 percentile as a percentage , e . g . 75 is the value that splits
 the data into the lower 75 % and upper 25 % ; 50 is the median [ 50.0]
 . . SeeAlso : : : func : ` numkit . timeseries . regularized _ function ` with : func : ` scipy . stats . scoreatpercentile `"""

implementation: return self . _decimate ( numkit . timeseries . percentile_histogrammed_function , a , maxpoints , ** kwargs )


signature:
def decimate_error ( self , a , maxpoints , ** kwargs ) :
    """Return data * a * error - decimated on * maxpoints * .
 Histograms each column into * maxpoints * bins and calculates an
 error estimate in each bin as the decimated data , using
 : func : ` numkit . timeseries . error _ histogrammed _ function ` . The
 coarse grained time in the first column contains the centers
 of the histogram time .
 If * a * contains < = * maxpoints * then * a * is simply returned ;
 otherwise a new array of the same dimensions but with a
 reduced number of * maxpoints * points is returned .
 . . SeeAlso : : : func : ` numkit . timeseries . tcorrel `
 . . Note : :
 Assumes that the first column is time .
 Does not work very well because often there are too few
 datapoints to compute a good autocorrelation function ."""

implementation:
warnings . warn ( "Using undocumented decimate_error() is highly EXPERIMENTAL" , category = gromacs . exceptions . LowAccuracyWarning )
return self . _decimate ( numkit . timeseries . error_histogrammed_function , a , maxpoints , ** kwargs )


signature:
def decimate_smooth ( self , a , maxpoints , window = "flat" ) :
    """Return smoothed data * a * decimated on approximately * maxpoints * points .
 1 . Produces a smoothed graph using the smoothing window * window * ;
 " flat " is a running average .
 2 . select points at a step size approximatelt producing maxpoints
 If * a * contains < = * maxpoints * then * a * is simply returned ;
 otherwise a new array of the same dimensions but with a
 reduced number of points ( close to * maxpoints * ) is returned .
 . . Note : :
 Assumes that the first column is time ( which will * never *
 be smoothed / averaged ) , except when the input array * a * is
 1D and therefore to be assumed to be data at equidistance
 timepoints .
 TODO :
 - Allow treating the 1st column as data"""

implementation:
ny = a . shape [ - 1 ]
# assume 1D or 2D array with last dimension varying fastest
# reduce size by averaging oover stepsize steps and then just
# picking every stepsize data points . ( primitive - - - can
# leave out bits at the end or end up with almost twice of
# maxpoints )
stepsize = int ( ny / maxpoints )
if stepsize % 2 == 0 :
    stepsize += 1
    # must be odd for the running average / smoothing window
out = numpy . empty_like ( a )
# smoothed
out [ 0 , : ] = a [ 0 ]
for i in range ( 1 , a . shape [ 0 ] ) : # process columns because smooth ( ) only handles 1D arrays : - p
    out [ i , : ] = numkit . timeseries . smooth ( a [ i ] , stepsize , window = window )
if maxpoints == self . maxpoints_default : # only warn if user did not set maxpoints
    warnings . warn ( "Plot had %d datapoints > maxpoints = %d; decimated to %d regularly " "spaced points with smoothing (%r) over %d steps." % ( ny , maxpoints , ny / stepsize , window , stepsize ) , category = AutoCorrectionWarning )
return out [ ... , : : stepsize ]


signature:
def assemble_topology ( self ) :
    """Call the various member self . _ make _ * functions to convert the topology object into a string"""

implementation:
self . logger . debug ( "starting to assemble topology..." )
top = ''
self . logger . debug ( "making atom/pair/bond/angle/dihedral/improper types" )
top += self . toptemplate
top = top . replace ( '*DEFAULTS*' , '' . join ( self . _make_defaults ( self . system ) ) )
top = top . replace ( '*ATOMTYPES*' , '' . join ( self . _make_atomtypes ( self . system ) ) )
top = top . replace ( '*NONBOND_PARAM*' , '' . join ( self . _make_nonbond_param ( self . system ) ) )
top = top . replace ( '*PAIRTYPES*' , '' . join ( self . _make_pairtypes ( self . system ) ) )
top = top . replace ( '*BONDTYPES*' , '' . join ( self . _make_bondtypes ( self . system ) ) )
top = top . replace ( '*CONSTRAINTTYPES*' , '' . join ( self . _make_constrainttypes ( self . system ) ) )
top = top . replace ( '*ANGLETYPES*' , '' . join ( self . _make_angletypes ( self . system ) ) )
top = top . replace ( '*DIHEDRALTYPES*' , '' . join ( self . _make_dihedraltypes ( self . system ) ) )
top = top . replace ( '*IMPROPERTYPES*' , '' . join ( self . _make_impropertypes ( self . system ) ) )
top = top . replace ( '*CMAPTYPES*' , '' . join ( self . _make_cmaptypes ( self . system ) ) )
for i , ( molname , m ) in enumerate ( self . system . dict_molname_mol . items ( ) ) :
    itp = self . itptemplate
    itp = itp . replace ( '*MOLECULETYPE*' , '' . join ( self . _make_moleculetype ( m , molname , m . exclusion_numb ) ) )
    itp = itp . replace ( '*ATOMS*' , '' . join ( self . _make_atoms ( m ) ) )
    itp = itp . replace ( '*BONDS*' , '' . join ( self . _make_bonds ( m ) ) )
    itp = itp . replace ( '*PAIRS*' , '' . join ( self . _make_pairs ( m ) ) )
    itp = itp . replace ( '*SETTLES*' , '' . join ( self . _make_settles ( m ) ) )
    itp = itp . replace ( '*VIRTUAL_SITES3*' , '' . join ( self . _make_virtual_sites3 ( m ) ) )
    itp = itp . replace ( '*EXCLUSIONS*' , '' . join ( self . _make_exclusions ( m ) ) )
    itp = itp . replace ( '*ANGLES*' , '' . join ( self . _make_angles ( m ) ) )
    itp = itp . replace ( '*DIHEDRALS*' , '' . join ( self . _make_dihedrals ( m ) ) )
    itp = itp . replace ( '*IMPROPERS*' , '' . join ( self . _make_impropers ( m ) ) )
    itp = itp . replace ( '*CMAPS*' , '' . join ( self . _make_cmaps ( m ) ) )
    if not self . multiple_output :
        top += itp
    else :
        outfile = "mol_{0}.itp" . format ( molname )
        top += '#include "mol_{0}.itp" \n' . format ( molname )
        with open ( outfile , "w" ) as f :
            f . writelines ( [ itp ] )
top += '\n[system]  \nConvertedSystem\n\n'
top += '[molecules] \n'
molecules = [ ( "" , 0 ) ]
for m in self . system . molecules :
    if ( molecules [ - 1 ] [ 0 ] != m . name ) :
        molecules . append ( [ m . name , 0 ] )
    if molecules [ - 1 ] [ 0 ] == m . name :
        molecules [ - 1 ] [ 1 ] += 1
for molname , n in molecules [ 1 : ] :
    top += '{0:s}     {1:d}\n' . format ( molname , n )
top += '\n'
with open ( self . outfile , 'w' ) as f :
    f . writelines ( [ top ] )


signature:
def topology ( struct = None , protein = 'protein' , top = 'system.top' , dirname = 'top' , posres = "posres.itp" , ff = "oplsaa" , water = "tip4p" , ** pdb2gmx_args ) :
    """Build Gromacs topology files from pdb .
 : Keywords :
 * struct *
 input structure ( * * required * * )
 * protein *
 name of the output files
 * top *
 name of the topology file
 * dirname *
 directory in which the new topology will be stored
 * ff *
 force field ( string understood by ` ` pdb2gmx ` ` ) ; default
 " oplsaa "
 * water *
 water model ( string ) , default " tip4p "
 * pdb2gmxargs *
 other arguments for ` ` pdb2gmx ` `
 . . note : :
 At the moment this function simply runs ` ` pdb2gmx ` ` and uses
 the resulting topology file directly . If you want to create
 more complicated topologies and maybe also use additional itp
 files or make a protein itp file then you will have to do this
 manually ."""

implementation:
structure = realpath ( struct )
new_struct = protein + '.pdb'
if posres is None :
    posres = protein + '_posres.itp'
pdb2gmx_args . update ( { 'f' : structure , 'o' : new_struct , 'p' : top , 'i' : posres , 'ff' : ff , 'water' : water } )
with in_dir ( dirname ) :
    logger . info ( "[{dirname!s}] Building topology {top!r} from struct = {struct!r}" . format ( ** vars ( ) ) )
    # perhaps parse output from pdb2gmx 4.5 . x to get the names of the chain itp files ?
    gromacs . pdb2gmx ( ** pdb2gmx_args )
return { 'top' : realpath ( dirname , top ) , 'struct' : realpath ( dirname , new_struct ) , 'posres' : realpath ( dirname , posres ) }


signature:
def make_main_index ( struct , selection = '"Protein"' , ndx = 'main.ndx' , oldndx = None ) :
    """Make index file with the special groups .
 This routine adds the group _ _ main _ _ and the group _ _ environment _ _
 to the end of the index file . _ _ main _ _ contains what the user
 defines as the * central * and * most important * parts of the
 system . _ _ environment _ _ is everything else .
 The template mdp file , for instance , uses these two groups for T - coupling .
 These groups are mainly useful if the default groups " Protein " and " Non - Protein "
 are not appropriate . By using symbolic names such as _ _ main _ _ one
 can keep scripts more general .
 : Returns :
 * groups * is a list of dictionaries that describe the index groups . See
 : func : ` gromacs . cbook . parse _ ndxlist ` for details .
 : Arguments :
 * struct * : filename
 structure ( tpr , pdb , gro )
 * selection * : string
 is a ` ` make _ ndx ` ` command such as ` ` " Protein " ` ` or ` ` r DRG ` ` which
 determines what is considered the main group for centering etc . It is
 passed directly to ` ` make _ ndx ` ` .
 * ndx * : string
 name of the final index file
 * oldndx * : string
 name of index file that should be used as a basis ; if None
 then the ` ` make _ ndx ` ` default groups are used .
 This routine is very dumb at the moment ; maybe some heuristics will be
 added later as could be other symbolic groups such as _ _ membrane _ _ ."""

implementation:
logger . info ( "Building the main index file {ndx!r}..." . format ( ** vars ( ) ) )
# pass 1 : select
# get a list of groups
# need the first " " to get make _ ndx to spit out the group list .
_ , out , _ = gromacs . make_ndx ( f = struct , n = oldndx , o = ndx , stdout = False , input = ( "" , "q" ) )
groups = cbook . parse_ndxlist ( out )
# find the matching groups ,
# there is a nasty bug in GROMACS where make _ ndx may have multiple
# groups , which caused the previous approach to fail big time .
# this is a work around the make _ ndx bug .
# striping the " " allows compatibility with existing make _ ndx selection commands .
selection = selection . strip ( "\"" )
selected_groups = [ g for g in groups if g [ 'name' ] . lower ( ) == selection . lower ( ) ]
if len ( selected_groups ) > 1 :
    logging . warn ( "make_ndx created duplicated groups, performing work around" )
if len ( selected_groups ) <= 0 :
    msg = "no groups found for selection {0}, available groups are {1}" . format ( selection , groups )
    logging . error ( msg )
    raise ValueError ( msg )
# Found at least one matching group , we ' re OK
# index of last group
last = len ( groups ) - 1
assert last == groups [ - 1 ] [ 'nr' ]
group = selected_groups [ 0 ]
# pass 2:
# 1 ) last group is _ _ main _ _
# 2 ) _ _ environment _ _ is everything else ( eg SOL , ions , . . . )
_ , out , _ = gromacs . make_ndx ( f = struct , n = ndx , o = ndx , stdout = False , # make copy selected group , this now has index last + 1
input = ( "{0}" . format ( group [ 'nr' ] ) , # rename this to _ _ main _ _
"name {0} __main__" . format ( last + 1 ) , # make a complement to this group , it get index last + 2
"! \"__main__\"" , # rename this to _ _ environment _ _
"name {0} __environment__" . format ( last + 2 ) , # list the groups
"" , # quit
"q" ) )
return cbook . parse_ndxlist ( out )