blog: five posts on SimurgArray (why, alternatives, impact, public release plan, usage and branding)
This commit is contained in:
1 parent
af39d0ee6a
commit
4ab227e909
6 files changed
+490
No files matched your search
@@ -0,0 +1,80 @@
|
||||
# Why SimurgArray should exist
|
||||
|
||||
*Part 1 of 5. Kemal Yaylali, September 2026*
|
||||
|
||||
Every genotyping array tells a small story before it tells you anything about DNA. A glass slide goes into a scanner, the scanner writes two IDAT files per sample (one red, one green), and a few hundred thousand bead intensities wait for someone to turn them into genotypes. That someone is almost always a piece of closed software. You click, it thinks, and out come the calls.
|
||||
|
||||
For most people this is perfectly fine. The calls are good. The labs are busy. Nobody has time to ask how a pair of numbers became "AB".
|
||||
|
||||
I had the time, and I had the question. SimurgArray is the answer I ended up writing.
|
||||
|
||||
## The black box in the middle
|
||||
|
||||
Illumina Infinium arrays are everywhere. Biobanks use them, consumer genetics companies use them, research groups use them because they are cheap per sample and wonderfully boring in the best sense: they work. Hundreds of millions of people have been genotyped this way.
|
||||
|
||||
The pipeline is conceptually simple:
|
||||
|
||||
1. Read the raw intensities from the IDAT files.
|
||||
2. Normalize them, because the red and green channels never quite agree with each other.
|
||||
3. Compare each sample to a cluster file (an EGT) that says where AA, AB and BB usually sit.
|
||||
4. Call genotypes, give each call a score, and write everything to a GTC file.
|
||||
5. Turn that into something the rest of the world reads, usually a VCF.
|
||||
|
||||
Steps 1 to 4 are where the interesting decisions live, and they have historically been done by software you can run but cannot read. Good open tools exist around the edges, and I will talk about them in the next post, but I could not find one place where the whole chain was open, tested against the vendor's own outputs, and documented well enough that a stranger could check every step.
|
||||
|
||||
So I built that place.
|
||||
|
||||
## What SimurgArray actually is
|
||||
|
||||
SimurgArray is a personal research toolkit that takes IDAT files all the way to QC reports, VCF and PLINK files, and then keeps going:
|
||||
|
||||
* Genotype calling that reproduces the vendor's GTC files byte for byte in 2138 of 2141 public 1000 Genomes Omni2.5 samples. The last three are documented, not hidden.
|
||||
* Sample and control QC with an HTML report you can actually click around in.
|
||||
* Copy number, loss of heterozygosity and mosaicism calling across the genome.
|
||||
* Pharmacogenomics: targeted copy number for genes like CYP2D6, star allele diplotypes and CPIC phenotypes.
|
||||
* Methylation array control QC.
|
||||
* ArrayTrain, which builds your own cluster file from your own cohort, so you are not forever borrowing someone else's.
|
||||
|
||||
Everything is specified item by item in a functional spec with 416 numbered requirements, and every algorithm points to where it came from: a paper, a public technical note, an expired patent, or an open source project with a compatible license. When our numbers differ from a reference tool, the difference goes into a file called `known_unknowns.md` with a date and an explanation. Thirty entries so far. Some of them are my favorite reading.
|
||||
|
||||
## Reason one: you should be able to check
|
||||
|
||||
Science has a slightly awkward relationship with tools it cannot inspect. We publish methods sections that say "genotypes were called with the manufacturer's software, default settings", and everybody nods, because what else would you say?
|
||||
|
||||
The problem shows up later. A cluster file that does not match your chips. A normalization version that changed between releases. A sex check that disagrees with the pedigree in 12 samples out of two thousand. With a black box you can only shrug. With open code you can open the file, find the line, and write down what happened.
|
||||
|
||||
SimurgArray was built around that idea. It has a differential testing harness that compares our outputs with reference tools field by field and labels each difference as exact, near, discrepancy or unknown. A nightly job runs it again at 02:30, when the Raspberry Pi has nothing better to do and the rest of the house is asleep.
|
||||
|
||||
## Reason two: the cluster file problem
|
||||
|
||||
Here is something that surprised me more than it should have. Genotype calls depend heavily on the cluster file, and the cluster file was trained by someone else, on samples you have never seen, possibly for a slightly different version of your chip.
|
||||
|
||||
On a public dataset of 360 GSA arrays I worked with, the only public cluster file available was made for a sibling chip. It works, mostly. The quality metrics politely complain the whole time.
|
||||
|
||||
With ArrayTrain you can train a cluster file from your own cohort. On that dataset, a cluster file trained from 120 arrays gave 99.44 % concordance with 30x whole genome sequencing, against 99.46 % for the vendor's file, while calling more genotypes. That is not a victory lap. It is a proof that the dependency is optional, which is a different and, I think, more useful thing.
|
||||
|
||||
## Reason three: it should run on a small computer
|
||||
|
||||
A lot of genomics software quietly assumes a server room. SimurgArray was developed and mostly validated on a Raspberry Pi 5 with 8 GB of memory. Heavy jobs run inside a memory guard, because I learned the hard way what happens when the kernel has to choose between my test suite and my web browser. The browser lost. So did the test suite, actually.
|
||||
|
||||
With the optional Rust kernels a GSA sample takes about a second on a single Pi core. On a cloud server core it is roughly 80 samples a minute. The few cloud validation runs I needed cost a few dollars in total, and every one of them was set to switch itself off and was checked afterwards to make sure nothing kept billing quietly in the background.
|
||||
|
||||
I care about this because the people who would benefit most from open array analysis are often the ones with the least infrastructure. More on that in part 3.
|
||||
|
||||
## Reason four: understanding is a feature
|
||||
|
||||
There is a kind of knowledge you only get by rebuilding something. I now know why the normalization uses the exact float operations it uses, why a median of an even number of values is not always the median you expect, and why a NaN can have a sign depending on which processor produced it. None of this is glamorous. All of it matters if you want two programs to agree to the last bit.
|
||||
|
||||
That understanding is now written down, in code and in documents, where it can outlive my own memory of it. Given how my memory works, that is a real advantage.
|
||||
|
||||
## What it is not
|
||||
|
||||
SimurgArray is a research tool. It is not a medical device, it is not for diagnosis, and its pharmacogenomics output is not a prescription. I say this plainly because PGx reports look very official, and a well formatted table can be more convincing than it deserves to be.
|
||||
|
||||
It also does not use anything it should not. No decompiled binaries, no vendor data in the repository, no copied GPL code. Tools under the GPL are only ever called as separate programs to compare against. When I borrowed from MIT, BSD or Apache licensed projects, the credit is in `THIRD_PARTY_NOTICES.md`, word for word.
|
||||
|
||||
## The short version
|
||||
|
||||
SimurgArray exists because array genotyping is too widely used to be understood by only one company, because cluster files should be something you can make yourself, and because a curious person with a small computer should be able to follow every number from the scanner to the VCF.
|
||||
|
||||
In the next post I will look at what else is out there, which is quite a lot, and why I still decided to write my own. The honest answer involves both good reasons and a certain amount of stubbornness.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Are there alternatives? Yes. Why build it anyway?
|
||||
|
||||
*Part 2 of 5. Kemal Yaylali, September 2026*
|
||||
|
||||
Whenever someone tells me they are writing their own genotype caller, my first instinct is to ask whether they have looked around. So it is only fair that I answer the same question about myself.
|
||||
|
||||
I did look around. There is a lot of good work out there. Some of it I admire, some of it I depend on, and some of it is the reason SimurgArray can check its own answers at all.
|
||||
|
||||
## What the vendor gives you
|
||||
|
||||
The array manufacturer offers its own software, and it is good at what it does.
|
||||
|
||||
**GenomeStudio** is the classic. A desktop application for Windows where you load a project, look at cluster plots, fix the loci that look strange and export reports. Generations of lab scientists learned arrays on it. It is free to use after registering, but it is closed, it wants a graphical desktop, and it does not scale nicely to tens of thousands of samples.
|
||||
|
||||
**The command line tools** (the array analysis platform and its predecessors) turn IDATs into GTC files without the graphical part. They are fast and they are the reference: when I say SimurgArray matches the vendor byte for byte, these are the outputs I mean. They are also closed, so when something looks odd you can only guess why.
|
||||
|
||||
**The vendor's newer analysis software** does genotyping, copy number and pharmacogenomics in one package, locally or in the cloud. I studied its public documentation closely, because it describes a sensible feature set and a clear list of outputs. It is still closed, and its licensing and platform assumptions are aimed at institutions, not at a person with a Raspberry Pi and a free evening.
|
||||
|
||||
None of this is a complaint. A company building good closed tools for paying customers is a normal thing. It just leaves a gap.
|
||||
|
||||
## What the open source world gives you
|
||||
|
||||
This is where it gets interesting, because several people have already done a lot of the hard work in the open.
|
||||
|
||||
**gtc2vcf** by Giulio Genovese is a bcftools plugin that converts GTC files (and IDATs, via an open reimplementation of the calling) into VCF. It is careful, fast and MIT licensed. SimurgArray uses it as an oracle all the time, and it helped me understand several details that the public documentation leaves out. If you only need GTC to VCF, you may not need anything else.
|
||||
|
||||
**MoChA**, from the same author, detects mosaic chromosomal alterations using phased BAF. It is the right tool for mosaicism in large cohorts, and it is the reason I know my own mosaic caller has a hard limit below about 20 % cell fraction without phasing.
|
||||
|
||||
**BeadArrayFiles** and **GTCtoVCF**, both from the vendor's own open source repositories, read the file formats and write VCF. Old, a bit dusty (GTCtoVCF needed two small patches to run on Python 3), and extremely useful as references.
|
||||
|
||||
**illuminaio** in Bioconductor reads IDAT files. It is GPL licensed, so SimurgArray only runs it as a separate program to compare results and never reuses its code.
|
||||
|
||||
**crlmm** and **Illuminus** are academic callers from the late 2000s with a real statistical model behind them. Their papers shaped how ArrayTrain thinks about clusters.
|
||||
|
||||
**PennCNV** and **QuantiSNP** are the long standing tools for copy number from LRR and BAF.
|
||||
|
||||
**PharmCAT**, **Stargazer**, **Aldy** and friends call star alleles, mostly from sequencing data or from VCFs you already have.
|
||||
|
||||
**sesame** and **minfi** handle methylation arrays in R, and SimurgArray's methylation QC is checked against sesame.
|
||||
|
||||
**PLINK 2** does everything downstream of a VCF, better than I ever would, and I would not dream of replacing it.
|
||||
|
||||
## So why build another one?
|
||||
|
||||
Because none of these, alone or together, gave me the thing I wanted: one open pipeline from raw IDAT to final report, bit exact with the vendor where that is possible, tested against every one of the tools above, and honest about where it differs.
|
||||
|
||||
Here are the specific reasons, in the order they occurred to me.
|
||||
|
||||
**The chain was broken in the middle.** You can read IDATs with one tool, convert GTCs with another, call CNVs with a third and PGx with a fourth. Each hands off to the next with its own conventions for strand, allele order, missing values and sample names. SimurgArray keeps one data model from start to finish, and every hand off is tested.
|
||||
|
||||
**Nobody promised to agree with the vendor to the last bit.** Close is usually fine. But close means you cannot tell a real difference from a rounding difference. Once normalization, calling and GTC writing are identical down to the byte, any remaining difference is information instead of noise. Getting there required reproducing float32 quirks, a particular median that is not quite a median, and the sign of a NaN. I am unreasonably proud of that last one.
|
||||
|
||||
**Cluster files were a dependency without an exit.** Every open caller I found needs a cluster file from the vendor. ArrayTrain removes that requirement. For a cohort whose ancestry is not well represented in the samples the vendor trained on, that might matter a lot. I will come back to this.
|
||||
|
||||
**I wanted it to run on small hardware.** Most pipelines assume a cluster or at least a workstation. SimurgArray was written on a Raspberry Pi and validated there as much as possible, with the cloud used only when a dataset simply did not fit, and even then for minutes at a time.
|
||||
|
||||
**I wanted a specification, not just code.** The functional spec lists 416 behaviours with IDs, from command line options to edge cases like an empty sample name column in the vendor's own template sheet. Tests cite those IDs. It sounds bureaucratic. It is actually liberating, because "is this a bug?" becomes a question with an answer.
|
||||
|
||||
**I wanted to learn it properly.** Reading code teaches you how something works. Reproducing it teaches you why. Several of the most interesting facts about arrays that I know now came from a test failing by one unit in the last place.
|
||||
|
||||
## And the stubbornness
|
||||
|
||||
I should be honest: there is also a bit of "how hard can it be". The answer, as usual, was "harder than that, but not impossible". The first estimate for normalization was a few weeks. The first version that matched the vendor bit for bit took longer, and taught me more about floating point contraction on ARM processors than I had planned to know.
|
||||
|
||||
It helped that the expired patents on the core normalization and clustering methods are public, that the technical notes are public, and that people like the authors above wrote their work down in the open. SimurgArray stands on all of that. It does not replace any of it.
|
||||
|
||||
## Where it fits
|
||||
|
||||
If you want a mature graphical tool with support, use the vendor's software. If you only need GTC to VCF, use gtc2vcf. If you want mosaicism in a biobank, use MoChA. If you want PGx from sequencing, use PharmCAT or Aldy.
|
||||
|
||||
If you want to go from a folder of IDAT files to genotypes, QC, CNVs, PGx and your own cluster file, on hardware you own, with every step open and every disagreement written down, SimurgArray is the tool I wish I had found when I started.
|
||||
|
||||
Next time: why I think this is useful beyond my own curiosity, and who might actually benefit.
|
||||
@@ -0,0 +1,65 @@
|
||||
# What good could it do?
|
||||
|
||||
*Part 3 of 5. Kemal Yaylali, September 2026*
|
||||
|
||||
"Benefit to humanity" is a big phrase for a tool that mostly reads binary files. I will try to keep this post the right size. SimurgArray will not cure anything. What it can do is lower a few barriers that currently decide who gets to do genetics research and how much of it they can trust.
|
||||
|
||||
Here is where I think it helps, roughly from the most certain to the most hopeful.
|
||||
|
||||
## 1. Reproducible science
|
||||
|
||||
Array genotypes feed genome wide association studies, polygenic scores, ancestry analyses and a great deal of population genetics. A lot of that work rests on a sentence like "calls were produced with the manufacturer's software". If someone wants to rerun the analysis five years later, with a different version of that software, the numbers may shift, and nobody can say exactly why.
|
||||
|
||||
With SimurgArray every run writes a manifest: software version, normalization version, cluster file checksum, command line, even which backend (Python or Rust) was used. The same inputs give the same bytes. And because the pipeline reproduces the vendor's GTC files exactly on public data, an old analysis can be rebuilt and compared field by field, instead of "roughly".
|
||||
|
||||
This is the least exciting benefit and probably the most important one.
|
||||
|
||||
## 2. Research where budgets are small
|
||||
|
||||
Genotyping arrays are the cheapest way to look at hundreds of thousands of variants in a person. That makes them the natural choice for biobanks and studies in countries where sequencing everyone is not realistic. Ironically, the analysis side is where those projects often struggle: licenses, servers, specialist staff, and software that assumes all three.
|
||||
|
||||
SimurgArray runs on a Raspberry Pi. I do not recommend running a national biobank on one (I did find its limits, usually around midnight), but a single ordinary server core handles about 80 GSA samples a minute. A modest machine can process a large study in an afternoon, and the software costs nothing.
|
||||
|
||||
The pipeline also produces the things a small team needs to trust its data without a bioinformatics department: control probe QC, sample QC, contamination estimates, relatedness, sex checks, and an HTML report that a lab person can open in a browser and actually understand.
|
||||
|
||||
## 3. Better calls for underrepresented populations
|
||||
|
||||
This is the part I find most hopeful.
|
||||
|
||||
A cluster file encodes where the genotype clouds sit for each SNP. It is trained on a set of samples, and those samples have ancestries. If your cohort comes from a population that was thin or absent in that training set, rare alleles that are common in your population may never have had a proper cluster. The caller then does its best with an imputed guess.
|
||||
|
||||
ArrayTrain lets a group train cluster files on their own samples. On public data, a cluster file trained from 120 arrays already matched the vendor's accuracy against whole genome sequencing within 0.02 percentage points, while calling more genotypes. I have only tested one cohort so far, so I will not claim more than that. But the direction is clear: the people who own the samples can own the clusters too.
|
||||
|
||||
## 4. Pharmacogenomics research that is open to inspection
|
||||
|
||||
A growing number of arrays include pharmacogenomic content, because a handful of genes (CYP2D6, CYP2C19, CYP2C9, SLCO1B1, DPYD and others) influence how people respond to common drugs. Calling star alleles from an array is tricky. CYP2D6 in particular has deletions, duplications and hybrid genes that a SNP array can only see indirectly.
|
||||
|
||||
SimurgArray builds its PGx database from open sources (CPIC, PharmVar, ClinPGx), calls targeted copy number, and reports diplotypes together with everything that went into them: which variants were seen, which were missing, which alternative diplotypes the array cannot tell apart. On public reference samples it agreed with the GeT RM consensus in 154 of 168 comparable gene calls, and the misses are listed and explained.
|
||||
|
||||
I want to be very clear here. This is research software. It is not for choosing a drug or a dose. But openness matters even for research: when an algorithm says someone is a poor metabolizer, a researcher should be able to see why, and disagree.
|
||||
|
||||
## 5. Copy number for rare disease research
|
||||
|
||||
Large deletions and duplications cause many rare diseases, and arrays are still a common first look. SimurgArray calls CNVs, loss of heterozygosity and mosaic events across the genome and writes them with ISCN style annotation.
|
||||
|
||||
Its honest numbers: on 360 public arrays compared with 30x sequencing, constitutional deletion calls were right far more often than mosaic ones, and rare deletions were found about 30 % of the time at the size and probe density we tested. Common CNVs are mostly invisible to the method by design, because the reference batch absorbs them. For rare disease research, rare events are the interesting ones, so that is the right trade, but it is a trade and it is written down.
|
||||
|
||||
## 6. Teaching
|
||||
|
||||
I learned more about arrays by rebuilding the pipeline than from any course. The code is written to be read. Every algorithm names its source. Every oddity the vendor has, and every place we deliberately behave differently, is documented with a date and a reason.
|
||||
|
||||
A student who wants to know how a genotype call happens can follow one sample through normalization, clustering and scoring, print intermediate values, and compare them with the reference tools. That used to require either a job at the company or a lot of guessing.
|
||||
|
||||
## 7. Keeping the ecosystem honest
|
||||
|
||||
Open alternatives are good for everyone, including the vendor. When a public tool can reproduce outputs exactly, differences become bug reports instead of mysteries. Several findings in `known_unknowns.md` are small documentation errors or version quirks that anyone using the official tools would benefit from knowing about.
|
||||
|
||||
## What it will not do
|
||||
|
||||
It will not replace clinical laboratories, their validated pipelines, or the people who sign reports. It will not make arrays as informative as sequencing. It will not replace the excellent open tools it builds on. And it will not make genetic data less sensitive: people who run it are responsible for handling their data properly, which the software supports with privacy options in its reports but cannot enforce.
|
||||
|
||||
## The small version of a big claim
|
||||
|
||||
If SimurgArray helps one underfunded study get cleaner genotypes, one student understand what a cluster file is, or one reviewer ask "which version of the normalization did you use?", it has done its job. The bird in its name is known for bringing many small travellers to one clear place. I will be happy if it brings a few people to a clearer view of their data.
|
||||
|
||||
Next time: what it would take to make SimurgArray public properly, and a realistic calendar for doing it.
|
||||
@@ -0,0 +1,105 @@
|
||||
# Going public: what it takes, and a calendar
|
||||
|
||||
*Part 4 of 5. Kemal Yaylali, September 2026*
|
||||
|
||||
Right now SimurgArray lives in a private repository on my own Git server. It has a license, a changelog, a user guide, wheels, a Docker image and a version number that just became 2.0.0. In other words, it looks public. It is not, yet.
|
||||
|
||||
Publishing code is easy. Publishing it responsibly is a checklist. This post is that checklist, followed by a calendar I intend to keep, give or take the usual week.
|
||||
|
||||
## What "public" means here
|
||||
|
||||
By public I mean four things:
|
||||
|
||||
1. The source code on a public host, with issues and pull requests open.
|
||||
2. Installable packages: a Python wheel, the optional Rust kernel wheels, a container image and a conda recipe.
|
||||
3. Documentation someone can follow without asking me anything.
|
||||
4. A citable record: a DOI for each release and a short preprint describing the methods and the validation.
|
||||
|
||||
## The checklist
|
||||
|
||||
### Licensing
|
||||
|
||||
SimurgArray is MIT licensed. Code borrowed from other projects came only from MIT, BSD and Apache licensed sources, and their license texts sit in `THIRD_PARTY_NOTICES.md` exactly as the authors wrote them. GPL tools are only ever run as separate programs for comparison, never copied.
|
||||
|
||||
Before going public I will do one more pass over every file to confirm that each ported function names its origin, and that nothing slipped in during the late night sessions. Late night sessions are when things slip in.
|
||||
|
||||
### Data that must never be published
|
||||
|
||||
The repository must not contain vendor manifests, cluster files, IDATs or GTCs. The `.gitignore` has blocked them from the start, and the test fixtures are Bioconductor example files under the Artistic 2.0 license plus synthetic data. Still, "we never committed it" is a claim, and a claim deserves a check. I will scan the complete Git history, not just the current tree, for large binaries and for file types that should not be there.
|
||||
|
||||
The same goes for secrets. The cloud scripts use credentials from the local environment, never from files in the repository, but a full history scan for keys is cheap and embarrassment is expensive. The cloud account credentials used during development will be rotated before the switch, as a matter of principle.
|
||||
|
||||
### Names and trademarks
|
||||
|
||||
The software reads file formats defined by Illumina and reproduces the behaviour of Illumina's algorithms from public documents and expired patents. Illumina, Infinium, GenCall, GenTrain and GenomeStudio are their trademarks. The documentation will say clearly that SimurgArray is independent and not affiliated with or endorsed by the vendor, and it will use those names only to describe compatibility.
|
||||
|
||||
The name SimurgArray itself needs a check on the Python package index, conda channels and container registries before anything is uploaded. If someone else has it, I will be sad for a day and then pick a variant.
|
||||
|
||||
### Third party data sources
|
||||
|
||||
The PGx database is built on the user's machine from public sources:
|
||||
|
||||
* CPIC (CC0),
|
||||
* PharmVar (their own terms),
|
||||
* ClinPGx (CC BY SA).
|
||||
|
||||
SimurgArray ships the builder, not the database, so each source keeps its own terms and attribution. The documentation will list those terms next to the download commands, so nobody has to find them in a footnote.
|
||||
|
||||
### Scope and safety language
|
||||
|
||||
Every README, report header and PGx output will state that the software is for research, not for diagnosis or treatment decisions. The PGx JSON already carries the database version and the evidence behind each call. That transparency is the main safety feature, but it is not a substitute for saying the obvious out loud.
|
||||
|
||||
### Engineering hygiene
|
||||
|
||||
* Continuous integration on public runners for x86_64 and aarch64: lint, type checks, unit tests.
|
||||
* Oracle tests that need large public datasets stay opt in, with a script that downloads everything with checksums.
|
||||
* Issue templates that ask for the command, the software version and the run manifest, because "it gave a wrong genotype" is hard to debug without them.
|
||||
* A contributing guide, a code of conduct and a security policy.
|
||||
* A short description of the release process, so that it is not only in my head.
|
||||
|
||||
### Documentation
|
||||
|
||||
The user guide covers every command. What is missing is a gentle path for newcomers: a tutorial that starts from public IDATs (the Bioconductor fixtures and the GEO dataset used in validation), runs the whole pipeline on a laptop, and explains each output. I also want one page per validation report written for people who do not want to read a JSON file. Most people.
|
||||
|
||||
### Citation
|
||||
|
||||
Each tagged release will get a DOI through Zenodo, and the repository will carry a citation file. A preprint on bioRxiv will describe the design, the bit exact reproduction, ArrayTrain, the CN and PGx modules, and every known limitation. If it is going to be cited, it should be cited for what it actually does.
|
||||
|
||||
## The calendar
|
||||
|
||||
The weeks start on Mondays. Everything below costs nothing except time, apart from an optional domain for the documentation site.
|
||||
|
||||
**Week of October 5, 2026: audit**
|
||||
Full history scan for vendor files and secrets. Credential rotation. Provenance pass over ported code. Trademark and disclaimer text in README, user guide and report templates.
|
||||
|
||||
**Week of October 12: public repository**
|
||||
Public mirror on a mainstream code host, continuous integration for both architectures, issue templates, contributing guide, code of conduct, security policy. The private Git server stays as my working copy.
|
||||
|
||||
**Week of October 19: packages**
|
||||
Check name availability. Upload version 2.0.0 wheels to the Python package index, the image to a public container registry, and submit the conda recipe for review.
|
||||
|
||||
**Weeks of October 26 and November 2: tutorial and docs site**
|
||||
End to end tutorial on public data, validation summaries rewritten for humans, documentation site generated from the repository.
|
||||
|
||||
**Week of November 16: soft launch**
|
||||
Announce to a few people who work with arrays and will not be polite about problems. Collect issues. Fix the embarrassing ones quietly and the interesting ones loudly.
|
||||
|
||||
**Weeks of November 30 and December 14: preprint**
|
||||
Write the methods paper, rerun every validation from a clean checkout so the numbers in the paper come from the public code, deposit data summaries, submit to bioRxiv.
|
||||
|
||||
**Week of January 11, 2027: version 2.1**
|
||||
First release shaped by other people's feedback. Likely candidates: a second cohort for ArrayTrain validation, iterative CN references for better rare event sensitivity, and anything the soft launch reveals.
|
||||
|
||||
After that, a steady rhythm: a minor release every two or three months, a DOI for each, and a public changelog that keeps the habit of writing down what changed and why.
|
||||
|
||||
## What could delay it
|
||||
|
||||
* **A name clash.** Solvable, mildly annoying.
|
||||
* **An unexpected license question about a source.** Solvable, possibly slow.
|
||||
* **Real life.** Unavoidable, frequently scheduled.
|
||||
|
||||
## Why announce a calendar at all
|
||||
|
||||
Because a public date is the best cure for "just one more feature". The software is already more complete than I planned when I started. What it needs now is other people using it, finding its mistakes and telling me which of its choices were wrong.
|
||||
|
||||
Next time, the last post: what using SimurgArray actually looks like, from a folder of IDATs to a report, and what the name and the bird are about.
|
||||
@@ -0,0 +1,158 @@
|
||||
# Using SimurgArray, and the bird behind the name
|
||||
|
||||
*Part 5 of 5. Kemal Yaylali, September 2026*
|
||||
|
||||
Four posts of reasons are enough. This one is about what it looks like when you actually use the thing, and about the name, which people ask about more often than they ask about normalization. Fair enough.
|
||||
|
||||
One small note first. The command examples below use the usual command line options, and those start with two little lines. The prose around them does not. That is a personal style choice and I am sticking to it.
|
||||
|
||||
## Installing
|
||||
|
||||
On any Linux or macOS machine with Python 3.12:
|
||||
|
||||
```bash
|
||||
uv venv && uv pip install simurg-2.0.0-py3-none-any.whl
|
||||
simurg --help
|
||||
```
|
||||
|
||||
If you have a C compiler and Rust, you can add the optional kernels, which make the heavy steps about three times faster and produce exactly the same bytes:
|
||||
|
||||
```bash
|
||||
uv pip install ./rust/simurg-core
|
||||
python -c "from simurg._core import backend; print(backend())"
|
||||
```
|
||||
|
||||
There is also a Docker image and a conda recipe. The user guide covers all of them.
|
||||
|
||||
## A first look at your files
|
||||
|
||||
Before running anything, it helps to know what you have. `simurg inspect` reads any IDAT, manifest, cluster file, GTC or sample sheet and prints what is inside:
|
||||
|
||||
```bash
|
||||
simurg inspect idats/204112350001_R01C01_Grn.idat
|
||||
simurg inspect GSA.bpm GSA.egt --json
|
||||
```
|
||||
|
||||
This is surprisingly useful. It will tell you, for instance, that your cluster file was made for a different manifest version than your chips, which is the kind of thing you would rather know on day one.
|
||||
|
||||
## From IDAT to genotypes
|
||||
|
||||
The main event. One command reads the IDATs, normalizes them, calls genotypes against the cluster file, writes a GTC per sample, and runs the sample and control QC:
|
||||
|
||||
```bash
|
||||
simurg genotype --bpm GSA.bpm --egt GSA.egt --csv GSA.csv \
|
||||
--idats idats/ --sheet SampleSheet.csv --out run/gtc --threads 0
|
||||
```
|
||||
|
||||
`threads 0` means "use every core". On a Raspberry Pi 5 that is four, which is plenty for a few dozen samples while you make tea.
|
||||
|
||||
What you get:
|
||||
|
||||
* one GTC file per sample, identical to what the vendor's command line tool would produce with the same inputs,
|
||||
* `sample_summary.tsv` with call rates, LogR deviation, sex estimates and flags,
|
||||
* control probe metrics, contamination estimates and a relatedness table for the batch,
|
||||
* a `run_manifest.json` that records every version, checksum and option used.
|
||||
|
||||
## Looking at the QC
|
||||
|
||||
```bash
|
||||
simurg qc report --data run/gtc --out run/qc_report --output-format both
|
||||
```
|
||||
|
||||
This writes a single HTML file you can email to a colleague, plus a spreadsheet. The report has linked views: select an odd looking sample in the call rate plot and it lights up in the control metrics, the sex check and the chip layout. There is a thresholds editor, so you can move a cutoff and see which samples fail before you commit to it.
|
||||
|
||||
My favorite part is the chip heatmap. When a whole row of a BeadChip fails together, you stop blaming the DNA and start asking about the scanner.
|
||||
|
||||
## To VCF and beyond
|
||||
|
||||
```bash
|
||||
simurg gtc-to-vcf --bpm GSA.bpm --csv GSA.csv --fasta GRCh38.fa --gtcs run/gtc --out run/vcf
|
||||
simurg export plink --vcfs run/vcf --gtcs run/gtc --out run/plink --format both
|
||||
```
|
||||
|
||||
The VCFs are on the plus strand, validated with bcftools, and agree with gtc2vcf and GTCtoVCF apart from a documented list of cases where one of them cannot resolve an insertion or deletion probe. PLINK 1 and PLINK 2 files come out identical to what plink2 itself produces from the same VCFs.
|
||||
|
||||
## Copy number, LOH and mosaicism
|
||||
|
||||
Build a model once per chip and batch, from at least 24 normal samples, then call:
|
||||
|
||||
```bash
|
||||
simurg cn build-model --bpm GSA.bpm --fasta GRCh38.fa --egt GSA.egt \
|
||||
--reference-gtcs normals/ --out gsa.simurg-cyto
|
||||
simurg cn call --bpm GSA.bpm --model gsa.simurg-cyto --gtcs run/gtc --fasta GRCh38.fa --out run/cn
|
||||
simurg cn annotate --vcfs run/cn
|
||||
```
|
||||
|
||||
Each sample gets a CNV VCF with deletions, duplications, LOH and mosaic events, a segments file, and ISCN style descriptions with cytobands and genes. The sample summary flags arrays with far too many events. On the public validation set, exactly one array raised that flag, and it deserved it.
|
||||
|
||||
## Pharmacogenomics
|
||||
|
||||
Build the database from open sources, check what your array can actually see, then call:
|
||||
|
||||
```bash
|
||||
bash scripts/pgx/fetch_sources.sh
|
||||
simurg pgx db build --sources data/pgx/sources --fasta GRCh38.fa \
|
||||
--manifests GSA_PGx.bpm --csv GSA_PGx.csv --out pgxdb/
|
||||
simurg pgx coverage --bpm GSA_PGx.bpm --db pgxdb/pgx_db.sqlite
|
||||
simurg pgx copy-number call --gtcs run/gtc --model cnmodel/GSA_PGx.simurg-pgxcn --fasta GRCh38.fa --out run/vcf
|
||||
simurg pgx star-allele call --vcfs run/vcf --db pgxdb/pgx_db.sqlite --out run/pgx
|
||||
simurg pgx phenotype --calls run/pgx --db pgxdb/pgx_db.sqlite
|
||||
```
|
||||
|
||||
The coverage step is the one I would not skip. It tells you, before you look at a single sample, which alleles your array can distinguish and which it cannot. A lot of confusion about array PGx comes from asking a chip a question it was never able to answer.
|
||||
|
||||
For each sample you get a diplotype summary, the supporting variants, the variants that were not covered, alternative diplotypes the array cannot tell apart, and a JSON file with the phenotype and the evidence. For research, as always.
|
||||
|
||||
## Training your own cluster file
|
||||
|
||||
```bash
|
||||
simurg train --gtcs cohort_gtc --bpm GSA.bpm --out mycohort.egt
|
||||
simurg genotype --bpm GSA.bpm --egt mycohort.egt --idats new_idats/ --out run2/gtc
|
||||
```
|
||||
|
||||
A hundred samples is the minimum. Training reads raw intensities, not genotypes, so it does not matter which cluster file your cohort was first called with. On the Pi, 120 GSA samples take a bit over an hour. I usually start it and go to bed, which is also how most of this project got done.
|
||||
|
||||
## Checking one run against another
|
||||
|
||||
```bash
|
||||
simurg compare run/gtc other_run/gtc --out compare_report
|
||||
```
|
||||
|
||||
Every field of every GTC or VCF is compared and labelled EXACT, NEAR, DISCREPANCY or UNKNOWN, with an HTML dashboard. This is the tool I used to build everything else, and it is the one I would miss most.
|
||||
|
||||
## About the name
|
||||
|
||||
In Persian and Turkic mythology the Simurg (Simurgh, Simorgh, depending on who is telling the story) is a great bird, old and wise, that lives on a mountain at the edge of the world. In Attar's twelfth century poem *The Conference of the Birds*, the birds of the world set out to find the Simurg and make it their king. Most give up along the way. When the survivors finally arrive, there are thirty of them, and they discover that "si murg" means "thirty birds". The Simurg they were looking for was themselves, together.
|
||||
|
||||
I liked the name because an array is exactly that: hundreds of thousands of tiny beads that only make sense once you look at them together. Then something happened that I did not plan. The public demo dataset I used for the pharmacogenomics validation was sold as 36 samples. When I checked identities against 1000 Genomes, it turned out to be 30 individuals.
|
||||
|
||||
Thirty birds. I took it as a sign that I had picked the right name, or at least a sign that I should stop looking for signs and get back to work.
|
||||
|
||||
## Branding
|
||||
|
||||
A tool for researchers does not need a marketing department, but it does need to be recognizable and consistent. Here is what I have settled on.
|
||||
|
||||
**Name.** SimurgArray in writing, `simurg` on the command line. Short to type, hard to mistype, and it does not collide with any genomics tool I know of.
|
||||
|
||||
**Tagline.** "Thirty birds, one picture." It is the whole idea in four words: many small signals, one honest result.
|
||||
|
||||
**Logo.** A bird in flight drawn only with dots on a square grid, the way beads sit on a BeadChip. The dots use the two scanner channels, red and green, and where they overlap the bird turns gold. It should work at 16 pixels as a favicon and at poster size, and it should look a little like a genotype cluster plot if you squint. People who work with arrays will squint.
|
||||
|
||||
**Colors.**
|
||||
* Channel red #C8453A
|
||||
* Channel green #2F8F5B
|
||||
* Simurg gold #D4A017 for highlights and the bird
|
||||
* Night indigo #1E2240 for backgrounds, because most of the work happened at night
|
||||
* Paper #F7F5EF for documents
|
||||
|
||||
**Type.** A clean sans serif for text and a monospace font for anything you might paste into a terminal. Numbers in reports always use tabular figures, so columns of call rates line up.
|
||||
|
||||
**Voice.** Plain, exact and a little dry. Say what the software does, show the number, name the limitation in the same paragraph. No "revolutionary", no "AI powered", no promises about medicine. If a result has a caveat, the caveat goes next to the result, not in a footnote.
|
||||
|
||||
**Reports.** Every HTML report carries the small dotted bird in the corner, the software version and the run manifest checksum. The bird is there for recognition. The checksum is there because the bird cannot prove anything on its own.
|
||||
|
||||
## Thank you
|
||||
|
||||
If you have read all five posts, you now know more about SimurgArray than most of the machines it has run on. The code goes public on the calendar from the previous post. Until then, if you work with arrays and want to try it, or want to tell me which of my choices are wrong, I would be glad to hear from you.
|
||||
|
||||
The birds made it to the mountain. Now the interesting part starts.
|
||||
@@ -0,0 +1,9 @@
|
||||
# SimurgArray blog
|
||||
|
||||
Five posts about why SimurgArray exists and where it is going.
|
||||
|
||||
1. [Why SimurgArray should exist](01_why_simurgarray_should_exist.md)
|
||||
2. [Are there alternatives? Yes. Why build it anyway?](02_alternatives_and_why_i_built_it_anyway.md)
|
||||
3. [What good could it do?](03_what_good_it_could_do.md)
|
||||
4. [Going public: what it takes, and a calendar](04_going_public_plan_and_calendar.md)
|
||||
5. [Using SimurgArray, and the bird behind the name](05_using_simurgarray_and_the_bird_behind_the_name.md)
|
||||
Reference in new issue
Block a user