HTML

Az élet kódjai

Csináld maga. Senki nem csinálja meg helyetted.

Friss topikok

Snakemake: bűvöljük a kígyót

2019.12.08. 22:55 Travis.CG

Egyik nap a munkatársaim azon dolgoztak, hogy olyan szkriptet írjanak, ami párhuzamosan elindítja a munkafolyamatokat, figyelik, melyik áll le hibával, stb. Gyakorlatilag egy feladat ütemezőt írtak. Miután rászántak több napot a szkript megírására, még ráment rengeteg idő, hogy a hibákat javítsák, teszteljék.

Ezek azok a programok, amelyeket teljesen felesleges megírni. Miért? Mert már létezik rájuk megoldás. Korábban írtam is róluk, de az idő előre haladtával a dolgok változtak. Lássuk most a legújabb kedvencemet a Snakemake-t.

A Snakemake első ránézésre egy Makefile-szerű rendszer, amivel hierarchikus munkafolyamatokat írhatunk le, de Python nyelven. Ez utóbbi azt jelenti, hogy bárhova beszúrhatunk Python kódot, azt a rendszer végrehajtja. Mivel a bioinformatikában szinte minden lépés fájlok pattogtatását vonja maga után, ezt teszi a Snakemake is. Figyeli, mely kimenetek, mely bemenetekhez tartoznak. Ez határozza meg, hogy mely lépések követik egymást.

Lássunk egy példát, ami a GATK néhány funkcióját valósítja meg. A teljes folyamatból csak azokat a lépéseket szedtem ki, amelyek a Snakemake egy-egy speciális funkciójával kapcsolatosak, és így segítenek megérteni ezt a programot. Egy átlagos GATK futtatás - rendkívül sematikusan - úgy néz ki, hogy először a BAM fájlokat dolgozzuk fel. Beállítjuk a minőségi mutatókat és a fájlokat olyan formára hozzuk, hogy a GATK szeresse. Ezután több BAM fájl eredményét kombináljuk, hogy a variációkat hatékonyabban találjuk meg. Végül ezen a kombinált VCF fájlon végzünk további műveleteket.

A folyamat leírása négy kötelező elemből épül fel: szabály neve, bemeneti fájlok, kimeneti fájlok, feladat.

rule sort:
   input:
   output:
   shell:

Mivel Pythonról van szó (Makefile örökséggel), a sor elején a behúzás kötelező. A rule kulcsszóval nevezzük el a lépést (jelen esetben sort), majd megadjuk a paramétereket. Ha például a BAM fájlokat sorba szeretnénk rendezni, akkor valami ilyesmit kell írnunk:

rule sort:
   input:
      "raw.bam"
   output:
      "sorted.bam"
   shell:
      "samtools sort -o {output} {input}"

Gyakorlatilag ez az alapja a rendszernek. A definíciók közönséges Python sztringek, a lépések között adhatunk Python kódot a rendszerhez. Például tegyük fel, hogy több lépés is igényli a referencia genomot. Létrehozhatunk neki egy változót.

reference = "/mnt/local/nfs/slowmachine/otherexporteddrive/raid/sshmount/nooneknowswhereitis/hg18.fa"
rule genotype:
   input:
      "vcf/genotype.gvcf.gz"
   output:
      "vcf/raw.vcf.gz"
   shell:
      "gatk GenotypeGVCFs -R %s -V {input} -O {output}" % (reference)

De nem muszáj shell szkripteket sem futtatni. A shell kulcsszó helyett, ha run-t használunk, akkor a rendszer a kódot fogja végrehajtani. Például a CombineGVCFs lépés a GATK-ban megköveteli, hogy minden egyes bemeneti fájl előtt legyen egy -V. Ezt nem tudjuk megoldani a Snakemake álltal biztosított hagyományos keretek között.

run:
   param = ""
   for i in input:
      param += " -V " + i
   cmd = "gatk CombineGVCFs %s -O {output} -R %s " % (param, reference)
   shell(cmd)

Még az sem baj, ha R kódot akarunk futtatni. A run helyett a script kulcsszó segítségével külső Python, R vagy Julia szkripteket futtathatunk.

Természetesen a bemeneti és kimeneti fájlok száma nem korlátozódik egyre. Az ApplyVQSR lépésnél például három bemeneti fájlra van szükségünk.

rule applysnp:
   input:
      tr="vcf/second12.snp.tr",
      recal="vcf/second12.snp.recal",
      vcf="vcf/second12.raw.vcf.gz"
   output:
      "vcf/second12.snpready.vcf.gz"
shell:
    "gatk ApplyVQSR -R %s -V {input.vcf} -O {output} --tmp-dir tmp/ --recal-file {input.recal} --tranches-file {input.tr} --mode SNP --truth-sensitivity-filter-level 95.0" % (reference)

Az egyes bemeneti állományokat névvel tudjuk megjelölni. Ugyan ez a módszer használható a kimeneti fájlok esetén.

A bemeneti és kimeneti állományok kezelése hasonló a Makefile-hoz. A Snakemake megvizsgálja, hogy a kineneti fájl létezik-e és újabb-e a bemeneti fájlnál. Ha igen, akkor a lépést nem hajtja végre. Ha nem (mert például módosításokat végeztünk rajta), végrehajtja a lépést. Amennyiben hiba történik egy lépésnél, akkor a csonka kimeneti fájlokat törli. Azért, hogy nyomon követhessük a lépéseket, szükségünk van napló fájlokra. Mivel ezeket nem célszerű törölni egy hibás futás során, azokat a log kulcsszóval definiálhatjuk, az input és output kulcsszavakhoz hasonlóan.

Ezen kívül még több kulcsszó is van. Megadhatjuk például a szükséges erőforrásokat is, hogy a Snakemake hatékonyan tudja futtatni a lépéseket. Erről még lesz szó.

Az eddigi példák csak egy fájlt használtak ki- és bemenetnek. De előfordulhat, hogy ugyan azt a lépést sok fájlon kell végrehajtani. Ilyenkor használjuk a helyettesítő neveket (a doksiban wildcards néven utalnak rá). A helyettesítő nevek hasonlóan működnek, mint a '*' a BASH-ben, de annál érzékenyebb paraméterezést tesznek lehetővé. Visszatérve a sorba rendezős lépésre, ha minden BAM fájlon végre akarjuk hajtani a rendezést, akkor a következő módosításra lesz szükségünk. Tegyük hozzá a naplózást is, valamint jelezzük a használni kívánt szálak számát is.

rule sort:
    input: "bam/{sample}.bam"
    output: "bam/{sample}.sort.bam"
    threads: 8
    log: "bam/{sample}.sort.log"
    shell:
       "samtools sort -@ {threads} -m 4G -o {output} {input} 2>{log}"

Ez alapján a Snakemake még nem tudja, hogyan helyettesítse be a {sample} nevet. Kell egy lépés, ahol ezt meghatározzuk, méghozzá egy olyan lépés során, ahol összefutnak a szálak (vagy elágaznak, attól függően, hogy a folyamat elejét vagy végét nézzük). Ez a mi esetünkben a CombineGVCFs lépés, mert az illesztésekből keletkező GVCF fájlok itt válnak eggyé.

PATIENTS = ["mother", "father", "sick_child", "healthy1", "healthy2"]
rule combine:
   input:
      expand("{sample}.gvcf.vcf.gz", sample = PATIENTS)
   output:
      "combined.gvcf.vcf.gz"

A parancs részét már korábban bemutattam, ezért azt nem írnám le még egyszer. A sample helyettesítő név jöhet például a PATIENTS tömbből, de akár az összes fájlt is kiolvashatjuk egy könyvtárból a glob_wildcards parancs segítségével.

Miuán összeállt a munkafolyamat, azt futtatni kell. A snakemake parancs megkeresi a Snakefile fájlt az aktuális könyvtárban, és lefuttatja az abban található első szabályt. Amennyiben a szabály feltétele egy másik szabály, akkor azt is lefuttatja, egészen addig, amig vagy nincs kész a kimeneti fájl, vagy nincs több szabály.

A szabályok hierarchiáját a --dag opcióval kiírhatjuk, ami a mi esetünkben így fest:

gatk.png

Megjegyezném, hogy ez nem egy valós futás, mert a GATK-nak minimum 10 teljes genom kell, hogy a genotipizálás hatékony legyen, de az nagyon áttekinthetetlen ábrát eredményez, ezért egyszerűsítettem le. A program felismeri, mely lépéseket tudja párhuzamosan végrehajtani, ezért érdemes a szálakat beállítani neki. Képes feladat ütemezőket is használni, sőt különböző felhős infrastruktúrákat, dockert, kubernetet is. (Talán még döglött kutyán is fut.)

Nagyon hasznos funkció, hogy van benne tesztelő üzemmód. A -n kapcsolóval nem hajt végre egyetlen lépést sem, de ellenőrzi a ki- és bemeneti állományokat. Ha hibát talál, jelzi. Egyetlen hátránya, hogy a Python kódot sem futtatja ilyenkor, tehát azt nem tudjuk meg, hogy a kódbetétek szintaxisa megfelelő-e.

Tehát mielőtt elkezdenéd írni a következő Halálcsillag vezérlő szkriptedet, hogy összefogd a rakoncátlan programokat, gondolkozz el rajta: tényleg szükség van rá?

Szólj hozzá!

Címkék: bioinformatika

A bejegyzés trackback címe:

https://cybernetic.blog.hu/api/trackback/id/tr5615308286

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása