Source code for schrodinger.application.jaguar.gui.tabs.optimization_tab

import warnings
from collections import OrderedDict
from itertools import combinations
from itertools import permutations

import schrodinger
from schrodinger.infra import mm
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtGui
from schrodinger.Qt import QtWidgets
from schrodinger.Qt.QtCore import Qt
from schrodinger.ui.qt.decorators import suppress_signals

from .. import ui
from .. import utils as gui_utils
from ..utils import JaguarSettingWarning
from . import coordinates
from .transition_state_tab import ActiveTransitionStateTab

maestro = schrodinger.get_maestro()
try:
    from schrodinger.maestro import markers
except ImportError:
    markers = None

DISTANCE_COORD = "Distance"
COORDINATE_TYPES = OrderedDict(
    (("Cartesian - X", mm.MMJAG_COORD_CART_X), ("Cartesian - Y",
                                                mm.MMJAG_COORD_CART_Y),
     ("Cartesian - Z", mm.MMJAG_COORD_CART_Z), ("Cartesian - XYZ",
                                                mm.MMJAG_COORD_CART_XYZ),
     (DISTANCE_COORD, mm.MMJAG_COORD_DISTANCE), ("Angle", mm.MMJAG_COORD_ANGLE),
     ("Dihedral", mm.MMJAG_COORD_TORSION)))

IP_472_OFF, IP_472_ON = list(range(1, 3))
INITIAL_NOPS_VAL = 10


[docs]class OptimizationTab(coordinates.CoordinateTab): NAME = "Optimization" UI_MODULES = (ui.optimization_tab_ui,) HELP_TOPIC = "JAGUAR_TOPIC_OPTIMIZATION_FOLDER" CONVERGENCE_CRITERIA = OrderedDict( (("Default", mm.MMJAG_IACCG_ACCURATE), ("Loose", mm.MMJAG_IACCG_QUICK), ("Tight", mm.MMJAG_IACCG_TIGHT), ("Custom", mm.MMJAG_IACCG_CUSTOM))) INITIAL_HESSIAN = OrderedDict( (("Schlegel guess", mm.MMJAG_INHESS_SCHLEGEL), ("Fischer-Almlof guess", mm.MMJAG_INHESS_FISCHER), ("Unit Hessian", mm.MMJAG_INHESS_UNIT), ("Quantum-mechanical", mm.MMJAG_INHESS_QM))) COORDINATE_OPTS = OrderedDict((("Redundant internal", mm.MMJAG_INTOPT_RED), ("Cartesian", mm.MMJAG_INTOPT_CART), ("Z-matrix", mm.MMJAG_INTOPT_ZMAT))) # Map that has constraint coordinate type as a key and a value # that is a tuple that contains two variables: bool to indicate # whether button should be visible and the text that should be # shown on the button. ALL_CONSTRAINTS_BUTTON = { mm.MMJAG_COORD_CART_X: (True, "Add Selected Atoms"), mm.MMJAG_COORD_CART_Y: (True, "Add Selected Atoms"), mm.MMJAG_COORD_CART_Z: (True, "Add Selected Atoms"), mm.MMJAG_COORD_CART_XYZ: (True, "Add Selected Atoms"), mm.MMJAG_COORD_DISTANCE: (True, "Add All Atom Pairs"), mm.MMJAG_COORD_ANGLE: (True, "Add All Bond Angles"), mm.MMJAG_COORD_TORSION: (True, "Add All Torsions") } SETS_IACCG_CUSTOM = True
[docs] def setup(self): super().setup() self.picker = coordinates.CoordinatePicker(COORDINATE_TYPES, self.ui.pick_cb, self.ui.coord_type_combo, self.ui.pick_combo) # create validators double_validator = QtGui.QDoubleValidator() double_validator.setDecimals(3) for widget in [ self.ui.energy_le, self.ui.gradient_rms_le, self.ui.max_disp_rms_le ]: widget.setValidator(double_validator) # add data to combo boxes self.ui.convergence_combo.addItemsFromDict(self.CONVERGENCE_CRITERIA) self.ui.hessian_combo.addItemsFromDict(self.INITIAL_HESSIAN) self.ui.coordinates_combo.addItemsFromDict(self.COORDINATE_OPTS) self.ui.custom_frame.setVisible(False) # setup coordinate table self.model = ConstraintCoordinatesModel(self) self.proxy = ConstraintCoordinatesProxyModel(self) self.proxy.setSourceModel(self.model) self.ui.tableView.setModel(self.proxy) self.ui.tableView.setItemDelegateForColumn( 2, ConstraintCoordinatesDelegate(self)) self.ui.tableView.selectionModel().selectionChanged.connect( self._highlightSelectedMarkers) # create connections self.model.dataChanged.connect(self.proxy.dataChanged) self.picker.pickCompleted.connect(self.pickCompleted) self.ui.delete_btn.clicked.connect(self.deleteCurrentRow) self.ui.delete_all_btn.clicked.connect(self.deleteAllRows) self.ui.convergence_combo.currentIndexChanged.connect( self.convergenceTypeChanged) self.ui.coord_type_combo.currentIndexChanged.connect( self.updateAllConstraintsPB) self.ui.all_constraints_btn.clicked.connect(self.addConsButtonPressed) self.updateAllConstraintsPB() # Since the mm.MMJAG_RKEY_NOPS_OPT_SWITCH must always be reset to # INITIAL_NOPS_VAL inside getMmJagKeywords, unless the user has # modified it, we must track the value of # mm.MMJAG_RKEY_NOPS_OPT_SWITCH to not overwrite user modified value. self.nops_opt_switch_value = INITIAL_NOPS_VAL
[docs] def getMmJagKeywords(self): """ This function returns dictionary of mmjag keywords for this tab. Since this tab does not set any keywords it returns an empty dictionary. :return: mmjag keywords dictionary :rtype: dict """ keywords = {} keywords[mm.MMJAG_IKEY_MAXITG] = self.ui.max_steps_sb.value() keywords.update(self.getConvergenceKeywords()) hessian = self.ui.hessian_combo.currentData() keywords[mm.MMJAG_IKEY_INHESS] = hessian coord_opt = self.ui.coordinates_combo.currentData() keywords[mm.MMJAG_IKEY_INTOPT] = coord_opt # FIXME there is no constant in mmjag_keywords for this option. ip_472 = IP_472_OFF if self.ui.save_geom_cb.isChecked(): ip_472 = IP_472_ON keywords[mm.MMJAG_IKEY_IP472] = ip_472 if self.ui.use_nops_cb.isChecked(): keywords[mm.MMJAG_RKEY_NOPS_OPT_SWITCH] = self.nops_opt_switch_value else: keywords[mm.MMJAG_RKEY_NOPS_OPT_SWITCH] = None return keywords
[docs] def getConvergenceKeywords(self): """ Get keywords from convergence criteria widgets. :return: A dictionary of keywords :rtype: dict """ keywords = {} conv = self.ui.convergence_combo.currentData() if conv != mm.MMJAG_IACCG_CUSTOM or self.SETS_IACCG_CUSTOM: keywords[mm.MMJAG_IKEY_IACCG] = conv keywords[mm.MMJAG_RKEY_GCONV2] = None keywords[mm.MMJAG_RKEY_GCONV6] = None keywords[mm.MMJAG_RKEY_GCONV7] = None if conv == mm.MMJAG_IACCG_CUSTOM: energy_change = gui_utils.validate_le_float_input( self.ui.energy_le, "Invalid input for energy change field.") keywords[mm.MMJAG_RKEY_GCONV7] = energy_change gradient_rms = gui_utils.validate_le_float_input( self.ui.gradient_rms_le, "Invalid input for gradient RMS field.") keywords[mm.MMJAG_RKEY_GCONV2] = gradient_rms max_disp_rms = gui_utils.validate_le_float_input( self.ui.max_disp_rms_le, "Invalid input for maximal displacement ") keywords[mm.MMJAG_RKEY_GCONV6] = max_disp_rms return keywords
[docs] def loadSettings(self, jag_input): """ Restore scan coordinates settings from Jaguar handle. :param jag_input: The Jaguar settings to base the tab settings on :type jag_input: `schrodinger.application.jaguar.input.JaguarInput` """ self._resetDefaults() max_steps = jag_input[mm.MMJAG_IKEY_MAXITG] self.ui.max_steps_sb.setValue(max_steps) self.loadConvergenceKeywords(jag_input) self.ui.hessian_combo.setCurrentMmJagData(jag_input, mm.MMJAG_IKEY_INHESS, "hessian") self.ui.coordinates_combo.setCurrentMmJagData(jag_input, mm.MMJAG_IKEY_INTOPT, "coordinates") save_geom = jag_input[mm.MMJAG_IKEY_IP472] save_geom_bool = save_geom == 2 self.ui.save_geom_cb.setChecked(save_geom_bool) self.loadConstraintCoordinates(jag_input) try: nops_opt_switch_val = jag_input[mm.MMJAG_RKEY_NOPS_OPT_SWITCH] except mm.MmException: msg = ('Unrecognized %s setting. "Use NOPS optimization switch" ' 'will not be modified.' % (mm.MMJAG_RKEY_NOPS_OPT_SWITCH)) warnings.warn(JaguarSettingWarning(msg)) return # See PANEL-5767 for details on how 1.0 was chosen. if nops_opt_switch_val > 1.0: self.ui.use_nops_cb.setChecked(True) self.nops_opt_switch_value = nops_opt_switch_val else: self.ui.use_nops_cb.setChecked(False) self.nops_opt_switch_value = INITIAL_NOPS_VAL
[docs] def loadConvergenceKeywords(self, jag_input): """ Load the convergence criteria settings. :param jag_input: The Jaguar settings to load. :type jag_input: `schrodinger.application.jaguar.input.JaguarInput` """ conv = jag_input.getValue(mm.MMJAG_IKEY_IACCG) if conv != mm.MMJAG_IACCG_CUSTOM or self.SETS_IACCG_CUSTOM: self.ui.convergence_combo.setCurrentMmJagData( jag_input, mm.MMJAG_IKEY_IACCG, "convergence") if self.ui.convergence_combo.currentData() == mm.MMJAG_IACCG_CUSTOM: # Custom convergence options energy_change = jag_input[mm.MMJAG_RKEY_GCONV7] self.ui.energy_le.setText(str(energy_change)) gradient_rms = jag_input[mm.MMJAG_RKEY_GCONV2] self.ui.gradient_rms_le.setText(str(gradient_rms)) max_disp_rms = jag_input[mm.MMJAG_RKEY_GCONV6] self.ui.max_disp_rms_le.setText(str(max_disp_rms))
[docs] def loadConstraintCoordinates(self, jag_input): """ Load constraint coordinates from Jaguar handle. :param jag_input: The Jaguar handle where tab settings are saved. :type jag_input: `schrodinger.application.jaguar.input.JaguarInput` """ # check that there is just single entry in workspace num_constraint = jag_input.constraintCount() if num_constraint == 0: return try: st = maestro.get_included_entry() except RuntimeError as err: msg = ("There should be exactly one entry included in workspace. " "Constraints can not be loaded.") warnings.warn(JaguarSettingWarning(msg)) refresh_markers = False for constraint in jag_input.constraints(): if constraint: (coord_type, atoms, value) = constraint self.addCoordinate(st, atoms, coord_type, value) refresh_markers = True if refresh_markers: self.refreshMarkers.emit()
[docs] def saveSettings(self, jag_input, eid=None): """ Save constraint coordinate settings in jaguar handle. See parent class for argument documentation """ for coord in self.model.coords: jag_input.setConstraint(coord.coordinate_type, coord.atom_indices, coord.target_value)
[docs] def deleteCurrentRow(self): """ This function is called to delete row which is currently selected from the coordinates table. """ selected = self.ui.tableView.selectedIndexes() if len(selected) == 0: return selected_row = selected[0].row() atoms = self._getAtomsForRow(selected_row) self._emitCoordinateDeleted(atoms) self.model.removeRow(selected_row) self.ui.tableView.clearSelection() if self.model.rowCount() == 0: self.ui.delete_btn.setDisabled(True) self.ui.delete_all_btn.setDisabled(True)
[docs] def deleteAllRows(self): """ This function is called to delete all rows from the coordinates table. """ self.ui.tableView.clearSelection() self.model.reset() self._marker_count.clear() self.allCoordinatesDeleted.emit() self.ui.delete_btn.setDisabled(True) self.ui.delete_all_btn.setDisabled(True)
[docs] def addCoordinate(self, st, atoms, coordinate_type, target_value=None): """ Add new coordinate row. :param st: structure :type st: `schrodinger.structure.Structure` :param atoms: atom indices :type atoms: list :param coordinate_type: coordinate type :type coordinate_type: int :param target_value: target coordinate value :type target_value: float """ err = self._determineIfConstraintsAddable() if err is not None: self.error(err) elif self.model.addCoordinate(st, atoms, coordinate_type, target_value): self._emitCoordinateAdded(atoms, coordinate_type) # select row that was just added last_row = self.model.rowCount() - 1 self.ui.tableView.selectRow(last_row) self.ui.delete_btn.setEnabled(True) self.ui.delete_all_btn.setEnabled(True)
[docs] def convergenceTypeChanged(self, index): """ This function is called when convergence type is changed. If 'Custom' is selected extra options frame is shown. Otherwise, it is hidden. :param index: convergence type combo box index :type index: int """ visible = False if self.ui.convergence_combo.currentData() == mm.MMJAG_IACCG_CUSTOM: visible = True self.ui.custom_frame.setVisible(visible)
[docs] def pickCompleted(self, atoms): """ This slot is called when required number of atoms for the current coordinate type has been picked. :param atoms: list of atom indices :type atoms: list """ try: st = maestro.get_included_entry() except RuntimeError as err: self.warning(str(err)) return coord_type = self.ui.coord_type_combo.currentData() self.addCoordinate(st, atoms, coord_type)
[docs] def updateAllConstraintsPB(self): """ This function is called when coordinate type is changed to update text and visibility of the button that adds all constraints. """ coord_type = self.ui.coord_type_combo.currentData() visible, text = self.ALL_CONSTRAINTS_BUTTON[coord_type] self.ui.all_constraints_btn.setVisible(visible) self.ui.all_constraints_btn.setText(text)
[docs] def addConsButtonPressed(self): """ This function is called when 'add all constraints/add selected atoms' button is clicked. It determines current coordinate type and calls appropriate function to add all/selected constraints. """ try: st = maestro.get_included_entry() except RuntimeError as err: self.warning(str(err)) return add_cons = [] coord_type = self.ui.coord_type_combo.currentData() if coord_type == mm.MMJAG_COORD_DISTANCE: add_cons = self.getAllAtomPairs(st) elif coord_type == mm.MMJAG_COORD_ANGLE: add_cons = self.getAllAngles(st) elif coord_type == mm.MMJAG_COORD_TORSION: add_cons = self.getAllTorsions(st) else: add_cons = [[anum] for anum in maestro.selected_atoms_get()] if not add_cons: self.warning("No atoms are selected in the Workspace") return # PANEL-20298: check if constraints are addable before adding any coordinates. # This ensures that error message is shown only once. err = self._determineIfConstraintsAddable() if err is not None: self.error(err) return for atoms in add_cons: self.addCoordinate(st, atoms, coord_type)
[docs] def getAllAtomPairs(self, st): """ This function returns a list of all possible atom pairs in a given structure. :param st: structure :type st: `schrodinger.structure.Structure` :return: list that contains pairs of atom indices :rtype: list """ atoms = [ [at1.index, at2.index] for at1, at2 in combinations(st.atom, 2) ] return atoms
[docs] def getAllAngles(self, st): """ This function returns list that contains lists of atoms for each bond angle in a given structure. :param st: structure :type st: `schrodinger.structure.Structure` :return: list that contains lists of atom indices for each bond angle :rtype: list """ atoms = [] for at2 in st.atom: for at1, at3 in permutations(at2.bonded_atoms, 2): atoms.append([at1.index, at2.index, at3.index]) return atoms
[docs] def getAllTorsions(self, st): """ This function returns list that contains lists of atoms for each torsion angle in a given structure. :param st: structure :type st: `schrodinger.structure.Structure` :return: list that contains lists of atom indices for each torsion :rtype: list """ atoms = [] for bond in st.bond: at2 = bond.atom1 at3 = bond.atom2 for at1 in at2.bonded_atoms: for at4 in at3.bonded_atoms: if at1 != at3 and at4 != at2: atoms.append( [at1.index, at2.index, at3.index, at4.index]) return atoms
[docs]class ConstraintCoordinateColumns(): """ Constants for table columns. """ NAMES = ('Atom Indices', 'Coordinate', 'Type', 'Target Value') NUM_COLS = len(NAMES) (INDICES, COORD_NAME, COORD_TYPE, TARGET_VAL) = list(range(NUM_COLS))
[docs]class ConstraintCoordinateData(coordinates.CoordinateData): """ This class stores all data for a single constraint coordinate. :ivar st: ct structure for which coordinates are defined :vartype st: `schrodinger.structure.Structure` :ivar atom_indices: indices of atoms, which define this coordinate :vartype atom_indices: list :ivar coordinate_name: name of this coordinate based on atom indices :vartype coordinate_name: str :ivar coordinate_type: coordinate type :vartype coordinate_type: int :ivar target_value: target value of this coordinate :vartype target_value: float """
[docs] def __init__(self, st, atoms, coordinate_type, target_value=None): """ Initialize coordinates data given a structure, set of atom indices and coordinate type. :param st: structure :type st: `schrodinger.structure.Structure` :param atoms: atom indices :type atoms: list :param coordinate_type: coordinate type :type coordinate_type: int :param target_value: target coordinate value :type target_value: float """ super(ConstraintCoordinateData, self).__init__(st, atoms, coordinate_type) self.target_value = target_value self.coordinate_name = self._getCoordinateName()
[docs]class ConstraintCoordinatesDelegate(QtWidgets.QItemDelegate): """ This delegate is used to validate values entered in 'target value' column. """ COLUMN = ConstraintCoordinateColumns()
[docs] def createEditor(self, parent, option, index): """ This function returns an editor widget (QLineEdit) for 'target value' column. :param parent: parent widget :type parent: `QtWidgets.QWidget` :param option: not used, but kept for compatibility :type option: `QtWidgets.QStyleOptionViewItem` :param index: model index :type index: `QtCore.QModelIndex` :return: QLineEdit editor widget :rtype: `QtWidgets.QLineEdit` """ editor = QtWidgets.QLineEdit(parent) double_validator = QtGui.QDoubleValidator(editor) # Here model is a proxy model which is responsible for column # visibility. So, 1 is the index of coordinate type column. coord_type_index = index.model().index(index.row(), 1) coord_type = index.model().data(coord_type_index, Qt.DisplayRole) if coord_type == DISTANCE_COORD: double_validator.setBottom(0.0) editor.setValidator(double_validator) return editor
[docs] def setEditorData(self, editor, index): """ This function read data from model, converts it to text and sets it in the editor widget. :param editor: editor widget :type editor: `QtWidgets.QLineEdit` :param index: model index :type index: `QtCore.QModelIndex` """ value = index.model().data(index, Qt.EditRole) s = "" if value is not None: s = "%.3f" % value editor.setText(s)
[docs] def setModelData(self, editor, model, index): """ This function reads text from QLineEdit and writes it to the model :param editor: editor widget :type editor: `QtWidgets.QLineEdit` :param model: data model :type model: `QtCore.QAbstractItemModel` :param index: model index :type index: `QtCore.QModelIndex` """ try: value = float(editor.text()) except ValueError: value = "" model.setData(index, value)
[docs]class ConstraintCoordinatesProxyModel(QtCore.QSortFilterProxyModel): """ A proxy model that allows to hide columns. """ COLUMN = ConstraintCoordinateColumns()
[docs] def __init__(self, parent): super(ConstraintCoordinatesProxyModel, self).__init__(parent) self.visible_columns = (self.COLUMN.COORD_NAME, self.COLUMN.COORD_TYPE, self.COLUMN.TARGET_VAL) # maintain Qt4 dynamicSortFilter default self.setDynamicSortFilter(False)
[docs] def filterAcceptsColumn(self, column, index): """ Modified from the parent class to define columns that should be visible. :param column: the column index :type column: int :param index: Unused, but kept for PyQt compatibility :type index: `QModelIndex` """ return column in self.visible_columns
[docs]class ConstraintCoordinatesModel(coordinates.CoordinatesModel): """ A model to store scan tab coordinates data. """ COLUMN = ConstraintCoordinateColumns()
[docs] def addCoordinate(self, st, atoms, coordinate_type, target_value=None): """ Add new coordinate row. :param st: structure :type st: `schrodinger.structure.Structure` :param atoms: atom indices :type atoms: list :param coordinate_type: coordinate type :type coordinate_type: int :param target_value: target coordinate value :type target_value: float """ if self.checkNewCoordinate(atoms, coordinate_type): new_row_num = len(self.coords) self.beginInsertRows(QtCore.QModelIndex(), new_row_num, new_row_num) new_coord = ConstraintCoordinateData(st, atoms, coordinate_type, target_value) self.coords.append(new_coord) self.endInsertRows() return True return False
[docs] def appendFromModel(self, model): """ Append the rows in the given model to this model :type: `ConstraintCoordinatesModel` :param: The model to append rows from """ # This method is used by the Jaguar Multistage panel when copying one # stage into another for coord in model.coords: self.addCoordinate(coord.st, coord.atom_indices, coord.coordinate_type, target_value=coord.target_value)
[docs] def flags(self, index): """ Returns flags for the specified cell. Whether it is editable or not. :param index: The index to retrieve flags for. :type index: `PyQt5.QtCore.QModelIndex` """ col = index.column() if col == self.COLUMN.TARGET_VAL: return Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable else: return Qt.ItemIsSelectable | Qt.ItemIsEnabled
[docs] def data(self, index, role=Qt.DisplayRole): """ Retrieve the requested data :param index: The index to retrieve data for :type index: `PyQt5.QtCore.QModelIndex` :param role: The role to retrieve data for :type role: int :return: The requested data """ if not index.isValid(): return if index.row() >= len(self.coords): return if role == Qt.TextAlignmentRole: return Qt.AlignLeft elif role == Qt.DisplayRole or role == Qt.EditRole: row = index.row() col = index.column() coord = self.coords[row] if col == self.COLUMN.INDICES: return coord.atom_indices elif col == self.COLUMN.COORD_NAME: return coord.coordinate_name elif col == self.COLUMN.COORD_TYPE: type_text = gui_utils.find_key_for_value( COORDINATE_TYPES, coord.coordinate_type) return type_text elif col == self.COLUMN.TARGET_VAL: return coord.target_value
[docs] def setData(self, index, value, role=Qt.EditRole): """ Modify coordinate values. :param index: the index of table cell :type index: `QtCore.QModelIndex` :param value: new value :type value: str :param role: The role to set data for. :type role: int """ if index.isValid() and role == Qt.EditRole: row = index.row() col = index.column() coord = self.coords[row] if col != self.COLUMN.TARGET_VAL: return False if value == "": value = None else: try: value = float(value) except: value = 0.0 coord.target_value = value self.dataChanged.emit(index, index) return True else: return super(ConstraintCoordinatesModel, self).setData(index, value, role)
[docs]class ActiveOptimizationTab(OptimizationTab): """ Tab used in place of optimization tab in Transition State Search panel :cvar activeConstraintsToggled: A signal emitted when the active constraints check box is toggled :vartype activeConstraintsToggled: `PyQt5.QtCore.pyqtSignal` """ activeConstraintsToggled = QtCore.pyqtSignal(bool)
[docs] def setup(self): """Setup UI elements""" super().setup() self.ui.active_constraints_chk = QtWidgets.QCheckBox( "Set constraints as active constraints") self.ui.constraint_layout.addWidget(self.ui.active_constraints_chk) self.ui.active_constraints_chk.setEnabled(False) self.ui.active_constraints_chk.toggled.connect( self.activeConstraintsToggled.emit) self.ts_search_method = ActiveTransitionStateTab.SEARCH_STANDARD
[docs] def saveSettings(self, jag_input, eid=None): """ Save per-atom settings to Jaguar input. :param jag_input: A JaguarInput object to save settings to :type jag_input: `schrodinger.application.jaguar.input.JaguarInput` :param eid: the eid to save settings for, always None because Transition State Search panel uses a MultiStructureTab :type eid: str or None """ if self.ui.active_constraints_chk.isChecked(): for coord in self.model.coords: jag_input.setActiveCoord(coord.coordinate_type, coord.atom_indices) else: for coord in self.model.coords: jag_input.setConstraint(coord.coordinate_type, coord.atom_indices, coord.target_value)
[docs] def loadConstraintCoordinates(self, jag_input): """ Load constraint coordinates from Jaguar handle. :param jag_input: The Jaguar handle where tab settings are saved. :type jag_input: `schrodinger.application.jaguar.input.JaguarInput` """ super().loadConstraintCoordinates(jag_input) self.enableActiveChkIfConstraintsAdded() if jag_input.anyConstraintsActive(): self.ui.active_constraints_chk.setChecked(True) if not jag_input.allConstraintsActive(): msg = ("Found mix of active and non-active constraints. " "Setting all constraints to active") warnings.warn(JaguarSettingWarning(msg)) else: self.ui.active_constraints_chk.setChecked(False)
[docs] def enableActiveChkIfConstraintsAdded(self): """ Enable the active constraints check box if there are constraints added to the list or disable it if there are not. """ if self.ts_search_method == ActiveTransitionStateTab.SEARCH_STANDARD: self.ui.active_constraints_chk.setEnabled( bool(self.model.rowCount()))
[docs] def addCoordinate(self, st, atoms, coordinate_type, target_value=None): """ Add a coordinate and enable active checkbox if successfully added """ super().addCoordinate(st, atoms, coordinate_type, target_value) self.enableActiveChkIfConstraintsAdded()
[docs] def deleteAllRows(self): """ Delete all constraint rows and disable active checkbox """ super().deleteAllRows() self.enableActiveChkIfConstraintsAdded()
[docs] def deleteCurrentRow(self): """ Delete current row and disable active checkbox if no more rows remain """ super().deleteCurrentRow() self.enableActiveChkIfConstraintsAdded()
[docs] def onSearchMethodChanged(self, method_id): """ Enable or disable active constraints toggle depending on the search method selection in the Transition State tab. :param method_id: button id corresponding to a search method selected in the Transition State tab. :type method_id: int """ self.ts_search_method = method_id visible = method_id == ActiveTransitionStateTab.SEARCH_STANDARD self.ui.active_constraints_chk.setVisible(visible) with suppress_signals(self.ui.active_constraints_chk): if not visible: self.ui.active_constraints_chk.setChecked(False) self.enableActiveChkIfConstraintsAdded()
[docs]class NoCustomIACCGOptimizationTab(OptimizationTab): """ Subclass of OptimizationTab that does not set the iaccg keyword """ SETS_IACCG_CUSTOM = False