def get_video(self, node):
        """
        Create a video object from a video embed
        """
        video = Video()
        video._embed_code = self.get_embed_code(node)
        video._embed_type = self.get_embed_type(node)
        video._width = self.get_width(node)
        video._height = self.get_height(node)
        video._src = self.get_src(node)
        video._provider = self.get_provider(video.src)
        return video

def get_video ( self , node ) : video = Video ( ) video . _embed_code = self . get_embed_code ( node ) video . _embed_type = self . get_embed_type ( node ) video . _width = self . get_width ( node ) video . _height = self . get_height ( node ) video . _src = self . get_src ( node ) video . _provider = self . get_provider ( video . src ) return video


def store_image(cls, http_client, link_hash, src, config):
        """\
        Writes an image src http string to disk as a temporary file
        and returns the LocallyStoredImage object
        that has the info you should need on the image
        """
        # check for a cache hit already on disk
        image = cls.read_localfile(link_hash, src, config)
        if image:
            return image

        # no cache found; do something else

        # parse base64 image
        if src.startswith('data:image'):
            image = cls.write_localfile_base64(link_hash, src, config)
            return image

        # download the image
        data = http_client.fetch(src)
        if data:
            image = cls.write_localfile(data, link_hash, src, config)
            if image:
                return image

        return None

def
store_image
(
cls
,
http_client
,
link_hash
,
src
,
config
)
:
# check for a cache hit already on disk
image
=
cls
.
read_localfile
(
link_hash
,
src
,
config
)
if
image
:
return
image
# no cache found; do something else
# parse base64 image
if
src
.
startswith
(
'data:image'
)
:
image
=
cls
.
write_localfile_base64
(
link_hash
,
src
,
config
)
return
image
# download the image
data
=
http_client
.
fetch
(
src
)
if
data
:
image
=
cls
.
write_localfile
(
data
,
link_hash
,
src
,
config
)
if
image
:
return
image
return


def get_siblings_content(self, current_sibling, baselinescore_siblings_para):
        """
        adds any siblings that may have a decent score to this node
        """
        if current_sibling.tag == 'p' and self.parser.getText(current_sibling):
            tmp = current_sibling
            if tmp.tail:
                tmp = deepcopy(tmp)
                tmp.tail = ''
            return [tmp]
        else:
            potential_paragraphs = self.parser.getElementsByTag(current_sibling, tag='p')
            if potential_paragraphs is None:
                return None

            paragraphs = list()
            for first_paragraph in potential_paragraphs:
                text = self.parser.getText(first_paragraph)
                if text:  # no len(text) > 0
                    word_stats = self.stopwords_class(language=self.get_language()).get_stopword_count(text)
                    paragraph_score = word_stats.get_stopword_count()
                    sibling_baseline_score = float(.30)
                    high_link_density = self.is_highlink_density(first_paragraph)
                    score = float(baselinescore_siblings_para * sibling_baseline_score)
                    if score < paragraph_score and not high_link_density:
                        para = self.parser.createElement(tag='p', text=text, tail=None)
                        paragraphs.append(para)
            return paragraphs

def
get_siblings_content
(
self
,
current_sibling
,
baselinescore_siblings_para
)
:
if
current_sibling
.
tag
==
'p'
and
self
.
parser
.
getText
(
current_sibling
)
:
tmp
=
current_sibling
if
tmp
.
tail
:
tmp
=
deepcopy
(
tmp
)
tmp
.
tail
=
''
return
[
tmp
]
else
:
potential_paragraphs
=
self
.
parser
.
getElementsByTag
(
current_sibling
,
tag
=
'p'
)
if
potential_paragraphs
is
:
return
paragraphs
=
list
(
)
for
first_paragraph
in
potential_paragraphs
:
text
=
self
.
parser
.
getText
(
first_paragraph
)
if
text
:
# no len(text) > 0
word_stats
=
self
.
stopwords_class
(
language
=
self
.
get_language
(
)
)
.
get_stopword_count
(
text
)
paragraph_score
=
word_stats
.
get_stopword_count
(
)
sibling_baseline_score
=
float
(
.30
)
high_link_density
=
self
.
is_highlink_density
(
first_paragraph
)
score
=
float
(
baselinescore_siblings_para
*
sibling_baseline_score
)
if
score
<
paragraph_score
and
not
high_link_density
:
para
=
self
.
parser
.
createElement
(
tag
=
'p'
,
text
=
text
,
tail
=
)
paragraphs
.
append
(
para
)
return
paragraphs


def is_highlink_density(self, element):
        """
        checks the density of links within a node,
        is there not much text and most of it contains linky shit?
        if so it's no good
        """
        links = self.parser.getElementsByTag(element, tag='a')
        if not links:
            return False

        text = self.parser.getText(element)
        words = text.split(' ')
        words_number = float(len(words))
        link_text_parts = []
        for link in links:
            link_text_parts.append(self.parser.getText(link))

        link_text = ''.join(link_text_parts)
        link_words = link_text.split(' ')
        number_of_link_words = float(len(link_words))
        number_of_links = float(len(links))
        link_divisor = float(number_of_link_words / words_number)
        score = float(link_divisor * number_of_links)
        if score >= 1.0:
            return True
        return False

def
is_highlink_density
(
self
,
element
)
:
links
=
self
.
parser
.
getElementsByTag
(
element
,
tag
=
'a'
)
if
not
links
:
return
False
text
=
self
.
parser
.
getText
(
element
)
words
=
text
.
split
(
' '
)
words_number
=
float
(
len
(
words
)
)
link_text_parts
=
[
]
for
link
in
links
:
link_text_parts
.
append
(
self
.
parser
.
getText
(
link
)
)
link_text
=
''
.
join
(
link_text_parts
)
link_words
=
link_text
.
split
(
' '
)
number_of_link_words
=
float
(
len
(
link_words
)
)
number_of_links
=
float
(
len
(
links
)
)
link_divisor
=
float
(
number_of_link_words
/
words_number
)
score
=
float
(
link_divisor
*
number_of_links
)
if
score
>=
1.0
:
return
True
return
False

checks the density of links within a node is there not much text and most of it contains linky shit? if so it s no good


def nodes_to_check(self, docs):
        """\
        returns a list of nodes we want to search
        on like paragraphs and tables
        """
        nodes_to_check = []

        for doc in docs:
            for tag in ['p', 'pre', 'td']:
                items = self.parser.getElementsByTag(doc, tag=tag)
                nodes_to_check += items
        return nodes_to_check

def nodes_to_check ( self , docs ) : nodes_to_check = [ ] for doc in docs : for tag in [ 'p' , 'pre' , 'td' ] : items = self . parser . getElementsByTag ( doc , tag = tag ) nodes_to_check += items return nodes_to_check


def post_cleanup(self):
        """\
        remove any divs that looks like non-content,
        clusters of links, or paras with no gusto
        """
        parse_tags = ['p']
        if self.config.parse_lists:
            parse_tags.extend(['ul', 'ol'])
        if self.config.parse_headers:
            parse_tags.extend(['h1', 'h2', 'h3', 'h4', 'h5', 'h6'])

        target_node = self.article.top_node
        node = self.add_siblings(target_node)
        for elm in self.parser.getChildren(node):
            e_tag = self.parser.getTag(elm)
            if e_tag not in parse_tags:
                if (self.is_highlink_density(elm) or self.is_table_and_no_para_exist(elm) or
                        not self.is_nodescore_threshold_met(node, elm)):
                    self.parser.remove(elm)
        return node

def post_cleanup ( self ) : parse_tags = [ 'p' ] if self . config . parse_lists : parse_tags . extend ( [ 'ul' , 'ol' ] ) if self . config . parse_headers : parse_tags . extend ( [ 'h1' , 'h2' , 'h3' , 'h4' , 'h5' , 'h6' ] ) target_node = self . article . top_node node = self . add_siblings ( target_node ) for elm in self . parser . getChildren ( node ) : e_tag = self . parser . getTag ( elm ) if e_tag not in parse_tags : if ( self . is_highlink_density ( elm ) or self . is_table_and_no_para_exist ( elm ) or not self . is_nodescore_threshold_met ( node , elm ) ) : self . parser . remove ( elm ) return node

\ remove any divs that looks like non - content clusters of links or paras with no gusto


def get_title(self):
        """\
        Fetch the article title and analyze it
        """
        title = ''

        # rely on opengraph in case we have the data
        if "title" in list(self.article.opengraph.keys()):
            return self.clean_title(self.article.opengraph['title'])
        elif self.article.schema and "headline" in self.article.schema:
            return self.clean_title(self.article.schema['headline'])

        # try to fetch the meta headline
        meta_headline = self.parser.getElementsByTag(self.article.doc,
                                                     tag="meta",
                                                     attr="name",
                                                     value="headline")
        if meta_headline is not None and len(meta_headline) > 0:
            title = self.parser.getAttribute(meta_headline[0], 'content')
            return self.clean_title(title)

        # otherwise use the title meta
        title_element = self.parser.getElementsByTag(self.article.doc, tag='title')
        if title_element is not None and len(title_element) > 0:
            title = self.parser.getText(title_element[0])
            return self.clean_title(title)

        return title


def get_canonical_link(self):
        """
        if the article has meta canonical link set in the url
        """
        if self.article.final_url:
            kwargs = {'tag': 'link', 'attr': 'rel', 'value': 'canonical'}
            meta = self.parser.getElementsByTag(self.article.doc, **kwargs)
            if meta is not None and len(meta) > 0:
                href = self.parser.getAttribute(meta[0], 'href')
                if href:
                    href = href.strip()
                    o = urlparse(href)
                    if not o.hostname:
                        tmp = urlparse(self.article.final_url)
                        domain = '%s://%s' % (tmp.scheme, tmp.hostname)
                        href = urljoin(domain, href)
                    return href
        return self.article.final_url

def get_canonical_link ( self ) : if self . article . final_url : kwargs = { 'tag' : 'link' , 'attr' : 'rel' , 'value' : 'canonical' } meta = self . parser . getElementsByTag ( self . article . doc , * * kwargs ) if meta is not None and len ( meta ) > 0 : href = self . parser . getAttribute ( meta [ 0 ] , 'href' ) if href : href = href . strip ( ) o = urlparse ( href ) if not o . hostname : tmp = urlparse ( self . article . final_url ) domain = '%s://%s' % ( tmp . scheme , tmp . hostname ) href = urljoin ( domain , href ) return href return self . article . final_url


def close(self):
        ''' Close the network connection and perform any other required cleanup

            Note:
                Auto closed when using goose as a context manager or when garbage collected '''
        if self.fetcher is not None:
            self.shutdown_network()
        self.finalizer.atexit = False

def close ( self ) : if self . fetcher is not None : self . shutdown_network ( ) self . finalizer . atexit = False


def extract(self, url=None, raw_html=None):
        ''' Extract the most likely article content from the html page

            Args:
                url (str): URL to pull and parse
                raw_html (str): String representation of the HTML page
            Returns:
                Article: Representation of the article contents \
                including other parsed and extracted metadata '''
        crawl_candidate = CrawlCandidate(self.config, url, raw_html)
        return self.__crawl(crawl_candidate)

def extract ( self , url = None , raw_html = None ) : crawl_candidate = CrawlCandidate ( self . config , url , raw_html ) return self . __crawl ( crawl_candidate )


def __crawl(self, crawl_candidate):
        ''' wrap the crawling functionality '''
        def crawler_wrapper(parser, parsers_lst, crawl_candidate):
            try:
                crawler = Crawler(self.config, self.fetcher)
                article = crawler.crawl(crawl_candidate)
            except (UnicodeDecodeError, ValueError) as ex:
                if parsers_lst:
                    parser = parsers_lst.pop(0)  # remove it also!
                    return crawler_wrapper(parser, parsers_lst, crawl_candidate)
                else:
                    raise ex
            return article

        # use the wrapper
        parsers = list(self.config.available_parsers)
        parsers.remove(self.config.parser_class)
        return crawler_wrapper(self.config.parser_class, parsers, crawl_candidate)

def
__crawl
(
self
,
crawl_candidate
)
:
def
crawler_wrapper
(
parser
,
parsers_lst
,
crawl_candidate
)
:
try
:
crawler
=
Crawler
(
self
.
config
,
self
.
fetcher
)
article
=
crawler
.
crawl
(
crawl_candidate
)
except
(
UnicodeDecodeError
,
ValueError
)
as
ex
:
if
parsers_lst
:
parser
=
parsers_lst
.
pop
(
0
)
# remove it also!
return
crawler_wrapper
(
parser
,
parsers_lst
,
crawl_candidate
)
else
:
raise
ex
return
article
# use the wrapper
parsers
=
list
(
self
.
config
.
available_parsers
)
parsers
.
remove
(
self
.
config
.
parser_class
)
return
crawler_wrapper
(
self
.
config
.
parser_class
,
parsers
,
crawl_candidate
)


def smart_unicode(string, encoding='utf-8', strings_only=False, errors='strict'):
    """
    Returns a unicode object representing 's'. Treats bytestrings using the
    'encoding' codec.

    If strings_only is True, don't convert (some) non-string-like objects.
    """
    # if isinstance(s, Promise):
    #     # The input is the result of a gettext_lazy() call.
    #     return s
    return force_unicode(string, encoding, strings_only, errors)

Returns a unicode object representing s . Treats bytestrings using the encoding codec .


def force_unicode(string, encoding='utf-8', strings_only=False, errors='strict'):
    """
    Similar to smart_unicode, except that lazy instances are resolved to
    strings, rather than kept as lazy objects.

    If strings_only is True, don't convert (some) non-string-like objects.
    """
    # Handle the common case first, saves 30-40% in performance when s
    # is an instance of unicode. This function gets called often in that
    # setting.
    if isinstance(string, str):
        return string
    if strings_only and is_protected_type(string):
        return string
    try:
        if not isinstance(string, str):
            if hasattr(string, '__unicode__'):
                string = string.__unicode__()
            else:
                try:
                    string = str(string, encoding, errors)
                except UnicodeEncodeError:
                    if not isinstance(string, Exception):
                        raise
                    # If we get to here, the caller has passed in an Exception
                    # subclass populated with non-ASCII data without special
                    # handling to display as a string. We need to handle this
                    # without raising a further exception. We do an
                    # approximation to what the Exception's standard str()
                    # output should be.
                    string = ' '.join([force_unicode(arg, encoding,
                                                     strings_only,
                                                     errors) for arg in string])
        elif not isinstance(string, str):
            # Note: We use .decode() here, instead of unicode(s, encoding,
            # errors), so that if s is a SafeString, it ends up being a
            # SafeUnicode at the end.
            string = string.decode(encoding, errors)
    except UnicodeDecodeError as ex:
        if not isinstance(string, Exception):
            raise DjangoUnicodeDecodeError(string, *ex.args)
        else:
            # If we get to here, the caller has passed in an Exception
            # subclass populated with non-ASCII bytestring data without a
            # working unicode method. Try to handle this without raising a
            # further exception by individually forcing the exception args
            # to unicode.
            string = ' '.join([force_unicode(arg, encoding, strings_only,
                                             errors) for arg in string])
    return string

Similar to smart_unicode except that lazy instances are resolved to strings rather than kept as lazy objects .


def smart_str(string, encoding='utf-8', strings_only=False, errors='strict'):
    """
    Returns a bytestring version of 's', encoded as specified in 'encoding'.

    If strings_only is True, don't convert (some) non-string-like objects.
    """
    if strings_only and isinstance(string, (type(None), int)):
        return string
    # if isinstance(s, Promise):
    #     return unicode(s).encode(encoding, errors)
    if isinstance(string, str):
        try:
            return string.encode(encoding, errors)
        except UnicodeEncodeError:
            return string.encode('utf-8', errors)
    elif not isinstance(string, bytes):
        try:
            return str(string).encode(encoding, errors)
        except UnicodeEncodeError:
            if isinstance(string, Exception):
                # An Exception subclass containing non-ASCII data that doesn't
                # know how to print itself properly. We shouldn't raise a
                # further exception.
                return ' '.join([smart_str(arg, encoding, strings_only,
                                           errors) for arg in string])
            return str(string).encode(encoding, errors)
    else:
        return string

Returns a bytestring version of s encoded as specified in encoding .


def get_urls(self):
        """Add URLs needed to handle image uploads."""
        urls = patterns(
            '',
            url(r'^upload/$', self.admin_site.admin_view(self.handle_upload), name='quill-file-upload'),
        )
        return urls + super(QuillAdmin, self).get_urls()

def get_urls ( self ) : urls = patterns ( '' , url ( r'^upload/$' , self . admin_site . admin_view ( self . handle_upload ) , name = 'quill-file-upload' ) , ) return urls + super ( QuillAdmin , self ) . get_urls ( )

Add URLs needed to handle image uploads .


def handle_upload(self, request):
        """Handle file uploads from WYSIWYG."""
        if request.method != 'POST':
            raise Http404

        if request.is_ajax():
            try:
                filename = request.GET['quillUploadFile']
                data = request
                is_raw = True
            except KeyError:
                return HttpResponseBadRequest("Invalid file upload.")
        else:
            if len(request.FILES) != 1:
                return HttpResponseBadRequest("Can only upload 1 file at a time.")
            try:
                data = request.FILES['quillUploadFile']
                filename = data.name
                is_raw = False
            except KeyError:
                return HttpResponseBadRequest('Missing image `quillUploadFile`.')

        url = save_file(data, filename, is_raw, default_storage)
        response_data = {}
        response_data['url'] = url

        # Response content type needs to be text/html here or else
        # IE will try to download the file.
        return HttpResponse(json.dumps(response_data), content_type="text/html; charset=utf-8")


def render(self, name, value, attrs={}):
        """Render the Quill WYSIWYG."""
        if value is None:
            value = ''
        final_attrs = self.build_attrs(attrs, name=name)
        quill_app = apps.get_app_config('quill')
        quill_config = getattr(quill_app, self.config)

        return mark_safe(render_to_string(quill_config['template'], {
            'final_attrs': flatatt(final_attrs),
            'value': value,
            'id': final_attrs['id'],
            'config': self.config,
        }))

def render ( self , name , value , attrs = { } ) : if value is None : value = '' final_attrs = self . build_attrs ( attrs , name = name ) quill_app = apps . get_app_config ( 'quill' ) quill_config = getattr ( quill_app , self . config ) return mark_safe ( render_to_string ( quill_config [ 'template' ] , { 'final_attrs' : flatatt ( final_attrs ) , 'value' : value , 'id' : final_attrs [ 'id' ] , 'config' : self . config , } ) )


def formfield(self, **kwargs):
        """Get the form for field."""
        defaults = {
            'form_class': RichTextFormField,
            'config': self.config,
        }
        defaults.update(kwargs)
        return super(RichTextField, self).formfield(**defaults)

def formfield ( self , * * kwargs ) : defaults = { 'form_class' : RichTextFormField , 'config' : self . config , } defaults . update ( kwargs ) return super ( RichTextField , self ) . formfield ( * * defaults )


def render_toolbar(context, config):
    """Render the toolbar for the given config."""
    quill_config = getattr(quill_app, config)
    t = template.loader.get_template(quill_config['toolbar_template'])
    return t.render(context)

def render_toolbar ( context , config ) : quill_config = getattr ( quill_app , config ) t = template . loader . get_template ( quill_config [ 'toolbar_template' ] ) return t . render ( context )

Render the toolbar for the given config .


def get_meta_image_url(request, image):
    """
    Resize an image for metadata tags, and return an absolute URL to it.
    """
    rendition = image.get_rendition(filter='original')
    return request.build_absolute_uri(rendition.url)

def get_meta_image_url ( request , image ) : rendition = image . get_rendition ( filter = 'original' ) return request . build_absolute_uri ( rendition . url )

Resize an image for metadata tags and return an absolute URL to it .


def check_mdrun_success(logfile):
    """Check if ``mdrun`` finished successfully.

    Analyses the output from ``mdrun`` in *logfile*. Right now we are
    simply looking for the line "Finished mdrun on node" in the last 1kb of
    the file. (The file must be seeakable.)

    :Arguments:
      *logfile* : filename
         Logfile produced by ``mdrun``.

    :Returns: ``True`` if all ok, ``False`` if not finished, and
              ``None`` if the *logfile* cannot be opened
    """
    if not os.path.exists(logfile):
        return None
    with open(logfile, 'rb') as log:
        log.seek(-1024, 2)
        for line in log:
            line = line.decode('ASCII')
            if line.startswith("Finished mdrun on"):
                return True
    return False

def
check_mdrun_success
(
logfile
)
:
if
not
os
.
path
.
exists
(
logfile
)
:
return
with
open
(
logfile
,
'rb'
)
as
log
:
log
.
seek
(
1024
,
2
)
for
line
in
log
:
line
=
line
.
decode
(
'ASCII'
)
if
line
.
startswith
(
"Finished mdrun on"
)
:
return
True
return
False


def get_double_or_single_prec_mdrun():
    """Return double precision ``mdrun`` or fall back to single precision.

    This convenience function tries :func:`gromacs.mdrun_d` first and
    if it cannot run it, falls back to :func:`gromacs.mdrun` (without
    further checking).

    .. versionadded:: 0.5.1
    """
    try:
        gromacs.mdrun_d(h=True, stdout=False, stderr=False)
        logger.debug("using double precision gromacs.mdrun_d")
        return gromacs.mdrun_d
    except (AttributeError, GromacsError, OSError):
        # fall back to mdrun if no double precision binary
        wmsg = "No 'mdrun_d' binary found so trying 'mdrun' instead.\n"\
            "(Note that energy minimization runs better with mdrun_d.)"
        logger.warn(wmsg)
        warnings.warn(wmsg, category=AutoCorrectionWarning)
        return gromacs.mdrun

Return double precision mdrun or fall back to single precision .


def commandline(self, **mpiargs):
        """Returns simple command line to invoke mdrun.

        If :attr:`mpiexec` is set then :meth:`mpicommand` provides the mpi
        launcher command that prefixes the actual ``mdrun`` invocation:

           :attr:`mpiexec` [*mpiargs*]  :attr:`mdrun` [*mdrun-args*]

        The *mdrun-args* are set on initializing the class. Override
        :meth:`mpicommand` to fit your system if the simple default
        OpenMP launcher is not appropriate.
        """
        cmd = self.MDRUN.commandline()
        if self.mpiexec:
            cmd = self.mpicommand(**mpiargs) + cmd
        return cmd

def commandline ( self , * * mpiargs ) : cmd = self . MDRUN . commandline ( ) if self . mpiexec : cmd = self . mpicommand ( * * mpiargs ) + cmd return cmd

Returns simple command line to invoke mdrun .


def mpicommand(self, *args, **kwargs):
        """Return a list of the mpi command portion of the commandline.

        Only allows primitive mpi at the moment:
           *mpiexec* -n *ncores* *mdrun* *mdrun-args*

        (This is a primitive example for OpenMP. Override it for more
        complicated cases.)
        """
        if self.mpiexec is None:
            raise NotImplementedError("Override mpiexec to enable the simple OpenMP launcher")
        # example implementation
        ncores = kwargs.pop('ncores', 8)
        return [self.mpiexec, '-n', str(ncores)]

Return a list of the mpi command portion of the commandline .


def prehook(self, **kwargs):
        """Launch local smpd."""
        cmd = ['smpd', '-s']
        logger.info("Starting smpd: "+" ".join(cmd))
        rc = subprocess.call(cmd)
        return rc

def
prehook
(
self
,
*
*
kwargs
)
:
cmd
=
[
'smpd'
,
'-s'
]
logger
.
info
(
"Starting smpd: "
+
" "
.
join
(
cmd
)
)
rc
=
subprocess
.
call
(
cmd
)
return
rc


def glob_parts(prefix, ext):
    """Find files from a continuation run"""
    if ext.startswith('.'):
        ext = ext[1:]
    files = glob.glob(prefix+'.'+ext) + glob.glob(prefix+'.part[0-9][0-9][0-9][0-9].'+ext)
    files.sort()   # at least some rough sorting...
    return files

def
glob_parts
(
prefix
,
ext
)
:
if
ext
.
startswith
(
'.'
)
:
ext
=
ext
[
1
:
]
files
=
glob
.
glob
(
prefix
+
'.'
+
ext
)
+
glob
.
glob
(
prefix
+
'.part[0-9][0-9][0-9][0-9].'
+
ext
)
files
.
sort
(
)
# at least some rough sorting...
return
files


def grompp_qtot(*args, **kwargs):
    """Run ``gromacs.grompp`` and return the total charge of the  system.

    :Arguments:
       The arguments are the ones one would pass to :func:`gromacs.grompp`.
    :Returns:
       The total charge as reported

    Some things to keep in mind:

    * The stdout output of grompp is only shown when an error occurs. For
      debugging, look at the log file or screen output and try running the
      normal :func:`gromacs.grompp` command and analyze the output if the
      debugging messages are not sufficient.

    * Check that ``qtot`` is correct. Because the function is based on pattern
      matching of the informative output of :program:`grompp` it can break when
      the output format changes. This version recognizes lines like ::

            '  System has non-zero total charge: -4.000001e+00'

      using the regular expression
      :regexp:`System has non-zero total charge: *(?P<qtot>[-+]?\d*\.\d+([eE][-+]\d+)?)`.

    """
    qtot_pattern = re.compile('System has non-zero total charge: *(?P<qtot>[-+]?\d*\.\d+([eE][-+]\d+)?)')
    # make sure to capture ALL output
    kwargs['stdout'] = False
    kwargs['stderr'] = False
    rc, output, error = grompp_warnonly(*args, **kwargs)
    gmxoutput = "\n".join([x for x in [output, error] if x is not None])
    if rc != 0:
        # error occured and we want to see the whole output for debugging
        msg = "grompp_qtot() failed. See warning and screen output for clues."
        logger.error(msg)
        import sys
        sys.stderr.write("=========== grompp (stdout/stderr) ============\n")
        sys.stderr.write(gmxoutput)
        sys.stderr.write("===============================================\n")
        sys.stderr.flush()
        raise GromacsError(rc, msg)
    qtot = 0
    for line in gmxoutput.split('\n'):
        m = qtot_pattern.search(line)
        if m:
            qtot = float(m.group('qtot'))
            break
    logger.info("system total charge qtot = {qtot!r}".format(**vars()))
    return qtot

Run gromacs . grompp and return the total charge of the system .


def _mdp_include_string(dirs):
    """Generate a string that can be added to a mdp 'include = ' line."""
    include_paths = [os.path.expanduser(p) for p in dirs]
    return ' -I'.join([''] + include_paths)

def
_mdp_include_string
(
dirs
)
:
include_paths
=
[
os
.
path
.
expanduser
(
p
)
for
p
in
dirs
]
return
' -I'
.
join
(
[
''
]
+
include_paths
)

Generate a string that can be added to a mdp include = line .


def create_portable_topology(topol, struct, **kwargs):
    """Create a processed topology.

    The processed (or portable) topology file does not contain any
    ``#include`` statements and hence can be easily copied around. It
    also makes it possible to re-grompp without having any special itp
    files available.

    :Arguments:
      *topol*
          topology file
      *struct*
          coordinat (structure) file

    :Keywords:
      *processed*
          name of the new topology file; if not set then it is named like
          *topol* but with ``pp_`` prepended
      *includes*
          path or list of paths of directories in which itp files are
          searched for
      *grompp_kwargs**
          other options for :program:`grompp` such as ``maxwarn=2`` can
          also be supplied

    :Returns: full path to the processed topology
    """
    _topoldir, _topol = os.path.split(topol)
    processed = kwargs.pop('processed', os.path.join(_topoldir, 'pp_'+_topol))
    grompp_kwargs, mdp_kwargs = filter_grompp_options(**kwargs)
    mdp_kwargs = add_mdp_includes(topol, mdp_kwargs)
    with tempfile.NamedTemporaryFile(suffix='.mdp') as mdp:
        mdp.write('; empty mdp file\ninclude = {include!s}\n'.format(**mdp_kwargs))
        mdp.flush()
        grompp_kwargs['p'] = topol
        grompp_kwargs['pp'] = processed
        grompp_kwargs['f'] =  mdp.name
        grompp_kwargs['c'] = struct
        grompp_kwargs['v'] = False
        try:
            gromacs.grompp(**grompp_kwargs)
        finally:
            utilities.unlink_gmx('topol.tpr', 'mdout.mdp')
    return utilities.realpath(processed)


def edit_txt(filename, substitutions, newname=None):
    """Primitive text file stream editor.

    This function can be used to edit free-form text files such as the
    topology file. By default it does an **in-place edit** of
    *filename*. If *newname* is supplied then the edited
    file is written to *newname*.

    :Arguments:
       *filename*
           input text file
       *substitutions*
           substitution commands (see below for format)
       *newname*
           output filename; if ``None`` then *filename* is changed in
           place [``None``]

    *substitutions* is a list of triplets; the first two elements are regular
    expression strings, the last is the substitution value. It mimics
    ``sed`` search and replace. The rules for *substitutions*:

    .. productionlist::
       substitutions: "[" search_replace_tuple, ... "]"
       search_replace_tuple: "(" line_match_RE "," search_RE "," replacement ")"
       line_match_RE: regular expression that selects the line (uses match)
       search_RE: regular expression that is searched in the line
       replacement: replacement string for search_RE

    Running :func:`edit_txt` does pretty much what a simple ::

         sed /line_match_RE/s/search_RE/replacement/

    with repeated substitution commands does.

    Special replacement values:
    - ``None``: the rule is ignored
    - ``False``: the line is deleted (even if other rules match)

    .. note::

       * No sanity checks are performed and the substitutions must be supplied
         exactly as shown.
       * All substitutions are applied to a line; thus the order of the substitution
         commands may matter when one substitution generates a match for a subsequent rule.
       * If replacement is set to ``None`` then the whole expression is ignored and
         whatever is in the template is used. To unset values you must provided an
         empty string or similar.
       * Delete a matching line if replacement=``False``.
    """
    if newname is None:
        newname = filename

    # No sanity checks (figure out later how to give decent diagnostics).
    # Filter out any rules that have None in replacement.
    _substitutions = [{'lRE': re.compile(str(lRE)),
                       'sRE': re.compile(str(sRE)),
                       'repl': repl}
                      for lRE,sRE,repl in substitutions if repl is not None]

    with tempfile.TemporaryFile() as target:
        with open(filename, 'rb') as src:
            logger.info("editing txt = {0!r} ({1:d} substitutions)".format(filename, len(substitutions)))
            for line in src:
                line = line.decode("utf-8")
                keep_line = True
                for subst in _substitutions:
                    m = subst['lRE'].match(line)
                    if m:              # apply substition to this line?
                        logger.debug('match:    '+line.rstrip())
                        if subst['repl'] is False:   # special rule: delete line
                            keep_line = False
                        else:                        # standard replacement
                            line = subst['sRE'].sub(str(subst['repl']), line)
                            logger.debug('replaced: '+line.rstrip())
                if keep_line:
                    target.write(line.encode('utf-8'))
                else:
                    logger.debug("Deleting line %r", line)

        target.seek(0)
        with open(newname, 'wb') as final:
            shutil.copyfileobj(target, final)
    logger.info("edited txt = {newname!r}".format(**vars()))


def make_ndx_captured(**kwargs):
    """make_ndx that captures all output

    Standard :func:`~gromacs.make_ndx` command with the input and
    output pre-set in such a way that it can be conveniently used for
    :func:`parse_ndxlist`.

    Example::
      ndx_groups = parse_ndxlist(make_ndx_captured(n=ndx)[0])

    Note that the convenient :func:`get_ndx_groups` function does exactly
    that and can probably used in most cases.

    :Arguments:
        keywords are passed on to :func:`~gromacs.make_ndx`
    :Returns:
        (*returncode*, *output*, ``None``)
    """
    kwargs['stdout']=False   # required for proper output as described in doc
    user_input = kwargs.pop('input',[])
    user_input = [cmd for cmd in user_input if cmd != 'q']  # filter any quit
    kwargs['input'] = user_input + ['', 'q']                # necessary commands
    return gromacs.make_ndx(**kwargs)


def parse_groups(output):
    """Parse ``make_ndx`` output and return groups as a list of dicts."""
    groups = []
    for line in output.split('\n'):
        m = NDXGROUP.match(line)
        if m:
            d = m.groupdict()
            groups.append({'name': d['GROUPNAME'],
                           'nr': int(d['GROUPNUMBER']),
                           'natoms': int(d['NATOMS'])})
    return groups

def parse_groups ( output ) : groups = [ ] for line in output . split ( '\n' ) : m = NDXGROUP . match ( line ) if m : d = m . groupdict ( ) groups . append ( { 'name' : d [ 'GROUPNAME' ] , 'nr' : int ( d [ 'GROUPNUMBER' ] ) , 'natoms' : int ( d [ 'NATOMS' ] ) } ) return groups

Parse make_ndx output and return groups as a list of dicts .


def delete_frames(self):
        """Delete all frames."""
        for frame in glob.glob(self.frameglob):
            os.unlink(frame)

def delete_frames ( self ) : for frame in glob . glob ( self . frameglob ) : os . unlink ( frame )


def gmx_resid(self, resid):
        """Returns resid in the Gromacs index by transforming with offset."""
        try:
            gmx_resid = int(self.offset[resid])
        except (TypeError, IndexError):
            gmx_resid = resid + self.offset
        except KeyError:
            raise KeyError("offset must be a dict that contains the gmx resid for {0:d}".format(resid))
        return gmx_resid

Returns resid in the Gromacs index by transforming with offset .


def combine(self, name_all=None, out_ndx=None, operation='|', defaultgroups=False):
        """Combine individual groups into a single one and write output.

        :Keywords:
           name_all : string
              Name of the combined group, ``None`` generates a name.  [``None``]
           out_ndx : filename
              Name of the output file that will contain the individual groups
              and the combined group. If ``None`` then default from the class
              constructor is used. [``None``]
           operation : character
              Logical operation that is used to generate the combined group from
              the individual groups: "|" (OR) or "&" (AND); if set to ``False``
              then no combined group is created and only the individual groups
              are written. ["|"]
           defaultgroups : bool
              ``True``: append everything to the default groups produced by
              :program:`make_ndx` (or rather, the groups provided in the ndx file on
              initialization --- if this was ``None`` then these are truly default groups);
              ``False``: only use the generated groups

        :Returns:
           ``(combinedgroup_name, output_ndx)``, a tuple showing the
           actual group name and the name of the file; useful when all names are autogenerated.

        .. Warning:: The order of the atom numbers in the combined group is
                     *not* guaranteed to be the same as the selections on input because
                     ``make_ndx`` sorts them ascending. Thus you should be careful when
                     using these index files for calculations of angles and dihedrals.
                     Use :class:`gromacs.formats.NDX` in these cases.

        .. SeeAlso:: :meth:`IndexBuilder.write`.
        """
        if not operation in ('|', '&', False):
            raise ValueError("Illegal operation {0!r}, only '|' (OR) and '&' (AND) or False allowed.".format(
                             operation))
        if name_all is None and operation:
            name_all = self.name_all or operation.join(self.indexfiles)
        if out_ndx is None:
            out_ndx = self.output

        if defaultgroups:
            # make a default file (using the original ndx where provided!!)
            fd, default_ndx = tempfile.mkstemp(suffix='.ndx', prefix='default__')
            try:
                self.make_ndx(o=default_ndx, input=['q'])
            except:
                utilities.unlink_gmx(default_ndx)
                raise
            ndxfiles = [default_ndx]
        else:
            ndxfiles = []

        ndxfiles.extend(self.indexfiles.values())

        if operation:
            # combine multiple selections and name them
            try:
                fd, tmp_ndx = tempfile.mkstemp(suffix='.ndx', prefix='combined__')
                # combine all selections by loading ALL temporary index files
                operation = ' '+operation.strip()+' '
                cmd = [operation.join(['"{0!s}"'.format(gname) for gname in self.indexfiles]),
                       '', 'q']
                rc,out,err = self.make_ndx(n=ndxfiles, o=tmp_ndx, input=cmd)
                if self._is_empty_group(out):
                    warnings.warn("No atoms found for {cmd!r}".format(**vars()),
                                  category=BadParameterWarning)

                # second pass for naming, sigh (or: use NDX ?)
                groups = parse_ndxlist(out)
                last = groups[-1]
                # name this group
                name_cmd = ["name {0:d} {1!s}".format(last['nr'], name_all), 'q']
                rc,out,err = self.make_ndx(n=tmp_ndx, o=out_ndx, input=name_cmd)
                # For debugging, look at out and err or set stdout=True, stderr=True
                # TODO: check out if at least 1 atom selected
                ##print "DEBUG: combine()"
                ##print out
            finally:
                utilities.unlink_gmx(tmp_ndx)
                if defaultgroups:
                    utilities.unlink_gmx(default_ndx)
        else:
            # just write individual groups in one file (name_all --> None)
            rc,out,err = self.make_ndx(n=ndxfiles, o=out_ndx, input=['','q'])

        return name_all, out_ndx

Combine individual groups into a single one and write output .


def cat(self, out_ndx=None):
        """Concatenate input index files.

        Generate a new index file that contains the default Gromacs index
        groups (if a structure file was defined) and all index groups from the
        input index files.

        :Arguments:
           out_ndx : filename
              Name of the output index file; if ``None`` then use the default
              provided to the constructore. [``None``].
        """
        if out_ndx is None:
            out_ndx = self.output
        self.make_ndx(o=out_ndx, input=['q'])
        return out_ndx

def cat ( self , out_ndx = None ) : if out_ndx is None : out_ndx = self . output self . make_ndx ( o = out_ndx , input = [ 'q' ] ) return out_ndx


def _process_command(self, command, name=None):
        """Process ``make_ndx`` command and  return name and temp index file."""

        self._command_counter += 1
        if name is None:
            name = "CMD{0:03d}".format(self._command_counter)

        # Need to build it with two make_ndx calls because I cannot reliably
        # name the new group without knowing its number.
        try:
            fd, tmp_ndx = tempfile.mkstemp(suffix='.ndx', prefix='tmp_'+name+'__')
            cmd = [command, '', 'q']   # empty command '' necessary to get list
            # This sometimes fails with 'OSError: Broken Pipe' --- hard to debug
            rc,out,err = self.make_ndx(o=tmp_ndx, input=cmd)
            self.check_output(out, "No atoms found for selection {command!r}.".format(**vars()), err=err)
            # For debugging, look at out and err or set stdout=True, stderr=True
            # TODO: check '  0 r_300_&_ALA_&_O     :     1 atoms' has at least 1 atom
            ##print "DEBUG: _process_command()"
            ##print out
            groups = parse_ndxlist(out)
            last = groups[-1]
            # reduce and name this group
            fd, ndx = tempfile.mkstemp(suffix='.ndx', prefix=name+'__')
            name_cmd = ["keep {0:d}".format(last['nr']),
                        "name 0 {0!s}".format(name), 'q']
            rc,out,err = self.make_ndx(n=tmp_ndx, o=ndx, input=name_cmd)
        finally:
            utilities.unlink_gmx(tmp_ndx)

        return name, ndx

Process make_ndx command and return name and temp index file .


def _process_range(self, selection, name=None):
        """Process a range selection.

        ("S234", "A300", "CA")   --> selected all CA in this range
        ("S234", "A300")         --> selected all atoms in this range

        .. Note:: Ignores residue type, only cares about the resid (but still required)
        """

        try:
            first, last, gmx_atomname = selection
        except ValueError:
            try:
                first, last = selection
                gmx_atomname = '*'
            except:
                logger.error("%r is not a valid range selection", selection)
                raise
        if name is None:
            name = "{first!s}-{last!s}_{gmx_atomname!s}".format(**vars())

        _first = self._translate_residue(first, default_atomname=gmx_atomname)
        _last = self._translate_residue(last, default_atomname=gmx_atomname)

        _selection = 'r {0:d} - {1:d} & & a {2!s}'.format(_first['resid'], _last['resid'], gmx_atomname)
        cmd = ['keep 0', 'del 0',
               _selection,
               'name 0 {name!s}'.format(**vars()),
               'q']
        fd, ndx = tempfile.mkstemp(suffix='.ndx', prefix=name+'__')
        rc,out,err = self.make_ndx(n=self.ndx, o=ndx, input=cmd)
        self.check_output(out, "No atoms found for "
                          "%(selection)r --> %(_selection)r" % vars())
        # For debugging, look at out and err or set stdout=True, stderr=True
        ##print "DEBUG: _process_residue()"
        ##print out

        return name, ndx


def _translate_residue(self, selection, default_atomname='CA'):
        """Translate selection for a single res to make_ndx syntax."""
        m = self.RESIDUE.match(selection)
        if not m:
            errmsg = "Selection {selection!r} is not valid.".format(**vars())
            logger.error(errmsg)
            raise ValueError(errmsg)

        gmx_resid = self.gmx_resid(int(m.group('resid')))    # magic offset correction
        residue = m.group('aa')
        if len(residue) == 1:
            gmx_resname = utilities.convert_aa_code(residue) # only works for AA
        else:
            gmx_resname = residue                            # use 3-letter for any resname

        gmx_atomname = m.group('atom')
        if gmx_atomname is None:
            gmx_atomname = default_atomname

        return {'resname':gmx_resname, 'resid':gmx_resid, 'atomname':gmx_atomname}

def
_translate_residue
(
self
,
selection
,
default_atomname
=
'CA'
)
:
m
=
self
.
RESIDUE
.
match
(
selection
)
if
not
m
:
errmsg
=
"Selection {selection!r} is not valid."
.
format
(
*
*
vars
(
)
)
logger
.
error
(
errmsg
)
raise
ValueError
(
errmsg
)
gmx_resid
=
self
.
gmx_resid
(
int
(
m
.
group
(
'resid'
)
)
)
# magic offset correction
residue
=
m
.
group
(
'aa'
)
if
len
(
residue
)
==
1
:
gmx_resname
=
utilities
.
convert_aa_code
(
residue
)
# only works for AA
else
:
gmx_resname
=
residue
# use 3-letter for any resname
gmx_atomname
=
m
.
group
(
'atom'
)
if
gmx_atomname
is
:
gmx_atomname
=
default_atomname
return
{
'resname'
:
gmx_resname
,
'resid'
:
gmx_resid
,
'atomname'
:
gmx_atomname
}

Translate selection for a single res to make_ndx syntax .


def check_output(self, make_ndx_output, message=None, err=None):
        """Simple tests to flag problems with a ``make_ndx`` run."""
        if message is None:
            message = ""
        else:
            message = '\n' + message
        def format(output, w=60):
            hrule = "====[ GromacsError (diagnostic output) ]".ljust(w,"=")
            return hrule + '\n' + str(output) + hrule

        rc = True
        if self._is_empty_group(make_ndx_output):
            warnings.warn("Selection produced empty group.{message!s}".format(**vars()), category=GromacsValueWarning)
            rc = False
        if self._has_syntax_error(make_ndx_output):
            rc = False
            out_formatted = format(make_ndx_output)
            raise GromacsError("make_ndx encountered a Syntax Error, "
                               "%(message)s\noutput:\n%(out_formatted)s" % vars())
        if make_ndx_output.strip() == "":
            rc = False
            out_formatted = format(err)
            raise GromacsError("make_ndx produced no output, "
                               "%(message)s\nerror output:\n%(out_formatted)s" % vars())
        return rc

Simple tests to flag problems with a make_ndx run .


def outfile(self, p):
        """Path for an output file.

        If :attr:`outdir` is set then the path is
        ``outdir/basename(p)`` else just ``p``
        """
        if self.outdir is not None:
            return os.path.join(self.outdir, os.path.basename(p))
        else:
            return p

def outfile ( self , p ) : if self . outdir is not None : return os . path . join ( self . outdir , os . path . basename ( p ) ) else : return p


def center_fit(self, **kwargs):
        """Write compact xtc that is fitted to the tpr reference structure.

        See :func:`gromacs.cbook.trj_fitandcenter` for details and
        description of *kwargs* (including *input*, *input1*, *n* and
        *n1* for how to supply custom index groups). The most important ones are listed
        here but in most cases the defaults should work.

        :Keywords:
           *s*
             Input structure (typically the default tpr file but can be set to
             some other file with a different conformation for fitting)
           *n*
             Alternative index file.
           *o*
             Name of the output trajectory.
           *xy* : Boolean
             If ``True`` then only fit in xy-plane (useful for a membrane normal
             to z). The default is ``False``.
           *force*
             - ``True``: overwrite existing trajectories
             - ``False``: throw a IOError exception
             - ``None``: skip existing and log a warning [default]

        :Returns:
              dictionary with keys *tpr*, *xtc*, which are the names of the
              the new files
        """
        kwargs.setdefault('s', self.tpr)
        kwargs.setdefault('n', self.ndx)
        kwargs['f'] = self.xtc
        kwargs.setdefault('o', self.outfile(self.infix_filename(None, self.xtc, '_centfit', 'xtc')))
        force = kwargs.pop('force', self.force)

        logger.info("Centering and fitting trajectory {f!r}...".format(**kwargs))
        with utilities.in_dir(self.dirname):
            if not self.check_file_exists(kwargs['o'], resolve="indicate", force=force):
                trj_fitandcenter(**kwargs)
            logger.info("Centered and fit trajectory: {o!r}.".format(**kwargs))
        return {'tpr': self.rp(kwargs['s']), 'xtc': self.rp(kwargs['o'])}

Write compact xtc that is fitted to the tpr reference structure .


def fit(self, xy=False, **kwargs):
        """Write xtc that is fitted to the tpr reference structure.

        Runs :class:`gromacs.tools.trjconv` with appropriate arguments
        for fitting. The most important *kwargs* are listed
        here but in most cases the defaults should work.

        Note that the default settings do *not* include centering or
        periodic boundary treatment as this often does not work well
        with fitting. It is better to do this as a separate step (see
        :meth:`center_fit` or :func:`gromacs.cbook.trj_fitandcenter`)

        :Keywords:
           *s*
             Input structure (typically the default tpr file but can be set to
             some other file with a different conformation for fitting)
           *n*
             Alternative index file.
           *o*
             Name of the output trajectory. A default name is created.
             If e.g. *dt* = 100  is one of the *kwargs* then the default name includes
             "_dt100ps".
          *xy* : boolean
             If ``True`` then only do a rot+trans fit in the xy plane
             (good for membrane simulations); default is ``False``.
          *force*
            ``True``: overwrite existing trajectories
            ``False``: throw a IOError exception
            ``None``: skip existing and log a warning [default]
          *fitgroup*
            index group to fit on ["backbone"]

            .. Note:: If keyword *input* is supplied then it will override
                      *fitgroup*; *input* = ``[fitgroup, outgroup]``
          *kwargs*
             kwargs are passed to :func:`~gromacs.cbook.trj_xyfitted`

        :Returns:
              dictionary with keys *tpr*, *xtc*, which are the names of the
              the new files
        """
        kwargs.setdefault('s', self.tpr)
        kwargs.setdefault('n', self.ndx)
        kwargs['f'] = self.xtc
        force = kwargs.pop('force', self.force)
        if xy:
            fitmode = 'rotxy+transxy'
            kwargs.pop('fit', None)
            infix_default = '_fitxy'
        else:
            fitmode = kwargs.pop('fit', 'rot+trans')  # user can use 'progressive', too
            infix_default = '_fit'

        dt = kwargs.get('dt')
        if dt:
            infix_default += '_dt{0:d}ps'.format(int(dt))    # dt in ps

        kwargs.setdefault('o', self.outfile(self.infix_filename(None, self.xtc, infix_default, 'xtc')))
        fitgroup = kwargs.pop('fitgroup', 'backbone')
        kwargs.setdefault('input', [fitgroup, "system"])

        if kwargs.get('center', False):
            logger.warn("Transformer.fit(): center=%(center)r used: centering should not be combined with fitting.", kwargs)
            if len(kwargs['inputs']) != 3:
                logger.error("If you insist on centering you must provide three groups in the 'input' kwarg: (center, fit, output)")
                raise ValuError("Insufficient index groups for centering,fitting,output")

        logger.info("Fitting trajectory %r to with xy=%r...", kwargs['f'], xy)
        logger.info("Fitting on index group %(fitgroup)r", vars())
        with utilities.in_dir(self.dirname):
            if self.check_file_exists(kwargs['o'], resolve="indicate", force=force):
                logger.warn("File %r exists; force regenerating it with force=True.", kwargs['o'])
            else:
                gromacs.trjconv(fit=fitmode, **kwargs)
                logger.info("Fitted trajectory (fitmode=%s): %r.", fitmode, kwargs['o'])
        return {'tpr': self.rp(kwargs['s']), 'xtc': self.rp(kwargs['o'])}

Write xtc that is fitted to the tpr reference structure .


def strip_fit(self, **kwargs):
        """Strip water and fit to the remaining system.

        First runs :meth:`strip_water` and then :meth:`fit`; see there
        for arguments.

        - *strip_input* is used for :meth:`strip_water` (but is only useful in
          special cases, e.g. when there is no Protein group defined. Then set
          *strip_input* = ``['Other']``.

        - *input* is passed on to :meth:`fit` and can contain the
          ``[center_group, fit_group, output_group]``

        - *fitgroup* is only passed to :meth:`fit` and just contains
          the group to fit to ("backbone" by default)

          .. warning:: *fitgroup* can only be a Gromacs default group and not
                       a custom group (because the indices change after stripping)

        - By default *fit* = "rot+trans" (and *fit* is passed to :meth:`fit`,
          together with the *xy* = ``False`` keyword)

        .. Note:: The call signature of :meth:`strip_water` is somewhat different from this one.
        """
        kwargs.setdefault('fit', 'rot+trans')
        kw_fit = {}
        for k in ('xy', 'fit', 'fitgroup', 'input'):
            if k in kwargs:
                kw_fit[k] = kwargs.pop(k)

        kwargs['input'] = kwargs.pop('strip_input', ['Protein'])
        kwargs['force'] = kw_fit['force'] = kwargs.pop('force', self.force)

        paths = self.strip_water(**kwargs)    # updates self.nowater
        transformer_nowater = self.nowater[paths['xtc']]  # make sure to get the one we just produced
        return transformer_nowater.fit(**kw_fit)

Strip water and fit to the remaining system .


def create(logger_name, logfile='gromacs.log'):
    """Create a top level logger.

    - The file logger logs everything (including DEBUG).
    - The console logger only logs INFO and above.

    Logging to a file and the console.

    See http://docs.python.org/library/logging.html?#logging-to-multiple-destinations

    The top level logger of the library is named 'gromacs'.  Note that
    we are configuring this logger with console output. If the root
    logger also does this then we will get two output lines to the
    console. We'll live with this because this is a simple
    convenience library...
    """

    logger = logging.getLogger(logger_name)

    logger.setLevel(logging.DEBUG)

    logfile = logging.FileHandler(logfile)
    logfile_formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
    logfile.setFormatter(logfile_formatter)
    logger.addHandler(logfile)

    # define a Handler which writes INFO messages or higher to the sys.stderr
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    # set a format which is simpler for console use
    formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
    console.setFormatter(formatter)

    logger.addHandler(console)

    return logger


def get_configuration(filename=CONFIGNAME):
    """Reads and parses the configuration file.

    Default values are loaded and then replaced with the values from
    ``~/.gromacswrapper.cfg`` if that file exists. The global
    configuration instance :data:`gromacswrapper.config.cfg` is updated
    as are a number of global variables such as :data:`configdir`,
    :data:`qscriptdir`, :data:`templatesdir`, :data:`logfilename`, ...

    Normally, the configuration is only loaded when the :mod:`gromacs`
    package is imported but a re-reading of the configuration can be forced
    anytime by calling :func:`get_configuration`.

    :Returns: a dict with all updated global configuration variables
    """
    global cfg, configuration    # very iffy --- most of the whole config mod should a class

    #: :data:`cfg` is the instance of :class:`GMXConfigParser` that makes all
    #: global configuration data accessible
    cfg = GMXConfigParser(filename=filename)   # update module-level cfg
    globals().update(cfg.configuration)        # update configdir, templatesdir ...
    configuration = cfg.configuration          # update module-level configuration
    return cfg

Reads and parses the configuration file .


def setup(filename=CONFIGNAME):
     """Prepare a default GromacsWrapper global environment.

     1) Create the global config file.
     2) Create the directories in which the user can store template and config files.

     This function can be run repeatedly without harm.
     """
     # setup() must be separate and NOT run automatically when config
     # is loaded so that easy_install installations work
     # (otherwise we get a sandbox violation)
     # populate cfg with defaults (or existing data)
     get_configuration()
     if not os.path.exists(filename):
          with open(filename, 'w') as configfile:
               cfg.write(configfile)  # write the default file so that user can edit
               msg = "NOTE: GromacsWrapper created the configuration file \n\t%r\n" \
                     "      for you. Edit the file to customize the package." % filename
               print(msg)

     # directories
     for d in config_directories:
          utilities.mkdir_p(d)

Prepare a default GromacsWrapper global environment .


def check_setup():
     """Check if templates directories are setup and issue a warning and help.

    Set the environment variable  :envvar:`GROMACSWRAPPER_SUPPRESS_SETUP_CHECK`
    skip the check and make it always return ``True``

    :return ``True`` if directories were found and ``False`` otherwise

     .. versionchanged:: 0.3.1
        Uses :envvar:`GROMACSWRAPPER_SUPPRESS_SETUP_CHECK` to suppress check
        (useful for scripts run on a server)
     """

     if "GROMACSWRAPPER_SUPPRESS_SETUP_CHECK" in os.environ:
         return True

     missing = [d for d in config_directories if not os.path.exists(d)]
     if len(missing) > 0:
         print("NOTE: Some configuration directories are not set up yet: ")
         print("\t{0!s}".format('\n\t'.join(missing)))
         print("NOTE: You can create the configuration file and directories with:")
         print("\t>>> import gromacs")
         print("\t>>> gromacs.config.setup()")
         return False
     return True

Check if templates directories are setup and issue a warning and help .


def get_tool_names():
    """ Get tool names from all configured groups.

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

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

Get tool names from all configured groups .


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 ...
          """
          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

def configuration ( self ) : 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

Dict of variables that we make available as globals in the module .


def getpath(self, section, option):
          """Return option as an expanded path."""
          return os.path.expanduser(os.path.expandvars(self.get(section, option)))

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


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`
          """
          return logging.getLevelName(self.get(section, option).upper())

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

Return the textual representation of logging level option or the number .


def _canonicalize(self, filename):
        """Use .collection as extension unless provided"""
        path, ext = os.path.splitext(filename)
        if not ext:
            ext = ".collection"
        return path + ext

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

Use . collection as extension unless provided


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

        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


def scale_impropers(mol, impropers, scale, banned_lines=None):
        """Scale improper dihedrals"""
        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


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
    """
    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

Convert string x to the most useful type i . e . int float or unicode string .


def to_int64(a):
    """Return view of the recarray with all int32 cast to int64."""
    # 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)

def
to_int64
(
a
)
:
# 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
)

Return view of the recarray with all int32 cast to int64 .


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
    """
    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)

def irecarray_to_py ( a ) : 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 )

Slow conversion of a recarray into a list of records with python types .


def col(self, c):
        """Parse colour specification"""
        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


def transform_args(self, *args, **kwargs):
        """Transform arguments and return them as a list suitable for Popen."""
        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)

Transform arguments and return them as a list suitable for Popen .


def help(self, long=False):
        """Print help; same as using ``?`` in ``ipython``. long=True also gives call signature."""
        print("\ncommand: {0!s}\n\n".format(self.command_name))
        print(self.__doc__)
        if long:
            print("\ncall method: command():\n")
            print(self.__call__.__doc__)

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

Print help ; same as using ? in ipython . long = True also gives call signature .


def _combineargs(self, *args, **kwargs):
        """Add switches as 'options' with value True to the options dict."""
        d = {arg: True for arg in args}   # switches are kwargs with value True
        d.update(kwargs)
        return d

def
_combineargs
(
self
,
*
args
,
*
*
kwargs
)
:
d
=
{
arg
:
True
for
arg
in
args
}
# switches are kwargs with value True
d
.
update
(
kwargs
)
return
d

Add switches as options with value True to the options dict .


def _build_arg_list(self, **kwargs):
        """Build list of arguments from the dict; keys must be valid  gromacs flags."""
        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))

Build list of arguments from the dict ; keys must be valid gromacs flags .


def transform_args(self,*args,**kwargs):
        """Combine arguments and turn them into gromacs tool arguments."""
        newargs = self._combineargs(*args, **kwargs)
        return self._build_arg_list(**newargs)

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

Combine arguments and turn them into gromacs tool arguments .


def _get_gmx_docs(self):
        """Extract standard gromacs doc

        Extract by running the program and chopping the header to keep from
        'DESCRIPTION' onwards.
        """
        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


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.
    """
    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))

Convert input to a numerical type if possible .


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
    """
    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)


def convert_aa_code(x):
    """Converts between 3-letter and 1-letter amino acid codes."""
    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)

Converts between 3 - letter and 1 - letter amino acid codes .


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.
    """
    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)

Context manager to execute a code block in a directory .


def unlink_f(path):
    """Unlink path but do not complain if file does not exist."""
    try:
        os.unlink(path)
    except OSError as err:
        if err.errno != errno.ENOENT:
            raise

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

Unlink path but do not complain if file does not exist .


def remove_legend(ax=None):
    """Remove legend for axes or gca.

    See http://osdir.com/ml/python.matplotlib.general/2005-07/msg00285.html
    """
    from pylab import gca, draw
    if ax is None:
        ax = gca()
    ax.legend_ = None
    draw()

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


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.
        """
        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

Supply a file name for the class object .


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
        """
        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)

If a file exists then continue with the action specified in resolve .


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]
          ============   ==========================
        """
        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

def strftime ( self , fmt = "%d:%H:%M:%S" ) : 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


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*.
    """
    from . import log
    log.create("gromacs", logfile=logfile)
    logging.getLogger("gromacs").info("GromacsWrapper %s STARTED logging to %r",
                                      __version__, logfile)

Start logging of messages to file and console .


def stop_logging():
    """Stop logging to logfile and console."""
    from . import log
    logger = logging.getLogger("gromacs")
    logger.info("GromacsWrapper %s STOPPED logging", get_version())
    log.clear_handlers(logger)

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


def tool_factory(clsname, name, driver, base=GromacsCommand):
    """ Factory for GromacsCommand derived types. """
    clsdict = {
        'command_name': name,
        'driver': driver,
        '__doc__': property(base._get_gmx_docs)
    }
    return type(clsname, (base,), clsdict)

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

Factory for GromacsCommand derived types .


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
    """
    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

def find_executables ( path ) : 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


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
    """
    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

def
load_v4_tools
(
)
:
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
,
)
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

Load Gromacs 4 . x tools automatically using some heuristic .


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
    """
    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

def
merge_ndx
(
*
args
)
:
ndxs
=
[
]
struct
=
for
fname
in
args
:
if
fname
.
endswith
(
'.ndx'
)
:
ndxs
.
append
(
fname
)
else
:
if
struct
is
not
:
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

Takes one or more index files and optionally one structure file and returns a path for a new merged index file .


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
    *a*.

    Returns (*a_masked*, *other_masked*) (where *other_masked* can be
    ``None``)
    """
    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

Create a array which masks jumps > = threshold .


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`.
        """
        a = self.array
        return numpy.ma.MaskedArray(a, mask=numpy.logical_not(numpy.isfinite(a)))

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


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`
        """
        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

def _tcorrel ( self , nstep = 100 , * * kwargs ) : 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


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.
        """
        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

Set and change the parameters for calculations with correlation functions .