コード例 #1
0
 def fetch_args(self, database_name, *, format_name=None):
     try:
         db_formats = self._fetchers[database_name]
     except KeyError:
         raise NoOpenerError("No such database '%s'" % database_name)
     from chimerax.core.commands import commas
     if format_name:
         try:
             provider_info = db_formats[format_name]
         except KeyError:
             # for backwards compatibility, try the nicknames of the format
             try:
                 df = self.session.data_formats[format_name]
             except KeyError:
                 nicks = []
             else:
                 nicks = df.nicknames + df.name
             for nick in nicks:
                 try:
                     provider_info = db_formats[nick]
                     format_name = nick
                 except KeyError:
                     continue
                 break
             else:
                 raise NoOpenerError(
                     "Format '%s' not supported for database '%s'."
                     "  Supported formats are: %s" %
                     (format_name, database_name,
                      commas([dbf for dbf in db_formats])))
     else:
         for format_name, provider_info in db_formats.items():
             if provider_info.is_default:
                 break
         else:
             raise NoOpenerError(
                 "No default format for database '%s'."
                 "  Possible formats are: %s" %
                 (database_name, commas([dbf for dbf in db_formats])))
     try:
         args = self.open_args(self.session.data_formats[format_name])
     except NoOpenerError:
         # fetch-only type (e.g. cellPACK)
         args = {}
     args.update(
         provider_info.bundle_info.run_provider(self.session, database_name,
                                                self).fetch_args)
     return args
コード例 #2
0
def _fetch_info(mgr, database_name, default_format_name):
    db_info = mgr.database_info(database_name)
    from chimerax.core.commands import commas
    if default_format_name:
        try:
            provider_info = db_info[default_format_name]
        except KeyError:
            raise UserError("Format '%s' not available for database '%s'.  Available"
                " formats are: %s" % (default_format_name, database_name,
                commas(db_info.keys())))
    else:
        for default_format_name, provider_info in db_info.items():
            if provider_info.is_default:
                break
        else:
            raise UserError("No default format for database '%s'.  Possible formats are:"
                " %s" % (database_name, commas(db_info.keys())))
    return (provider_info.bundle_info.run_provider(mgr.session, database_name, mgr),
        default_format_name)
コード例 #3
0
def cmd_save_formats(session):
    '''Report file formats and suffixes that the save command knows about.'''
    from chimerax.core.commands import commas
    all_formats = session.save_command.save_data_formats
    by_category = {}
    for fmt in all_formats:
        by_category.setdefault(fmt.category.title(), []).append(fmt)
    titles = list(by_category.keys())
    titles.sort()
    lines = []
    for title in titles:
        formats = by_category[title]
        if session.ui.is_gui:
            lines.extend([
                '<table border=1 cellspacing=0 cellpadding=2>',
                '<tr><th colspan="3">%s' % title,
                '<tr><th>File format<th>Short name(s)<th>Suffixes'
            ])
        else:
            session.logger.info(title)
            session.logger.info('File format, Short name(s), Suffixes:')
        formats.sort(key = lambda f: f.name.lower())
        for f in formats:
            if session.ui.is_gui:
                from html import escape
                if f.reference_url:
                    descrip = '<a href="%s">%s</a>' % (f.reference_url, escape(f.synopsis))
                else:
                    descrip = escape(f.synopsis)
                lines.append('<tr><td>%s<td>%s<td>%s' % (descrip,
                    escape(commas(f.nicknames)), escape(', '.join(f.suffixes))))
            else:
                session.logger.info('    %s: %s: %s' % (f.synopsis,
                    commas(f.nicknames), ', '.join(f.suffixes)))
        if session.ui.is_gui:
            lines.append('</table>')
            lines.append('<p></p>')
    if session.ui.is_gui:
        msg = '\n'.join(lines)
        session.logger.info(msg, is_html=True)
コード例 #4
0
def _list_colors(session, colors_dict, kind, url=None):
    from chimerax.core.commands import commas, plural_form
    import html
    logger = session.logger
    if not colors_dict:
        logger.info("No %s colors." % kind)
        return
    is_html = session.ui.is_gui
    colors = []
    for name, c in colors_dict.items():
        if is_html:
            colors.append(html.escape(name) + html_color_swatch(c))
        else:
            colors.append(name)
    noun = plural_form(colors, 'color')
    if url is None or not is_html:
        label = "%d %s %s: " % (len(colors), kind, noun)
    else:
        label = "%d <a href=\"%s\">%s %s</a>: " % (len(colors), url, kind, noun)
    logger.info(label + commas(colors, 'and') + '.', is_html=is_html)
コード例 #5
0
ファイル: palette.py プロジェクト: Yongcheng123/ChimeraX
def _list(session, colormaps, kind, url=None):
    from chimerax.core.commands import plural_form, commas
    import html
    logger = session.logger
    if not colormaps:
        logger.info("No %s palettes." % kind)
        return
    is_html = session.ui.is_gui
    palettes = []
    for name, cm in colormaps.items():
        if cm.name is not None:
            name = cm.name
        if is_html:
            palettes.append(html.escape(name))
        else:
            palettes.append(name)
    noun = plural_form(palettes, "palette")
    if url is None or not is_html:
        label = "%d %s %s: " % (len(palettes), kind, noun)
    else:
        label = "%d <a href=\"%s\">%s %s</a>: " % (len(palettes), url, kind, noun)
    logger.info(label + commas(palettes, "and") + '.', is_html=is_html)
コード例 #6
0
def fetch_info(mgr, file_arg, format_name, database_name):
    if not database_name and exists_locally(file_arg, format_name):
        return None
    if ':' in file_arg:
        db_name, ident = file_arg.split(':', maxsplit=1)
        if len(db_name) < 2:
            return None
    elif database_name:
        db_name = database_name
        ident = file_arg
    elif likely_pdb_id(file_arg, format_name):
        db_name = "pdb"
        ident = file_arg
    else:
        return None
    from .manager import NoOpenerError
    try:
        db_formats = list(mgr.database_info(db_name).keys())
    except NoOpenerError as e:
        raise LimitationError(str(e))
    if format_name and format_name not in db_formats:
        # for backwards compatibiity, accept formal format name or nicknames
        try:
            df = mgr.session.data_formats[format_name]
        except KeyError:
            nicks = []
        else:
            nicks = df.nicknames + [df.name]
        for nick in nicks:
            if nick in db_formats:
                format_name = nick
                break
        else:
            from chimerax.core.commands import commas
            raise UserError("Format '%s' not supported for database '%s'.  Supported"
                " formats are: %s" % (format_name, db_name,
                commas([dbf for dbf in db_formats])))
    return (ident, db_name, format_name)
コード例 #7
0
ファイル: __init__.py プロジェクト: Yongcheng123/ChimeraX
def _uninstall_bundle(toolshed,
                      bundle,
                      logger,
                      *,
                      session=None,
                      force_remove=False):
    """Supported API. Uninstall bundle by removing the corresponding Python distribution.

    Parameters
    ----------
    bundle : string or :py:class:`BundleInfo` instance or sequence of them
        If string, path to wheel installer.
        If instance, should be from the available bundle list.
    logger : :py:class:`~chimerax.core.logger.Logger` instance
        Logging object where warning and error messages are sent.

    Raises
    ------
    ToolshedInstalledError
        Raised if the bundle is not installed.

    Notes
    -----
    A :py:const:`TOOLSHED_BUNDLE_UNINSTALLED` trigger is fired after package removal.
    """
    import re
    _debug("uninstall_bundle", bundle)
    if isinstance(bundle, (str, BundleInfo)):
        bundles = [bundle]
    else:
        bundles = bundle
    uninstall_now = []
    uninstall_later = []
    for bundle in bundles:
        if isinstance(bundle, str):
            bundle = toolshed.find_bundle(bundle, logger, installed=True)
        if bundle is None or not bundle.installed:
            raise ToolshedInstalledError("bundle %r not installed" %
                                         bundle.name)
        if _can_uninstall(bundle):
            uninstall_now.append(bundle)
        else:
            uninstall_later.append(bundle)
    if not force_remove:
        all_bundles = set()
        all_bundles.update(uninstall_now)
        all_bundles.update(uninstall_later)
        for bi in all_bundles:
            needed_by = bi.dependents(logger)
            needed_by -= all_bundles
            if needed_by:
                from chimerax.core.commands import commas, plural_form
                other = plural_form(needed_by, "another", "other")
                bundles = plural_form(needed_by, "bundles")
                logger.error(
                    "Unable to uninstall %s because it is needed by %s %s: %s"
                    % (bi.name, other, bundles,
                       commas((bi.name for bi in needed_by), 'and')))
                return
    if uninstall_now:
        for bundle in uninstall_now:
            bundle.deregister(logger)
            bundle.unload(logger)
        results = _pip_uninstall(uninstall_now, logger)
        uninstalled = re.findall(r"^\s*Successfully uninstalled.*$", results,
                                 re.M)
        if uninstalled:
            logger.info('\n'.join(uninstalled))
        toolshed.reload(logger, rebuild_cache=True, report=True)
        toolshed.triggers.activate_trigger(TOOLSHED_BUNDLE_UNINSTALLED, bundle)
    if uninstall_later:
        for bundle in uninstall_later:
            bundle.deregister(logger)
            bundle.unload(logger)
        message = "ChimeraX must be restarted to finish uninstalling."
        _add_restart_action("uninstall", uninstall_later, [], logger, message,
                            session)
コード例 #8
0
ファイル: toolshed.py プロジェクト: Yongcheng123/ChimeraX
def _display_bundles(bi_list, toolshed, logger, use_html=False, full=True):
    def bundle_key(bi):
        return bi.name

    info = ""
    if use_html:
        from html import escape
        info = """
<style>
table.bundle {
    border-collapse: collapse;
    border-spacing: 2px;
}
th.bundle {
    font-style: italic;
    text-align: left;
}
</style>
        """
        info += "<ul>\n"
        for bi in sorted(bi_list, key=bundle_key):
            name = bi.name
            if full:
                info += "<p>\n"
            info += "<li>\n"
            if full:
                info += "<dt>\n"
            info += "<b>%s</b> (%s): <i>%s</i>\n" % (
                toolshed.bundle_link(name), bi.version, escape(bi.synopsis))
            if full:
                info += "<dd>\n"
                info += "%s: %s<p>" % (plural_form(
                    bi.categories, "Category"), commas(bi.categories, 'and'))
                info += _reSt_to_html(bi.description)
                if bi.tools or bi.commands or bi.formats:
                    info += "<table class='bundle' border='1'>\n"
                if bi.tools:
                    info += "<tr><th class='bundle' colspan='3'>%s:</th></tr>\n" % plural_form(
                        bi.tools, "Tool")
                for t in bi.tools:
                    info += "<tr><td><b>%s</b></td> <td colspan='2'><i>%s</i></td></tr>\n" % (
                        t.name, escape(t.synopsis))
                if bi.commands:
                    info += "<tr><th class='bundle' colspan='3'>%s:</th></tr>\n" % plural_form(
                        bi.commands, "Command")
                for c in bi.commands:
                    info += "<tr><td><b>%s</b></td> <td colspan='2'><i>%s</i></td></tr>\n" % (
                        c.name, escape(c.synopsis))
                if bi.selectors:
                    info += "<tr><th class='bundle' colspan='3'>%s:</th></tr>\n" % plural_form(
                        bi.selectors, "Selector")
                for s in bi.selectors:
                    info += "<tr><td><b>%s</b></td> <td colspan='2'><i>%s</i></td></tr>\n" % (
                        s.name, escape(s.synopsis))
                if bi.formats:
                    info += "<tr><th class='bundle' colspan='3'>%s:</th></tr>\n" % plural_form(
                        bi.formats, "Format")
                for f in bi.formats:
                    can_open = ' open' if f.has_open else ''
                    can_save = ' save' if f.has_save else ''
                    info += "<tr><td><b>%s</b></td> <td><i>%s</i></td><td>%s%s</td></tr>\n" % (
                        f.name, f.category, can_open, can_save)
                if bi.tools or bi.commands or bi.formats:
                    info += "</table>\n"
                info += "</dl>\n"
            info += "</li>\n"
        info += "</ul>\n"
    else:
        for bi in sorted(bi_list, key=bundle_key):
            name = bi.name
            if name.startswith('ChimeraX-'):
                name = name[len('ChimeraX-'):]
            info += "%s (%s) [%s]: %s\n" % (name, bi.version, ', '.join(
                bi.categories), bi.synopsis)
            if full:
                if bi.tools:
                    info += "  %s:\n" % plural_form(bi.tools, "Tool")
                for t in bi.tools:
                    info += "    %s: %s\n" % (t.name, t.synopsis)
                if bi.commands:
                    info += "  %s:\n" % plural_form(bi.commands, "Command")
                for c in bi.commands:
                    info += "    %s: %s\n" % (c.name, c.synopsis)
                if bi.selectors:
                    info += "  %s:\n" % plural_form(bi.selectors, "Selector")
                for s in bi.selectors:
                    info += "    %s: %s\n" % (s.name, s.synopsis)
                if bi.formats:
                    info += "  %s:\n" % plural_form(bi.formats, "Format")
                for f in bi.formats:
                    can_open = ' open' if f.has_open else ''
                    can_save = ' save' if f.has_save else ''
                    info += "    %s [%s]%s%s\n" % (f.name, f.category,
                                                   can_open, can_save)
    logger.info(info, is_html=use_html)
コード例 #9
0
ファイル: transparency.py プロジェクト: Yongcheng123/ChimeraX
def transparency(session, objects, percent, what=None, target=None):
    """Set transparency of atoms, ribbons, surfaces, ....

    Parameters
    ----------
    objects : Objects or None
      Which objects to set transparency.
    percent : float
      Percent transparent from 0 completely opaque, to 100 completely transparent.
    target : string
      Characters indicating what to make transparent:
      a = atoms, b = bonds, p = pseudobonds, c = cartoon, r = cartoon, s = surfaces, A = all
    """
    if objects is None:
        from chimerax.core.objects import all_objects
        objects = all_objects(session)

    from .color import get_targets
    target, _ = get_targets(target, what, 's')

    alpha = int(2.56 * (100 - percent))
    alpha = min(255, max(0, alpha))    # 0-255 range

    what = []

    if 'a' in target or 's' in target:
        atoms = objects.atoms

    if 'a' in target:
        # atoms
        c = atoms.colors
        c[:, 3] = alpha
        atoms.colors = c
        what.append('%d atoms' % len(atoms))

    if 'b' in target:
        # bonds
        bonds = objects.bonds
        if bonds:
            c = bonds.colors
            c[:, 3] = alpha
            bonds.colors = c
            what.append('%d bonds' % len(bonds))

    if 'p' in target:
        # pseudobonds
        bonds = objects.pseudobonds
        if bonds:
            c = bonds.colors
            c[:, 3] = alpha
            bonds.colors = c
            what.append('%d pseudobonds' % len(bonds))

    if 's' in target:
        surfs = _set_surface_transparency(atoms, objects.models, session, alpha)
        what.append('%d surfaces' % len(surfs))

    if 'c' in target or 'r' in target:
        residues = objects.residues
        c = residues.ribbon_colors
        c[:, 3] = alpha
        residues.ribbon_colors = c
        what.append('%d residues' % len(residues))

    if not what:
        what.append('nothing')

    from chimerax.core.commands import commas
    session.logger.status('Set transparency of %s' % commas(what, 'and'))
コード例 #10
0
ファイル: defattr.py プロジェクト: Yongcheng123/ChimeraX
def defattr(session, file_name, *, log=False, restriction=None):
    """define attributes on objects

    Parameters
    ----------
    file_name : string
      Input file in 'defattr' format
    log : bool
      Whether to log assignment info
    restriction : Structures Collection or None
      If not None, structures to restrict the assignments to
      (in addition to any restrictions in the defattr file)
    """

    if restriction is None:
        from chimerax.atomic import all_structures
        restriction = all_structures(session)

    control_defaults = {
        'match mode': "any",
        'recipient': "atoms",
        'none handling': "None"
    }
    from chimerax.atomic import Atom, Bond, Pseudobond, Residue, Chain, Structure
    recipient_info = {
        "atoms": (Atom, lambda objs: objs.atoms),
        "bonds": (Bond, lambda objs: objs.bonds),
        "pseudobonds": (Pseudobond, lambda objs: objs.pseudobonds),
        "residues": (Residue, lambda objs: objs.residues),
        "chains": (Chain, lambda objs: objs.chains),
        # since we always restrict to structures, can just use Objects.models()
        "molecules": (Structure, lambda objs: objs.models),
        "structures": (Structure, lambda objs: objs.models),
    }
    legal_control_values = {
        'match mode': set(["any", "non-zero", "1-to-1"]),
        'recipient': set(recipient_info.keys()),
        'none handling': set(["None", "string", "delete"])
    }
    all_info = []

    def append_all_info(attr_info,
                        data_info,
                        line_num,
                        *,
                        ai=all_info,
                        fn=file_name):
        if 'attribute' not in attr_info:
            raise SyntaxError(
                "No attribute name defined for data lines %d and earlier in %s"
                % (line_num, fn))
        if not data_info:
            raise SyntaxError("No data lines for attribute '%s' in %s" %
                              (attr_info['attribute'], fn))
        ai.append((attr_info, data_info))

    from chimerax.core.commands import AtomSpecArg, AttrNameArg, AnnotationError, NoneArg, ColorArg, commas
    from chimerax.core.commands import IntArg, FloatArg
    from chimerax.io import open_input
    with open_input(file_name, encoding="utf-8") as f:
        data = []
        attrs = {}
        for lnum, raw_line in enumerate(f):
            # spaces in values could be significant, so instead of stripping just drop the '\n'
            # (which all line endings are translated to if newline=None [default] for open())
            line = raw_line[:-1]
            if not line.strip() or line[0] == '#':
                continue

            if line[0] == '\t':
                # data line
                datum = line[1:].split('\t')
                if len(datum) != 2:
                    raise SyntaxError(
                        "Data line %d in %s not of the form: <tab> atomspec <tab> value"
                        % (lnum + 1, file_name))
                data.append((lnum + 1, *datum))
                continue
            # control line
            try:
                name, value = line.split(": ")
            except ValueError:
                raise SyntaxError(
                    "Line %d in %s is either not of the form 'name: value'"
                    " or is missing initial tab" % (lnum + 1, file_name))
            name = name.strip().lower()
            value = value.strip()
            if name in attrs:
                # presumably another set of control/data lines starting
                append_all_info(attrs, data, lnum + 1)
                attrs = {}
                data = []
            if name == 'attribute':
                try:
                    final_value, *args = AttrNameArg.parse(value, session)
                except AnnotationError as e:
                    raise SyntaxError(
                        "Bad attribute name ('%s') given on line %d of %s: %s"
                        % (value, lnum + 1, file_name, str(e)))
            elif name not in legal_control_values:
                raise SyntaxError(
                    "Unrecognized control type ('%s') given on line %d of %s" %
                    (name, lnum + 1, file_name))
            elif value not in legal_control_values[name]:
                raise SyntaxError(
                    "Illegal control value ('%s') for %s given on line %d of %s; legal"
                    " values are: %s" % (value, name, lnum + 1, file_name,
                                         commas(legal_control_values[name])))
            else:
                final_value = value
            attrs[name] = final_value
        append_all_info(attrs, data, lnum + 1)

    for attr_info, data_info in all_info:
        attr_name = attr_info['attribute']
        color_attr = attr_name.lower().endswith(
            'color') or attr_name.lower().endswith('colour')

        match_mode = attr_info.get('match mode',
                                   control_defaults['match mode'])

        none_handling = attr_info.get('none handling',
                                      control_defaults['none handling'])
        none_okay = none_handling != 'string'
        none_seen = False
        eval_vals = ["true", "false"]
        if none_okay:
            eval_vals.append("none")

        recipient = attr_info.get('recipient', control_defaults['recipient'])
        recip_class, instance_fetch = recipient_info[recipient]
        seen_types = set()
        try:
            pre_existing_attr = getattr(recip_class, attr_name)
        except AttributeError:
            pass
        else:
            if callable(pre_existing_attr):
                raise ValueError(
                    "%s is a method of the %s class and cannot be redefined" %
                    (attr_name, recip_class.__name__))
            if attr_name[0].isupper():
                raise ValueError(
                    "%s is a constant in the %s class and cannot be redefined"
                    % (attr_name, recip_class.__name__))

        for line_num, spec, value_string in data_info:
            try:
                atom_spec, *args = AtomSpecArg.parse(spec, session)
            except AnnotationError as e:
                raise SyntaxError("Bad atom specifier (%s) on line %d of %s" %
                                  (spec, line_num, file_name))

            try:
                objects = atom_spec.evaluate(session, models=restriction)
            except Exception as e:
                raise SyntaxError(
                    "Error evaluating atom specifier (%s) on line %d of %s: %s"
                    % (spec, line_num, file_name, str(e)))

            matches = instance_fetch(objects)

            if not matches and match_mode != "any":
                raise SyntaxError(
                    "Selector (%s) on line %d of %s matched nothing" %
                    (spec, line_num, file_name))
            if len(matches) > 1 and match_mode == "1-to-1":
                raise SyntaxError(
                    "Selector (%s) on line %d of %s matched multiple %s" %
                    (spec, line_num, file_name, recipient))

            if log:
                session.logger.info(
                    "Selector %s matched %s" %
                    (spec, commas([str(x)
                                   for x in matches], conjunction="and")))

            if not value_string:
                raise SyntaxError("No data value on line %d of %s" %
                                  (line_num, file_name))

            # Can't just use normal argument parsers willy nilly since strings are allowed to have
            # leading/trailing whitespace, don't want to accept shorten ed forms of booleans, etc.
            if color_attr:
                try:
                    value, text, rest = ColorArg.parse(value_string, session)
                    if rest:
                        raise AnnotationError("trailing text")
                    seen_types.add("color")
                    value = value.uint8x4()
                except AnnotationError:
                    if none_okay:
                        try:
                            value, text, rest = NoneArg.parse(
                                value_string, session)
                            if rest:
                                raise AnnotationError("trailing text")
                            seen_types.add(None)
                        except AnnotationError:
                            raise SyntaxError(
                                "Value (%s) on line %d of %s is not recognizable as either a"
                                " color value or None" %
                                (value_string, line_num, file_name))
                    else:
                        raise SyntaxError(
                            "Value (%s) on line %d of %s is not recognizable as a color value"
                            % (value_string, line_num, file_name))
            else:
                if value_string.strip() != value_string:
                    value = value_string
                    seen_types.add(str)
                elif value_string.startswith('"') and value_string.endswith(
                        '"'):
                    value = value_string[1:-1]
                    seen_types.add(str)
                elif value_string.lower() in eval_vals:
                    value = eval(value_string.capitalize())
                    if value is None:
                        seen_types.add(None)
                    else:
                        seen_types.add(bool)
                else:
                    try:
                        value, text, rest = IntArg.parse(value_string, session)
                        if rest:
                            raise AnnotationError("trailing text")
                        seen_types.add(int)
                    except AnnotationError:
                        try:
                            value, text, rest = FloatArg.parse(
                                value_string, session)
                            if rest:
                                raise AnnotationError("trailing text")
                            seen_types.add(float)
                        except AnnotationError:
                            value = value_string
                            seen_types.add(str)

            for match in matches:
                if value is not None or none_handling == "None":
                    setattr(match, attr_name, value)
                elif hasattr(match, attr_name):
                    if pre_existing_attr:
                        raise RuntimeError(
                            "Cannot remove builtin attribute %s from class %s"
                            % (attr_name, recip_class.__name__))
                    else:
                        delattr(match, attr_name)

            can_return_none = None in seen_types
            seen_types.discard(None)
            if len(seen_types) == 1:
                seen_type = seen_types.pop()
                attr_type = None if seen_type == "color" else seen_type
            elif seen_types == set([int, float]):
                attr_type = float
            else:
                attr_type = None
            recip_class.register_attr(session,
                                      attr_name,
                                      "defattr command",
                                      attr_type=attr_type,
                                      can_return_none=can_return_none)
コード例 #11
0
ファイル: cmd.py プロジェクト: Yongcheng123/ChimeraX
def nucleotides_dimensions_list(session):
    dimensions = NA.list_dimensions()
    from chimerax.core.commands import commas
    session.logger.info("Nucleotides dimensions: " + commas(dimensions, 'and'))
コード例 #12
0
ファイル: coulombic.py プロジェクト: Yongcheng123/ChimeraX
def assign_charges(session, uncharged_residues, his_scheme):
    from chimerax.atomic import Atom
    Atom.register_attr(session,
                       "charge",
                       "coulombic coloring",
                       attr_type=float)
    by_structure = {}
    for r in uncharged_residues:
        #if r.name == 'HIS':
        #    r._coulombic_his_scheme = his_scheme
        by_structure.setdefault(r.structure, []).append(r)

    missing_heavies = []
    extra_atoms = []
    copy_needed = {}
    for struct, residue_list in list(by_structure.items()):
        from chimerax.atomic import Residues
        by_structure[struct] = residues = Residues(residue_list)
        missing, extra = check_residues(residues)
        heavies = [info for info in missing if not info[1].startswith('H')]
        missing_heavies.extend(heavies)
        copy_needed[struct] = len(heavies) < len(missing)
        extra_atoms.extend(extra)

    if extra_atoms:
        from chimerax.core.commands import commas
        if len(extra_atoms) <= 7:
            atoms_text = commas([str(a) for a in extra_atoms],
                                conjunction="and")
        else:
            atoms_text = commas([str(a) for a in extra_atoms[:5]] +
                                ["%d other atoms" % (len(extra_atoms) - 5)],
                                conjunction="and")
        if len([a for a in extra_atoms
                if a.element.number == 1]) == len(extra_atoms):
            hint = "  Try deleting all hydrogens first."
        else:
            hint = ""
        raise ChargeError(
            "Atoms with non-standard names found in standard residues: %s.%s" %
            (atoms_text, hint))

    if missing_heavies:
        from chimerax.core.commands import commas
        if len(missing_heavies) <= 7:
            atoms_text = commas(
                [str(r) + ' ' + an for r, an in missing_heavies],
                conjunction="and")
        else:
            atoms_text = commas(
                [str(r) + ' ' + an for r, an in missing_heavies[:5]] +
                ["%d other atoms" % (len(missing_heavies) - 5)],
                conjunction="and")
        session.logger.warning(
            "The following heavy (non-hydrogen) atoms are missing, which may result"
            " in inaccurate electrostatics: %s" % atoms_text)

    for struct, struct_residues in by_structure.items():
        if copy_needed[struct]:
            session.logger.status("Copying %s" % struct, secondary=True)
            charged_struct = struct.copy(name="copy of " + struct.name)
            orig_a_to_copy = {}
            copy_a_to_orig = {}
            for o_a, c_a in zip(struct.atoms, charged_struct.atoms):
                orig_a_to_copy[o_a] = c_a
                copy_a_to_orig[c_a] = o_a
            orig_r_to_copy = {}
            copy_r_to_orig = {}
            for o_r, c_r in zip(struct.residues, charged_struct.residues):
                orig_r_to_copy[o_r] = c_r
                copy_r_to_orig[c_r] = o_r
            from chimerax.addh.cmd import cmd_addh
            hbond = False
            if his_scheme is None:
                if len(struct_residues[struct_residues.names == "HIS"]) > 0:
                    hbond = True
            from chimerax.atomic import AtomicStructures
            addh_structures = AtomicStructures([charged_struct])
            session.logger.status("Adding hydrogens to copy of %s" % struct,
                                  secondary=True)
            session.silent = True
            try:
                cmd_addh(session, addh_structures, hbond=hbond)
            finally:
                session.silent = False
            charged_residues = [orig_r_to_copy[r] for r in struct_residues]
            session.logger.status("Assigning charges to copy of %s" % struct,
                                  secondary=True)
        else:
            charged_struct = struct
            charged_residues = struct_residues

        # assign charges
        assign_residue_charges(charged_residues, his_scheme)

        if copy_needed[struct]:
            session.logger.status("Copying charges back to %s" % struct,
                                  secondary=True)
            for o_r in struct_residues:
                for o_a in o_r.atoms:
                    c_a = orig_a_to_copy[o_a]
                    for nb in c_a.neighbors:
                        if nb.residue == c_a.residue and nb not in copy_a_to_orig:
                            c_a.charge += nb.charge
                    o_a.charge = c_a.charge
            session.logger.status("Destroying copy of %s" % struct,
                                  secondary=True)
            charged_struct.delete()
コード例 #13
0
def cmd_coulombic(session,
                  atoms,
                  *,
                  surfaces=None,
                  his_scheme=None,
                  offset=1.4,
                  spacing=1.0,
                  padding=5.0,
                  map=False,
                  palette=None,
                  range=None,
                  dist_dep=True,
                  dielectric=4.0):
    if map:
        session.logger.warning(
            "Computing electrostatic volume map not yet supported")
    session.logger.status("Computing Coulombic charge surface%s" %
                          ("/volume" if map else ""))
    if palette is None:
        from chimerax.core.colors import BuiltinColormaps
        cmap = BuiltinColormaps["red-white-blue"]
    if not cmap.values_specified:
        rmin, rmax = (-10.0, 10.0) if range is None else range
        cmap = cmap.linear_range(rmin, rmax)
    session.logger.status("Matching atoms to surfaces", secondary=True)
    atoms_per_surf = []
    from chimerax.atomic import all_atomic_structures, MolecularSurface, all_atoms
    if atoms is None:
        if surfaces is None:
            # surface all chains
            for struct in all_atomic_structures(session):
                # don't create surface until charges checked
                if struct.num_chains == 0:
                    atoms_per_surf.append((struct.atoms, None, None))
                else:
                    for chain in struct.chains:
                        atoms_per_surf.append(
                            (chain.existing_residues.atoms, None, None))
        else:
            for srf in surfaces:
                if isinstance(srf, MolecularSurface):
                    atoms_per_surf.append((srf.atoms, None, srf))
                else:
                    atoms_per_surf.append((all_atoms(session), None, srf))
    else:
        if surfaces is None:
            # on a per-structure basis, determine if the atoms contain any polymers, and if so then
            # surface those chains (and not non-polymers); otherwise surface the atoms
            by_chain = {}
            for struct, chain_id, chain_atoms in atoms.by_chain:
                chains = chain_atoms.unique_residues.unique_chains
                if chains:
                    by_chain.setdefault(struct, {})[chains[0]] = chain_atoms
            for struct, struct_atoms in atoms.by_structure:
                try:
                    for chain, shown_atoms in by_chain[struct].items():
                        chain_atoms = chain.existing_residues.atoms
                        atoms_per_surf.append(
                            (chain_atoms, chain_atoms & shown_atoms, None))
                except KeyError:
                    atoms_per_surf.append((struct_atoms, None, None))
        else:
            for srf in surfaces:
                atoms_per_surf.append((atoms, None, srf))

    # check whether the atoms have charges, and if not, that we know how to assign charges
    # to the requested atoms
    problem_residues = set()
    needs_assignment = set()
    for surf_atoms, shown_atoms, srf in atoms_per_surf:
        for r in surf_atoms.unique_residues:
            if getattr(r, '_coulombic_his_scheme', his_scheme) != his_scheme:
                # should only be set on HIS residues
                needs_assignment.add(r)
            else:
                for a in r.atoms:
                    try:
                        a.charge + 1.0
                    except (AttributeError, TypeError):
                        if r.name in chargeable_residues:
                            needs_assignment.add(r)
                        else:
                            problem_residues.add(r.name)
                        break
    if problem_residues:
        session.logger.status("")
        from chimerax.core.commands import commas
        raise UserError(
            "Don't know how to assign charges to the following residue types: %s"
            % commas(problem_residues, conjunction='and'))

    if needs_assignment:
        session.logger.status("Assigning charges", secondary=True)
        from .coulombic import assign_charges, ChargeError
        try:
            assign_charges(session, needs_assignment, his_scheme)
        except ChargeError as e:
            session.logger.status("")
            raise UserError(str(e))

    # Since electrostatics are long range, unlike mlp, don't compute a map (with a distance cutoff)
    # by default.  Instead, compute the values at the surface vertices directly.  Only compute a
    # map afterward if requested.
    from chimerax.core.undo import UndoState
    undo_state = UndoState('coulombic')
    undo_owners = []
    undo_old_vals = []
    undo_new_vals = []
    for surf_atoms, shown_atoms, srf in atoms_per_surf:
        if srf is None:
            session.logger.status("Creating surface", secondary=True)
            from chimerax.surface import surface
            data = [(surf.atoms, surf) for surf in surface(
                session, surf_atoms if shown_atoms is None else shown_atoms)]
        else:
            data = [(surf_atoms, srf)]
        session.logger.status("Computing electrostatics", secondary=True)
        for charged_atoms, target_surface in data:
            undo_owners.append(target_surface)
            undo_old_vals.append(target_surface.vertex_colors)
            if target_surface.normals is None:
                session.logger.warning(
                    "Surface %s has no vertex normals set, using distance from surface"
                    " of 0 instead of %g" % (target_surface, offset))
                target_points = target_surface.vertices
            else:
                target_points = target_surface.vertices + offset * target_surface.normals
            import numpy, os
            from ._esp import potential_at_points
            cpu_count = os.cpu_count()
            vertex_values = potential_at_points(
                target_surface.scene_position.transform_points(target_points),
                charged_atoms.scene_coords,
                numpy.array([a.charge for a in charged_atoms],
                            dtype=numpy.double), dist_dep, dielectric,
                1 if cpu_count is None else cpu_count)
            rgba = cmap.interpolated_rgba(vertex_values)
            from numpy import uint8
            rgba8 = (255 * rgba).astype(uint8)
            target_surface.vertex_colors = rgba8
            undo_new_vals.append(rgba8)
    undo_state.add(undo_owners,
                   "vertex_colors",
                   undo_old_vals,
                   undo_new_vals,
                   option="S")
    session.undo.register(undo_state)

    session.logger.status("", secondary=True)
    session.logger.status("Finished computing Coulombic charge surface%s" %
                          ("/volume" if map else ""))
コード例 #14
0
def cmd_open_formats(session):
    '''Report file formats, suffixes and databases that the open command knows about.'''
    from chimerax.core.commands import commas
    all_formats = session.open_command.open_data_formats
    by_category = {}
    for fmt in all_formats:
        by_category.setdefault(fmt.category.title(), []).append(fmt)
    titles = list(by_category.keys())
    titles.sort()
    lines = []
    for title in titles:
        formats = by_category[title]
        if session.ui.is_gui:
            lines.extend([
                '<table border=1 cellspacing=0 cellpadding=2>',
                '<tr><th colspan="3">%s' % title,
                '<tr><th>File format<th>Short name(s)<th>Suffixes'
            ])
        else:
            session.logger.info(title)
            session.logger.info('File format, Short name(s), Suffixes:')
        formats.sort(key = lambda f: f.name.lower())
        for f in formats:
            if session.ui.is_gui:
                from html import escape
                if f.reference_url:
                    descrip = '<a href="%s">%s</a>' % (f.reference_url, escape(f.synopsis))
                else:
                    descrip = escape(f.synopsis)
                lines.append('<tr><td>%s<td>%s<td>%s' % (descrip,
                    escape(commas(f.nicknames)), escape(', '.join(f.suffixes))))
            else:
                session.logger.info('    %s: %s: %s' % (f.synopsis,
                    commas(f.nicknames), ', '.join(f.suffixes)))
        if session.ui.is_gui:
            lines.append('</table>')
            lines.append('<p></p>')
        else:
            session.logger.info('\n')

    if session.ui.is_gui:
        lines.extend(['<table border=1 cellspacing=0 cellpadding=2>', '<tr><th>Database<th>Formats'])
    else:
        session.logger.info('Database, Formats:')
    database_names = session.open_command.database_names
    database_names.sort(key=lambda dbn: dbn.lower())
    for db_name in database_names:
        db_info = session.open_command.database_info(db_name)
        if 'web fetch' in db_info.keys() or db_name == 'help':
            continue
        for fmt_name, fetcher_info in db_info.items():
            if fetcher_info.is_default:
                default_name = session.data_formats[fmt_name].nicknames[0]
                break
        else:
            continue
        format_names = [session.data_formats[fmt_name].nicknames[0] for fmt_name in db_info.keys()]
        format_names.sort()
        format_names.remove(default_name)
        format_names.insert(0, default_name)
        if not session.ui.is_gui:
            session.logger.info('    %s: %s' % (db_name, ', '.join(format_names)))
            continue
        line = '<tr><td>%s<td>%s' % (db_name, ', '.join(format_names))
        lines.append(line)

    if session.ui.is_gui:
        lines.append('</table>')
        msg = '\n'.join(lines)
        session.logger.info(msg, is_html=True)