Source code for schrodinger.application.jaguar.gui.tabs.reaction_molecules_tab
from schrodinger import get_maestro
from .. import ui
from .base_tab import BaseTab
from .molecule_tab import MoleculeTabNoInputSelector
maestro = get_maestro()
REACTANT_PREFIX = "Reactant"
PRODUCT_PREFIX = "Product"
# TODO: Renumber participants when one is deleted?
# TODO: sorting will be broken if the participant numbering goes into
# double digits, since it's a text sort not a numerical one
[docs]class ReactionMoleculesTab(BaseTab):
""""
The Molecules tab used in the Reactions panel.
:note: This tab does not implement loadSettings() or reset(). However,
resetting the Reactions tab will remove all structures, which will result in
this tab being cleared. Also note that this tab does not load default mmjag
settings into its MoleculeSubTab components. Instead, we assume that the
initial settings for MoleculeSubTab conform to mmjag defaults, which they
do, assuming that the mmjag defaults for symmetry, charge, and spin
multiplicity don't change.
"""
NAME = "Molecules"
HELP_TOPIC = "JAGUAR_TOPIC_MOLECULE_FOLDER"
UI_MODULES = (ui.reaction_molecules_tab_ui,)
[docs] def setup(self):
self.participant_txt_to_molecule_widget = {}
self.ui.molecules_combo.currentTextChanged.connect(
self.showMoleculeWidgetForParticipant)
[docs] def newParticipant(self, txt):
"""
Adds a participant to the combo box, and adds a molecule widget to
the stacked widget.
:param txt: The txt to show along with the participant in combo
:type txt: str
"""
molecule_widget = MoleculeTabNoInputSelector(self.ui.molecules_stacked)
self.participant_txt_to_molecule_widget[txt] = molecule_widget
self.ui.molecules_stacked.addWidget(molecule_widget)
self.ui.molecules_combo.currentTextChanged.disconnect(
self.showMoleculeWidgetForParticipant)
# Re-sort to put reactant before product, with ascending #'s
current_text = self.ui.molecules_combo.currentText()
self.ui.molecules_combo.clear()
for txt in sorted(self.participant_txt_to_molecule_widget):
if txt.startswith(REACTANT_PREFIX):
self.ui.molecules_combo.addItem(txt)
for txt in sorted(self.participant_txt_to_molecule_widget):
if txt.startswith(PRODUCT_PREFIX):
self.ui.molecules_combo.addItem(txt)
if current_text:
self.ui.molecules_combo.setCurrentIndex(
self.ui.molecules_combo.findText(current_text))
self.ui.molecules_combo.currentTextChanged.connect(
self.showMoleculeWidgetForParticipant)
[docs] def removeParticipant(self, txt):
"""
Removes participant from combo box and removes its molecule widget
:param txt: Text for molecule matching combo text
:type txt: str
"""
molecule_widget = self.participant_txt_to_molecule_widget[txt]
self.ui.molecules_stacked.removeWidget(molecule_widget)
del self.participant_txt_to_molecule_widget[txt]
self.ui.molecules_combo.removeItem(
self.ui.molecules_combo.findText(txt))
[docs] def changeMoleculeForParticipant(self, txt, struct):
"""
Show a molecule widget in the stackedWidget for a participant
:param txt: Text for molecule matching combo text
:type txt: str
:param struct: The new structure for the participant
:type struct: structure.Structure
"""
molecule_widget = self.participant_txt_to_molecule_widget[txt]
molecule_widget.setStructure(struct)
[docs] def getParticipants(self):
"""
Return structures and keywords for all participants
:return: A tuple of:
- A list of all reactants
- A list of all products
Each participant is represented as a tuple of:
- The structure (`schrodinger.structure.Structure`)
- the molecule mmjag keywords (dict)
:rtype: tuple
"""
reactants = []
products = []
all_participants = self.participant_txt_to_molecule_widget.items()
for name, widget in sorted(all_participants):
struc = widget.getStructure()
keywords = widget.getMmJagKeywords()
if name.startswith(REACTANT_PREFIX):
reactants.append((struc, keywords))
elif name.startswith(PRODUCT_PREFIX):
products.append((struc, keywords))
else:
raise RuntimeError("Unrecognized participant: %s" % name)
return reactants, products
[docs] def validate(self):
"""
Make sure that all participants have a valid basis selected
:return: None if all participants are valid. An error string otherwise.
:rtype: NoneType or str
"""
all_participants = self.participant_txt_to_molecule_widget.items()
for name, widget in sorted(all_participants):
msg = widget.validate()
if msg:
index = self.ui.molecules_combo.findText(name)
self.ui.molecules_combo.setCurrentIndex(index)
return "The selected basis set for %s is invalid." % name