6 from ost
import settings
17 from ost
import bindings
23 """Scorer specific for a reference/model pair
25 Finds best possible binding site representation of reference in model given
26 lDDT score. Uses :class:`ost.mol.alg.chain_mapping.ChainMapper` to deal with
29 :param reference: Reference structure
30 :type reference: :class:`ost.mol.EntityView`/:class:`ost.mol.EntityHandle`
31 :param model: Model structure
32 :type model: :class:`ost.mol.EntityView`/:class:`ost.mol.EntityHandle`
33 :param residue_number_alignment: Passed to ChainMapper constructor
34 :type residue_number_alignment: :class:`bool`
37 residue_number_alignment=
False):
39 resnum_alignments=residue_number_alignment)
40 self.
ref = self.chain_mapper.target
43 def ScoreBS(self, ligand, radius = 4.0, lddt_radius=10.0):
44 """Computes binding site lDDT score given *ligand*. Best possible
45 binding site representation is selected by lDDT but other scores such as
46 CA based RMSD and GDT are computed too and returned.
48 :param ligand: Defines the scored binding site, i.e. provides positions
49 to perform proximity search
50 :type ligand: r'((Residue)|(Chain)|(Entity))((View)|(Handle))'
51 :param radius: Reference residues with any atom position within *radius*
52 of *ligand* consitute the scored binding site
53 :type radius: :class:`float`
54 :param lddt_radius: Passed as *inclusion_radius* to
55 :class:`ost.mol.alg.lddt.lDDTScorer`
56 :type lddt_radius: :class:`float`
57 :returns: Object of type :class:`ost.mol.alg.chain_mapping.ReprResult`
58 containing all atom lDDT score and mapping information.
59 None if no representation could be found.
63 ref_residues_hashes = set()
64 for ligand_at
in ligand.atoms:
65 close_atoms = self.ref.FindWithin(ligand_at.GetPos(), radius)
66 for close_at
in close_atoms:
67 ref_res = close_at.GetResidue()
68 h = ref_res.handle.GetHashCode()
69 if h
not in ref_residues_hashes:
70 ref_residues_hashes.add(h)
75 ref_bs = self.ref.CreateEmptyView()
76 for ch
in self.ref.chains:
78 if r.handle.GetHashCode()
in ref_residues_hashes:
79 ref_bs.AddResidue(r, mol.ViewAddFlag.INCLUDE_ALL)
82 bs_repr = self.chain_mapper.GetRepr(ref_bs, self.
mdl,
83 inclusion_radius = lddt_radius)
91 """ Helper class to access the various scores available from ost.mol.alg
93 Deals with structure cleanup, chain mapping, interface identification etc.
94 Intermediate results are available as attributes.
96 :param model: Model structure - a deep copy is available as :attr:`model`.
97 Additionally, :func:`ost.mol.alg.Molck` using *molck_settings*
99 :type model: :class:`ost.mol.EntityHandle`/:class:`ost.mol.EntityView`
100 :param target: Target structure - a deep copy is available as :attr:`target`.
101 Additionally, :func:`ost.mol.alg.Molck` using *molck_settings*
103 :type target: :class:`ost.mol.EntityHandle`/:class:`ost.mol.EntityView`
104 :param resnum_alignments: Whether alignments between chemically equivalent
105 chains in *model* and *target* can be computed
106 based on residue numbers. This can be assumed in
107 benchmarking setups such as CAMEO/CASP.
108 :type resnum_alignments: :class:`bool`
109 :param molck_settings: Settings used for Molck on *model* and *target*, if
110 set to None, a default object is constructed by
111 setting everything except rm_zero_occ_atoms and
113 :class:`ost.mol.alg.MolckSettings` constructor.
114 :type molck_settings: :class:`ost.mol.alg.MolckSettings`
115 :param cad_score_exec: Explicit path to voronota-cadscore executable from
116 voronota installation from
117 https://github.com/kliment-olechnovic/voronota. If
118 not given, voronota-cadscore must be in PATH if any
119 of the CAD score related attributes is requested.
120 :type cad_score_exec: :class:`str`
121 :param custom_mapping: Provide custom chain mapping between *model* and
122 *target*. Dictionary with target chain names as key
123 and model chain names as value.
124 :type custom_mapping: :class:`dict`
125 :param usalign_exec: Explicit path to USalign executable used to compute
126 TM-score. If not given, TM-score will be computed
127 with OpenStructure internal copy of USalign code.
128 :type usalign_exec: :class:`str`
129 :param lddt_no_stereochecks: Whether to compute lDDT without stereochemistry
131 :type lddt_no_stereochecks: :class:`bool`
132 :param n_max_naive: Parameter for chain mapping. If the number of possible
133 mappings is <= *n_max_naive*, the full
134 mapping solution space is enumerated to find the
135 the optimum. A heuristic is used otherwise. The default
136 of 40320 corresponds to an octamer (8! = 40320).
137 A structure with stoichiometry A6B2 would be
139 :type n_max_naive: :class:`int`
140 :param oum: Override USalign Mapping. Inject mapping of :class:`Scorer`
141 object into USalign to compute TM-score. Experimental feature
143 :type oum: :class:`bool`
144 :param min_pep_length: Relevant parameter if short peptides are involved in
145 scoring. Minimum peptide length for a chain in the
146 target structure to be considered in chain mapping.
147 The chain mapping algorithm first performs an all vs.
148 all pairwise sequence alignment to identify \"equal\"
149 chains within the target structure. We go for simple
150 sequence identity there. Short sequences can be
151 problematic as they may produce high sequence identity
152 alignments by pure chance.
153 :type min_pep_length: :class:`int`
154 :param min_nuc_length: Relevant parameter if short nucleotides are involved
155 in scoring. Minimum nucleotide length for a chain in
156 the target structure to be considered in chain
157 mapping. The chain mapping algorithm first performs
158 an all vs. all pairwise sequence alignment to
159 identify \"equal\" chains within the target
160 structure. We go for simple sequence identity there.
161 Short sequences can be problematic as they may
162 produce high sequence identity alignments by pure
164 :type min_nuc_length: :class:`int`
166 def __init__(self, model, target, resnum_alignments=False,
167 molck_settings =
None, cad_score_exec =
None,
168 custom_mapping=
None, usalign_exec =
None,
169 lddt_no_stereochecks=
False, n_max_naive=40320,
170 oum=
False, min_pep_length = 6, min_nuc_length = 4):
178 self.
_model = self._model_orig.Copy()
183 self.
_target = self._target_orig.Copy()
185 if molck_settings
is None:
190 rm_zero_occ_atoms=
False,
194 Molck(self.
_model, conop.GetDefaultLib(), molck_settings)
195 Molck(self.
_target, conop.GetDefaultLib(), molck_settings)
196 self.
_model = self._model.Select(
"peptide=True or nucleotide=True")
197 self.
_target = self._target.Select(
"peptide=True or nucleotide=True")
200 for ch
in self._model.chains:
201 if ch.GetName().strip() ==
"":
202 raise RuntimeError(
"Model chains must have valid chain names")
203 if ch.GetName().strip() ==
"'" or ch.GetName().strip() ==
'"':
204 raise RuntimeError(
"Model chains cannot be named with quote signs (' or \"\")")
207 for ch
in self._target.chains:
208 if ch.GetName().strip() ==
"":
209 raise RuntimeError(
"Target chains must have valid chain names")
210 if ch.GetName().strip() ==
"'" or ch.GetName().strip() ==
'"':
211 raise RuntimeError(
"Target chains cannot be named with quote signs (' or \"\")")
213 if resnum_alignments:
217 for ch
in self._model.chains:
218 ins_codes = [r.GetNumber().GetInsCode()
for r
in ch.residues]
219 if len(set(ins_codes)) != 1
or ins_codes[0] !=
'\0':
220 raise RuntimeError(
"Residue numbers in each model chain "
221 "must not contain insertion codes if "
222 "resnum_alignments are enabled")
223 nums = [r.GetNumber().GetNum()
for r
in ch.residues]
224 if not all(i < j
for i, j
in zip(nums, nums[1:])):
225 raise RuntimeError(
"Residue numbers in each model chain "
226 "must be strictly increasing if "
227 "resnum_alignments are enabled")
229 for ch
in self._target.chains:
230 ins_codes = [r.GetNumber().GetInsCode()
for r
in ch.residues]
231 if len(set(ins_codes)) != 1
or ins_codes[0] !=
'\0':
232 raise RuntimeError(
"Residue numbers in each target chain "
233 "must not contain insertion codes if "
234 "resnum_alignments are enabled")
235 nums = [r.GetNumber().GetNum()
for r
in ch.residues]
236 if not all(i < j
for i, j
in zip(nums, nums[1:])):
237 raise RuntimeError(
"Residue numbers in each target chain "
238 "must be strictly increasing if "
239 "resnum_alignments are enabled")
241 if usalign_exec
is not None:
242 if not os.path.exists(usalign_exec):
243 raise RuntimeError(f
"USalign exec ({usalign_exec}) "
245 if not os.access(usalign_exec, os.X_OK):
246 raise RuntimeError(f
"USalign exec ({usalign_exec}) "
247 f
"is not executable")
344 if custom_mapping
is not None:
349 """ Model with Molck cleanup
351 :type: :class:`ost.mol.EntityHandle`
357 """ The original model passed at object construction
359 :type: :class:`ost.mol.EntityHandle`/:class:`ost.mol.EntityView`
365 """ Target with Molck cleanup
367 :type: :class:`ost.mol.EntityHandle`
373 """ The original target passed at object construction
375 :type: :class:`ost.mol.EntityHandle`/:class:`ost.mol.EntityView`
381 """ Alignments of :attr:`model`/:attr:`target` chains
383 Alignments for each pair of chains mapped in :attr:`mapping`.
384 First sequence is target sequence, second sequence the model sequence.
386 :type: :class:`list` of :class:`ost.seq.AlignmentHandle`
388 if self.
_aln is None:
394 """ Stereochecked equivalent of :attr:`aln`
396 The alignments may differ, as stereochecks potentially remove residues
398 :type: :class:`list` of :class:`ost.seq.AlignmentHandle`
406 """ Alignments of :attr:`model_orig`/:attr:`target_orig` chains
408 Selects for peptide and nucleotide residues before sequence
409 extraction. Includes residues that would be removed by molck in
410 structure preprocessing.
412 :type: :class:`list` of :class:`ost.seq.AlignmentHandle`
420 """ View of :attr:`~model` that has stereochemistry checks applied
422 First, a selection for peptide/nucleotide residues is performed,
423 secondly peptide sidechains with stereochemical irregularities are
424 removed (full residue if backbone atoms are involved). Irregularities
425 are clashes or bond lengths/angles more than 12 standard deviations
426 from expected values.
428 :type: :class:`ost.mol.EntityView`
436 """ Clashing model atoms
438 :type: :class:`list` of :class:`ost.mol.alg.stereochemistry.ClashInfo`
446 """ Model bonds with unexpected stereochemistry
448 :type: :class:`list` of
449 :class:`ost.mol.alg.stereochemistry.BondViolationInfo`
457 """ Model angles with unexpected stereochemistry
459 :type: :class:`list` of
460 :class:`ost.mol.alg.stereochemistry.AngleViolationInfo`
468 """ Same as :attr:`~stereochecked_model` for :attr:`~target`
470 :type: :class:`ost.mol.EntityView`
478 """ Clashing target atoms
480 :type: :class:`list` of :class:`ost.mol.alg.stereochemistry.ClashInfo`
488 """ Target bonds with unexpected stereochemistry
490 :type: :class:`list` of
491 :class:`ost.mol.alg.stereochemistry.BondViolationInfo`
499 """ Target angles with unexpected stereochemistry
501 :type: :class:`list` of
502 :class:`ost.mol.alg.stereochemistry.AngleViolationInfo`
510 """ Chain mapper object for given :attr:`target`
512 :type: :class:`ost.mol.alg.chain_mapping.ChainMapper`
524 """ Full chain mapping result for :attr:`target`/:attr:`model`
526 :type: :class:`ost.mol.alg.chain_mapping.MappingResult`
530 self.chain_mapper.GetMapping(self.
model,
536 """ Interface residues in :attr:`~model`
538 Thats all residues having a contact with at least one residue from
539 another chain (CB-CB distance <= 8A, CA in case of Glycine)
541 :type: :class:`dict` with chain names as key and and :class:`list`
542 with residue numbers of the respective interface residues.
551 """ Same as :attr:`~model_interface_residues` for :attr:`~target`
553 :type: :class:`dict` with chain names as key and and :class:`list`
554 with residue numbers of the respective interface residues.
563 """ lDDT scorer for :attr:`~stereochecked_target` (default parameters)
565 :type: :class:`ost.mol.alg.lddt.lDDTScorer`
576 """ Backbone only lDDT scorer for :attr:`~target`
578 No stereochecks applied for bb only lDDT which considers CA atoms
579 for peptides and C3' atoms for nucleotides.
581 :type: :class:`ost.mol.alg.lddt.lDDTScorer`
589 """ QS scorer constructed from :attr:`~mapping`
591 The scorer object is constructed with default parameters and relates to
592 :attr:`~model` and :attr:`~target` (no stereochecks).
594 :type: :class:`ost.mol.alg.qsscore.QSScorer`
609 """ Global lDDT score in range [0.0, 1.0]
611 Computed based on :attr:`~stereochecked_model`. In case of oligomers,
612 :attr:`~mapping` is used.
614 :type: :class:`float`
616 if self.
_lddt is None:
622 """ Per residue lDDT scores in range [0.0, 1.0]
624 Computed based on :attr:`~stereochecked_model` but scores for all
625 residues in :attr:`~model` are reported. If a residue has been removed
626 by stereochemistry checks, the respective score is set to 0.0. If a
627 residue is not covered by the target or is in a chain skipped by the
628 chain mapping procedure (happens for super short chains), the respective
629 score is set to None. In case of oligomers, :attr:`~mapping` is used.
639 """ Backbone only global lDDT score in range [0.0, 1.0]
641 Computed based on :attr:`~model` on backbone atoms only. This is CA for
642 peptides and C3' for nucleotides. No stereochecks are performed. In case
643 of oligomers, :attr:`~mapping` is used.
645 :type: :class:`float`
653 """ Backbone only per residue lDDT scores in range [0.0, 1.0]
655 Computed based on :attr:`~model` on backbone atoms only. This is CA for
656 peptides and C3' for nucleotides. No stereochecks are performed. If a
657 residue is not covered by the target or is in a chain skipped by the
658 chain mapping procedure (happens for super short chains), the respective
659 score is set to None. In case of oligomers, :attr:`~mapping` is used.
671 Computed based on :attr:`model` using :attr:`mapping`
673 :type: :class:`float`
681 """ Global QS-score - only computed on aligned residues
683 Computed based on :attr:`model` using :attr:`mapping`. The QS-score
684 computation only considers contacts between residues with a mapping
685 between target and model. As a result, the score won't be lowered in
686 case of additional chains/residues in any of the structures.
688 :type: :class:`float`
696 """ Interfaces in :attr:`~target` with non-zero contribution to
697 :attr:`~qs_global`/:attr:`~qs_best`
699 Chain names are lexicographically sorted.
701 :type: :class:`list` of :class:`tuple` with 2 elements each:
712 """ Interfaces in :attr:`~model` with non-zero contribution to
713 :attr:`~qs_global`/:attr:`~qs_best`
715 Chain names are lexicographically sorted.
717 :type: :class:`list` of :class:`tuple` with 2 elements each:
729 """ Interfaces in :attr:`~qs_target_interfaces` that can be mapped
732 Target chain names are lexicographically sorted.
734 :type: :class:`list` of :class:`tuple` with 4 elements each:
735 (trg_ch1, trg_ch2, mdl_ch1, mdl_ch2)
739 flat_mapping = self.mapping.GetFlatMapping()
741 if i[0]
in flat_mapping
and i[1]
in flat_mapping:
742 self._qs_interfaces.append((i[0], i[1],
749 """ QS-score for each interface in :attr:`qs_interfaces`
751 :type: :class:`list` of :class:`float`
759 """ QS-score for each interface in :attr:`qs_interfaces`
761 Only computed on aligned residues
763 :type: :class:`list` of :class:`float`
773 A contact is a pair or residues from distinct chains that have
774 a minimal heavy atom distance < 5A. Contacts are specified as
775 :class:`tuple` with two strings in format:
776 <cname>.<rnum>.<ins_code>
778 :type: :class:`list` of :class:`tuple`
794 """ Interfaces in :class:`target` which have at least one contact
796 Contact as defined in :attr:`~native_contacts`,
797 chain names are lexicographically sorted.
799 :type: :class:`list` of :class:`tuple` with 2 elements each
803 tmp = self.contact_scorer.cent1.interacting_chains
804 tmp = [(min(x[0],x[1]), max(x[0],x[1]))
for x
in tmp]
810 """ Interfaces in :class:`model` which have at least one contact
812 Contact as defined in :attr:`~native_contacts`,
813 chain names are lexicographically sorted.
815 :type: :class:`list` of :class:`tuple` with 2 elements each
819 tmp = self.contact_scorer.cent2.interacting_chains
820 tmp = [(min(x[0],x[1]), max(x[0],x[1]))
for x
in tmp]
826 """ Fraction of model contacts that are also present in target
828 :type: :class:`float`
836 """ Fraction of target contacts that are correctly reproduced in model
838 :type: :class:`float`
846 """ ICS (Interface Contact Similarity) score
848 Combination of :attr:`~ics_precision` and :attr:`~ics_recall`
851 :type: :class:`float`
853 if self.
_ics is None:
859 """ Per-interface ICS precision
861 :attr:`~ics_precision` for each interface in
862 :attr:`~contact_target_interfaces`
864 :type: :class:`list` of :class:`float`
873 """ Per-interface ICS recall
875 :attr:`~ics_recall` for each interface in
876 :attr:`~contact_target_interfaces`
878 :type: :class:`list` of :class:`float`
886 """ Per-interface ICS (Interface Contact Similarity) score
888 :attr:`~ics` for each interface in
889 :attr:`~contact_target_interfaces`
891 :type: :class:`float`
901 """ Fraction of model interface residues that are also interface
904 :type: :class:`float`
912 """ Fraction of target interface residues that are also interface
915 :type: :class:`float`
923 """ IPS (Interface Patch Similarity) score
925 Jaccard coefficient of interface residues in target and their mapped
926 counterparts in model
928 :type: :class:`float`
930 if self.
_ips is None:
936 """ Per-interface IPS precision
938 :attr:`~ips_precision` for each interface in
939 :attr:`~contact_target_interfaces`
941 :type: :class:`list` of :class:`float`
950 """ Per-interface IPS recall
952 :attr:`~ips_recall` for each interface in
953 :attr:`~contact_target_interfaces`
955 :type: :class:`list` of :class:`float`
963 """ Per-interface IPS (Interface Patch Similarity) score
965 :attr:`~ips` for each interface in
966 :attr:`~contact_target_interfaces`
968 :type: :class:`list` of :class:`float`
977 """ Interfaces in :attr:`target` that are relevant for DockQ
979 In principle a subset of :attr:`~contact_target_interfaces` that only
980 contains peptide sequences. Chain names are lexicographically sorted.
982 :type: :class:`list` of :class:`tuple` with 2 elements each:
987 pep_seqs = set([s.GetName()
for s
in self.chain_mapper.polypep_seqs])
989 if interface[0]
in pep_seqs
and interface[1]
in pep_seqs:
990 self._dockq_target_interfaces.append(interface)
995 """ Interfaces in :attr:`dockq_target_interfaces` that can be mapped
998 Target chain names are lexicographically sorted
1000 :type: :class:`list` of :class:`tuple` with 4 elements each:
1001 (trg_ch1, trg_ch2, mdl_ch1, mdl_ch2)
1005 flat_mapping = self.mapping.GetFlatMapping()
1007 if i[0]
in flat_mapping
and i[1]
in flat_mapping:
1008 self._dockq_interfaces.append((i[0], i[1],
1010 flat_mapping[i[1]]))
1015 """ DockQ scores for interfaces in :attr:`~dockq_interfaces`
1017 :class:`list` of :class:`float`
1025 """ fnat scores for interfaces in :attr:`~dockq_interfaces`
1027 fnat: Fraction of native contacts that are also present in model
1029 :class:`list` of :class:`float`
1031 if self.
_fnat is None:
1037 """ N native contacts for interfaces in :attr:`~dockq_interfaces`
1039 :class:`list` of :class:`int`
1041 if self.
_nnat is None:
1047 """ N model contacts for interfaces in :attr:`~dockq_interfaces`
1049 :class:`list` of :class:`int`
1051 if self.
_nmdl is None:
1057 """ fnonnat scores for interfaces in :attr:`~dockq_interfaces`
1059 fnat: Fraction of model contacts that are not present in target
1061 :class:`list` of :class:`float`
1069 """ irmsd scores for interfaces in :attr:`~dockq_interfaces`
1071 irmsd: RMSD of interface (RMSD computed on N, CA, C, O atoms) which
1072 consists of each residue that has at least one heavy atom within 10A of
1075 :class:`list` of :class:`float`
1083 """ lrmsd scores for interfaces in :attr:`~dockq_interfaces`
1085 lrmsd: The interfaces are superposed based on the receptor (rigid
1086 min RMSD superposition) and RMSD for the ligand is reported.
1087 Superposition and RMSD are based on N, CA, C and O positions,
1088 receptor is the chain contributing to the interface with more
1091 :class:`list` of :class:`float`
1099 """ Average of DockQ scores in :attr:`dockq_scores`
1101 In its original implementation, DockQ only operates on single
1102 interfaces. Thus the requirement to combine scores for higher order
1105 :type: :class:`float`
1113 """ Same as :attr:`dockq_ave`, weighted by native contacts
1115 :type: :class:`float`
1123 """ Same as :attr:`~dockq_ave` but penalizing for missing interfaces
1125 Interfaces that are not covered in model are added as 0.0
1126 in average computation.
1128 :type: :class:`float`
1136 """ Same as :attr:`~dockq_ave_full`, but weighted
1138 Interfaces that are not covered in model are added as 0.0 in
1139 average computations and the respective weights are derived from
1140 number of contacts in respective target interface.
1148 """ Mapped representative positions in target
1150 Thats CA positions for peptide residues and C3' positions for
1151 nucleotides. Has same length as :attr:`~mapped_model_pos` and mapping
1152 is based on :attr:`~mapping`.
1154 :type: :class:`ost.geom.Vec3List`
1162 """ Mapped representative positions in model
1164 Thats CA positions for peptide residues and C3' positions for
1165 nucleotides. Has same length as :attr:`~mapped_target_pos` and mapping
1166 is based on :attr:`~mapping`.
1168 :type: :class:`ost.geom.Vec3List`
1176 """ :attr:`~mapped_model_pos` with :attr:`~transform` applied
1178 :type: :class:`ost.geom.Vec3List`
1183 self._transformed_mapped_model_pos.ApplyTransform(self.
transform)
1188 """ Number of target residues which have no mapping to model
1198 """ Transform: :attr:`~mapped_model_pos` onto :attr:`~mapped_target_pos`
1200 Computed using Kabsch minimal rmsd algorithm
1202 :type: :class:`ost.geom.Mat4`
1215 """ GDT with thresholds: 8.0A, 4.0A, 2.0A and 1.0A
1217 Computed on :attr:`~transformed_mapped_model_pos` and
1218 :attr:`mapped_target_pos`
1220 :type: :class:`float`
1228 self.
_gdtts = float(n) / n_full
1235 """ GDT with thresholds: 4.0A, 2.0A, 1.0A and 0.5A
1237 Computed on :attr:`~transformed_mapped_model_pos` and
1238 :attr:`mapped_target_pos`
1240 :type: :class:`float`
1248 self.
_gdtha = float(n) / n_full
1257 Computed on :attr:`~transformed_mapped_model_pos` and
1258 :attr:`mapped_target_pos`
1260 :type: :class:`float`
1262 if self.
_rmsd is None:
1269 """ The global CAD atom-atom (AA) score
1271 Computed based on :attr:`~model`. In case of oligomers, :attr:`~mapping`
1274 :type: :class:`float`
1282 """ The per-residue CAD atom-atom (AA) scores
1284 Computed based on :attr:`~model`. In case of oligomers, :attr:`~mapping`
1287 :type: :class:`dict`
1295 """ Patch QS-scores for each residue in :attr:`model_interface_residues`
1297 Representative patches for each residue r in chain c are computed as
1300 * mdl_patch_one: All residues in c with CB (CA for GLY) positions within
1301 8A of r and within 12A of residues from any other chain.
1302 * mdl_patch_two: Closest residue x to r in any other chain gets
1303 identified. Patch is then constructed by selecting all residues from
1304 any other chain within 8A of x and within 12A from any residue in c.
1305 * trg_patch_one: Chain name and residue number based mapping from
1307 * trg_patch_two: Chain name and residue number based mapping from
1310 Results are stored in the same manner as
1311 :attr:`model_interface_residues`, with corresponding scores instead of
1312 residue numbers. Scores for residues which are not
1313 :class:`mol.ChemType.AMINOACIDS` are set to None. Additionally,
1314 interface patches are derived from :attr:`model`. If they contain
1315 residues which are not covered by :attr:`target`, the score is set to
1318 :type: :class:`dict` with chain names as key and and :class:`list`
1319 with scores of the respective interface residues.
1327 """ Same as :attr:`patch_qs` but for DockQ scores
1335 """ TM-score computed with USalign
1337 USalign executable can be specified with usalign_exec kwarg at Scorer
1338 construction, an OpenStructure internal copy of the USalign code is
1341 :type: :class:`float`
1349 """ Mapping computed with USalign
1351 Dictionary with target chain names as key and model chain names as
1352 values. No guarantee that all chains are mapped. USalign executable
1353 can be specified with usalign_exec kwarg at Scorer construction, an
1354 OpenStructure internal copy of the USalign code is used otherwise.
1356 :type: :class:`dict`
1362 def _aln_helper(self, target, model):
1367 for ch
in target.chains:
1368 cname = ch.GetName()
1369 s =
''.join([r.one_letter_code
for r
in ch.residues])
1370 s = seq.CreateSequence(ch.GetName(), s)
1371 s.AttachView(target.Select(f
"cname='{cname}'"))
1372 trg_seqs[ch.GetName()] = s
1374 for ch
in model.chains:
1375 cname = ch.GetName()
1376 s =
''.join([r.one_letter_code
for r
in ch.residues])
1377 s = seq.CreateSequence(cname, s)
1378 s.AttachView(model.Select(f
"cname='{cname}'"))
1379 mdl_seqs[ch.GetName()] = s
1382 trg_pep_chains = [s.GetName()
for s
in self.chain_mapper.polypep_seqs]
1383 trg_nuc_chains = [s.GetName()
for s
in self.chain_mapper.polynuc_seqs]
1384 trg_pep_chains = set(trg_pep_chains)
1385 trg_nuc_chains = set(trg_nuc_chains)
1386 for trg_ch, mdl_ch
in self.mapping.GetFlatMapping().items():
1387 if mdl_ch
in mdl_seqs
and trg_ch
in trg_seqs:
1388 if trg_ch
in trg_pep_chains:
1389 stype = mol.ChemType.AMINOACIDS
1390 elif trg_ch
in trg_nuc_chains:
1391 stype = mol.ChemType.NUCLEOTIDES
1393 raise RuntimeError(
"Chain name inconsistency... ask "
1395 alns.append(self.chain_mapper.Align(trg_seqs[trg_ch],
1398 alns[-1].AttachView(0, trg_seqs[trg_ch].GetAttachedView())
1399 alns[-1].AttachView(1, mdl_seqs[mdl_ch].GetAttachedView())
1402 def _compute_pepnuc_aln(self):
1403 query =
"peptide=true or nucleotide=true"
1404 pep_nuc_target = self.target_orig.Select(query)
1405 pep_nuc_model = self.model_orig.Select(query)
1408 def _compute_aln(self):
1411 def _compute_stereochecked_aln(self):
1415 def _compute_lddt(self):
1417 flat_mapping = self.mapping.GetFlatMapping(mdl_as_key=
True)
1420 stereochecked_alns = dict()
1422 mdl_seq = aln.GetSequence(1)
1423 stereochecked_alns[mdl_seq.name] = aln
1425 for aln
in self.
aln:
1426 mdl_seq = aln.GetSequence(1)
1427 alns[mdl_seq.name] = aln
1434 lddt_chain_mapping = dict()
1435 for mdl_ch, trg_ch
in flat_mapping.items():
1437 lddt_chain_mapping[mdl_ch] = trg_ch
1438 lddt_score = self.lddt_scorer.lDDT(self.
model,
1439 chain_mapping = lddt_chain_mapping,
1440 residue_mapping = alns,
1441 check_resnames=
False,
1442 local_lddt_prop=
"lddt")[0]
1444 for r
in self.model.residues:
1445 cname = r.GetChain().GetName()
1446 if cname
not in local_lddt:
1447 local_lddt[cname] = dict()
1448 if r.HasProp(
"lddt"):
1449 score = round(r.GetFloatProp(
"lddt"), 3)
1450 local_lddt[cname][r.GetNumber()] = score
1454 local_lddt[cname][r.GetNumber()] =
None
1457 lddt_chain_mapping = dict()
1458 for mdl_ch, trg_ch
in flat_mapping.items():
1459 if mdl_ch
in stereochecked_alns:
1460 lddt_chain_mapping[mdl_ch] = trg_ch
1462 chain_mapping = lddt_chain_mapping,
1463 residue_mapping = stereochecked_alns,
1464 check_resnames=
False,
1465 local_lddt_prop=
"lddt")[0]
1467 for r
in self.model.residues:
1468 cname = r.GetChain().GetName()
1469 if cname
not in local_lddt:
1470 local_lddt[cname] = dict()
1471 if r.HasProp(
"lddt"):
1472 score = round(r.GetFloatProp(
"lddt"), 3)
1473 local_lddt[cname][r.GetNumber()] = score
1476 mdl_res = self.stereochecked_model.FindResidue(cname, r.GetNumber())
1477 if mdl_res.IsValid():
1480 local_lddt[cname][r.GetNumber()] =
None
1487 if cname
in flat_mapping:
1488 for col
in alns[cname]:
1489 if col[0] !=
'-' and col[1] !=
'-':
1490 if col.GetResidue(1).number == r.number:
1491 trg_r = col.GetResidue(0)
1494 local_lddt[cname][r.GetNumber()] =
None
1496 local_lddt[cname][r.GetNumber()] = 0.0
1498 self.
_lddt = lddt_score
1501 def _compute_bb_lddt(self):
1505 for aln
in self.
aln:
1506 mdl_seq = aln.GetSequence(1)
1507 alns[mdl_seq.name] = aln
1510 flat_mapping = self.mapping.GetFlatMapping(mdl_as_key=
True)
1511 lddt_chain_mapping = dict()
1512 for mdl_ch, trg_ch
in flat_mapping.items():
1514 lddt_chain_mapping[mdl_ch] = trg_ch
1516 lddt_score = self.bb_lddt_scorer.lDDT(self.
model,
1517 chain_mapping = lddt_chain_mapping,
1518 residue_mapping = alns,
1519 check_resnames=
False,
1520 local_lddt_prop=
"bb_lddt")[0]
1522 for r
in self.model.residues:
1523 cname = r.GetChain().GetName()
1524 if cname
not in local_lddt:
1525 local_lddt[cname] = dict()
1526 if r.HasProp(
"bb_lddt"):
1527 score = round(r.GetFloatProp(
"bb_lddt"), 3)
1528 local_lddt[cname][r.GetNumber()] = score
1532 local_lddt[cname][r.GetNumber()] =
None
1537 def _compute_qs(self):
1538 qs_score_result = self.qs_scorer.Score(self.mapping.mapping)
1540 self.
_qs_best = qs_score_result.QS_best
1542 def _compute_per_interface_qs_scores(self):
1547 trg_ch1 = interface[0]
1548 trg_ch2 = interface[1]
1549 mdl_ch1 = interface[2]
1550 mdl_ch2 = interface[3]
1551 qs_res = self.qs_scorer.ScoreInterface(trg_ch1, trg_ch2,
1553 self._per_interface_qs_best.append(qs_res.QS_best)
1554 self._per_interface_qs_global.append(qs_res.QS_global)
1556 def _compute_ics_scores(self):
1557 contact_scorer_res = self.contact_scorer.ScoreICS(self.mapping.mapping)
1560 self.
_ics = contact_scorer_res.ics
1564 flat_mapping = self.mapping.GetFlatMapping()
1566 trg_ch1 = trg_int[0]
1567 trg_ch2 = trg_int[1]
1568 if trg_ch1
in flat_mapping
and trg_ch2
in flat_mapping:
1569 mdl_ch1 = flat_mapping[trg_ch1]
1570 mdl_ch2 = flat_mapping[trg_ch2]
1571 res = self.contact_scorer.ScoreICSInterface(trg_ch1, trg_ch2,
1573 self._per_interface_ics_precision.append(res.precision)
1574 self._per_interface_ics_recall.append(res.recall)
1575 self._per_interface_ics.append(res.ics)
1577 self._per_interface_ics_precision.append(
None)
1578 self._per_interface_ics_recall.append(
None)
1579 self._per_interface_ics.append(
None)
1581 def _compute_ips_scores(self):
1582 contact_scorer_res = self.contact_scorer.ScoreIPS(self.mapping.mapping)
1585 self.
_ips = contact_scorer_res.ips
1590 flat_mapping = self.mapping.GetFlatMapping()
1592 trg_ch1 = trg_int[0]
1593 trg_ch2 = trg_int[1]
1594 if trg_ch1
in flat_mapping
and trg_ch2
in flat_mapping:
1595 mdl_ch1 = flat_mapping[trg_ch1]
1596 mdl_ch2 = flat_mapping[trg_ch2]
1597 res = self.contact_scorer.ScoreIPSInterface(trg_ch1, trg_ch2,
1599 self._per_interface_ips_precision.append(res.precision)
1600 self._per_interface_ips_recall.append(res.recall)
1601 self._per_interface_ips.append(res.ips)
1603 self._per_interface_ips_precision.append(
None)
1604 self._per_interface_ips_recall.append(
None)
1605 self._per_interface_ips.append(
None)
1607 def _compute_dockq_scores(self):
1618 for aln
in self.
aln:
1619 trg_s = aln.GetSequence(0)
1620 mdl_s = aln.GetSequence(1)
1621 dockq_alns[(trg_s.GetName(), mdl_s.GetName())] = aln
1624 trg_ch1 = interface[0]
1625 trg_ch2 = interface[1]
1626 mdl_ch1 = interface[2]
1627 mdl_ch2 = interface[3]
1628 aln1 = dockq_alns[(trg_ch1, mdl_ch1)]
1629 aln2 = dockq_alns[(trg_ch2, mdl_ch2)]
1630 res = dockq.DockQ(self.
model, self.
target, mdl_ch1, mdl_ch2,
1631 trg_ch1, trg_ch2, ch1_aln=aln1,
1633 self._fnat.append(res[
"fnat"])
1634 self._fnonnat.append(res[
"fnonnat"])
1635 self._irmsd.append(res[
"irmsd"])
1636 self._lrmsd.append(res[
"lrmsd"])
1637 self._dockq_scores.append(res[
"DockQ"])
1638 self._nnat.append(res[
"nnat"])
1639 self._nmdl.append(res[
"nmdl"])
1644 not_covered_counts = list()
1647 if interface
not in proc_trg_interfaces:
1651 trg_ch1 = interface[0]
1652 trg_ch2 = interface[1]
1654 trg_ch1, trg_ch2, trg_ch1, trg_ch2)
1655 not_covered_counts.append(res[
"nnat"])
1662 weights = np.array(self.
_nnat)
1667 self.
_dockq_wave = np.sum(np.multiply(weights/np.sum(weights), scores))
1668 scores = np.append(scores, [0.0]*len(not_covered_counts))
1669 weights = np.append(weights, not_covered_counts)
1677 def _extract_mapped_pos(self):
1681 processed_trg_chains = set()
1682 for trg_ch, mdl_ch
in self.mapping.GetFlatMapping().items():
1683 processed_trg_chains.add(trg_ch)
1684 aln = self.mapping.alns[(trg_ch, mdl_ch)]
1686 if col[0] !=
'-' and col[1] !=
'-':
1687 trg_res = col.GetResidue(0)
1688 mdl_res = col.GetResidue(1)
1689 trg_at = trg_res.FindAtom(
"CA")
1690 mdl_at = mdl_res.FindAtom(
"CA")
1691 if not trg_at.IsValid():
1692 trg_at = trg_res.FindAtom(
"C3'")
1693 if not mdl_at.IsValid():
1694 mdl_at = mdl_res.FindAtom(
"C3'")
1695 self._mapped_target_pos.append(trg_at.GetPos())
1696 self._mapped_model_pos.append(mdl_at.GetPos())
1700 for ch
in self.mapping.target.chains:
1701 if ch.GetName()
not in processed_trg_chains:
1704 def _compute_cad_score(self):
1706 raise RuntimeError(
"CAD score computations rely on residue numbers "
1707 "that are consistent between target and model "
1708 "chains, i.e. only work if resnum_alignments "
1709 "is True at Scorer construction.")
1712 settings.Locate(
"voronota-cadscore",
1714 except Exception
as e:
1715 raise RuntimeError(
"voronota-cadscore must be in PATH for CAD "
1716 "score scoring")
from e
1717 cad_bin_dir = os.path.dirname(cad_score_exec)
1718 m = self.mapping.GetFlatMapping(mdl_as_key=
True)
1719 cad_result = cadscore.CADScore(self.
model, self.
target,
1723 cad_bin_path=cad_bin_dir,
1727 for r
in self.model.residues:
1728 cname = r.GetChain().GetName()
1729 if cname
not in local_cad:
1730 local_cad[cname] = dict()
1731 if r.HasProp(
"localcad"):
1732 score = round(r.GetFloatProp(
"localcad"), 3)
1733 local_cad[cname][r.GetNumber()] = score
1735 local_cad[cname][r.GetNumber()] =
None
1740 def _get_repr_view(self, ent):
1741 """ Returns view with representative peptide atoms => CB, CA for GLY
1743 Ensures that each residue has exactly one atom with assertions
1745 :param ent: Entity for which you want the representative view
1746 :param ent: :class:`ost.mol.EntityHandle`/:class:`ost.mol.EntityView`
1747 :returns: :class:`ost.mol.EntityView` derived from ent
1749 repr_ent = ent.Select(
"(aname=\"CB\" or (rname=\"GLY\" and aname=\"CA\"))")
1750 for r
in repr_ent.residues:
1751 assert(len(r.atoms) == 1)
1754 def _get_interface_residues(self, ent):
1755 """ Get interface residues
1757 Thats all residues having a contact with at least one residue from another
1758 chain (CB-CB distance <= 8A, CA in case of Glycine)
1760 :param ent: Model for which to extract interface residues
1761 :type ent: :class:`ost.mol.EntityView`
1762 :returns: :class:`dict` with chain names as key and and :class:`list`
1763 with residue numbers of the respective interface residues.
1767 result = {ch.GetName(): list()
for ch
in ent.chains}
1768 for ch
in ent.chains:
1769 cname = ch.GetName()
1770 sel = repr_ent.Select(f
"(cname='{cname}' and 8 <> [cname!='{cname}'])")
1771 result[cname] = [r.GetNumber()
for r
in sel.residues]
1774 def _do_stereochecks(self):
1775 """ Perform stereochemistry checks on model and target
1777 data = stereochemistry.GetDefaultStereoData()
1778 l_data = stereochemistry.GetDefaultStereoLinkData()
1780 a, b, c, d = stereochemistry.StereoCheck(self.
model, stereo_data = data,
1781 stereo_link_data = l_data)
1787 a, b, c, d = stereochemistry.StereoCheck(self.
target, stereo_data = data,
1788 stereo_link_data = l_data)
1795 def _get_interface_patches(self, mdl_ch, mdl_rnum):
1796 """ Select interface patches representative for specified residue
1798 The patches for specified residue r in chain c are selected as follows:
1800 * mdl_patch_one: All residues in c with CB (CA for GLY) positions within 8A
1801 of r and within 12A of residues from any other chain.
1802 * mdl_patch_two: Closest residue x to r in any other chain gets identified.
1803 Patch is then constructed by selecting all residues from any other chain
1804 within 8A of x and within 12A from any residue in c.
1805 * trg_patch_one: Chain name and residue number based mapping from
1807 * trg_patch_two: Chain name and residue number based mapping from
1810 :param mdl_ch: Name of chain in *self.model* of residue of interest
1811 :type mdl_ch: :class:`str`
1812 :param mdl_rnum: Residue number of residue of interest
1813 :type mdl_rnum: :class:`ost.mol.ResNum`
1814 :returns: Tuple with 5 elements: 1) :class:`bool` flag whether all residues
1815 in *mdl* patches are covered in *trg* 2) mtl_patch_one
1816 3) mdl_patch_two 4) trg_patch_one 5) trg_patch_two
1819 repr_mdl = self.
_get_repr_view(self.model.Select(
"peptide=true"))
1822 r = self.model.FindResidue(mdl_ch, mdl_rnum)
1824 raise RuntimeError(f
"Cannot find residue {mdl_rnum} in chain {mdl_ch}")
1825 if r.GetName() ==
"GLY":
1826 at = r.FindAtom(
"CA")
1828 at = r.FindAtom(
"CB")
1829 if not at.IsValid():
1830 raise RuntimeError(
"Cannot find interface views for res without CB/CA")
1837 q1 = f
"(cname='{mdl_ch}' and 8 <> {{{r_pos[0]},{r_pos[1]},{r_pos[2]}}})"
1839 q2 = f
"(12 <> [cname!={mdl_ch}])"
1840 mdl_patch_one = self.model.CreateEmptyView()
1841 sel = repr_mdl.Select(
" and ".join([q1, q2]))
1842 for r
in sel.residues:
1843 mdl_r = self.model.FindResidue(r.GetChain().GetName(), r.GetNumber())
1844 mdl_patch_one.AddResidue(mdl_r, mol.ViewAddFlag.INCLUDE_ALL)
1850 sel = repr_mdl.Select(f
"(cname!='{mdl_ch}')")
1851 close_stuff = sel.FindWithin(r_pos, 8)
1854 for close_at
in close_stuff:
1857 min_pos = close_at.GetPos()
1861 q1 = f
"(cname!='{mdl_ch}' and 8 <> {{{min_pos[0]},{min_pos[1]},{min_pos[2]}}})"
1863 q2 = f
"(12 <> [cname='{mdl_ch}'])"
1864 mdl_patch_two = self.model.CreateEmptyView()
1865 sel = repr_mdl.Select(
" and ".join([q1, q2]))
1866 for r
in sel.residues:
1867 mdl_r = self.model.FindResidue(r.GetChain().GetName(), r.GetNumber())
1868 mdl_patch_two.AddResidue(mdl_r, mol.ViewAddFlag.INCLUDE_ALL)
1871 flat_mapping = self.mapping.GetFlatMapping(mdl_as_key=
True)
1872 full_trg_coverage =
True
1873 trg_patch_one = self.target.CreateEmptyView()
1874 for r
in mdl_patch_one.residues:
1876 mdl_cname = r.GetChain().GetName()
1877 if mdl_cname
in flat_mapping:
1878 aln = self.mapping.alns[(flat_mapping[mdl_cname], mdl_cname)]
1880 if col[0] !=
'-' and col[1] !=
'-':
1881 if col.GetResidue(1).GetNumber() == r.GetNumber():
1882 trg_r = col.GetResidue(0)
1884 if trg_r
is not None:
1885 trg_patch_one.AddResidue(trg_r.handle,
1886 mol.ViewAddFlag.INCLUDE_ALL)
1888 full_trg_coverage =
False
1890 trg_patch_two = self.target.CreateEmptyView()
1891 for r
in mdl_patch_two.residues:
1893 mdl_cname = r.GetChain().GetName()
1894 if mdl_cname
in flat_mapping:
1895 aln = self.mapping.alns[(flat_mapping[mdl_cname], mdl_cname)]
1897 if col[0] !=
'-' and col[1] !=
'-':
1898 if col.GetResidue(1).GetNumber() == r.GetNumber():
1899 trg_r = col.GetResidue(0)
1901 if trg_r
is not None:
1902 trg_patch_two.AddResidue(trg_r.handle,
1903 mol.ViewAddFlag.INCLUDE_ALL)
1905 full_trg_coverage =
False
1907 return (full_trg_coverage, mdl_patch_one, mdl_patch_two,
1908 trg_patch_one, trg_patch_two)
1910 def _compute_patchqs_scores(self):
1912 for cname, rnums
in self.model_interface_residues.items():
1916 r = self.model.FindResidue(cname, rnum)
1917 if r.IsValid()
and r.GetChemType() == mol.ChemType.AMINOACIDS:
1918 full_trg_coverage, mdl_patch_one, mdl_patch_two, \
1919 trg_patch_one, trg_patch_two = \
1921 if full_trg_coverage:
1922 score = self.
_patchqs(mdl_patch_one, mdl_patch_two,
1923 trg_patch_one, trg_patch_two)
1924 scores.append(score)
1927 def _compute_patchdockq_scores(self):
1929 for cname, rnums
in self.model_interface_residues.items():
1933 r = self.model.FindResidue(cname, rnum)
1934 if r.IsValid()
and r.GetChemType() == mol.ChemType.AMINOACIDS:
1935 full_trg_coverage, mdl_patch_one, mdl_patch_two, \
1936 trg_patch_one, trg_patch_two = \
1938 if full_trg_coverage:
1939 score = self.
_patchdockq(mdl_patch_one, mdl_patch_two,
1940 trg_patch_one, trg_patch_two)
1941 scores.append(score)
1944 def _patchqs(self, mdl_patch_one, mdl_patch_two, trg_patch_one, trg_patch_two):
1945 """ Score interface residue patches with QS-score
1947 In detail: Construct two entities with two chains each. First chain
1948 consists of residues from <x>_patch_one and second chain consists of
1949 <x>_patch_two. The returned score is the QS-score between the two
1952 :param mdl_patch_one: Interface patch representing scored residue
1953 :type mdl_patch_one: :class:`ost.mol.EntityView`
1954 :param mdl_patch_two: Interface patch representing scored residue
1955 :type mdl_patch_two: :class:`ost.mol.EntityView`
1956 :param trg_patch_one: Interface patch representing scored residue
1957 :type trg_patch_one: :class:`ost.mol.EntityView`
1958 :param trg_patch_two: Interface patch representing scored residue
1959 :type trg_patch_two: :class:`ost.mol.EntityView`
1960 :returns: PatchQS score
1965 alnA = seq.CreateAlignment()
1966 s =
''.join([r.one_letter_code
for r
in mdl_patch_one.residues])
1967 alnA.AddSequence(seq.CreateSequence(
"A", s))
1968 s =
''.join([r.one_letter_code
for r
in trg_patch_one.residues])
1969 alnA.AddSequence(seq.CreateSequence(
"A", s))
1971 alnB = seq.CreateAlignment()
1972 s =
''.join([r.one_letter_code
for r
in mdl_patch_two.residues])
1973 alnB.AddSequence(seq.CreateSequence(
"B", s))
1974 s =
''.join([r.one_letter_code
for r
in trg_patch_two.residues])
1975 alnB.AddSequence(seq.CreateSequence(
"B", s))
1976 alns = {(
"A",
"A"): alnA, (
"B",
"B"): alnB}
1978 scorer =
QSScorer(qs_ent_mdl, [[
"A"], [
"B"]], qs_ent_trg, alns)
1979 score_result = scorer.Score([[
"A"], [
"B"]])
1981 return score_result.QS_global
1983 def _patchdockq(self, mdl_patch_one, mdl_patch_two, trg_patch_one,
1985 """ Score interface residue patches with DockQ
1987 In detail: Construct two entities with two chains each. First chain
1988 consists of residues from <x>_patch_one and second chain consists of
1989 <x>_patch_two. The returned score is the QS-score between the two
1992 :param mdl_patch_one: Interface patch representing scored residue
1993 :type mdl_patch_one: :class:`ost.mol.EntityView`
1994 :param mdl_patch_two: Interface patch representing scored residue
1995 :type mdl_patch_two: :class:`ost.mol.EntityView`
1996 :param trg_patch_one: Interface patch representing scored residue
1997 :type trg_patch_one: :class:`ost.mol.EntityView`
1998 :param trg_patch_two: Interface patch representing scored residue
1999 :type trg_patch_two: :class:`ost.mol.EntityView`
2000 :returns: DockQ score
2004 dockq_result = dockq.DockQ(t, m,
"A",
"B",
"A",
"B")
2005 if dockq_result[
"nnat"] > 0:
2006 return dockq_result[
"DockQ"]
2009 def _qs_ent_from_patches(self, patch_one, patch_two):
2010 """ Constructs Entity with two chains named "A" and "B""
2012 Blindly adds all residues from *patch_one* to chain A and residues from
2013 patch_two to chain B.
2015 ent = mol.CreateEntity()
2017 added_ch = ed.InsertChain(
"A")
2018 for r
in patch_one.residues:
2019 added_r = ed.AppendResidue(added_ch, r.GetName())
2020 added_r.SetChemClass(str(r.GetChemClass()))
2022 ed.InsertAtom(added_r, a.handle)
2023 added_ch = ed.InsertChain(
"B")
2024 for r
in patch_two.residues:
2025 added_r = ed.AppendResidue(added_ch, r.GetName())
2026 added_r.SetChemClass(str(r.GetChemClass()))
2028 ed.InsertAtom(added_r, a.handle)
2031 def _set_custom_mapping(self, mapping):
2032 """ sets self._mapping with a full blown MappingResult object
2034 :param mapping: mapping with trg chains as key and mdl ch as values
2035 :type mapping: :class:`dict`
2039 chem_mapping, chem_group_alns, mdl = \
2040 chain_mapper.GetChemMapping(self.
model)
2045 if len(mapping) != len(set(mapping.keys())):
2046 raise RuntimeError(f
"Expect unique trg chain names in mapping. Got "
2047 f
"{mapping.keys()}")
2048 if len(mapping) != len(set(mapping.values())):
2049 raise RuntimeError(f
"Expect unique mdl chain names in mapping. Got "
2050 f
"{mapping.values()}")
2052 trg_chains = set([ch.GetName()
for ch
in chain_mapper.target.chains])
2053 mdl_chains = set([ch.GetName()
for ch
in mdl.chains])
2054 for k,v
in mapping.items():
2055 if k
not in trg_chains:
2056 raise RuntimeError(f
"Target chain \"{k}\" is not available "
2057 f
"in target processed for chain mapping "
2059 if v
not in mdl_chains:
2060 raise RuntimeError(f
"Model chain \"{v}\" is not available "
2061 f
"in model processed for chain mapping "
2064 for trg_ch, mdl_ch
in mapping.items():
2065 trg_group_idx =
None
2066 mdl_group_idx =
None
2067 for idx, group
in enumerate(chain_mapper.chem_groups):
2071 for idx, group
in enumerate(chem_mapping):
2075 if trg_group_idx
is None or mdl_group_idx
is None:
2076 raise RuntimeError(
"Could not establish a valid chem grouping "
2077 "of chain names provided in custom mapping.")
2079 if trg_group_idx != mdl_group_idx:
2080 raise RuntimeError(f
"Chem group mismatch in custom mapping: "
2081 f
"target chain \"{trg_ch}\" groups with the "
2082 f
"following chemically equivalent target "
2084 f
"{chain_mapper.chem_groups[trg_group_idx]} "
2085 f
"but model chain \"{mdl_ch}\" maps to the "
2086 f
"following target chains: "
2087 f
"{chain_mapper.chem_groups[mdl_group_idx]}")
2089 pairs = set([(trg_ch, mdl_ch)
for trg_ch, mdl_ch
in mapping.items()])
2091 chain_mapping._GetRefMdlAlns(chain_mapper.chem_groups,
2092 chain_mapper.chem_group_alignments,
2098 final_mapping = list()
2099 for ref_chains
in chain_mapper.chem_groups:
2100 mapped_mdl_chains = list()
2101 for ref_ch
in ref_chains:
2102 if ref_ch
in mapping:
2103 mapped_mdl_chains.append(mapping[ref_ch])
2105 mapped_mdl_chains.append(
None)
2106 final_mapping.append(mapped_mdl_chains)
2109 for ref_group, mdl_group
in zip(chain_mapper.chem_groups,
2111 for ref_ch, mdl_ch
in zip(ref_group, mdl_group):
2112 if ref_ch
is not None and mdl_ch
is not None:
2113 aln = ref_mdl_alns[(ref_ch, mdl_ch)]
2114 trg_view = chain_mapper.target.Select(f
"cname='{ref_ch}'")
2115 mdl_view = mdl.Select(f
"cname='{mdl_ch}'")
2116 aln.AttachView(0, trg_view)
2117 aln.AttachView(1, mdl_view)
2118 alns[(ref_ch, mdl_ch)] = aln
2121 chain_mapper.chem_groups,
2123 final_mapping, alns)
2125 def _compute_tmscore(self):
2129 flat_mapping = self.mapping.GetFlatMapping()
2130 res = res = bindings.WrappedMMAlign(self.
model, self.
target,
2131 mapping=flat_mapping)
2133 res = bindings.WrappedMMAlign(self.
model, self.
target)
2136 flat_mapping = self.mapping.GetFlatMapping()
2139 custom_chain_mapping = flat_mapping)
2146 for a,b
in zip(res.ent1_mapped_chains, res.ent2_mapped_chains):
def _compute_dockq_scores
void Molck(ost::mol::EntityHandle &ent, ost::conop::CompoundLibPtr lib, const MolckSettings &settings, bool prune=true)
def _get_interface_residues
_contact_model_interfaces
_per_interface_ics_precision
def transformed_mapped_model_pos
_per_interface_ics_recall
def contact_model_interfaces
def per_interface_qs_global
def per_interface_ics_precision
def per_interface_qs_best
def per_interface_ips_precision
def _compute_stereochecked_aln
def per_interface_ips_recall
_per_interface_ips_recall
Real Distance(const Vec3 &p1, const Vec3 &p2)
returns the distance between two points
_transformed_mapped_model_pos
def dockq_target_interfaces
def per_interface_ics_recall
def model_interface_residues
def contact_target_interfaces
def _compute_per_interface_qs_scores
_per_interface_ips_precision
def target_interface_residues
def _get_interface_patches
_target_interface_residues
def _compute_patchdockq_scores
_contact_target_interfaces
_model_interface_residues
def _compute_patchqs_scores