Chapter 10: ACMG Combining Rules, Bayesian Framework & Clinical Report Generation
Chapter 10: ACMG Combining Rules, Bayesian Framework & Clinical Report Generation
In this final capstone chapter, we bring every strand of the masterclass together. We master the formal ACMG criteria combination rules matrix, explore the mathematical Bayesian point system, solve the Variant of Uncertain Significance (VUS) dilemma, and engineer an automated clinical diagnostic report pipeline.
Every genomic variant evaluated in diagnostic medicine must be assigned to exactly one of the five formal ACMG tiers:
1. ACMG Combining Rules for Final Verdict Matrix
| Final Classification Tier | Minimum ACMG Criteria Combination Required |
|---|---|
| Pathogenic |
• (1 PVS1 + ≥1 PS) • (1 PVS1 + ≥2 PM) • (1 PVS1 + 1 PM + 1 PP) • (1 PVS1 + ≥2 PP) • (≥2 PS) • (1 PS + ≥3 PM) • (1 PS + 2 PM + ≥2 PP) • (1 PS + 1 PM + ≥4 PP) |
| Likely Pathogenic |
• (1 PVS1 + 1 PM) • (1 PS + 1–2 PM) • (1 PS + ≥2 PP) • (≥3 PM) • (2 PM + ≥2 PP) • (1 PM + ≥4 PP) |
| Variant of Uncertain Significance (VUS) |
Triggers when criteria for Pathogenic/Likely Pathogenic or Benign are not met, OR when conflicting evidence occurs. Example: PM2 + PP3 + PP5 = VUS (does not reach Likely Pathogenic threshold). |
| Likely Benign |
• (1 BS1 + ≥1 BP) • (≥2 BP) |
| Benign |
• 1 BA1 (Stand-Alone >5% frequency in gnomAD) • (≥2 BS) |
2. The Bayesian Point Framework (Tavtigian / ClinGen)
To remove arbitrary threshold boundaries, modern computational genetics formulates ACMG rules as an exponential Bayesian point scale:
PVS1= +8 Points (Odds of Pathogenicity $O_P = 350:1$)PS1–PS4= +4 Points each ($O_P = 18.7:1$)PM1–PM6= +2 Points each ($O_P = 4.3:1$)PP1–PP5= +1 Point each ($O_P = 2.08:1$)BP1–BP7= -1 Point eachBS1–BS4= -4 Points eachBA1= Stand-Alone Benign ($-\infty$)
Score ≥ +10: Pathogenic • Score +6 to +9: Likely Pathogenic • Score 0 to +5: VUS • Score -1 to -6: Likely Benign • Score ≤ -7: Benign.
3. Automated Clinical Genetics Report Generator in Python
Below is a production-grade Python implementation of the ACMG combining rules engine that formats a final clinical diagnostic report:
class ACMGClassifier:
def __init__(self, gene: str, hgvs_c: str, hgvs_p: str, criteria: list):
self.gene = gene
self.hgvs_c = hgvs_c
self.hgvs_p = hgvs_p
self.criteria = set([c.upper().strip() for c in criteria])
def classify(self) -> str:
c = self.criteria
# 1. Stand-Alone Benign Check
if 'BA1' in c or sum(1 for x in c if x.startswith('BS')) >= 2:
return "BENIGN"
# Count pathogenic evidence weights
pvs = 1 if 'PVS1' in c else 0
ps = sum(1 for x in c if x.startswith('PS'))
pm = sum(1 for x in c if x.startswith('PM'))
pp = sum(1 for x in c if x.startswith('PP'))
# Count benign evidence weights
bs = sum(1 for x in c if x.startswith('BS'))
bp = sum(1 for x in c if x.startswith('BP'))
# Check for Pathogenic
if (pvs == 1 and ps >= 1) or (pvs == 1 and pm >= 2) or (pvs == 1 and pm == 1 and pp >= 1) or (pvs == 1 and pp >= 2) or (ps >= 2) or (ps == 1 and pm >= 3) or (ps == 1 and pm == 2 and pp >= 2) or (ps == 1 and pm == 1 and pp >= 4):
return "PATHOGENIC"
# Check for Likely Pathogenic
if (pvs == 1 and pm == 1) or (ps == 1 and 1 <= pm <= 2) or (ps == 1 and pp >= 2) or (pm >= 3) or (pm == 2 and pp >= 2) or (pm == 1 and pp >= 4):
return "LIKELY PATHOGENIC"
# Check for Likely Benign
if (bs >= 1 and bp >= 1) or (bp >= 2):
return "LIKELY BENIGN"
return "VARIANT OF UNCERTAIN SIGNIFICANCE (VUS)"
def generate_report(self, patient_id: str) -> str:
verdict = self.classify()
return f"""========================================================================================
CLINICAL MOLECULAR GENETICS LABORATORY REPORT
========================================================================================
PATIENT ID: {patient_id}
PRIMARY FINDING: {self.gene} ({self.hgvs_c}, {self.hgvs_p})
ACMG CRITERIA: {', '.join(sorted(self.criteria))}
FINAL DIAGNOSIS: {verdict}
----------------------------------------------------------------------------------------
CLINICAL EVIDENCE RATIONALE:
- The variant was analyzed following ACMG/AMP 2015 and ClinGen recommendations.
- Functional and population database evidence triggered criteria: {', '.join(sorted(self.criteria))}.
- Final diagnostic verdict calculated as {verdict}.
========================================================================================"""
# Example Execution: BRCA1 Frameshift Variant
classifier = ACMGClassifier("BRCA1", "c.5266dupC", "p.Gln1756Profs*74", ["PVS1", "PM2", "PS4"])
print(classifier.generate_report("PATIENT_OMICS_8921"))Common Pitfalls & Troubleshooting Checklist
- Java Heap Exhaustion (GATK / Picard): If processes terminate with
java.lang.OutOfMemoryError, set your environment variable explicitly:export _JAVA_OPTIONS="-Xmx16g -Djava.io.tmpdir=/tmp". - Index Timestamp Mismatch: If tools complain that a BAM index is missing or out of date, regenerate with
samtools index -@ 4 sample.bam. - Conda Channel Conflicts: Avoid ABI incompatibilities between bioconda and conda-forge by setting strict priority:
conda config --set channel_priority strict. - Chromosome Naming Contamination: Always verify whether reference FASTA headers use
chr1or1; divergent naming causes silent alignment drops.