Teil 3: Joint Calling für eine Kohorte¶
In Teil 2 hast du eine Pipeline für das Variant Calling pro Probe erstellt, die die Daten jeder Probe unabhängig verarbeitet hat. Jetzt erweitern wir die Pipeline um Joint Variant Calling, wie in Teil 1 beschrieben.
Aufgabe¶
In diesem Teil des Kurses werden wir den Workflow erweitern, um Folgendes zu tun:
- Eine Indexdatei für jede BAM-Eingabedatei mit Samtools generieren
- GATK HaplotypeCaller auf jeder BAM-Eingabedatei ausführen, um ein GVCF mit genomischen Variantenaufrufen pro Probe zu generieren
- Alle GVCFs sammeln und in einem GenomicsDB-Datenspeicher kombinieren
- Joint Genotyping auf dem kombinierten GVCF-Datenspeicher ausführen, um ein VCF auf Kohortenebene zu erzeugen
Dieser Teil baut direkt auf dem Workflow aus Teil 2 auf.
Wie man von diesem Abschnitt aus beginnt
Dieser Abschnitt des Kurses setzt voraus, dass du Teil 2: Variant Calling pro Probe abgeschlossen hast und eine funktionierende genomics.nf-Pipeline besitzt.
Falls du Teil 2 nicht abgeschlossen hast oder für diesen Teil neu beginnen möchtest, kannst du die Lösung von Teil 2 als Ausgangspunkt verwenden.
Führe diese Befehle im Verzeichnis nf4-science/genomics/ aus:
cp solutions/part2/genomics-2.nf genomics.nf
cp solutions/part2/nextflow.config .
cp solutions/part2/modules/* modules/
Damit erhältst du einen vollständigen Workflow für das Variant Calling pro Probe. Du kannst testen, ob er erfolgreich läuft, indem du folgenden Befehl ausführst:
Lektionsplan¶
Wir haben dies in zwei Schritte unterteilt:
- Den Variant-Calling-Schritt pro Probe so ändern, dass ein GVCF erzeugt wird. Dies umfasst die Aktualisierung von Prozessbefehlen und Ausgaben.
- Einen Joint-Genotyping-Schritt hinzufügen, der die GVCFs pro Probe kombiniert und genotypisiert.
Dies führt den
collect()-Operator, Groovy-Closures für die Befehlszeilenkonstruktion und Prozesse mit mehreren Befehlen ein.
Note
Stelle sicher, dass du dich im richtigen Arbeitsverzeichnis befindest:
cd /workspaces/training/nf4-science/genomics
1. Den Variant-Calling-Schritt pro Probe so ändern, dass ein GVCF erzeugt wird¶
Die Pipeline aus Teil 2 erzeugt VCF-Dateien, aber Joint Calling erfordert GVCF-Dateien. Wir müssen den GVCF-Variant-Calling-Modus aktivieren und die Ausgabedateierweiterung aktualisieren.
Erinnere dich an den GVCF-Variant-Calling-Befehl aus Teil 1:
gatk HaplotypeCaller \
-R /data/ref/ref.fasta \
-I /data/bam/reads_mother.bam \
-O reads_mother.g.vcf \
-L /data/ref/intervals.bed \
-ERC GVCF
Im Vergleich zum Basis-HaplotypeCaller-Befehl, den wir in Teil 2 eingebunden haben, sind die Unterschiede der Parameter -ERC GVCF und die Ausgabeerweiterung .g.vcf.
1.1. HaplotypeCaller mitteilen, dass ein GVCF ausgegeben werden soll, und die Ausgabeerweiterung aktualisieren¶
Öffne die Moduldatei modules/gatk_haplotypecaller.nf, um zwei Änderungen vorzunehmen:
- Füge den Parameter
-ERC GVCFzum GATK-HaplotypeCaller-Befehl hinzu; - Aktualisiere den Ausgabedateipfad, um die entsprechende Erweiterung
.g.vcfzu verwenden, gemäß GATK-Konvention.
Stelle sicher, dass du am Ende der vorherigen Zeile einen Backslash (\) hinzufügst, wenn du -ERC GVCF hinzufügst.
Wir müssen auch den Ausgabeblock aktualisieren, um zur neuen Dateierweiterung zu passen.
Da wir die Befehlsausgabe von .vcf auf .g.vcf geändert haben, muss der output:-Block des Prozesses dieselbe Änderung widerspiegeln.
1.2. Die Ausgabedateierweiterung im Prozess-Ausgabeblock aktualisieren¶
Wir müssen auch die Veröffentlichungs- und Ausgabekonfiguration des Workflows aktualisieren, um die neuen GVCF-Ausgaben widerzuspiegeln.
1.3. Die Veröffentlichungsziele für die neuen GVCF-Ausgaben aktualisieren¶
Da wir jetzt GVCFs anstelle von VCFs produzieren, sollten wir den publish:-Abschnitt des Workflows aktualisieren, um aussagekräftigere Namen zu verwenden.
Wir werden die GVCF-Dateien auch zur Klarheit in ihr eigenes Unterverzeichnis organisieren.
Jetzt aktualisiere den Ausgabeblock entsprechend.
1.4. Den Ausgabeblock für die neue Verzeichnisstruktur aktualisieren¶
Wir müssen auch den output-Block aktualisieren, um die GVCF-Dateien in ein Unterverzeichnis gvcf zu legen.
Mit dem aktualisierten Modul, den Veröffentlichungszielen und dem Ausgabeblock können wir die Änderungen testen.
1.5. Die Pipeline ausführen¶
Führe den Workflow aus, um zu überprüfen, dass die Änderungen funktionieren.
Befehlsausgabe
Die Nextflow-Ausgabe sieht genauso aus wie zuvor, aber die .g.vcf-Dateien und ihre Indexdateien sind jetzt in Unterverzeichnissen organisiert.
Verzeichnisinhalt (Symlinks gekürzt)
results/
├── gvcf/
│ ├── reads_father.bam.g.vcf -> */27/0d7eb9*/reads_father.bam.g.vcf
│ ├── reads_father.bam.g.vcf.idx -> */27/0d7eb9*/reads_father.bam.g.vcf.idx
│ ├── reads_mother.bam.g.vcf -> */e4/4ed55e*/reads_mother.bam.g.vcf
│ ├── reads_mother.bam.g.vcf.idx -> */e4/4ed55e*/reads_mother.bam.g.vcf.idx
│ ├── reads_son.bam.g.vcf -> */08/e95962*/reads_son.bam.g.vcf
│ └── reads_son.bam.g.vcf.idx -> */08/e95962*/reads_son.bam.g.vcf.idx
└── indexed_bam/
├── reads_father.bam -> */9a/c7a873*/reads_father.bam
├── reads_father.bam.bai -> */9a/c7a873*/reads_father.bam.bai
├── reads_mother.bam -> */f1/8d8486*/reads_mother.bam
├── reads_mother.bam.bai -> */f1/8d8486*/reads_mother.bam.bai
├── reads_son.bam -> */cc/fbc705*/reads_son.bam
└── reads_son.bam.bai -> */cc/fbc705*/reads_son.bam.bai
Wenn du eine der GVCF-Dateien öffnest und durchscrollst, kannst du überprüfen, dass GATK HaplotypeCaller GVCF-Dateien wie gewünscht erzeugt hat.
Fazit¶
Wenn du den Ausgabedateinamen eines Tool-Befehls änderst, müssen der output:-Block des Prozesses und die Veröffentlichungs-/Ausgabekonfiguration entsprechend aktualisiert werden.
Wie geht es weiter?¶
Lerne, wie du den Inhalt eines Kanals sammelst und als einzelne Eingabe an den nächsten Prozess weitergibst.
2. Einen Joint-Genotyping-Schritt hinzufügen¶
Wir müssen jetzt die GVCFs pro Probe sammeln, sie in einem GenomicsDB-Datenspeicher kombinieren und Joint Genotyping ausführen, um ein VCF auf Kohortenebene zu erzeugen.
Wie in Teil 1 beschrieben, ist dies eine Operation mit zwei Tools: GenomicsDBImport kombiniert die GVCFs, dann erzeugt GenotypeGVCFs die finalen Variantenaufrufe.
Wir werden beide Tools in einem einzigen Prozess namens GATK_JOINTGENOTYPING einbinden.
Erinnere dich an die beiden Befehle aus Teil 1:
gatk GenomicsDBImport \
-V reads_mother.g.vcf \
-V reads_father.g.vcf \
-V reads_son.g.vcf \
-L /data/ref/intervals.bed \
--genomicsdb-workspace-path family_trio_gdb
Der erste Befehl nimmt die GVCFs pro Probe und eine Intervalldatei und erzeugt einen GenomicsDB-Datenspeicher.
Der zweite nimmt diesen Datenspeicher, ein Referenzgenom und erzeugt das finale VCF auf Kohortenebene.
Die Container-URI ist dieselbe wie für HaplotypeCaller: community.wave.seqera.io/library/gatk4:4.5.0.0--730ee8817e436867.
2.1. Die Eingaben einrichten¶
Der Joint-Genotyping-Prozess benötigt zwei Arten von Eingaben, die wir noch nicht haben: einen beliebigen Kohortennamen und die gesammelten GVCF-Ausgaben von allen Proben, die zusammen gebündelt sind.
2.1.1. Einen cohort_name-Parameter hinzufügen¶
Wir müssen einen beliebigen Namen für die Kohorte angeben.
Später in der Trainingsreihe lernst du, wie man Probenmetadaten für solche Zwecke verwendet, aber für jetzt deklarieren wir einfach einen CLI-Parameter mit params und geben ihm einen Standardwert zur Vereinfachung.
2.1.2. Die HaplotypeCaller-Ausgaben über Proben hinweg sammeln¶
Wenn wir den Ausgabekanal von GATK_HAPLOTYPECALLER direkt in den neuen Prozess einstecken würden, würde Nextflow den Prozess für jedes Proben-GVCF separat aufrufen.
Wir möchten alle drei GVCFs (und ihre Indexdateien) bündeln, sodass Nextflow sie alle zusammen an einen einzigen Prozessaufruf übergibt.
Das können wir mit dem Kanaloperator collect() tun.
Füge die folgenden Zeilen zum workflow-Body hinzu, direkt nach dem Aufruf von GATK_HAPLOTYPECALLER:
Aufgeschlüsselt:
- Wir nehmen den Ausgabekanal von
GATK_HAPLOTYPECALLERmit der.out-Eigenschaft. - Da wir die Ausgaben mit
emit:in Abschnitt 1 benannt haben, können wir die GVCFs mit.vcfund die Indexdateien mit.idxauswählen. Ohne benannte Ausgaben müssten wir.out[0]und.out[1]verwenden. - Der
collect()-Operator bündelt alle Dateien in einem einzigen Element, sodassall_gvcfs_challe drei GVCFs zusammen enthält undall_idxs_challe drei Indexdateien zusammen enthält.
Wir können die GVCFs und ihre Indexdateien separat sammeln (anstatt sie in Tupeln zusammenzuhalten), weil Nextflow alle Eingabedateien zusammen für die Ausführung bereitstellt, sodass die Indexdateien neben den GVCFs vorhanden sein werden.
Tip
Du kannst den view()-Operator verwenden, um den Inhalt von Kanälen vor und nach der Anwendung von Kanaloperatoren zu inspizieren.
2.2. Den Joint-Genotyping-Prozess schreiben und im Workflow aufrufen¶
Nach demselben Muster, das wir in Teil 2 verwendet haben, schreiben wir die Prozessdefinition in eine Moduldatei, importieren sie in den Workflow und rufen sie mit den Eingaben auf, die wir gerade vorbereitet haben.
2.2.1. Einen String konstruieren, um jedem GVCF ein -V-Argument zu geben¶
Bevor wir beginnen, die Prozessdefinition auszufüllen, müssen wir eine Sache klären.
Der GenomicsDBImport-Befehl erwartet für jede GVCF-Datei ein separates -V-Argument, so:
gatk GenomicsDBImport \
-V reads_mother.bam.g.vcf \
-V reads_father.bam.g.vcf \
-V reads_son.bam.g.vcf \
...
Wenn wir -V ${all_gvcfs_ch} schreiben würden, würde Nextflow einfach die Dateinamen verketten und dieser Teil des Befehls würde so aussehen:
Aber wir brauchen den String so:
Wichtig ist, dass wir diesen String dynamisch aus den Dateien konstruieren müssen, die im gesammelten Kanal sind. Nextflow (über Groovy) bietet eine prägnante Möglichkeit dazu:
Aufgeschlüsselt:
all_gvcfs.collect { gvcf -> "-V ${gvcf}" }iteriert über jeden Dateipfad und stellt-Vvoran, wodurch["-V A.g.vcf", "-V B.g.vcf", "-V C.g.vcf"]erzeugt wird..join(' ')verkettet sie mit Leerzeichen:"-V A.g.vcf -V B.g.vcf -V C.g.vcf".- Das Ergebnis wird einer lokalen Variable
gvcfs_line(definiert mitdef) zugewiesen, die wir in die Befehlsvorlage interpolieren können.
Diese Zeile kommt in den script:-Block des Prozesses, vor die Befehlsvorlage.
Du kannst beliebigen Groovy-Code zwischen script: und dem öffnenden """ der Befehlsvorlage platzieren.
Dann kannst du auf diesen gesamten String als gvcfs_line im script:-Block des Prozesses verweisen.
2.2.2. Das Modul für den Joint-Genotyping-Prozess ausfüllen¶
Jetzt können wir uns an das Schreiben des vollständigen Prozesses machen.
Öffne modules/gatk_jointgenotyping.nf und betrachte die Gliederung der Prozessdefinition.
Fülle die Prozessdefinition mit den oben bereitgestellten Informationen aus und überprüfe dann deine Arbeit anhand der Lösung im Tab "Danach" unten.
| modules/gatk_jointgenotyping.nf | |
|---|---|
Es gibt mehrere Dinge, die hier erwähnenswert sind.
Wie zuvor sind mehrere Eingaben aufgelistet, obwohl die Befehle nicht direkt darauf verweisen: all_idxs, ref_index und ref_dict.
Ihre Auflistung stellt sicher, dass Nextflow diese Dateien im Arbeitsverzeichnis neben den Dateien bereitstellt, die in den Befehlen erscheinen, die GATK basierend auf Namenskonventionen zu finden erwartet.
Die Variable gvcfs_line verwendet die oben beschriebene Groovy-Closure, um die -V-Argumente für GenomicsDBImport zu konstruieren.
Dieser Prozess führt zwei Befehle seriell aus, genau wie du es im Terminal tun würdest.
GenomicsDBImport kombiniert die GVCFs pro Probe in einen Datenspeicher, dann liest GenotypeGVCFs diesen Datenspeicher und erzeugt das finale VCF auf Kohortenebene.
Der GenomicsDB-Datenspeicher (${cohort_name}_gdb) ist ein Zwischenartefakt, das nur innerhalb des Prozesses verwendet wird; er erscheint nicht im Ausgabeblock.
Sobald du dies abgeschlossen hast, ist der Prozess einsatzbereit. Um ihn im Workflow zu verwenden, musst du das Modul importieren und einen Prozessaufruf hinzufügen.
2.2.3. Das Modul importieren¶
Füge die Import-Anweisung zu genomics.nf hinzu, unterhalb der bestehenden Import-Anweisungen:
Der Prozess ist jetzt im Workflow-Scope verfügbar.
2.2.4. Den Prozessaufruf hinzufügen¶
Füge den Aufruf von GATK_JOINTGENOTYPING im Workflow-Body hinzu, nach den collect()-Zeilen:
Der Prozess ist jetzt vollständig verdrahtet. Als Nächstes konfigurieren wir, wie die Ausgaben veröffentlicht werden.
2.3. Die Ausgabebehandlung konfigurieren¶
Wir müssen die Joint-VCF-Ausgaben veröffentlichen. Füge Veröffentlichungsziele und Ausgabeblock-Einträge für die Joint-Genotyping-Ergebnisse hinzu.
2.3.1. Veröffentlichungsziele für das Joint-VCF hinzufügen¶
Füge das Joint-VCF und seinen Index zum publish:-Abschnitt des Workflows hinzu:
Jetzt aktualisiere den Ausgabeblock entsprechend.
2.3.2. Ausgabeblock-Einträge für das Joint-VCF hinzufügen¶
Füge Einträge für die Joint-VCF-Dateien hinzu. Wir werden sie im Wurzelverzeichnis der Ergebnisse ablegen, da dies die finale Ausgabe ist.
Mit dem Prozess, den Veröffentlichungszielen und dem Ausgabeblock an ihrem Platz können wir den vollständigen Workflow testen.
2.4. Den Workflow ausführen¶
Führe den Workflow aus, um zu überprüfen, dass alles funktioniert.
Befehlsausgabe
Die ersten beiden Schritte werden aus dem vorherigen Lauf gecacht, und der neue GATK_JOINTGENOTYPING-Schritt läuft einmal auf den gesammelten Eingaben von allen drei Proben.
Die finale Ausgabedatei, family_trio.joint.vcf (und ihr Index), befinden sich im Ergebnisverzeichnis.
Verzeichnisinhalt (Symlinks gekürzt)
results/
├── family_trio.joint.vcf -> */a6/7cc8ed*/family_trio.joint.vcf
├── family_trio.joint.vcf.idx -> */a6/7cc8ed*/family_trio.joint.vcf.idx
├── gvcf/
│ ├── reads_father.bam.g.vcf -> */27/0d7eb9*/reads_father.bam.g.vcf
│ ├── reads_father.bam.g.vcf.idx -> */27/0d7eb9*/reads_father.bam.g.vcf.idx
│ ├── reads_mother.bam.g.vcf -> */e4/4ed55e*/reads_mother.bam.g.vcf
│ ├── reads_mother.bam.g.vcf.idx -> */e4/4ed55e*/reads_mother.bam.g.vcf.idx
│ ├── reads_son.bam.g.vcf -> */08/e95962*/reads_son.bam.g.vcf
│ └── reads_son.bam.g.vcf.idx -> */08/e95962*/reads_son.bam.g.vcf.idx
└── indexed_bam/
├── reads_father.bam -> */9a/c7a873*/reads_father.bam
├── reads_father.bam.bai -> */9a/c7a873*/reads_father.bam.bai
├── reads_mother.bam -> */f1/8d8486*/reads_mother.bam
├── reads_mother.bam.bai -> */f1/8d8486*/reads_mother.bam.bai
├── reads_son.bam -> */cc/fbc705*/reads_son.bam
└── reads_son.bam.bai -> */cc/fbc705*/reads_son.bam.bai
Wenn du die Joint-VCF-Datei öffnest, kannst du überprüfen, dass der Workflow die erwarteten Variantenaufrufe erzeugt hat.
Du hast jetzt einen automatisierten, vollständig reproduzierbaren Joint-Variant-Calling-Workflow!
Note
Denke daran, dass die Datendateien, die wir dir gegeben haben, nur einen winzigen Teil von Chromosom 20 abdecken. Die tatsächliche Größe eines Variant-Callsets würde in Millionen von Varianten gezählt werden. Deshalb verwenden wir nur winzige Teilmengen von Daten zu Trainingszwecken!
Fazit¶
Du weißt, wie man Ausgaben aus einem Kanal sammelt und sie als einzelne Eingabe an einen anderen Prozess bündelt. Du weißt auch, wie man eine Befehlszeile mit Groovy-Closures konstruiert und wie man mehrere Befehle in einem einzigen Prozess ausführt.
Wie geht es weiter?¶
Feiere deinen Erfolg und mach eine wohlverdiente Pause.
Im nächsten Teil dieses Kurses lernst du, wie man eine produktionsreife Variant-Calling-Pipeline von nf-core ausführt und sie mit der Pipeline vergleicht, die du manuell erstellt hast.