PGx: CYP2D6 structures from sub-region CN — *68+*4, *36+*10, *13 (PGX-013/018)

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.
This commit is contained in:
kemal committed 2026-09-29 16:29:54 +01:00
1 parent 9a02f39d01
commit b96ae21c70
7 files changed
+129 -31

No files matched your search

+19 -4
View File
@@ -23,11 +23,22 @@ import numpy.typing as npt
from simurg import __version__
from simurg.core.errors import ExitCode, SimurgError
from simurg.core.log import Reporter
from simurg.pgx.star import CALLED, MASKED, NO_CALL, NOT_COVERED, GeneModel, Observations, Solution, call_gene
from simurg.pgx.star import (
CALLED,
MASKED,
NO_CALL,
NOT_COVERED,
GeneModel,
Observations,
Solution,
call_gene,
cyp2d6_structure,
)
MAX_EDIT_DISTANCE = 3 # PGX-019
CN_REGION = {"CYP2D6": "CYP2D6.p5"} # PGX-013: total gene copies from the 5′ region
CN_SOLUTION_REGIONS = {"CYP2D6": ("CYP2D6.p5", "CYP2D6.intron.2", "CYP2D6.exon.9")} # PGX-027 copy_number_solution
CN_ONLY_GENES = {"GSTM1": "GSTM1", "GSTT1": "GSTT1", "UGT2B17": "UGT2B17"} # PGX-006: *0 from whole-gene CN
ALL_BASES = ("star_allele", "haplotype_named", "variant_based", "tagging_variant")
TAG_CAVEAT = "tag reliability varies by population"
@@ -350,8 +361,11 @@ def call_one_gene(
vrec = variant_records(m, recs)
region = CN_REGION.get(gene)
gcn = cn.get(region) if region else None
sols, feasible = call_gene(m, obs, cn=gcn if region else None, ploidy=ploidy,
max_candidates=o.max_candidates, feasible_ratio=o.feasible_ratio) # fmt: skip
structure = None
if gene == "CYP2D6" and gcn is not None:
structure = cyp2d6_structure(gcn, cn.get("CYP2D6.intron.2"), cn.get("CYP2D6.exon.9"))
sols, feasible = call_gene(m, obs, cn=gcn if region else None, ploidy=ploidy, max_candidates=o.max_candidates,
feasible_ratio=o.feasible_ratio, structure=structure) # fmt: skip
if not sols:
return None, [], [], [], []
top = sols[0]
@@ -398,7 +412,8 @@ def call_one_gene(
if al["background_allele"]),
"variant_change": ";".join(d["variant_change"] or []),
"score": f"{s_.score:.4f}", "raw_score": f"{s_.raw_score:.4f}",
"copy_number_solution": f"{region}={gcn}" if region and gcn is not None else "",
"copy_number_solution": ";".join(f"{r}={cn.get(r)}" for r in CN_SOLUTION_REGIONS.get(gene, ())
if cn.get(r) is not None),
"flags": ";".join(sflags)}) # fmt: skip
for al in d["alleles"]:
for sv in al["supporting_variants"]: