mva-hackathon-2026 / scripts /structure_context.py
MarxistLeninist's picture
Mirror of Marxist-Leninist/mva-hackathon-2026 incl. genome-wide addendum, dosage model, contraindications
4533472 verified
Raw History Blame Contribute Delete
2.8 kB
#!/usr/bin/env python3
"""Report local AlphaFold confidence and predicted contacts around a residue.
The result is hypothesis-generating only. Predicted contacts are not experimental
evidence of folding, binding, or variant pathogenicity.
"""
from __future__ import annotations
import argparse
import hashlib
import json
from math import dist
from pathlib import Path
def parse_atoms(path: Path):
atoms = []
with path.open(encoding="utf-8") as handle:
for line in handle:
if not line.startswith("ATOM"):
continue
atoms.append(
{
"atom": line[12:16].strip(),
"residue": line[17:20].strip(),
"number": int(line[22:26]),
"xyz": tuple(float(line[a:b]) for a, b in ((30, 38), (38, 46), (46, 54))),
"plddt": float(line[60:66]),
}
)
return atoms
def summarize(path: Path, residue_number: int, radius: float):
atoms = parse_atoms(path)
target = [atom for atom in atoms if atom["number"] == residue_number]
if not target:
raise ValueError(f"residue {residue_number} not found")
side_chain = [atom for atom in target if atom["atom"] not in {"N", "CA", "C", "O"}]
contacts = []
for atom in side_chain:
for other in atoms:
if other["number"] == residue_number:
continue
distance = dist(atom["xyz"], other["xyz"])
if distance <= radius:
contacts.append(
{
"target_atom": atom["atom"],
"other_residue": other["number"],
"other_residue_name": other["residue"],
"other_atom": other["atom"],
"distance_angstrom": round(distance, 3),
}
)
return {
"model_file_sha256": hashlib.sha256(path.read_bytes()).hexdigest(),
"residue_number": residue_number,
"residue_name": target[0]["residue"],
"mean_plddt": round(sum(atom["plddt"] for atom in target) / len(target), 2),
"contact_radius_angstrom": radius,
"predicted_contacts": sorted(contacts, key=lambda item: item["distance_angstrom"]),
"interpretation_limit": "AlphaFold geometry is a hypothesis, not functional or clinical evidence.",
}
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("pdb", type=Path)
parser.add_argument("--residue", type=int, default=1002)
parser.add_argument("--radius", type=float, default=3.2)
args = parser.parse_args()
print(json.dumps(summarize(args.pdb, args.residue, args.radius), indent=2))
if __name__ == "__main__":
main()