Sub-region CNs (p5, intron 2, exon 9) resolve full copies and *36/*68/*13 units; candidates carry the tandem names, background alleles, and CPIC activity sums. GeT-RM: CYP2D6 13/15 top (NA12878 *3/*68+*4 and NA11832 *1/*68+*4 exact), 15/15 within feasible; all genes 132/144. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01814GKVzZVL3FuF3DeiZXhv
5.4 KiB
V2 — PGx DB and star-allele calling (PGX-001 … PGX-021)
Status: implemented for CPIC star-allele genes, interim validation (2026-09-29).
scripts/pgx/fetch_sources.sh→ CPIC API tables (CC0, data version 2026-08-03).simurg pgx db build→ deterministic SQLite: 22 genes, 1354 alleles, 1897 normalised variant rows; GSA v4 PGx probe map 5002 links; two builds byte-identical.simurg pgx star-allele call→diplotype_summary.tsv,pgx_calls.json(11 star-allele genes).simurg pgx phenotype(aliasannotate) → per-sample<sample>.pgx.json(simurg.pgx/1) anddiplotype_annotations.tsvwith#metadata lines (PGX-024 … PGX-028); CPIC activity scores (xN = N × activity, *5/*0 = 0) and function-count lookups; disagreeing feasible solutions →Indeterminateplus per-solution phenotypes.tests/unit/test_pgx_phenotype.py.- Unit tests:
tests/unit/test_pgx_db.py,tests/unit/test_pgx_star.py.
Data and truth
- Arrays: the GSA v4 PGx demo (36 arrays = 30 CEPH/1000G individuals,
scripts/pgx/demo36_identity.tsv), SNV VCFs and PGx CN VCFs from SimurgArray. - Star-allele truth: GeT-RM consolidated PGx/HLA table (CDC, 2025 V4) — 16 of the 30 individuals
(
scripts/pgx/getrm_truth.py). - Probe mask (PGX-010): array vs 1000G 30x (NYGC phased panel, fetched per gene over HTTPS) for the other 14
individuals (
scripts/pgx/derive_masks.py), so the mask is independent of the GeT-RM validation set: 8 of 658 assessed records (23 probe names) below 95 % concordance — e.g. CYP2C19 rs367543002 and CYP2D6 rs1135836 called homozygous ALT in every sample, the UGT1A1C>CATATTA-repeat probe. Regenerate with the command in the script header (the mask lists vendor probe names and is not committed).
Result (16 individuals; replicate arrays counted once)
| Gene | Top solution = GeT-RM | Truth among array-equivalent feasible solutions |
|---|---|---|
| CYP2C9 | 15/15 | 15/15 |
| CYP2C19 | 14/15 | 15/15 |
| CYP2D6 | 13/15 | 15/15 |
| CYP3A5 | 15/15 | 15/15 |
| TPMT | 15/16 | 15/16 |
| CYP2B6 | 12/14 | 12/14 |
| CYP4F2 | 8/9 | 8/9 |
| NAT2 | 8/9 | 8/9 |
| NUDT15 | 1/1 | 1/1 |
| VKORC1 (rs9923231, c.-1639G>A) | 13/15 | 13/15 |
| GSTM1 (CN: DEL/DEL vs present) | 9/9 | 9/9 |
| GSTT1 (CN 0/1/2) | 7/9 | 7/9 |
| UGT2B17 (CN) | 2/2 | 2/2 |
| total | 132/144 (91.7 %) | 135/144 (93.8 %) |
PGX-032 target (≥ 90 % for CYP2D6/CYP2C19/CYP2C9 against truth): 42/45 = 93 % (top solution), 45/45 within the array-equivalent feasible solutions.
CYP2D6 structures (PGX-013) come from the three sub-region CNs (simurg.pgx.star.cyp2d6_structure): NA12878
*3/*68+*4 and NA11832 *1/*68+*4 are called exactly as GeT-RM reports them; one sample is called *36+*10/*4
(p5 = intron 2 = 3, exon 9 = 2; no GeT-RM truth). The two remaining top-solution misses are *1 vs *2, which this
array cannot separate (both within the feasible set).
Details and every discordant call: V2_pgx_star_getrm16.json.
Not in the total (GeT-RM uses pre-2023 names the CPIC definitions no longer carry): UGT1A1 (GeT-RM *60;
0/9 top) and SLCO1B1 (*1B/*17/*21 vs CPIC *37/*15/*20; 9/15 top).
Remaining discordances: CYP2D6 *2 vs *1 where the array cannot separate them (prior picks *1), CYP2C19 *8, TPMT *21, CYP2B6 *27, CYP4F2 *2 — rare alleles whose defining variants are absent or masked on this array.
Error model (K-029)
After masking, 0 of 9 740 array calls at DB variants disagreed with 1000G 30x in any GenCall-score bin (0.15–1.0), so the per-call error is 1e-3 (GS ≥ 0.15) and errors are handled by the probe mask. The first model, ε = 0.5·(1 − GS)², let correct low-GS calls lose to the prior (CYP2C9 7/15 → 15/15 after the change).
Caveats
- 16 individuals, one array type, European (CEPH) only; masks from 14 individuals (spec: ≥ 100 samples).
- CPIC now defines the GRCh38 reference as its own allele where it differs from *1 (CYP2C19 *38): a sample heterozygous at the *1-defining rs3758581 fits *1/*38 best (raw score 0.98), but *38 has no CPIC frequency, so the prior keeps *1/*1 on top — which is what legacy GeT-RM reports.
simurg pgx coverage(PGX-009/035) on GSA v4 PGx with the mask: 438 alleles callable, 68 array-equivalent to another allele, 88 not covered, 4 masked. Against the reference's known limitations: CYP4F2 *2 not covered (reported as *1) and *4 ≡ *3 — as the reference; UGT1A1 *28 callable (its C>CAT probe matches 1000G) and *37 masked (the C>CATAT probe fails); CYP2D6 *40/*58 and NUDT15 *6/*9 are separable here (CPIC core definitions differ from the reference's).- Detail outputs (PGX-016 … PGX-020, PGX-027/028, PGX-031):
supporting_variants.tsv,unresolved_variants.tsv,variants_not_covered.tsv, per-allele supporting/unresolved sites for both alleles of every candidate,variant_changevs the top solution (distant_alternativeabove 3 changes),unexplained_variants, full HGVS on GRCh38 RefSeq accessions. - All CPIC gene kinds are called: star alleles, G6PD (named haplotypes; males hemizygous from the VCF ploidy),
variant-based genes (ABCG2, CACNA1S, CFTR, DPYD, IFNL3, MT-RNR1, RYR1, VKORC1; genotype as
rs… REF/ALTorReference, phenotype diplotype from the two lowest-activity carried variants), HLA-A/B tag variants (PGX-007, positions resolved from the manifest's probes, flagtag_caveat), and GSTM1/GSTT1/UGT2B17*0genotypes from the targeted CN (PGX-006). - Not yet: PharmVar-only genes (CYP2A6, CYP3A4, CYP1A2, …); DPWG tables.