P4 validated on 2141 vendor GTCs; legacy AutoCall 1.6.2 preset
ci / test (3.12) (push) Failing after 8s
ci / test (3.13) (push) Failing after 9s

- vendor comparison (1000 Genomes Omni2.5, AutoCall 1.6.2.2): every
  computed field identical in 2138/2141 samples; the 3 others trace back
  to the single-locus raw-intensity rule (K-009); sex rule 1 matches all
- AutoCall 1.6.2.x leaves GC10/GC50/#calls/#no-calls at 0 in GTC v3:
  new `--preset autocall-1.6.2` (1.1.2 normalization, sex rule 1, GTC v3,
  legacy statistics); the sample summary keeps the real statistics
- NaN sign canonicalised to the x86 pattern (K-014); report P4.md

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01814GKVzZVL3FuF3DeiZXhv
This commit is contained in:
kemalandClaude Opus 5.5 committed 2026-09-28 01:21:49 +01:00
1 parent eb19ac7f91
commit 8b1e5d8dab
9 files changed
+792 -29

No files matched your search

+20 -12
View File
@@ -27,7 +27,14 @@ from simurg.formats.gtc import write_gtc
from simurg.formats.idat import check_pair, read_idat
from simurg.genotype.baf_lrr import chrom_core
from simurg.genotype.clusters import align_clusters
from simurg.genotype.sample import GenotypeParams, ManifestContext, genotype_sample, manifest_context
from simurg.genotype.sample import (
GenotypeParams,
ManifestContext,
genotype_sample,
manifest_context,
params_for_preset,
summary_stats,
)
from simurg.genotype.sex import SexParams
from simurg.pipeline.inputs import check_paths, resolve_sample_set, sample_dir, sheet_values
from simurg.signal.normalization.apply import normalize, polar
@@ -77,9 +84,10 @@ class GenotypeOptions:
layout: str = "nested"
on_duplicate_idat: str = "error"
cutoff: float = 0.15
norm_version: str = "1.2.0"
sex_version: int = 2
gtc_version: int = 5
preset: str = "current"
norm_version: str | None = None # None: from the preset
sex_version: int | None = None
gtc_version: int | None = None
autocall_date: str | None = None
assay_control_probes: tuple[str, ...] = ("TGA_Ctrl_5716",)
argv: list[str] = field(default_factory=list)
@@ -133,11 +141,7 @@ def _process(job: Job) -> dict[str, Any]:
call_rate=float(g.call_rate),
logr_dev=float(g.logr_dev),
sex_est=g.gender_char,
gc10=float(g.gc10),
gc50=float(g.gc50),
n_calls=g.num_calls,
n_nocalls=g.num_no_calls,
n_intensity_only=g.num_intensity_only,
**summary_stats(g, ctx.manifest.intensity_only, params.cutoff),
p05_x=int(g.percentiles_x[0]),
p50_x=int(g.percentiles_x[1]),
p95_x=int(g.percentiles_x[2]),
@@ -261,13 +265,17 @@ def run_genotype(opts: GenotypeOptions, rep: Reporter) -> int:
auto_1_22 = np.array([chrom_core(c) in {str(i) for i in range(1, 23)} for c in manifest.chroms])
name_idx = manifest.name_index()
probes = {p: name_idx[p] for p in opts.assay_control_probes if p in name_idx}
params = GenotypeParams(
params = params_for_preset(
opts.preset,
cutoff=opts.cutoff,
norm_version=opts.norm_version,
sex=SexParams(version=opts.sex_version),
sex=SexParams(version=opts.sex_version) if opts.sex_version else None,
gtc_version=opts.gtc_version,
autocall_date=opts.autocall_date,
)
rm.set_option("effective_norm_version", params.norm_version, f"preset:{opts.preset}")
rm.set_option("effective_sex_version", params.sex.version, f"preset:{opts.preset}")
rm.set_option("effective_gtc_version", params.gtc_version, f"preset:{opts.preset}")
started = _dt.datetime.now()
workers = max(1, min(opts.threads or (os.cpu_count() or 1), len(jobs) or 1))
@@ -335,7 +343,7 @@ def run_genotype(opts: GenotypeOptions, rep: Reporter) -> int:
"warnings": rep.warning_counts(),
}
rm.add_output(summary_tsv, SUMMARY_SCHEMA)
rm.schema_versions["*.gtc"] = f"gtc/{opts.gtc_version}"
rm.schema_versions["*.gtc"] = f"gtc/{params.gtc_version}"
rm.status = "completed"
rm.write(opts.out / "run_manifest.json")
rep.info(f"done: {ok}/{len(out_rows)} samples genotyped; summary {summary_tsv}")