import schrodinger.structutils.analyze as analyze
import schrodinger.structutils.build as build
import schrodinger.structutils.smiles as smiles
import schrodinger.utils.sea as sea
from schrodinger.application.bioluminate import protein
from schrodinger.application.desmond import constants
from schrodinger.application.desmond.struc import get_reference_ct
PROTEIN_ASL = "(protein)"
MAX_RING_SIZE = 8
[docs]def removeAminoAcids(ligand_list):
"""
This function iterates over ligand structures in the given list
and removes those that have amino acid names in their pdb residue
name.
:param ligand_list: list of ligand structures
:type ligand_list: list
:return: a list of `Ligand` instances
:rtype: list
"""
AMINO_ACID_NAMES = (protein.Mutator.SUPPORTED_BUILD_RESIDUES +
["HID", "ARN", "ASH", "GLH", "LYN"])
new_list = []
for ligand in ligand_list:
if not ligand.st.atom[1].pdbres.strip() in AMINO_ACID_NAMES:
new_list.append(ligand)
return new_list
[docs]def getLigand(cms_st):
"""
This parses a CMS for the ligand to use.
:param cms_st: A CMS to find a ligand within
:type cms_st: cms.Cms object
:return: (ligand structure, ligand asl)
:rtype: (Structure, str)
"""
ligand_list = analyze.find_ligands(cms_st)
# only filter ligand list when it has more than 1 ligand
if len(ligand_list) > 1:
ligand_list = removeAminoAcids(ligand_list)
if len(ligand_list) == 0:
return None, None
ligand_st = ligand_list[0].st
ligand_asl = str(ligand_list[0].ligand_asl)
return ligand_st, ligand_asl
[docs]def getASLExcludingLigand(asl_type, protein_asl=PROTEIN_ASL, ligand_asl=''):
"""
This gives an ASL for a subsection of the protein without the ligand.
:param asl_type: Type of protein wanted, Heavy, Backbone, etc
:type asl_type: str
:param protein_asl: The ASL to describe the entire protein
:type protein_asl: str
:param ligand_asl: The ASL to describe the ligand
:type ligand_asl: str
:return: ASL for the protein component minus the ligand
:rtype: str
"""
if ligand_asl:
exclude_ligand = 'and not (%s)' % ligand_asl
else:
exclude_ligand = ''
types = {
'Heavy': "(%s and not (atom.ele H) %s)",
'Backbone': "((%s and backbone) and not (atom.ele H) %s)",
'C-Alpha': "((%s and backbone ) and ( atom.ptype ' CA ') %s)",
'All residues': "(%s %s)",
'Side chains': "(%s and sidechain %s)"
}
return types[asl_type] % (protein_asl, exclude_ligand)
[docs]def getRMSDKeywords(protein_asl, ligand_asl, ref_struct_fname=None, frame=0):
"""
Returns keywords for RMSD analysis of protein components.
:param protein_asl: The ASL to describe the entire protein
:type protein_asl: str
:param ligand_asl: The ASL to describe the ligand
:type ligand_asl: str or None
:param ref_struct_fname: Path to the structure to do the RMSD against
:type ref_struct_fname: None or `str`
:param frame: The frame to take the RMSD against, ignored if
ref_struct_fname!=None
:type frame: int
:return: Keyword(s) for calculation
:rtype: sea.Map
"""
types = ["Backbone", "Side chains", "C-Alpha", "Heavy"]
for rmsd_type in types:
asl = getASLExcludingLigand(rmsd_type, protein_asl, ligand_asl)
ark_kw = sea.Map()
ark_kw["RMSD"] = sea.Map()
ark_kw["RMSD"]["Unit"] = "Angstrom"
#Either use a reference frame, or a reference structure
if ref_struct_fname:
ark_kw["RMSD"]["Reference_Struct"] = ref_struct_fname
else:
ark_kw["RMSD"]["Frame"] = frame
ark_kw["RMSD"]["Type"] = "ASL"
ark_kw["RMSD"]["SelectionType"] = rmsd_type
ark_kw["RMSD"]["ASL"] = asl
ark_kw["RMSD"]["Panel"] = 'pl_interact_survey'
ark_kw["RMSD"]["Tab"] = 'pl_rmsd_tab'
if asl:
ark_kw["RMSD"]["ASL"] = asl
yield ark_kw
[docs]def getRMSDLigandKW(ligand_asl, fitby, ref_struct_fname=None, frame=0):
"""
Returns keywords for RMSD analysis of the ligand.
:param ligand_asl: The ASL to describe the ligand
:type ligand_asl: str
:param fitby: None or an ASL to describe what portion of the CMS to fit
:type fitby: None or str
:param ref_struct_fname: Path to the structure to do the RMSD against
:type ref_struct_fname: None or `str`
:param frame: The frame to take the RMSD against, ignored if
ref_struct_fname!=None
:type frame: int
"""
ark_kw = sea.Map()
ark_kw["RMSD"] = sea.Map()
ark_kw["RMSD"]["Unit"] = "Angstrom"
#Either use a reference frame, or a reference structure
if ref_struct_fname:
ark_kw["RMSD"]["Reference_Struct"] = ref_struct_fname
else:
ark_kw["RMSD"]["Frame"] = frame
ark_kw["RMSD"]["Type"] = "Ligand"
ark_kw["RMSD"]["SelectionType"] = "Ligand"
ark_kw["RMSD"]["Panel"] = 'pl_interact_survey'
ark_kw["RMSD"]["Tab"] = 'pl_rmsd_tab'
ark_kw["RMSD"]["UseSymmetry"] = 'yes'
ark_kw["RMSD"]["ASL"] = ligand_asl
if fitby:
ark_kw["RMSD"]["FitBy"] = fitby
return ark_kw
[docs]def getRMSFProtKeywords(protein_asl,
ligand_asl,
ref_struct_fname=None,
frame=0):
"""
Returns keywords for RMSF analysis of protein components.
:param protein_asl: The ASL to describe the entire protein
:type protein_asl: str
:param ligand_asl: The ASL to describe the ligand
:type ligand_asl: str
:param ref_struct_fname: A structure to do the RMSF against
:type ref_struct_fname: None or schrodinger.structure.Structure
:param frame: The frame to take the RMSF against, ignored if
ref_struct_fname!=None
:type frame: int
:return: Keyword(s) for calculation
:rtype: sea.Map
"""
types = ["Backbone", "Side chains", "C-Alpha", "Heavy"]
for rmsf_type in types:
asl = getASLExcludingLigand(rmsf_type, protein_asl, ligand_asl)
ark_kw = sea.Map()
ark_kw["RMSF"] = sea.Map()
ark_kw["RMSF"]["Unit"] = "Angstrom"
#Either use a reference frame, or a reference structure
if ref_struct_fname:
ark_kw["RMSF"]["Reference_Struct"] = ref_struct_fname
else:
ark_kw["RMSF"]["Frame"] = frame
#ark_kw["RMSF"]["FitBy"] = "backbone"
ark_kw["RMSF"]["FitBy"] = getASLExcludingLigand("Backbone", protein_asl,
ligand_asl)
ark_kw["RMSF"]["Type"] = "ASL"
ark_kw["RMSF"]["SelectionType"] = rmsf_type
ark_kw["RMSF"]["ASL"] = asl
ark_kw["RMSF"]["Panel"] = 'pl_interact_survey'
ark_kw["RMSF"]["Tab"] = 'p_rmsf_tab'
yield ark_kw
[docs]def getSSEProtKeywords(protein_asl, ligand_asl):
"""
Returns keywords for SSE analysis
:param protein_asl: The ASL to describe the entire protein
:type protein_asl: str
:param ligand_asl: The ASL to describe the ligand
:type ligand_asl: str
:return: Keyword(s) for calculation
:rtype: sea.Map
"""
# add secondary structure analysis for protein
ark_kw = sea.Map()
ark_kw["SecondaryStructure"] = sea.Map()
asl = getASLExcludingLigand("All residues", protein_asl, ligand_asl)
ark_kw["SecondaryStructure"]["Type"] = "ASL"
ark_kw["SecondaryStructure"]["SelectionType"] = asl
ark_kw["SecondaryStructure"]["ASL"] = asl
ark_kw["SecondaryStructure"]["Panel"] = "pl_interact_survey"
ark_kw["SecondaryStructure"]["Tab"] = "p_sse_tab"
ark_kw["SecondaryStructure"][
"Legend"] = "-1: NONE; 0: LOOP; 1: HELIX; 2: STRAND; 3:TURN"
yield ark_kw
[docs]def getRMSFLigandKW(fitby_asl, ligand_asl, ref_struct_fname=None, frame=0):
"""
Returns keywords for RMSF analysis of the ligand.
:param ligand_asl: The ASL to describe the ligand
:type ligand_asl: str
:param fitby: None or an ASL to describe what portion of the CMS to fit
:type fitby: None or str
:param ref_struct_fname: A structure to do the RMSF against
:type ref_struct_fname: None or schrodinger.structure.Structure
:param frame: The frame to take the RMSF against, ignored if
ref_struct_fname!=None
:type frame: int
"""
ark_kw = sea.Map()
ark_kw["RMSF"] = sea.Map()
ark_kw["RMSF"]["Unit"] = "Angstrom"
#Either use a reference frame, or a reference structure
if ref_struct_fname:
ark_kw["RMSF"]["Reference_Struct"] = ref_struct_fname
else:
ark_kw["RMSF"]["Frame"] = frame
ark_kw["RMSF"]["FitBy"] = fitby_asl
ark_kw["RMSF"]["ASL"] = ligand_asl
ark_kw["RMSF"]["Type"] = "ASL"
ark_kw["RMSF"]["Panel"] = 'pl_interact_survey'
ark_kw["RMSF"]["Tab"] = 'l_rmsf_tab'
return ark_kw
[docs]def getProtLigInterKW(protein_asl, ligand_asl, metal_asl=None):
"""
Returns keywords for PLI analysis
:param protein_asl: The ASL to describe the entire protein
:type protein_asl: str
:param ligand_asl: The ASL to describe the ligand
:type ligand_asl: str
:param metal_asl: The ASL to describe metals or ions.
If None, use all metals and ions in
the input structure.
:type metal_asl: str or None
"""
ark_kw = sea.Map()
ark_kw["ProtLigInter"] = sea.Map()
ark_kw["ProtLigInter"]["ASL"] = protein_asl
ark_kw["ProtLigInter"]["LigandASL"] = ligand_asl
if metal_asl is not None:
ark_kw["ProtLigInter"]["MetalASL"] = metal_asl
ark_kw["ProtLigInter"]["Panel"] = 'pl_interact_survey'
ark_kw["ProtLigInter"]["Tab"] = 'pl_inter_tab'
return ark_kw
[docs]def getSolubilityKeywords(molecule_asl):
"""
Returns keywords for analyzing solubility's sublimation leg.
Here we look at the environment of the molecule and its interactions
with it.
"""
ark_kw = sea.Map()
ark_kw['AmorphousCrystalInter'] = sea.Map()
ark_kw['AmorphousCrystalInter']['ASL'] = molecule_asl
return ark_kw
[docs]def get_idx(ligand_st, lig_idx):
"""
This will get the atoms index associated with an asl index
:param ligand_st : ligand structure
:type ligand_st : structure
:param lig_idx : ligand atom index
:type lig_idx : int
:return : atom_index of the asl selection for that atom
:rtype : atom_index
"""
if constants.ORIGINAL_INDEX in list(ligand_st.atom[lig_idx].property):
atom_index = ligand_st.atom[lig_idx].property[constants.ORIGINAL_INDEX]
elif 'i_i_internal_atom_index' in list(ligand_st.atom[lig_idx].property):
atom_index = ligand_st.atom[lig_idx].property['i_i_internal_atom_index']
#FIXME: what if both condition is False?
return atom_index
[docs]def sort_atoms(st, a_id, exclude_atom_id=None, for_fep=False):
"""
Extract atoms that are bonded to a_id atom (excluding the exclude_atom_id
atom) and returns a list of atoms in the order such that hydrogens are last
:param st: small molecule structure
:type st: structure
:param a_id: index of the atom whose bonded atoms you want to return
:type a_id: int
:param exclude_atom_id: remove that atom from the list
:type exclude_atom_id: int
:param for_fep: if this options is ture, then return only atoms that is
mapped to another atoms (contains i_fep_mapping prop)
:type for_fep: bool
:rtype: int
:return: The index of the first heavy atom a_id, that is bounded, and that
doesn't exclude_atom_id
"""
bonded_atoms = []
# sort atoms such that hydrogen and/or linear atoms appear last
for atom in st.atom[a_id].bonded_atoms:
if atom.index == exclude_atom_id:
continue
a_type = 1 if atom.atomic_number == 1 else 0
bond_order = st.getBond(st.atom[a_id], atom).order
if bond_order == 0:
continue
cm = sum([a.atomic_weight for a in atom.bonded_atoms])
angle = st.measure(exclude_atom_id, a_id,
atom.index) if exclude_atom_id else 0.0
# this is to make the algorithm to be less conformation dependant but
# we want to bias the selection away from linear atoms.
angle = angle if angle > 170. else 0.
bonded_atoms.append((a_type, bond_order, cm, angle, atom.index))
bonded_atoms = [atom_props[-1] for atom_props in sorted(bonded_atoms)]
if not for_fep:
return bonded_atoms[0]
# if for_fep, make sure to return the mapped atom
for ba in bonded_atoms:
if st.atom[ba].property.get(constants.FEP_MAPPING, 0):
return ba
return None
[docs]def get_rotatable_bonds(st):
"""
returns all rotatable bonds, defined as torsions. returns original atoms indeces.
:param st: structure of a ligand
:type st: structure
:rtype: list
:return: a list of four atoms that define a rotatable bond
"""
rb_atoms = []
for rb in analyze.rotatable_bonds_iterator(st, max_size=MAX_RING_SIZE):
a2, a3 = rb
a1 = sort_atoms(st, a2, a3)
a4 = sort_atoms(st, a3, a2)
b1 = st.atom[a1].property[constants.ORIGINAL_INDEX]
b2 = st.atom[a2].property[constants.ORIGINAL_INDEX]
b3 = st.atom[a3].property[constants.ORIGINAL_INDEX]
b4 = st.atom[a4].property[constants.ORIGINAL_INDEX]
rb_atoms.append([b1, b2, b3, b4])
return rb_atoms
[docs]def canonicalize_ligand(st):
"""
Use uSMILES to canonicalize the ligand structure, this is so we get the
order of the rotatable bonds(torsions) in the same order, regardless of
the atom order
:param st: structure of a ligand
:type st: structure
:rtype: structure
:return: a structure file with reordered atoms according to unique SMILES
"""
smiles_generator = smiles.SmilesGenerator(
smiles.STEREO_FROM_ANNOTATION_AND_GEOM, unique=True)
# get all heavy atoms and polar hydrogens
asl = '(not a.e H) or ( atom.ele H and not /C0-H0/ )'
heavy_polarH_list = analyze.evaluate_asl(st, asl)
new_st = st.extract(heavy_polarH_list)
# get a list of left over hydrogens
pol_h = [atom.index for atom in new_st.atom if atom.element == 'H']
smi, atom_list = smiles_generator.getSmilesAndMap(new_st)
# add the polar hydrogens to the end of the list
for h in pol_h:
if h not in atom_list:
atom_list.append(h)
return build.reorder_atoms(new_st, atom_list)
[docs]def getLigandPropsKeywords(ligand_asl,
calcRMSD,
ref_struct_fname=None,
frame=None):
"""
Returns keywords for ligand-specific analysis
* Intramolecular Hbonds
* Molecular Surface Area (Cannolly surface)
* Solvent Accessible Surface Area
* Polar Surface area
* Radius of Gyration
:param ligand_asl: The ASL to describe the ligand
:type ligand_asl: str
:param calcRMSD: Bool to also set up RMSD jobs
:type calcRMSD: bool
:param ref_struct_fname: path to the reference structure
:param frame: frame index
:type frame: `int`
:return: Keyword(s) for calculation
:rtype: sea.Map
"""
ark_kw = sea.Map()
ark_kw["LigandHBonds"] = sea.Map()
ark_kw["LigandHBonds"]["ASL1"] = ligand_asl
ark_kw["LigandHBonds"]["Name"] = 'Intramolecular Hydrogen Bonds'
ark_kw["LigandHBonds"]["Type"] = 'ASL'
ark_kw["LigandHBonds"]["Unit"] = 'Numb. of HBonds'
ark_kw["LigandHBonds"]["Panel"] = 'pl_interact_survey'
ark_kw["LigandHBonds"]["ReturnHBonds"] = 'True'
ark_kw["LigandHBonds"]["Tab"] = 'l_properties_tab'
yield ark_kw
ark_kw = sea.Map()
ark_kw["Molecular_Surface_Area"] = sea.Map()
ark_kw["Molecular_Surface_Area"]['ASL'] = ligand_asl
ark_kw["Molecular_Surface_Area"]['Grid_Spacing'] = 0.5
ark_kw["Molecular_Surface_Area"]["Unit"] = 'Angstrom^2'
ark_kw["Molecular_Surface_Area"]['Panel'] = 'pl_interact_survey'
ark_kw["Molecular_Surface_Area"]['Tab'] = 'l_properties_tab'
yield ark_kw
ark_kw = sea.Map()
ark_kw["SA_Surface_Area"] = sea.Map()
ark_kw["SA_Surface_Area"]['ASL'] = ligand_asl
# TODO: need a better definition to exclude FEP image
ions_asl = '(metals) or (metalloids)'
if 'protein' in ligand_asl:
exclude_asl = 'not ((%s) or (ions) or (water) or %s)' % (ligand_asl,
ions_asl)
else:
exclude_asl = 'not ((protein) or (%s) or (ions) or (water) or %s)' % \
(ligand_asl, ions_asl)
ark_kw["SA_Surface_Area"]['Exclude_ASL'] = exclude_asl
ark_kw["SA_Surface_Area"]['Resolution'] = 0.3
ark_kw["SA_Surface_Area"]["Unit"] = 'Angstrom^2'
ark_kw["SA_Surface_Area"]['Panel'] = 'pl_interact_survey'
ark_kw["SA_Surface_Area"]['Tab'] = 'l_properties_tab'
yield ark_kw
ark_kw = sea.Map()
ark_kw["Polar_Surface_Area"] = sea.Map()
ark_kw["Polar_Surface_Area"]['ASL'] = ligand_asl
ark_kw["Polar_Surface_Area"]['Resolution'] = 0.3
ark_kw["Polar_Surface_Area"]["Unit"] = 'Angstrom^2'
ark_kw["Polar_Surface_Area"]['Panel'] = 'pl_interact_survey'
ark_kw["Polar_Surface_Area"]['Tab'] = 'l_properties_tab'
yield ark_kw
ark_kw = sea.Map()
ark_kw["Rad_Gyration"] = sea.Map()
ark_kw["Rad_Gyration"]['ASL'] = ligand_asl
ark_kw["Rad_Gyration"]["Unit"] = 'Angstrom'
ark_kw["Rad_Gyration"]['Panel'] = 'pl_interact_survey'
ark_kw["Rad_Gyration"]['Tab'] = 'l_properties_tab'
yield ark_kw
if calcRMSD:
ark_kw = sea.Map()
ark_kw["RMSD"] = sea.Map()
ark_kw["RMSD"]["Unit"] = "Angstrom"
if ref_struct_fname:
ark_kw["RMSD"]["Reference_Struct"] = ref_struct_fname
else:
ark_kw["RMSD"]["Frame"] = frame
ark_kw["RMSD"]["Type"] = "Ligand"
ark_kw["RMSD"]["SelectionType"] = "Ligand"
ark_kw["RMSD"]["Panel"] = 'pl_interact_survey'
ark_kw["RMSD"]["Tab"] = 'l_properties_tab'
ark_kw["RMSD"]["UseSymmetry"] = 'yes'
ark_kw["RMSD"]["ASL"] = ligand_asl
yield ark_kw
def _getLoneTorsionFEP(lig_st, core_rb):
"""
This method returns Torsions/RB that are not in the core_rb.
"""
ret_torsions = []
for rb in analyze.rotatable_bonds_iterator(lig_st, max_size=MAX_RING_SIZE):
a2, a3 = rb
if (a2, a3) in core_rb or (a3, a2) in core_rb:
continue
a1 = sort_atoms(lig_st, a2, a3)
a4 = sort_atoms(lig_st, a3, a2)
ret_torsions.append((a1, a2, a3, a4))
return ret_torsions
[docs]def getFEPTorsionKeywords(lig1_st,
lig2_st,
lig1_asl,
lig2_asl,
fep_lambda=0,
is_covalent=False):
"""
For a pair for ligands/fragments that, whose atoms are mapped, return sea
object of torsions for each rotatable bond.
"""
def get_ark_tor(lig_st, rb, asl, fep_pair=None):
fsys_ct_rb = lig_to_fullsys_aid(rb, lig_st)
# Use the analysis reference coords if present
ref_lig_st = get_reference_ct(lig_st)
ref_lig_st = get_reference_ct(
ref_lig_st,
prop_names=constants.ANALYSIS_REFERENCE_COORD_PROPERTIES)
ark_kw = sea.Map()
ark_kw["Torsion"] = sea.Map()
ark_kw["Torsion"]["a1"] = fsys_ct_rb[0]
ark_kw["Torsion"]["a2"] = fsys_ct_rb[1]
ark_kw["Torsion"]["a3"] = fsys_ct_rb[2]
ark_kw["Torsion"]["a4"] = fsys_ct_rb[3]
ark_kw["Torsion"]["Unit"] = "Degrees"
ark_kw["Torsion"]["Panel"] = 'pl_interact_survey'
ark_kw["Torsion"]["Tab"] = 'l_torsions_tab'
ark_kw["Torsion"]["LigandASL"] = asl
ark_kw["Torsion"]["StartingConformation"] = ref_lig_st.measure(*rb)
if fep_pair is not None:
ark_kw["Torsion"]["FEP_pair"] = fep_pair
return ark_kw
core1, core2, lone1, lone2 = _getFEPTorsion(lig1_st, lig2_st, is_covalent)
ret_list = sea.List()
if fep_lambda == 0:
for irb, rb in enumerate(core1, start=1):
ret_list.append(get_ark_tor(lig1_st, rb, lig1_asl, irb))
for rb in lone1:
ret_list.append(get_ark_tor(lig1_st, rb, lig1_asl))
else:
for irb, rb in enumerate(core2, start=1):
ret_list.append(get_ark_tor(lig2_st, rb, lig2_asl, irb))
for rb in lone2:
ret_list.append(get_ark_tor(lig2_st, rb, lig2_asl))
return ret_list
def _valid_mapped_fep_atom(atom):
"""
Check if atom is alchemically mapped
"""
return atom.property.get(constants.FEP_MAPPING, 0) != 0
def _getFEPTorsion(lig1_st, lig2_st, is_covalent):
"""
This method generates torsions that represent rotatable bonds by taking two
ligands, that are alchemically-mapped. The torsions generated are mapped
between the two ligands. CoreRBs are the ones where the dihedrals are
mapped, loneRBs are those that are not mapped.
:param is_covalent: if the covalent ligand is used, the provided structures
will be a subset -- sidechain residue + ligand
:type is_covalent: bool
"""
core1_rb = []
core2_rb = []
cpx1_frag1_map = None
if is_covalent:
cpx1_frag1_map = {
atom.property[constants.ORIGINAL_INDEX]: atom.index
for atom in lig1_st.atom
}
# Add mapping information to lig1_st
for atom in lig2_st.atom:
m_idx = atom.property.get(constants.FEP_MAPPING, 0)
if m_idx:
m_idx = m_idx if not cpx1_frag1_map else cpx1_frag1_map[m_idx]
lig1_st.atom[m_idx].property[constants.FEP_MAPPING] = atom.index
# get RBs that are common to lig1 and lig2
for rb in analyze.rotatable_bonds_iterator(lig1_st, max_size=MAX_RING_SIZE):
a2, a3 = rb
if not (_valid_mapped_fep_atom(lig1_st.atom[a2]) and
_valid_mapped_fep_atom(lig1_st.atom[a3])):
continue
a2_2 = lig1_st.atom[a2].property[constants.FEP_MAPPING]
a3_2 = lig1_st.atom[a3].property[constants.FEP_MAPPING]
bond_2 = lig2_st.getBond(lig2_st.atom[a2_2], lig2_st.atom[a3_2])
# Check that the rotatable bond is also in lig2_st (DESMOND-10109)
if bond_2 and analyze.is_bond_rotatable(bond_2):
core1_rb.append((a2, a3))
core2_rb.append((a2_2, a3_2))
# get torsions in core for both ligands
core_tors1 = []
core_tors2 = []
for rb1, rb2 in zip(core1_rb[:], core2_rb[:]):
a2_rb1, a3_rb1 = rb1
a1_rb1 = sort_atoms(lig1_st, a2_rb1, a3_rb1, True)
a4_rb1 = sort_atoms(lig1_st, a3_rb1, a2_rb1, True)
if not (a1_rb1 and a4_rb1):
core1_rb.remove(rb1)
core2_rb.remove(rb2)
continue
a2_rb2, a3_rb2 = rb2
a1_rb2 = lig1_st.atom[a1_rb1].property[constants.FEP_MAPPING]
a4_rb2 = lig1_st.atom[a4_rb1].property[constants.FEP_MAPPING]
if not (a1_rb2 and a4_rb2):
core1_rb.remove(rb1)
core2_rb.remove(rb2)
continue
core_tors1.append((a1_rb1, a2_rb1, a3_rb1, a4_rb1))
core_tors2.append((a1_rb2, a2_rb2, a3_rb2, a4_rb2))
lone_tors1 = _getLoneTorsionFEP(lig1_st, core1_rb)
lone_tors2 = _getLoneTorsionFEP(lig2_st, core2_rb)
return core_tors1, core_tors2, lone_tors1, lone_tors2
[docs]def lig_to_fullsys_aid(torsion_list, st):
"""
Convert ligand atom IDs to full-system atom IDs
"""
a, b, c, d = torsion_list
return [
st.atom[a].property[constants.ORIGINAL_INDEX],
st.atom[b].property[constants.ORIGINAL_INDEX],
st.atom[c].property[constants.ORIGINAL_INDEX],
st.atom[d].property[constants.ORIGINAL_INDEX]
]
[docs]def getTorsionKeywords(ligand_st, ligand_asl):
"""
Returns keywords for ligand torsion analysis
:param ligand_st: Structure of the ligand
:type ligand_st: schrodinger.structure.Structure
:param ligand_asl: The ASL to describe the ligand
:type ligand_asl: str
:return: Keyword(s) for calculation
:rtype: sea.Map
"""
new_ligand_st = canonicalize_ligand(ligand_st)
rb_list = get_rotatable_bonds(new_ligand_st)
for rb in rb_list:
ark_kw = sea.Map()
ark_kw["Torsion"] = sea.Map()
ark_kw["Torsion"]["a1"] = rb[0]
ark_kw["Torsion"]["a2"] = rb[1]
ark_kw["Torsion"]["a3"] = rb[2]
ark_kw["Torsion"]["a4"] = rb[3]
ark_kw["Torsion"]["Unit"] = "Degrees"
ark_kw["Torsion"]["Panel"] = 'pl_interact_survey'
ark_kw["Torsion"]["Tab"] = 'l_torsions_tab'
ark_kw["Torsion"]["LigandASL"] = ligand_asl
yield ark_kw
[docs]def getPPIKeywords(protein_asl):
"""
Returns keywords for PLI analysis
:param protein_asl: The ASL to describe the entire protein
:type protein_asl: str
"""
ark_kw = sea.Map()
ark_kw["ProtProtInter"] = sea.Map()
ark_kw["ProtProtInter"]["ASL"] = protein_asl
return ark_kw
[docs]def getPLISKWList(cms_st,
ligand_st,
ligand_asl,
ref_struct_fname,
frame=0,
protein_asl=PROTEIN_ASL,
want_rmsd=True,
want_prmsf=True,
want_lrmsf=True,
want_pli=True,
want_ltorsion=True,
want_lprops=True,
want_ppi=True,
protein_fep=False,
metal_asl=None):
"""
Generate the entire keyword list for all PLI calculations. Also returns
the ligand_asl used in those keywords.
:param ligand_st: Structure of the ligand
:type ligand_st: schrodinger.structure.Structure
:param ligand_asl: The ASL to describe the ligand
:type ligand_asl: str
:param ref_struct_fname: Path to the structure to do the RMSD against
:type ref_struct_fname: None or `str`
:param frame: The frame to take the RMSF/RMSD against, ignored if
ref_struct_fname!=None
:type frame: int
:param protein_asl: The ASL to describe the entire protein
:type protein_asl: str
:param want_rmsd: Whether to add RMSD keywords
:type want_rmsd: bool
:param want_prmsf: Whether to add RMSF keywords for protein
:type want_prmsf: bool
:param want_lrmsf: Whether to add an RMSF ligand keyword
:type want_lrmsf: bool
:param want_pli: Whether to add a PLI keyword
:type want_pli: bool
:param want_ppi: Whether to add a PPI keyword
:type want_ppi: bool
:param want_ltorsion: Whether to add a ligand torsions keyword
:type want_ltorsion: bool
:param want_lprops: Whether to add ligand properties keyword
:type want_lprops: bool
:param protein_fep: Whether the input system is a protein_fep job
:type protein_fep: bool
:param metal_asl: The ASL to describe metals or ions.
If None, use '(ions) or (metals) or (metalloids)'.
:type metal_asl: str or None
:return: Keyword(s) for calculation
:rtype: sea.List
"""
lst = sea.List()
lig_asl = '' if protein_fep else ligand_asl
if want_rmsd:
for ark_kw in getRMSDKeywords(protein_asl,
lig_asl,
ref_struct_fname,
frame=frame):
lst.append(ark_kw)
if ligand_asl:
for fitby in [None, protein_asl]:
ark_kw = getRMSDLigandKW(ligand_asl,
fitby,
ref_struct_fname,
frame=frame)
lst.append(ark_kw)
if want_prmsf:
for ark_kw in getSSEProtKeywords(protein_asl, lig_asl):
lst.append(ark_kw)
for ark_kw in getRMSFProtKeywords(protein_asl,
lig_asl,
ref_struct_fname,
frame=frame):
lst.append(ark_kw)
if want_lrmsf:
ark_kw = getRMSFLigandKW(ligand_asl + " and not atom.e H",
ligand_asl + " and not atom.e H",
ref_struct_fname)
lst.append(ark_kw)
if protein_asl:
ark_kw = getRMSFLigandKW(protein_asl,
ligand_asl + " and not atom.e H",
ref_struct_fname)
lst.append(ark_kw)
if want_pli:
lst.append(
getProtLigInterKW(protein_asl, ligand_asl, metal_asl=metal_asl))
if want_ppi:
lst.append(getPPIKeywords(protein_asl))
if want_ltorsion:
for ark_kw in getTorsionKeywords(ligand_st, ligand_asl):
lst.append(ark_kw)
if want_lprops:
# if want_rmsd is not selected, then ligand RMSD will not be
# calculated. So bool 'calcRMSD' is passed for RMSD calculation.
calcRMSD = not want_rmsd
for ark_kw in getLigandPropsKeywords(ligand_asl, calcRMSD,
ref_struct_fname, frame):
lst.append(ark_kw)
return lst