P4 validated on 2141 vendor GTCs; legacy AutoCall 1.6.2 preset

- 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
This commit is contained in:
kemal committed 2026-09-28 01:21:49 +01:00
1 parent 7fb3967c3f
commit f469c97917
9 files changed
+792 -29

No files matched your search

+3
View File
@@ -4,6 +4,9 @@ Plan §20 lists the open questions; this file records what the implementation ha
| ID | Date | Topic | Finding | Status |
|---|---|---|---|---|
| K-016 | 2026-09-28 | Sex rule of AutoCall 1.6.2.2 | Rule 1 (X heterozygosity) matches all 2141 vendor GTCs; rule 2 (X/Y intensity) differs in 12. | resolved |
| K-015 | 2026-09-28 | Legacy GTC v3 statistics | AutoCall 1.6.2.2 writes GC10 = GC50 = 0 and #calls = #no-calls = 0 in GTC v3 (it does fill LogR dev and #intensity-only). gtc2vcf's AutoConvert 1.6.3.1 preset fills them, so this is specific to 1.6.2.x. Emulated by `--preset autocall-1.6.2`; the sample summary still reports the real statistics. | resolved; cloud re-run pending |
| K-014 | 2026-09-28 | NaN sign | NaNs produced by libm (e.g. log2 of a negative extrapolated R) take the platform's default sign: + on aarch64, − on x86-64. SimurgArray always writes 0xFFC00000 (the reference's `-NAN`, x86 behaviour). The aarch64-built oracle differs in 1 locus of 9 GSA samples; oracle tests compare with NaNs canonicalised. | resolved |
| K-013 | 2026-09-27 | Normalization version of public vendor GTCs | The 1000 Genomes Omni2.5 GTCs (AutoCall 1.6.2.2) are reproduced bit-for-bit by normalization 1.1.2 (109 191/109 191 bins, reserved fields included). | resolved |
| K-012 | 2026-09-27 | FMA and bit-exactness | gcc on aarch64 contracts a*b+c into FMA by default; the gtc2vcf oracle then differs from the vendor by up to 4 ULP in some bins. Oracles are built with `-ffp-contract=off`. Any future C/Rust port (P9) must also forbid FMA contraction in exact mode. | resolved; constraint for P9 |
| K-011 | 2026-09-27 | Plan U1 (channel order) | Infinium II X = Red, Y = Grn confirmed on 2141 vendor GTCs (the GTC PDF's "Raw X = green" wording is wrong). | resolved |
+55
View File
@@ -0,0 +1,55 @@
# Phase P4 validation report — genotype calling and GTC output
Date: 2026-09-28. Development and oracle tests on the Pi; vendor comparison on a self-destructing AWS spot instance
(`run-20260927T233126Z`, 44 min, ≈ $0.19). Summary: `P4_omni2141_summary.json`.
## Delivered
| Item | Module |
|---|---|
| Cluster file aligned to manifest order (float32 mean R) | `genotype/clusters.py` |
| GenCall-equivalent calling: SD flair, six-case half-flattened likelihoods, priors/posteriors, fuzzy sub-scores, score map | `genotype/gencall.py` |
| BAF / LRR / LogR dev (Peiffer 2006), canonical NaN pattern | `genotype/baf_lrr.py` |
| Sex estimate, rules v1 and v2 | `genotype/sex.py` |
| IDAT pair → complete GTC (v5 or v3), TOP-strand base calls, sample stats, presets | `genotype/sample.py` |
| `simurg genotype` (GTC per sample, `sample_summary.tsv/json` per OUT-060…063, run manifest) | `pipeline/genotype.py` |
## Acceptance (plan §18 P4)
### Against the oracle (gtc2vcf built without FMA), P0 GSA data
| Check | Result |
|---|---|
| 36 samples × normalization 1.2.0 and 1.1.2: whole GTC files after aligning the four free-text fields (file names, AutoCall date/version) | **72/72 byte-identical** |
Every data field matches bit for bit: raw X/Y, transforms, genotypes, GenCall scores, TOP base calls, BAF, LRR, call
rate, sex, LogR dev, GC10/GC50, call counts, percentiles and controls. The only adjustment is the sign of NaNs that
libm computes (K-014).
### Against 2141 vendor GTCs (1000 Genomes Omni2.5, AutoCall 1.6.2.2, cluster file `HumanOmni2.5-4v1-Multi_B.egt`)
| Field | Samples that differ | Explanation |
|---|---|---|
| genotypes | 3 (5 loci in total) | the 3 samples of K-009, whose raw intensity differs in one locus; that difference shifts their normalization |
| GenCall scores | 3 (18 229 loci) | same 3 samples (the transform change moves every score of the affected bin) |
| normalization transforms | 2 | same K-009 samples |
| raw X / raw Y | 1 / 2 | K-009 |
| call rate, LogR dev | 2 / 3 | follow from the above |
| base calls | 3 | follow from genotypes |
| **sex (rule 1)** | **0 of 2141** | rule 2 would differ in 12 samples, so AutoCall 1.6.2.2 uses rule 1 |
| GC10, GC50, #calls, #no-calls | 2141 | AutoCall 1.6.2.2 leaves these at 0 in GTC v3 (K-015); now emulated by `--preset autocall-1.6.2` |
So in 2138 of 2141 samples every computed field agrees with the vendor; the remaining 3 samples trace back to the
single-locus raw-intensity rule of K-009. Whole-file byte identity was 0/2141 in this run only because of the four
legacy-empty statistics; the preset that reproduces them was added after the run (unit-tested, not yet re-run on
the cloud — expected 2138/2141).
Not covered here: BAF and LRR against vendor output (GTC v3 has no BAF/LRR fields). The 1000 Genomes Sanger set
ships a GenomeStudio Final Report with BAF/LRR for 177 samples — optional follow-up run (≈ $0.10).
## Performance
| Machine | Result |
|---|---|
| Raspberry Pi 5, GSA (683 k loci) | 3.6 s per sample (1 core); 36 samples in 2 min with 4 workers |
| AWS m7g.4xlarge, Omni2.5 (2.45 M loci), 16 workers | 2141 samples genotyped and compared in 19.6 min; peak RSS 3.2 GB |
+615
View File
@@ -0,0 +1,615 @@
{
"n_gtc": 2141,
"n_compared": 2141,
"errors": [],
"byte_identical": 0,
"samples_with_no_field_diff": 0,
"samples_with_field_diff": {
"gc10": 2141,
"gc50": 2141,
"num_calls": 2141,
"num_no_calls": 2141,
"slide_identifier": 2141,
"raw_x": 1,
"genotypes": 3,
"genotype_scores": 3,
"base_calls": 3,
"call_rate": 2,
"logr_dev": 3,
"raw_y": 2,
"normalization_transforms": 2
},
"genotype_diff_loci_total": 5,
"score_diff_loci_total": 18229,
"max_score_abs_diff": 0.9426311254501343,
"cluster_files": [
"HumanOmni2.5-4v1-Multi_B.egt"
],
"sex_agreement_by_version": {
"1": 2141,
"2": 2129
},
"ref_sex_counts": {
"M": 1054,
"F": 1087,
"U": 0
},
"examples": [
{
"gtc": "/work/omni/data/5426511011/5426511011_R01C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6847535967826843",
"0.0"
],
"gc50": [
"0.8497611880302429",
"0.0"
],
"num_calls": [
"2433210",
"0"
],
"num_no_calls": [
"16790",
"0"
],
"slide_identifier": [
"'5426511011'",
"''"
]
},
"sex_by_version": {
"1": "F",
"2": "F"
},
"sex_ref": "F",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Wednesday, August 25, 2010 7:11:03 PM"
}
},
{
"gtc": "/work/omni/data/5426511011/5426511011_R02C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6842713356018066",
"0.0"
],
"gc50": [
"0.8497611880302429",
"0.0"
],
"num_calls": [
"2436202",
"0"
],
"num_no_calls": [
"13798",
"0"
],
"slide_identifier": [
"'5426511011'",
"''"
]
},
"sex_by_version": {
"1": "M",
"2": "M"
},
"sex_ref": "M",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Wednesday, August 25, 2010 7:24:37 PM"
}
},
{
"gtc": "/work/omni/data/5426511011/5426511011_R03C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6842615604400635",
"0.0"
],
"gc50": [
"0.8497611880302429",
"0.0"
],
"num_calls": [
"2435069",
"0"
],
"num_no_calls": [
"14931",
"0"
],
"slide_identifier": [
"'5426511011'",
"''"
]
},
"sex_by_version": {
"1": "F",
"2": "F"
},
"sex_ref": "F",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Wednesday, August 25, 2010 7:37:41 PM"
}
},
{
"gtc": "/work/omni/data/5426511011/5426511011_R04C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6863988637924194",
"0.0"
],
"gc50": [
"0.8497668504714966",
"0.0"
],
"num_calls": [
"2435856",
"0"
],
"num_no_calls": [
"14144",
"0"
],
"slide_identifier": [
"'5426511011'",
"''"
]
},
"sex_by_version": {
"1": "F",
"2": "F"
},
"sex_ref": "F",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Wednesday, August 25, 2010 7:45:50 PM"
}
},
{
"gtc": "/work/omni/data/5426511013/5426511013_R01C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6843520402908325",
"0.0"
],
"gc50": [
"0.8497611880302429",
"0.0"
],
"num_calls": [
"2434354",
"0"
],
"num_no_calls": [
"15646",
"0"
],
"slide_identifier": [
"'5426511013'",
"''"
]
},
"sex_by_version": {
"1": "M",
"2": "M"
},
"sex_ref": "M",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Thursday, August 26, 2010 12:08:26 AM"
}
},
{
"gtc": "/work/omni/data/5426511013/5426511013_R02C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.685818076133728",
"0.0"
],
"gc50": [
"0.8497965335845947",
"0.0"
],
"num_calls": [
"2439588",
"0"
],
"num_no_calls": [
"10412",
"0"
],
"slide_identifier": [
"'5426511013'",
"''"
]
},
"sex_by_version": {
"1": "F",
"2": "F"
},
"sex_ref": "F",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Thursday, August 26, 2010 12:22:41 AM"
}
},
{
"gtc": "/work/omni/data/5426511013/5426511013_R03C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6856454014778137",
"0.0"
],
"gc50": [
"0.8497673273086548",
"0.0"
],
"num_calls": [
"2442131",
"0"
],
"num_no_calls": [
"7869",
"0"
],
"slide_identifier": [
"'5426511013'",
"''"
]
},
"sex_by_version": {
"1": "M",
"2": "M"
},
"sex_ref": "M",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Thursday, August 26, 2010 12:37:24 AM"
}
},
{
"gtc": "/work/omni/data/5426511013/5426511013_R04C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6856228113174438",
"0.0"
],
"gc50": [
"0.8497611880302429",
"0.0"
],
"num_calls": [
"2440841",
"0"
],
"num_no_calls": [
"9159",
"0"
],
"slide_identifier": [
"'5426511013'",
"''"
]
},
"sex_by_version": {
"1": "F",
"2": "F"
},
"sex_ref": "F",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Thursday, August 26, 2010 12:46:33 AM"
}
},
{
"gtc": "/work/omni/data/5426511028/5426511028_R01C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6833689212799072",
"0.0"
],
"gc50": [
"0.8496665954589844",
"0.0"
],
"num_calls": [
"2435388",
"0"
],
"num_no_calls": [
"14612",
"0"
],
"slide_identifier": [
"'5426511028'",
"''"
]
},
"sex_by_version": {
"1": "M",
"2": "M"
},
"sex_ref": "M",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Thursday, August 26, 2010 8:13:23 AM"
}
},
{
"gtc": "/work/omni/data/5426511028/5426511028_R02C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6857903599739075",
"0.0"
],
"gc50": [
"0.8497611880302429",
"0.0"
],
"num_calls": [
"2435889",
"0"
],
"num_no_calls": [
"14111",
"0"
],
"slide_identifier": [
"'5426511028'",
"''"
]
},
"sex_by_version": {
"1": "F",
"2": "F"
},
"sex_ref": "F",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Thursday, August 26, 2010 8:28:43 AM"
}
},
{
"gtc": "/work/omni/data/5426511028/5426511028_R03C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6847374439239502",
"0.0"
],
"gc50": [
"0.8497611880302429",
"0.0"
],
"num_calls": [
"2435026",
"0"
],
"num_no_calls": [
"14974",
"0"
],
"slide_identifier": [
"'5426511028'",
"''"
]
},
"sex_by_version": {
"1": "F",
"2": "F"
},
"sex_ref": "F",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Thursday, August 26, 2010 8:40:16 AM"
}
},
{
"gtc": "/work/omni/data/5426511028/5426511028_R04C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6849170923233032",
"0.0"
],
"gc50": [
"0.8497409820556641",
"0.0"
],
"num_calls": [
"2433211",
"0"
],
"num_no_calls": [
"16789",
"0"
],
"slide_identifier": [
"'5426511028'",
"''"
]
},
"sex_by_version": {
"1": "F",
"2": "F"
},
"sex_ref": "F",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Thursday, August 26, 2010 8:50:08 AM"
}
},
{
"gtc": "/work/omni/data/5426511029/5426511029_R01C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.683781087398529",
"0.0"
],
"gc50": [
"0.8497233390808105",
"0.0"
],
"num_calls": [
"2439124",
"0"
],
"num_no_calls": [
"10876",
"0"
],
"slide_identifier": [
"'5426511029'",
"''"
]
},
"sex_by_version": {
"1": "M",
"2": "M"
},
"sex_ref": "M",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Thursday, August 26, 2010 9:12:02 AM"
}
},
{
"gtc": "/work/omni/data/5426511029/5426511029_R02C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6832002401351929",
"0.0"
],
"gc50": [
"0.8497028946876526",
"0.0"
],
"num_calls": [
"2437630",
"0"
],
"num_no_calls": [
"12370",
"0"
],
"slide_identifier": [
"'5426511029'",
"''"
]
},
"sex_by_version": {
"1": "M",
"2": "M"
},
"sex_ref": "M",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Thursday, August 26, 2010 9:26:14 AM"
}
},
{
"gtc": "/work/omni/data/5426511029/5426511029_R03C01.gtc",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"field_diffs": {
"gc10": [
"0.6829559803009033",
"0.0"
],
"gc50": [
"0.8496484756469727",
"0.0"
],
"num_calls": [
"2435690",
"0"
],
"num_no_calls": [
"14310",
"0"
],
"slide_identifier": [
"'5426511029'",
"''"
]
},
"sex_by_version": {
"1": "F",
"2": "F"
},
"sex_ref": "F",
"byte_identical": false,
"ref_layout_canonical": true,
"metadata": {
"autocall_version": "1.6.2.2",
"cluster_file": "HumanOmni2.5-4v1-Multi_B.egt",
"imaging_date": "Thursday, August 26, 2010 9:40:16 AM"
}
}
],
"params": {
"norm_version": "1.1.2",
"sex_version": 1
},
"seconds": 1174.6,
"passed": false
}