예제 #1
0
class ModellerLauncher(ToolInstance):
    """Generate the inputs needed by Modeller for comparative modeling"""

    help = "help:user/tools/modeller.html"
    SESSION_SAVE = False

    def __init__(self, session, tool_name):
        ToolInstance.__init__(self, session, tool_name)

        from chimerax.ui import MainToolWindow
        self.tool_window = MainToolWindow(self,
                                          close_destroys=False,
                                          statusbar=False)
        parent = self.tool_window.ui_area

        from PyQt5.QtWidgets import QListWidget, QFormLayout, QAbstractItemView, QGroupBox, QVBoxLayout
        from PyQt5.QtWidgets import QDialogButtonBox as qbbox
        interface_layout = QVBoxLayout()
        interface_layout.setContentsMargins(0, 0, 0, 0)
        interface_layout.setSpacing(0)
        parent.setLayout(interface_layout)
        alignments_area = QGroupBox("Sequence alignments")
        interface_layout.addWidget(alignments_area)
        interface_layout.setStretchFactor(alignments_area, 1)
        alignments_layout = QVBoxLayout()
        alignments_layout.setContentsMargins(0, 0, 0, 0)
        alignments_area.setLayout(alignments_layout)
        self.alignment_list = AlignmentListWidget(session)
        self.alignment_list.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        self.alignment_list.keyPressEvent = session.ui.forward_keystroke
        self.alignment_list.value_changed.connect(self._list_selection_cb)
        self.alignment_list.alignments_changed.connect(
            self._update_sequence_menus)
        alignments_layout.addWidget(self.alignment_list)
        alignments_layout.setStretchFactor(self.alignment_list, 1)
        targets_area = QGroupBox("Target sequences")
        self.targets_layout = QFormLayout()
        targets_area.setLayout(self.targets_layout)
        interface_layout.addWidget(targets_area)
        self.seq_menu = {}
        self._update_sequence_menus(session.alignments.alignments)
        options_area = QGroupBox("Options")
        options_layout = QVBoxLayout()
        options_layout.setContentsMargins(0, 0, 0, 0)
        options_area.setLayout(options_layout)
        interface_layout.addWidget(options_area)
        interface_layout.setStretchFactor(options_area, 2)
        from chimerax.ui.options import CategorizedSettingsPanel, BooleanOption, IntOption, PasswordOption, \
            OutputFolderOption
        panel = CategorizedSettingsPanel(category_sorting=False, buttons=False)
        options_layout.addWidget(panel)
        from .settings import get_settings
        settings = get_settings(session)
        panel.add_option(
            "Basic",
            BooleanOption(
                "Make multichain model from multichain template",
                settings.multichain,
                None,
                balloon=
                "If false, all chains (templates) associated with an alignment will be used in combination\n"
                "to model the target sequence of that alignment, i.e. a monomer will be generated from the\n"
                "alignment.  If true, the target sequence will be modeled from each template, i.e. a multimer\n"
                "will be generated from the alignment (assuming multiple chains are associated).",
                attr_name="multichain",
                settings=settings))
        max_models = 1000
        panel.add_option(
            "Basic",
            IntOption(
                "Number of models",
                settings.num_models,
                None,
                attr_name="num_models",
                settings=settings,
                min=1,
                max=max_models,
                balloon=
                "Number of model structures to generate.  Must be no more than %d.\n"
                "Warning: please consider the calculation time" % max_models))
        key = "" if settings.license_key is None else settings.license_key
        panel.add_option(
            "Basic",
            PasswordOption(
                "Modeller license key",
                key,
                None,
                attr_name="license_key",
                settings=settings,
                balloon=
                "Your Modeller license key.  You can obtain a license key by registering at the Modeller web site"
            ))
        panel.add_option(
            "Advanced",
            BooleanOption(
                "Use fast/approximate mode (produces only one model)",
                settings.fast,
                None,
                attr_name="fast",
                settings=settings,
                balloon=
                "If enabled, use a fast approximate method to generate a single model.\n"
                "Typically use to get a rough idea what the model will look like or\n"
                "to check that the alignment is reasonable."))
        panel.add_option(
            "Advanced",
            BooleanOption(
                "Include non-water HETATM residues from template",
                settings.het_preserve,
                None,
                attr_name="het_preserve",
                settings=settings,
                balloon=
                "If enabled, all non-water HETATM residues in the template\n"
                "structure(s) will be transferred into the generated models."))
        panel.add_option(
            "Advanced",
            BooleanOption(
                "Build models with hydrogens",
                settings.hydrogens,
                None,
                attr_name="hydrogens",
                settings=settings,
                balloon=
                "If enabled, the generated models will include hydrogen atoms.\n"
                "Otherwise, only heavy atom coordinates will be built.\n"
                "Increases computation time by approximately a factor of 4."))
        panel.add_option(
            "Advanced",
            OutputFolderOption(
                "Temporary folder location (optional)",
                settings.temp_path,
                None,
                attr_name="temp_path",
                settings=settings,
                balloon=
                "Specify a folder for temporary files.  If not specified,\n"
                "a location will be generated automatically."))
        panel.add_option(
            "Advanced",
            BooleanOption(
                "Include water molecules from template",
                settings.water_preserve,
                None,
                attr_name="water_preserve",
                settings=settings,
                balloon="If enabled, all water molecules in the template\n"
                "structure(s) will be included in the generated models."))
        from PyQt5.QtCore import Qt
        from chimerax.ui.widgets import Citation
        interface_layout.addWidget(Citation(
            session, "A. Sali and T.L. Blundell.\n"
            "Comparative protein modelling by satisfaction of spatial restraints.\n"
            "J. Mol. Biol. 234, 779-815, 1993.",
            prefix="Publications using Modeller results should cite:",
            pubmed_id=18428767),
                                   alignment=Qt.AlignCenter)
        bbox = qbbox(qbbox.Ok | qbbox.Cancel | qbbox.Help)
        bbox.accepted.connect(self.launch_modeller)
        bbox.rejected.connect(self.delete)
        from chimerax.core.commands import run
        bbox.helpRequested.connect(
            lambda run=run, ses=session: run(ses, "help " + self.help))
        interface_layout.addWidget(bbox)
        self.tool_window.manage(None)

    def delete(self):
        ToolInstance.delete(self)

    def launch_modeller(self):
        from chimerax.core.commands import run, FileNameArg, StringArg
        from chimerax.core.errors import UserError
        alignments = self.alignment_list.value
        if not alignments:
            raise UserError("No alignments chosen for modeling")
        aln_seq_args = []
        for aln in alignments:
            seq_menu = self.seq_menu[aln]
            seq = seq_menu.value
            if not seq:
                raise UserError("No target sequence chosen for alignment %s" %
                                aln.ident)
            aln_seq_args.append(
                StringArg.unparse("%s:%d" %
                                  (aln.ident, aln.seqs.index(seq) + 1)))
        from .settings import get_settings
        settings = get_settings(self.session)
        run(
            self.session,
            "modeller comparative %s multichain %s numModels %d fast %s hetPreserve %s"
            " hydrogens %s%s waterPreserve %s" %
            (" ".join(aln_seq_args), repr(
                settings.multichain).lower(), settings.num_models,
             repr(settings.fast).lower(), repr(settings.het_preserve).lower(),
             repr(settings.hydrogens).lower(), " tempPath %s" %
             FileNameArg.unparse(settings.temp_path) if settings.temp_path else
             "", repr(settings.water_preserve).lower()))
        self.delete()

    def _list_selection_cb(self):
        layout = self.targets_layout
        while layout.count() > 0:
            item = layout.takeAt(0)
            if not item:
                break
            widget = item.widget()
            if isinstance(widget, AlignSeqMenuButton):
                widget.setHidden(True)
            else:
                widget.deleteLater()
        for sel_aln in self.alignment_list.value:
            mb = self.seq_menu[sel_aln]
            mb.setHidden(False)
            layout.addRow(sel_aln.ident, mb)

    def _update_sequence_menus(self, alignments):
        alignment_set = set(alignments)
        for aln, mb in list(self.seq_menu.items()):
            if aln not in alignment_set:
                row, role = self.targets_layout.getWidgetPosition(mb)
                if row >= 0:
                    self.targets_layout.removeRow(row)
                del self.seq_menu[aln]
        for aln in alignments:
            if aln not in self.seq_menu:
                self.seq_menu[aln] = AlignSeqMenuButton(
                    aln, no_value_button_text="No target chosen")