Parte 3: Joint calling su una coorte¶
Traduzione assistita da IA - scopri di più e suggerisci miglioramenti
In precedenza, avete costruito una pipeline di variant calling per-campione che processava i dati di ciascun campione in modo indipendente. Ora la estenderemo per implementare il joint variant calling, come descritto nella Parte 1 (caso d'uso multi-campione).
Come iniziare da questa sezione
Questa sezione del corso presuppone che abbiate completato la Parte 1: Panoramica del metodo, la Parte 2: Variant calling per-campione e che abbiate una pipeline genomics.nf funzionante.
Se non avete completato la Parte 2 o volete ripartire da zero per questa parte, potete usare la soluzione della Parte 2 come punto di partenza.
Eseguite questi comandi dall'interno della directory nf4-science/genomics/:
cp solutions/part2/genomics-2.nf genomics.nf
cp solutions/part2/nextflow.config .
cp solutions/part2/modules/* modules/
Questo vi fornisce un flusso di lavoro completo di variant calling per-campione. Potete verificare che funzioni correttamente eseguendo il seguente comando:
Compito¶
In questa parte del corso, estenderemo il flusso di lavoro per fare quanto segue:
- Generare un file indice per ciascun file BAM di input usando Samtools
- Eseguire GATK HaplotypeCaller su ciascun file BAM di input per generare un GVCF delle chiamate di varianti genomiche per-campione
- Raccogliere tutti i GVCF e combinarli in un data store GenomicsDB
- Eseguire il joint genotyping sul data store GVCF combinato per produrre un VCF a livello di coorte
Questo implementa il metodo descritto nella Parte 1: Panoramica del metodo (seconda sezione che copre il caso d'uso multi-campione) e si basa direttamente sul flusso di lavoro prodotto dalla Parte 2: Variant calling per-campione.
Piano della lezione¶
Abbiamo suddiviso questo in due fasi:
- Modificare il passaggio di variant calling per-campione per produrre un GVCF. Questo copre l'aggiornamento dei comandi e degli output del processo.
- Aggiungere un passaggio di joint genotyping che combina e genotipizza i GVCF per-campione.
Questo introduce l'operatore
collect(), le closure Groovy per la costruzione della riga di comando e i processi multi-comando.
Questo automatizza i passaggi della seconda sezione della Parte 1: Panoramica del metodo, dove avete eseguito questi comandi manualmente nei loro container.
Suggerimento
Assicuratevi di essere nella directory di lavoro corretta:
cd /workspaces/training/nf4-science/genomics
1. Modificare il passaggio di variant calling per-campione per produrre un GVCF¶
La pipeline della Parte 2 produce file VCF, ma il joint calling richiede file GVCF. Dobbiamo attivare la modalità di variant calling GVCF e aggiornare l'estensione del file di output.
Ricordate il comando di variant calling GVCF dalla Parte 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
Rispetto al comando base HaplotypeCaller che abbiamo incapsulato nella Parte 2, le differenze sono il parametro -ERC GVCF e l'estensione di output .g.vcf.
1.1. Dire a HaplotypeCaller di emettere un GVCF e aggiornare l'estensione di output¶
Aprite il file modulo modules/gatk_haplotypecaller.nf per apportare due modifiche:
- Aggiungere il parametro
-ERC GVCFal comando GATK HaplotypeCaller; - Aggiornare il percorso del file di output per usare l'estensione corrispondente
.g.vcf, secondo la convenzione GATK.
Assicuratevi di aggiungere una barra rovesciata (\) alla fine della riga precedente quando aggiungete -ERC GVCF.
Dobbiamo anche aggiornare il blocco output per corrispondere alla nuova estensione del file.
Poiché abbiamo cambiato l'output del comando da .vcf a .g.vcf, il blocco output: del processo deve riflettere lo stesso cambiamento.
1.2. Aggiornare l'estensione del file di output nel blocco outputs del processo¶
Dobbiamo anche aggiornare la configurazione di publish e output del flusso di lavoro per riflettere i nuovi output GVCF.
1.3. Aggiornare i target di publish per i nuovi output GVCF¶
Poiché ora stiamo producendo GVCF invece di VCF, dovremmo aggiornare la sezione publish: del flusso di lavoro per usare nomi più descrittivi.
Organizzeremo anche i file GVCF nella loro sottodirectory per maggiore chiarezza.
Ora aggiorniamo il blocco output per corrispondere.
1.4. Aggiornare il blocco output per la nuova struttura di directory¶
Dobbiamo anche aggiornare il blocco output per mettere i file GVCF in una sottodirectory gvcf.
Con il modulo, i target di publish e il blocco output tutti aggiornati, possiamo testare le modifiche.
1.5. Eseguire la pipeline¶
Eseguite il flusso di lavoro per verificare che le modifiche funzionino.
Output del comando
L'output di Nextflow appare uguale a prima, ma i file .g.vcf e i loro file indice sono ora organizzati in sottodirectory.
Contenuto della directory (symlink abbreviati)
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
Se aprite uno dei file GVCF e scorrete attraverso di esso, potete verificare che GATK HaplotypeCaller abbia prodotto file GVCF come richiesto.
Takeaway¶
Quando modificate il nome del file di output di un comando di uno strumento, il blocco output: del processo e la configurazione publish/output devono essere aggiornati per corrispondere.
Cosa c'è dopo?¶
Imparate a raccogliere i contenuti di un canale e passarli al processo successivo come singolo input.
2. Aggiungere un passaggio di joint genotyping¶
Ora dobbiamo raccogliere i GVCF per-campione, combinarli in un data store GenomicsDB ed eseguire il joint genotyping per produrre un VCF a livello di coorte.
Come trattato nella Parte 1, questa è un'operazione a due strumenti: GenomicsDBImport combina i GVCF, poi GenotypeGVCFs produce le chiamate di varianti finali.
Incapsuleremo entrambi gli strumenti in un singolo processo chiamato GATK_JOINTGENOTYPING.
Ricordate i due comandi dalla Parte 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
Il primo comando prende i GVCF per-campione e un file di intervalli, e produce un data store GenomicsDB.
Il secondo prende quel data store, un genoma di riferimento, e produce il VCF finale a livello di coorte.
L'URI del container è lo stesso di HaplotypeCaller: community.wave.seqera.io/library/gatk4:4.5.0.0--730ee8817e436867.
2.1. Configurare gli input¶
Il processo di joint genotyping necessita di due tipi di input che non abbiamo ancora: un nome arbitrario di coorte e gli output GVCF raccolti da tutti i campioni raggruppati insieme.
2.1.1. Aggiungere un parametro cohort_name¶
Dobbiamo fornire un nome arbitrario per la coorte.
Più avanti nella serie di formazione imparerete come usare i metadati dei campioni per questo tipo di cose, ma per ora dichiariamo semplicemente un parametro CLI usando params.
Useremo questo parametro per nominare il file di output finale.
2.1.2. Aggiungere un valore predefinito per cohort_name nel profilo test¶
Aggiungiamo anche un valore predefinito per il parametro cohort_name nel profilo test:
| nextflow.config | |
|---|---|
Successivamente, dovremo raccogliere gli output per-campione in modo che possano essere processati insieme.
2.1.3. Raccogliere gli output di HaplotypeCaller attraverso i campioni¶
Se dovessimo collegare il canale di output da GATK_HAPLOTYPECALLER direttamente al nuovo processo, Nextflow chiamerebbe il processo su ciascun GVCF di campione separatamente.
Vogliamo raggruppare tutti e tre i GVCF (e i loro file indice) in modo che Nextflow li passi tutti insieme a una singola chiamata di processo.
Possiamo farlo usando l'operatore di canale collect().
Aggiungete le seguenti righe al corpo del workflow, subito dopo la chiamata a GATK_HAPLOTYPECALLER:
Scomponendo questo:
- Prendiamo il canale di output da
GATK_HAPLOTYPECALLERusando la proprietà.out. - Poiché abbiamo nominato gli output usando
emit:nella sezione 1, possiamo selezionare i GVCF con.vcfe i file indice con.idx. Senza output nominati, dovremmo usare.out[0]e.out[1]. - L'operatore
collect()raggruppa tutti i file in un singolo elemento, quindiall_gvcfs_chcontiene tutti e tre i GVCF insieme, eall_idxs_chcontiene tutti e tre i file indice insieme.
Possiamo raccogliere i GVCF e i loro file indice separatamente (invece di tenerli insieme in tuple) perché Nextflow metterà in stage tutti i file di input insieme per l'esecuzione, quindi i file indice saranno presenti accanto ai GVCF.
Suggerimento
Potete usare l'operatore view() per ispezionare i contenuti dei canali prima e dopo l'applicazione degli operatori di canale.
2.2. Scrivere il processo di joint genotyping e chiamarlo nel flusso di lavoro¶
Seguendo lo stesso schema che abbiamo usato nella Parte 2, scriveremo la definizione del processo in un file modulo, lo importeremo nel flusso di lavoro e lo chiameremo sugli input che abbiamo appena preparato.
2.2.1. Costruire una stringa per dare a ciascun GVCF un argomento -V¶
Prima di iniziare a riempire la definizione del processo, c'è una cosa da risolvere.
Il comando GenomicsDBImport si aspetta un argomento -V separato per ciascun file GVCF, così:
gatk GenomicsDBImport \
-V reads_mother.bam.g.vcf \
-V reads_father.bam.g.vcf \
-V reads_son.bam.g.vcf \
...
Se dovessimo scrivere -V ${all_gvcfs_ch}, Nextflow concatenerebbe semplicemente i nomi dei file e quella parte del comando apparirebbe così:
Ma abbiamo bisogno che la stringa appaia così:
Importante, dobbiamo costruire questa stringa dinamicamente da qualunque file sia nel canale raccolto. Nextflow (tramite Groovy) fornisce un modo conciso per farlo:
Scomponendo questo:
all_gvcfs.collect { gvcf -> "-V ${gvcf}" }itera su ciascun percorso di file e antepone-Vad esso, producendo["-V A.g.vcf", "-V B.g.vcf", "-V C.g.vcf"]..join(' ')li concatena con spazi:"-V A.g.vcf -V B.g.vcf -V C.g.vcf".- Il risultato è assegnato a una variabile locale
gvcfs_line(definita condef), che possiamo interpolare nel template del comando.
Questa riga va all'interno del blocco script: del processo, prima del template del comando.
Potete inserire codice Groovy arbitrario tra script: e l'apertura """ del template del comando.
Poi sarete in grado di riferirvi a quella intera stringa come gvcfs_line nel blocco script: del processo.
2.2.2. Riempire il modulo per il processo di joint genotyping¶
Successivamente, possiamo affrontare la scrittura del processo completo.
Aprite modules/gatk_jointgenotyping.nf ed esaminate la struttura della definizione del processo.
Procedete e riempite la definizione del processo usando le informazioni fornite sopra, poi verificate il vostro lavoro confrontandolo con la soluzione nella scheda "Dopo" qui sotto.
Ci sono diverse cose che vale la pena evidenziare qui.
Come in precedenza, diversi input sono elencati anche se i comandi non vi fanno riferimento direttamente: all_idxs, ref_index e ref_dict.
Elencarli assicura che Nextflow metta in stage questi file nella directory di lavoro accanto ai file che appaiono nei comandi, che GATK si aspetta di trovare in base alle convenzioni di denominazione.
La variabile gvcfs_line usa la closure Groovy descritta sopra per costruire gli argomenti -V per GenomicsDBImport.
Questo processo esegue due comandi in serie, proprio come fareste nel terminale.
GenomicsDBImport combina i GVCF per-campione in un data store, poi GenotypeGVCFs legge quel data store e produce il VCF finale a livello di coorte.
Il data store GenomicsDB (${cohort_name}_gdb) è un artefatto intermedio usato solo all'interno del processo; non appare nel blocco output.
Una volta completato questo, il processo è pronto per l'uso. Per usarlo nel flusso di lavoro, dovrete importare il modulo e aggiungere una chiamata di processo.
2.2.3. Importare il modulo¶
Aggiungete l'istruzione import a genomics.nf, sotto le istruzioni import esistenti:
Il processo è ora disponibile nello scope del flusso di lavoro.
2.2.4. Aggiungere la chiamata di processo¶
Aggiungete la chiamata a GATK_JOINTGENOTYPING nel corpo del flusso di lavoro, dopo le righe collect():
| genomics.nf | |
|---|---|
| genomics.nf | |
|---|---|
Il processo è ora completamente collegato. Successivamente, configuriamo come vengono pubblicati gli output.
2.3. Configurare la gestione degli output¶
Dobbiamo pubblicare gli output del VCF joint. Aggiungete target di publish e voci del blocco output per i risultati del joint genotyping.
2.3.1. Aggiungere target di publish per il VCF joint¶
Aggiungete il VCF joint e il suo indice alla sezione publish: del flusso di lavoro:
Ora aggiornate il blocco output per corrispondere.
2.3.2. Aggiungere voci del blocco output per il VCF joint¶
Aggiungete voci per i file VCF joint. Li metteremo alla radice della directory results poiché questo è l'output finale.
Con il processo, i target di publish e il blocco output tutti a posto, possiamo testare il flusso di lavoro completo.
2.4. Eseguire il flusso di lavoro¶
Eseguite il flusso di lavoro per verificare che tutto funzioni.
Output del comando
I primi due passaggi sono in cache dall'esecuzione precedente, e il nuovo passaggio GATK_JOINTGENOTYPING viene eseguito una volta sugli input raccolti da tutti e tre i campioni.
Il file di output finale, family_trio.joint.vcf (e il suo indice), sono nella directory results.
Contenuto della directory (symlink abbreviati)
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
Se aprite il file VCF joint, potete verificare che il flusso di lavoro abbia prodotto le chiamate di varianti attese.
Ora avete un flusso di lavoro di joint variant calling automatizzato e completamente riproducibile!
Nota
Tenete presente che i file di dati che vi abbiamo fornito coprono solo una piccola porzione del cromosoma 20. La dimensione reale di un callset di varianti sarebbe contata in milioni di varianti. Ecco perché usiamo solo piccoli sottoinsiemi di dati per scopi di formazione!
Takeaway¶
Sapete come raccogliere output da un canale e raggrupparli come singolo input per un altro processo. Sapete anche come costruire una riga di comando usando le closure Groovy, e come eseguire comandi multipli in un singolo processo.
Cosa c'è dopo?¶
Datevi una grande pacca sulla spalla! Avete completato il corso Nextflow for Genomics.
Passate al riepilogo finale del corso per rivedere ciò che avete imparato e scoprire cosa viene dopo.