Tester une pipeline de variants structuraux passe par des VCF d’entrée qui couvrent les cas attendus en sortie de caller, à savoir des enregistrements Manta ou DELLY avec leurs particularités de format, des SV qui chevauchent des régions blacklistées par ENCODE, des SV qui correspondent à des variants germinaux connus dans gnomAD, et des plages réalistes pour SVLEN, HOMLEN ou VAF. Ces VCF servent à valider les règles de filtrage, à reproduire des cas limites et à faire tourner la CI sans rejouer un caller complet sur des BAM.
Le problème vient du fait que ces VCF de référence sont rares et peu adaptés. Les jeux publics restent niches, ne couvrent pas toutes les combinaisons utiles, et ne portent pas l’étiquetage interne nécessaire pour vérifier qu’un filtre a bien fait son travail. La solution courante consiste à fabriquer des VCF à la main, ce qui revient à empiler des fichiers approximatifs qui dérivent du format réel et qui ne se prêtent pas à de la régression reproductible. Des générateurs synthétiques existent pour les SNV, mais l’écosystème SV n’a pas d’équivalent en ligne de commande qui produise du VCF caller-spécifique avec injection d’artefacts contrôlée.
svForge couvre ce besoin avec une CLI qui produit du VCF Manta ou DELLY prêt à passer dans une pipeline.
Méthode
L’outil tire ses variants depuis une banque YAML pondérée qui couvre les types DEL, DUP, INV, INS et BND sur hg38. Chaque tirage retourne un enregistrement caller-spécifique conforme à VCFv4.1 pour Manta et VCFv4.2 pour DELLY, avec les champs INFO et FORMAT attendus par le caller cible. Les paramètres de variabilité (--svlen-range, --homlen-range, --vaf-range) restreignent les plages d’échantillonnage et --svtypes filtre les types retenus.
Deux modes d’injection complètent la génération de fond. La fraction --gnomad-fraction remplace une part des enregistrements par des SV tirés d’un mini-catalogue gnomAD bundlé, et --blacklist-fraction fait de même avec un sous-ensemble de la blacklist ENCODE. Chaque enregistrement injecté porte un tag INFO/SVFORGE_SOURCE qui prend la valeur bank, gnomad ou blacklist, ce qui rend la vérification en aval directe : un filtre gnomAD bien réglé doit faire disparaître toutes les lignes SVFORGE_SOURCE=gnomad du VCF de sortie.
Reproductibilité et traçabilité
Le tirage adopte un seed explicite via --seed et le seed effectivement utilisé est toujours écrit dans le header du VCF généré, y compris quand il a été tiré au hasard. Une exécution sans seed reste donc rejouable à l’identique à partir du fichier produit seul. La ligne de commande logguée dans le header est passée par sanitize_command() qui retire les chemins absolus, ce qui évite que des chemins de home utilisateur ou de cluster fuitent dans les VCF partagés.
Un header ##svforgeWarning=SYNTHETIC_DATA_DO_NOT_USE_FOR_CLINICAL_DIAGNOSIS est injecté de force dans tous les fichiers et n’est pas configurable, pour qu’aucun VCF généré ne puisse être confondu avec une sortie de caller réelle.
Validation
La sous-commande svforge validate reprend un VCF généré et vérifie que les enregistrements taggués gnomad et blacklist correspondent exactement aux entrées des catalogues bundlés. Le code de retour vaut 0 si la correspondance est exacte, non nul sinon, et un rapport TSV détaillé est disponible avec --report-tsv. Cette étape sert de garde-fou pour les pipelines qui s’appuient sur le tag SVFORGE_SOURCE comme oracle.
Modularité
Les writers Manta et DELLY sont enregistrés via le point d’entrée svforge.writers dans pyproject.toml. Un caller tiers s’ajoute en publiant un package Python qui expose une nouvelle entrée sous ce groupe, sans toucher au cœur de svForge. La banque par défaut est elle aussi remplaçable via --bank qui prend un YAML arbitraire, et --header-template accepte un template VCF maison pour les déploiements qui imposent des champs INFO ou FILTER spécifiques.
Usage
Une génération typique produit un VCF Manta de 50 enregistrements pour un échantillon nommé :
svforge gen --caller manta --out synthetic.vcf.gz --n 50 --sample-name TUMOR01 --seed 42
Pour les pipelines somatiques, gen-pair produit deux VCF cohérents tumeur et normal en une seule invocation, avec un nombre d’événements somatiques et germinaux paramétrable :
svforge gen-pair \
--caller manta \
--out-tumor tumor.vcf.gz \
--out-normal normal.vcf.gz \
--n-somatic 30 \
--n-germline 10 \
--tumor-sample-name TUMOR_01 \
--normal-sample-name NORMAL_01 \
--seed 99
L’injection d’artefacts s’active par fraction et se combine avec les autres options de sampling :
svforge gen --caller manta --out out.vcf.gz --n 100 --sample-name S1 \
--gnomad-fraction 0.15 --blacklist-fraction 0.1 --seed 7
La validation reprend le VCF produit et confirme que les enregistrements injectés sont conformes aux catalogues :
svforge validate --vcf out.vcf.gz --report-tsv validate_report.tsv
L’outil est publié sur PyPI et installable par pip install svforge. La v1 cible hg38 uniquement et requiert Python 3.10 ou supérieur. Le code source est disponible sur GitHub sous licence MIT.
github.com pieetie/svforge Code source sur GitHub