P6 complete: optional VCF fields, SNV+indel merging, auxiliary MNV loci, PLINK 2 .pgen
ci / test (3.12) (push) Failing after 8s
ci / test (3.13) (push) Failing after 10s

- gtc-to-vcf --info-fields ASSAY_TYPE,NORM_BIN,GENTRAIN,CLUSTER_SEP,ILMN_STRAND,PROBE_IDS (--egt) and
  --extra-format X,Y,NORMX,NORMY,THETA,R, in per-sample VCFs and the --merge BCF (OUT-012, plan §8.3);
  equal to gtc2vcf's values (THETA/R missing where both normalized intensities are 0, K-023)
- --merge-snv-indel (OUT-021, EDGE-013): alleles extended to the longest REF; SNV probes read the base at POS
- --auxiliary-loci (OUT-035, EDGE-015): rules (a)-(e), E_AUX_INVALID; rule (d) uses the last plus-strand base
  for minus-strand designs (spec amended, as GTCtoVCF)
- export plink --format bed|pgen|both: PLINK 2 fixed-width .pgen/.pvar/.psam; plink2 reads it back to a .bed
  byte-identical to ours
- cohort store keeps raw/normalized intensities for the BCF path; tests (unit + gtc2vcf oracle); docs

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 14:29:42 +01:00
1 parent 63bb40c4e5
commit 2e8478cc6a
13 files changed
+611 -50

No files matched your search

+34 -3
View File
@@ -397,6 +397,22 @@ def gtc_to_vcf_cmd(
merge: Annotated[
bool, typer.Option("--merge", help="One multi-sample BCF (+ .csi) instead of per-sample VCFs.")
] = False,
auxiliary_loci: Annotated[
Path | None, typer.Option("--auxiliary-loci", help="VCF of true MNV definitions for manifest probes (OUT-035).")
] = None,
merge_snv_indel: Annotated[
bool, typer.Option("--merge-snv-indel", help="One record for an SNV and an indel at the same position.")
] = False,
info_fields: Annotated[
str,
typer.Option(
"--info-fields", help="Comma list: ASSAY_TYPE,NORM_BIN,GENTRAIN,CLUSTER_SEP,ILMN_STRAND,PROBE_IDS"
),
] = "",
extra_format: Annotated[
str, typer.Option("--extra-format", help="Comma list: X,Y,NORMX,NORMY,THETA,R (single-probe records)")
] = "",
egt: Annotated[Path | None, typer.Option("--egt", help="Cluster file (INFO GENTRAIN, CLUSTER_SEP).")] = None,
force: Annotated[bool, typer.Option("--force", help="Replace existing outputs.")] = False,
log_json: Annotated[bool, typer.Option("--log-json", "--json-log", help="JSON Lines log on stderr.")] = False,
debug: Annotated[bool, typer.Option("--debug", help="Debug logging with tracebacks.")] = False,
@@ -417,7 +433,12 @@ def gtc_to_vcf_cmd(
out=out, bpm=bpm, fasta=fasta, gtcs=gtcs, sheet=sheet, csv=csv, bgzip=not no_bgzip, genome_cache=genome_cache,
exclude_loci=exclude_loci, include_loci=include_loci, unsquash_duplicates=unsquash_duplicates,
inf1_nocall_informative=inf1_nocall_informative, drop_ambiguous=drop_ambiguous, filter_gs=filter_gs,
contig_alias=contig_alias, ploidy_policy=ploidy_policy, threads=threads, merge=merge, force=force,
contig_alias=contig_alias, ploidy_policy=ploidy_policy, threads=threads, merge=merge,
merge_snv_indel=merge_snv_indel,
auxiliary_loci=auxiliary_loci,
force=force,
info_fields=[x.strip().upper() for x in info_fields.split(",") if x.strip()],
extra_format=[x.strip().upper() for x in extra_format.split(",") if x.strip()], egt=egt,
argv=sys.argv[1:],
) # fmt: skip
run_guarded(rep, lambda: run_gtc_to_vcf(opts, rep))
@@ -485,6 +506,7 @@ def export_plink_cmd(
sheet: Annotated[Path | None, typer.Option("--sheet", help="Sample sheet (reported sex).")] = None,
gtcs: Annotated[Path | None, typer.Option("--gtcs", help="GTC folder (estimated sex).")] = None,
multiallelic: Annotated[str, typer.Option("--multiallelic", help="split|drop")] = "split",
fmt: Annotated[str, typer.Option("--format", help="bed (PLINK 1), pgen (PLINK 2) or both")] = "bed",
prefix: Annotated[str, typer.Option("--prefix", help="Output file prefix.")] = "cohort",
force: Annotated[bool, typer.Option("--force", help="Replace existing outputs.")] = False,
log_json: Annotated[bool, typer.Option("--log-json", "--json-log")] = False,
@@ -495,8 +517,17 @@ def export_plink_cmd(
from simurg.pipeline.export import PlinkOptions, run_export_plink
rep = _plain_reporter("export plink", log_json, debug, quiet)
opts = PlinkOptions(out=out, vcfs=vcfs, sheet=sheet, gtcs=gtcs, multiallelic=multiallelic, prefix=prefix,
force=force, argv=sys.argv[1:]) # fmt: skip
opts = PlinkOptions(
out=out,
vcfs=vcfs,
sheet=sheet,
gtcs=gtcs,
multiallelic=multiallelic,
format=fmt,
prefix=prefix,
force=force,
argv=sys.argv[1:],
)
run_guarded(rep, lambda: run_export_plink(opts, rep))