Source code for modelcif.qa_metric

"""Classes to annotate models with quality scores.

   To use, first declare a class for the desired score by deriving
   from both a subclass of :class:`MetricMode` (which defines the part
   of the system the metric applies to) and a subclass of :class:`MetricType`
   (which describes the meaning of the score value). Set the ``software``
   attribute to point to the software used to calculate the metric
   (as a :class:`modelcif.SoftwareGroup` or :class:`modelcif.Software` object).
   For example to declare a global distance score::

       class MyScore(modelcif.qa_metric.Global, modelcif.qa_metric.Distance):
           "My distance-based quality score"
           software = modelcif.Software(...)

   The name and description of the score in the mmCIF file will be taken from
   the name and docstring of the Python class, unless the
   :attr:`MetricMode.name` or :attr:`MetricMode.description` attributes are
   overridden in the subclass.

   QA metric objects should be added to
   :attr:`modelcif.model.Model.qa_metrics`.
"""

from ihm.util import _text_choice_property


[docs] class MetricMode: """Base class for the mode of a quality metric. Use a derived class such as :class:`Global`, :class:`Local`, :class:`LocalPairwise`, :class:`Feature`, :class:`FeaturePairwise`, or :class:`Dihedral` for declaring a new score. """ name = property(lambda x: type(x).__name__, doc="Short name of this score. By default it is just the " "class name, but this can be overridden in subclasses " "(for example to create names containing spaces).") description = property(lambda x: x.__doc__.split("\n")[0], doc="Longer text description of this score. By " "default it is the first line of the " "docstring.")
[docs] class Global(MetricMode): """A score that is calculated per-model. :param float value: The score value (see :class:`MetricType`). """ mode = "global" def __init__(self, value): self.value = value def __repr__(self): return "<%s(value=%r)>" % (type(self).__name__, self.value)
[docs] class Local(MetricMode): """A score that is calculated on a single residue. :param residue: The residue that is scored. :type residue: :class:`modelcif.Residue` :param float value: The score value (see :class:`MetricType`). """ mode = "local" def __init__(self, residue, value): self.residue = residue self.value = value def __repr__(self): return "<%s(residue=%r, value=%r)>" % (type(self).__name__, self.residue, self.value)
[docs] class LocalPairwise(MetricMode): """A score that is calculated between two residues. :param residue1: The first residue that is scored. :type residue1: :class:`modelcif.Residue` :param residue2: The second residue that is scored. :type residue2: :class:`modelcif.Residue` :param float value: The score value (see :class:`MetricType`). """ mode = "local-pairwise" def __init__(self, residue1, residue2, value): self.residue1 = residue1 self.residue2 = residue2 self.value = value def __repr__(self): return ("<%s(residue1=%r, residue2=%r, value=%r)>" % (type(self).__name__, self.residue1, self.residue2, self.value))
[docs] class Feature(MetricMode): """A score that is calculated on a single feature. :param feature: The feature that is scored. :type feature: :class:`modelcif.Feature` :param float value: The score value (see :class:`MetricType`). """ mode = "per-feature" def __init__(self, feature, value): self.feature = feature self.value = value def __repr__(self): return "<%s(feature=%r, value=%r)>" % (type(self).__name__, self.feature, self.value) _all_features = property(lambda self: (self.feature,))
[docs] class FeaturePairwise(MetricMode): """A score that is calculated between two features. :param feature1: The first feature that is scored. :type feature1: :class:`modelcif.Feature` :param feature2: The second feature that is scored. :type feature2: :class:`modelcif.Feature` :param float value: The score value (see :class:`MetricType`). """ mode = "per-feature-pair" def __init__(self, feature1, feature2, value): self.feature1 = feature1 self.feature2 = feature2 self.value = value def __repr__(self): return ("<%s(feature1=%r, feature2=%r, value=%r)>" % (type(self).__name__, self.feature1, self.feature2, self.value)) _all_features = property(lambda self: (self.feature1, self.feature2))
[docs] class Dihedral(MetricMode): """A score that is calculated on a dihedral. :param int atom_id_1: The first atom ID in the dihedral. :param int atom_id_2: The second atom ID in the dihedral. :param int atom_id_3: The third atom ID in the dihedral. :param int atom_id_4: The fourth atom ID in the dihedral. :param float value: The score value (see :class:`MetricType`). :param str quality: Outcome or result of the analysis. :param str smarts_pattern: Optional SMARTS pattern that specifies the dihedral angle in its chemical environment; or that defines the fragment used for dihedral scanning. """ mode = "dihedral" def __init__(self, atom_id_1, atom_id_2, atom_id_3, atom_id_4, value, quality, smarts_pattern=None): self.atom_id_1, self.atom_id_2 = atom_id_1, atom_id_2 self.atom_id_3, self.atom_id_4 = atom_id_3, atom_id_4 self.value = value self.quality, self.smarts_pattern = quality, smarts_pattern quality = _text_choice_property( "quality", ["relaxed", "tolerable", "strained"], doc="Outcome or result of the analysis.") def __repr__(self): return ("<%s(atom_id_1=%r, atom_id_2=%r, atom_id_3=%r, atom_id_4=%r, " "value=%r)>" % (type(self).__name__, self.atom_id_1, self.atom_id_2, self.atom_id_3, self.atom_id_4, self.value))
[docs] class MetricType: """Base class for the type of a quality metric. Generally a derived class such as :class:`ZScore` or :class:`Distance` is used to declare a new score, but a custom type can also be declared by deriving from this class and providing a docstring to describe the metric type:: class MPQSMetricType(modelcif.qa_metric.MetricType): "composite score, values >1.1 are reliable" """ type = "other" def _get_other_details(self): # Find most derived class of MetricType before we pulled in MetricMode # and use the first line of its docstring as other_details if self.type == MetricType.type: for base in type(self).mro(): if (issubclass(base, MetricType) and base is not MetricType and not issubclass(base, MetricMode)): return base.__doc__.split('\n')[0] other_details = property( _get_other_details, doc="More information about this metric type. By default it is the " "first line of the MetricType subclass docstring.")
[docs] class ZScore(MetricType): """Score that is the number of standard deviations from optimal/best. See :class:`MetricType` for more information.""" type = "zscore" other_details = None
[docs] class Energy(MetricType): """Energy score (the lower the energy, the better the quality). See :class:`MetricType` for more information.""" type = "energy" other_details = None
[docs] class Distance(MetricType): """Distance score (the lower the distance, the better the quality). See :class:`MetricType` for more information.""" type = "distance" other_details = None
[docs] class NormalizedScore(MetricType): """Normalized score ranging from 0 to 1. See :class:`MetricType` for more information.""" type = "normalized score" other_details = None
[docs] class PAE(MetricType): """Score that is a predicted aligned error. See :class:`MetricType` for more information.""" type = "PAE" other_details = None
[docs] class ContactProbability(MetricType): """Score that is a contact probability of a pairwise interaction. See :class:`MetricType` for more information.""" type = "contact probability" other_details = None
[docs] class PLDDT(MetricType): """Predicted lDDT-CA score in [0,100] (higher score, means better accuracy). See :class:`MetricType` for more information.""" type = "pLDDT" other_details = None
[docs] class PLDDT01(MetricType): """Predicted lDDT-CA score in [0,1] (higher score, means better accuracy). See :class:`MetricType` for more information.""" type = "pLDDT in [0,1]" other_details = None
[docs] class PLDDTAllAtom(MetricType): """Predicted lDDT all atom score in [0,100] (higher score, means better accuracy). See :class:`MetricType` for more information.""" type = "pLDDT all-atom" other_details = None
[docs] class PLDDTAllAtom01(MetricType): """Predicted lDDT all atom score in [0,1] (higher score, means better accuracy). See :class:`MetricType` for more information.""" type = "pLDDT all-atom in [0,1]" other_details = None
[docs] class PLDDTToPolymer(MetricType): """Predicted lDDT with distances from each atom to CA or C1' of nearby polymer residues [0,100] (higher score, means better accuracy). See :class:`MetricType` for more information.""" type = "pLDDT to polymer" other_details = None
[docs] class PTM(MetricType): """Predicted TM-score in [0,1] (higher value means higher confidence). See :class:`MetricType` for more information.""" type = "pTM" other_details = None
[docs] class IpTM(MetricType): """Protein-protein interface score, based on TM-score in [0,1]. See :class:`MetricType` for more information.""" type = "ipTM" other_details = None
[docs] class Boolean(MetricType): """0 or 1 depending on whether a check passed. See :class:`MetricType` for more information.""" type = "boolean" other_details = None