Source code for schrodinger.application.jaguar.macro_pka_validation
"""
Macro-pKa keywords input validation and specialized Exceptions
"""
# Contributors: Mark A. Watson
import schrodinger.application.jaguar.workflow_validation as wv
import schrodinger.application.jaguar.macro_pka_constants as constants
from schrodinger.application.jaguar.utils import get_total_charge
from schrodinger.application.jaguar.exceptions import JaguarRuntimeError
PROT_CHARGES = [1, 0]
DEPROT_CHARGES = [0, -1]
[docs]def check_conflicts(kwd, all_keywords):
"""
Raise Exception if keyword value is inconsistent with the
other keywords. This is done in an adhoc case-by-case way.
:type kwd: WorkflowKeyword
:param kwd: reference Macro-pKa keyword
:type all_keywords: dict of WorkflowKeyword instances indexed by name
:param all_keywords: all the other Macro-pKa keywords set
:raise WorkflowKeywordConflictError if conflicting values found.
:return: True otherwise
"""
# Add any known conflicts here...
allowed_charges = [PROT_CHARGES, DEPROT_CHARGES]
conflicting_keys = ['protonate', 'deprotonate']
for ikey, key in enumerate(conflicting_keys):
if kwd.name == key and kwd.value:
other_key = conflicting_keys[ikey - 1]
val = False
if all_keywords[other_key].value != val:
raise wv.WorkflowKeywordConflictError(kwd.name, other_key, val)
other_key = 'relative_charges'
val = allowed_charges[ikey]
if all_keywords[other_key].value != all_keywords[other_key].default:
raise wv.WorkflowKeywordConflictError(kwd.name, other_key, val)
# General test for mutually exclusive options...
non_default = (1 if all_keywords[key].value != all_keywords[key].default
else 0 for key in constants.MUTUALLY_EXCLUSIVE_1)
if sum(non_default) > 1:
msg = "The following keywords are mutually exclusive;"
msg += f" please adjust input file:\n{constants.MUTUALLY_EXCLUSIVE_1}"
raise wv.WorkflowKeywordConflictError(msg=msg)
# Process any known aliases...
_process_aliases(kwd, all_keywords)
return True
def _process_aliases(kwd, all_keywords):
"""
Handle alias keywords which map to the same input attribute.
:type kwd: WorkflowKeyword
:param kwd: reference Macro-pKa keyword
:type all_keywords: dict of WorkflowKeyword instances indexed by name
:param all_keywords: all the other Macro-pKa keywords set
"""
# Add any known aliases here...
if kwd.name == 'protonate':
if kwd.value == True:
all_keywords['relative_charges'].value = PROT_CHARGES
elif kwd.name == 'deprotonate':
if kwd.value == True:
all_keywords['relative_charges'].value = DEPROT_CHARGES
[docs]def validate_structures(spec):
"""
Perform a check to ensure that charge/multiplicity are consistent.
:type spec: MacroKaInput
:param spec: Macro-pKa input instance
:raise: WorkflowConservationError if any test fails.
"""
st = spec.getInputMolecule()
if st is None:
raise JaguarRuntimeError("No input molecule specified!")
charge = get_total_charge(st)
# There is no way to set multiplicity by the user; the backend assume 1
mult = 1
_validate_charges(st, charge, mult)
def _validate_charges(st, charge, mult):
"""
Validate a structure.
:type st: `structure.Structure`
:param st: structure instance
:type charge: int
:param charge: structure total charge
:type mult: int
:param mult: specified multiplicity
:raise: WorkflowConservationError if the specification is invalid.
"""
wv.estate_is_physical(st, charge, mult)
wv.charge_is_consistent(st, charge)