GATK Germline SNP INDEL V2.0
This article is an upgraded version of Gatk Germline snps-indels Pipeline for Analyzing Genetic Diseases (Deafness), aiming to provide an out-of-the-box analysis pipeline with deployment and migration as simple as possible.
Updates are as follows:
The human reference genome and other referenced database files have been upgraded from GRCh37 (hg19) to GRCh38 (hg38)
The annotation software has been switched from annovar to Ensemble VEP (108.2); Annovar requires a commercial license, while VEP is under the Apache 2.0 license and can be used freely
The software used by the pipeline has been changed from pre-installed to docker+conda installation on first use; the initial run initializes the environment and downloads the necessary files, making migration easier
To allow the pipeline to run directly without deployment, a docker container is used here to ensure a consistent runtime environment: see the article Building a Bioinformatics Base Environment Image Based on Docker. The solution adopted here is a docker+conda environment with an SSH service, with the entire pipeline running in a single general-purpose container.
The code in this article is long and may be somewhat complex. If you want to run it directly, you can download the workflow file, import it into the sliverworkspace graphical bioinformatics platform and run it directly, then obtain and view the graphical analysis report
The related code and workflow files can be accessed at the author's GitHub project page
Workflow import operation

Pipeline overview diagram

Data preparation:
SRR9993255_R1.fastq.gz SRR9993255_R2.fastq.gz
SRX6732499: Targeted NGS of human: blood sample
1 ILLUMINA (Illumina HiSeq X Ten) run: 679,472 spots, 203.8M bases, 80.8Mb downloads
If the downloaded data is in SRA format, you can use the official NCBI tool sra-toolkit to split it into fastq.gz files
fastq-dump SRR9993255 --split-3 --gzip
Obtaining SRR9993255_R1.fastq.gz SRR9993255_R2.fastq.gz
Environment setup:
This article uses docker + conda (mamba) as the base analysis environment,
Image acquisition: for the installation of docker/docker-compose and image building, see:
Building a Bioinformatics Base Environment Image Based on Docker,
# Pull the docker image
docker pull doujiangbaozi/sliverworkspace:latest
# List docker images
docker imagesBase environment configuration, the docker-compose.yml config file, which can be modified as needed
version: "3"
services:
SarsCov2:
image: doujiangbaozi/sliverworkspace:latest
container_name: Germline
volumes:
- /media/sliver/Data/data:/opt/data:rw #Mount the raw data, place it under the SC2 directory
- /media/sliver/Manufacture/GL2/envs:/root/mambaforge-pypy3/envs:rw #Mount the envs conda environment directory
- /media/sliver/Manufacture/GL2/config:/opt/config:rw #Mount the config conda config file directory
- /media/sliver/Manufacture/GL2/ref:/opt/ref:rw #Mount the reference directory
- /media/sliver/Manufacture/GL2/result:/opt/result:rw #Mount the intermediate files and output results directory
ports:
- "9024:9024" #ssh connection port, can be modified as needed
environment:
- TZ=Asia/Shanghai #Set the time zone
- PS=20191124 #Change the default ssh password
- PT=9024 #Change the default ssh connection portRunning the base environment
# Run in the directory containing docker-compose.yml
docker-compose up -d
# Or
docker-compose up -d -f /path/docker-compose.yaml
# Check whether docker is running normally, run in the docker-compose.yaml directory
docker-compose ps
# Or
docker psUsing the docker container is similar to logging into a remote server
# Log in to docker via the ssh service; it can be deployed locally or remotely
ssh root@192.168.6.6 -p9024
# If you see the following prompt, you have logged in successfully
(base) root@SliverWorkstation:~#Software versions
| Software name | Software version | Remarks |
|---|---|---|
| fastqc | 0.12.1 | |
| multiqc | 1.21 | |
| bwa | 0.7.17 | |
| sambamba | 1.0.1 | The static build runs about twice as fast as the mamba-installed version |
| samtools | 1.16.1 | |
| bedtools | 2.30.0 | |
| fastp | 0.23.2 | |
| gatk | 4.5.0.0 | |
| ensembl-vep | 108.2 | VEP software version |
| version_vep_cache | 108 | VEP cache version |
Analysis results
| File name | Remarks |
|---|---|
| report.pdf | Report printed as a PDF file based on the report designer |
| SRR9993255/qc/multiqc_report.html | multiqc report file |
| SRR9993255/SRR9993255.result.qc.tsv | Data QC results |
| SRR9993255/SRR9993255.result.variants.tsv | Pathogenic variant results |
| SRR9993255/vcf/SRR9993255_filtered.vcf | VCF file after hard filtering |
| SRR9993255/vcf/SRR9993255_filtered_vep.tsv | File annotated with VEP |
| SRR9993255/qc/SRR9993255_depth.tsv | Sequencing depth statistics obtained with samtools depth, used for plotting to display the overall sequencing depth |
Analysis workflow
Variable setup:
| Variable name | Value | Remarks |
|---|---|---|
| sn | SRR9993255 | Sample ID |
| pn | GM02 | Pipeline code |
| project_bed | hg38.exon.bed | Whole-exome BED file for the hg38 reference genome |
| version_reference | hg38 | Reference genome version hg |
| version_fastqc | 0.12.1 | |
| version_multiqc | 1.21 | |
| version_fastp | 0.23.4 | |
| version_bwa | 0.7.17 | |
| version_samtools | 1.20 | |
| version_bedtoos | 2.31.1 | |
| version_sambamba | 1.0.1 | |
| version_gatk | 4.5.0.0 | |
| version_vep | 108.2 | ensembl-vep software version |
| version_vep_cache | 108 | ensembl-vep database version |
#Variable initialization and assignment
sn=SRR9993255 #Sample ID
pn=GM02 #Pipeline project code
data=/opt/data #Data input directory
result=/opt/result #Data output and intermediate files directory
envs=/root/mambaforge-pypy3/envs #Directory of environments installed by conda
threads=32 #Number of available threads
whitelist=/opt/ref/whitelist.csv #File of deafness-related genes and variants
version_reference=hg38 #Reference genome version
project_bed=hg38.exon.bed #BED file used by the pipeline; if absent, one will be computed
version_fastqc=0.12.1 #fastqc version
version_multiqc=1.21 #multiqc version
version_fastp=0.23.4 #fastp version
version_bwa=0.7.18 #bwa version
version_samtools=1.20 #samtools version
version_bedtools=2.31.1 #bedtools version
version_sambamba=1.0.1 #sambamba version
version_gatk=4.5.0.0 #gatk version
version_vep=108.2 #VEP software version
version_vep_cache=108 #vep-cache version1. Filtering with fastp using default parameters to check raw data quality, clean data:
#conda checks whether the environment exists; on first run, if it does not exist, the environment is created and software installed
if [ ! -d "${envs}/${pn}.fastp" ]; then
echo "Creating the environment ${pn}.fastp"
mamba create -n ${pn}.fastp -y fastp=${version_fastp} fastqc=${version_fastqc} multiqc=${version_multiqc}
fi
mamba activate ${pn}.fastp
mkdir -p ${result}/${sn}/clean
mkdir -p ${result}/${sn}/qc
fastqc -t ${threads}\
${data}/${pn}/${sn}_R1.fastq.gz \
${data}/${pn}/${sn}_R2.fastq.gz \
-o ${result}/${sn}/qc &
#Using default parameters
fastp \
-w ${threads} \
-i ${data}/${pn}/${sn}_R1.fastq.gz \
-I ${data}/${pn}/${sn}_R2.fastq.gz \
-o ${result}/${sn}/clean/${sn}_fastp_R1.fastq.gz \
-O ${result}/${sn}/clean/${sn}_fastp_R2.fastq.gz \
-j ${result}/${sn}/qc/${sn}_fastp.json \
-h ${result}/${sn}/qc/${sn}_fastp.html &
wait
fastqc -t ${threads}\
${result}/${sn}/clean/${sn}_fastp_R1.fastq.gz \
${result}/${sn}/clean/${sn}_fastp_R2.fastq.gz \
-o ${result}/${sn}/qc
mamba deactivate2. Alignment, sorting, duplicate marking; QC
#conda checks whether the environment exists; on first run, if it does not exist, the environment is created and software installed
if [ ! -d "${envs}/${pn}.align" ]; then
mamba create -n ${pn}.align -y bwa=${version_bwa} samtools=${version_samtools} bedtools=${version_bedtools}
fi
mamba activate ${pn}.align
#Download the sambamba static build from GitHub; it is more than twice as fast as the mamba-installed version.
if [ ! -f "${envs}/${pn}.align/bin/sambamba" ]; then
aria2c https://github.com/biod/sambamba/releases/download/v${version_sambamba}/sambamba-${version_sambamba}-linux-amd64-static.gz -d ${envs}/${pn}.align/bin
gzip -cdf ${envs}/${pn}.align/bin/sambamba-${version_sambamba}-linux-amd64-static.gz > ${envs}/${pn}.align/bin/sambamba
chmod a+x ${envs}/${pn}.align/bin/sambamba
fi
#Install bamdst from GitHub source
if [ ! -f "${envs}/bamdst/bamdst" ]; then
apt-get update && apt-get install -y git make gcc zlib1g-dev
git clone https://github.com/shiquan/bamdst.git "${envs}/bamdst"
cd ${envs}/bamdst
make
cd ${result}
fi
if [ "${version_reference}" == "hg19" ]; then
echo "USE reference Version : ${version_reference}"
mkdir -p /opt/ref/hg19
#If the reference genome sequence is not detected, download the sequence and create the index with bwa
if [ ! -f "/opt/ref/hg19/hg19.fasta" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg19/ucsc.hg19.fasta.gz -d /opt/ref/hg19 -o hg19.fasta.gz
cd /opt/ref/hg19 && gzip -d /opt/ref/hg19/hg19.fasta.gz
else
if [ -f "/opt/ref/hg19/ucsc.hg19.fasta.gz.aria2" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg19/ucsc.hg19.fasta.gz -c -d /opt/ref/hg19 -o hg19.fasta.gz
cd /opt/ref/hg19 && gzip -d /opt/ref/hg19/hg19.fasta.gz
fi
fi
#Check whether index files exist; if not, create the index
if [ ! -f /opt/ref/hg19/hg19.fasta.amb ] ||
[ ! -f /opt/ref/hg19/hg19.fasta.ann ] ||
[ ! -f /opt/ref/hg19/hg19.fasta.bwt ] ||
[ ! -f /opt/ref/hg19/hg19.fasta.pac ] ||
[ ! -f /opt/ref/hg19/hg19.fasta.sa ]; then
bwa index /opt/ref/hg19/hg19.fasta
fi
#Check whether the samtools index exists; if not, create the reference genome index with samtools
if [ ! -f "/opt/ref/hg19/hg19.fasta.fai" ]; then
samtools faidx /opt/ref/hg19/hg19.fasta
fi
elif [ "${version_reference}" == "hg38" ]; then
echo "USE reference Version : ${version_reference}"
mkdir -p /opt/ref/hg38
if [ ! -f "/opt/ref/hg38/hg38.fasta" ]; then
aria2c ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/Homo_sapiens_assembly38.fasta.gz -d /opt/ref/hg38 -o hg38.fasta.gz
cd /opt/ref/hg38 && gzip -d /opt/ref/hg38/hg38.fasta.gz
elif [ -f "/opt/ref/hg38/hg38.fasta.aria2" ]; then
aria2c ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/Homo_sapiens_assembly38.fasta.gz -c -d /opt/ref/hg38 -o hg38.fasta.gz
cd /opt/ref/hg38 && gzip -d /opt/ref/hg38/hg38.fasta.gz
fi
#Check whether index files exist; if not, create the index
if [ ! -f /opt/ref/hg38/hg38.fasta.amb ] ||
[ ! -f /opt/ref/hg38/hg38.fasta.ann ] ||
[ ! -f /opt/ref/hg38/hg38.fasta.bwt ] ||
[ ! -f /opt/ref/hg38/hg38.fasta.pac ] ||
[ ! -f /opt/ref/hg38/hg38.fasta.sa ]; then
bwa index /opt/ref/hg38/hg38.fasta
fi
#Check whether the samtools index exists; if not, create the reference genome index with samtools
if [ ! -f "/opt/ref/hg38/hg38.fasta.fai" ]; then
samtools faidx /opt/ref/hg38/hg38.fasta
fi
fi
cd ${result}
mkdir -p ${result}/${sn}/align
bwa mem \
-t ${threads} -M \
-R "@RG\\tID:${sn}\\tLB:${sn}\\tPL:Illumina\\tPU:NextSeq550\\tSM:${sn}" \
/opt/ref/${version_reference}/${version_reference}.fasta \
${result}/${sn}/clean/${sn}_fastp_R1.fastq.gz \
${result}/${sn}/clean/${sn}_fastp_R2.fastq.gz \
| sambamba view -S -f bam -l 0 /dev/stdin \
| sambamba sort -t ${threads} -m 2G \
--tmpdir=${result}/${sn} \
-o ${result}/${sn}/align/${sn}_sorted.bam /dev/stdin
#Temporarily increase the number of open files, otherwise errors easily occur
ulimit -n 10240
sambamba markdup \
--tmpdir ${result}/${sn} \
-t ${threads} \
${result}/${sn}/align/${sn}_sorted.bam \
${result}/${sn}/align/${sn}_marked.bam
mv ${result}/${sn}/align/${sn}_marked.bam.bai ${result}/${sn}/align/${sn}_marked.bai
rm -f ${result}/${sn}/align/${sn}_sorted.bam
if [ "${project_bed}" == "None" ]; then
#The data file does not come with a BED file, so compute one with bedtools (reverse complement)
bedtools genomecov -ibam ${result}/${sn}/align/${sn}_marked.bam -bg > ${result}/${sn}/align/${sn}_bedtools.bed
bedtools merge -i ${result}/${sn}/align/${sn}_bedtools.bed > ${result}/${sn}/align/${sn}_merged.bed
samtools flagstat --threads ${threads} \
${result}/${sn}/align/${sn}_marked.bam > ${result}/${sn}/qc/${sn}_marked.flagstat &
${envs}/bamdst/bamdst \
-p ${result}/${sn}/align/${sn}_merged.bed \
-o ${result}/${sn}/qc \
--cutoffdepth 20 \
${result}/${sn}/align/${sn}_marked.bam &
else
if [ ! -f "/opt/ref/${version_reference}/${project_bed}" ]; then
mkdir -p /opt/ref/${version_reference}
aria2c https://raw.githubusercontent.com/doujiangbaozi/sliverworkspace-util/main/germline/projects/${project_bed} -d /opt/ref/${version_reference}
fi
samtools flagstat --threads ${threads} \
${result}/${sn}/align/${sn}_marked.bam > ${result}/${sn}/qc/${sn}_marked.flagstat &
${envs}/bamdst/bamdst \
-p /opt/ref/${version_reference}/${project_bed} \
-o ${result}/${sn}/qc \
--cutoffdepth 20 \
${result}/${sn}/align/${sn}_marked.bam &
fi
wait
mamba deactivate3. GATK: generate the base quality score recalibration table
#conda checks whether the environment exists; on first run, if it does not exist, the environment is created and software installed
if [ ! -f "${envs}/${pn}.gatk/bin/gatk" ]; then
mamba create -n ${pn}.gatk -y gatk4=${version_gatk} \
r-base=3.6.2 \
r-data.table=1.12.8 \
r-dplyr=0.8.5 \
r-getopt=1.20.3 \
r-ggplot2=3.3.0 \
r-gplots=3.0.3 \
r-gsalib=2.1 \
r-optparse=1.6.4 \
r-backports=1.1.10 \
tabix \
pandas
fi
mamba activate ${pn}.gatk
if [ "${version_reference}" == hg19 ]; then
echo "USE reference Version : ${version_reference}"
#Here is a huge pitfall: for the hg19 reference files provided in the bundle directory of the Broad Institute FTP site, running with the default format throws errors saying there is no index, and creating the index with GATK still fails; in fact, the gz files need to be recompressed with bgzip and indexed with tabix
if [ ! -f "/opt/ref/hg19/dbsnp_138.hg19.vcf.gz" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg19/dbsnp_138.hg19.vcf.gz -d /opt/ref/hg19
else
if [ -f "/opt/ref/hg19/dbsnp_138.hg19.vcf.gz.aria2" ]; then
echo 'download continue...'
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg19/dbsnp_138.hg19.vcf.gz -c -d /opt/ref/hg19
fi
fi
if [ ! -f "/opt/ref/hg19/dbsnp_138.hg19.vcf.gz.tbi" ]; then
gzip -k -f -d /opt/ref/hg19/dbsnp_138.hg19.vcf.gz > /opt/ref/hg19/dbsnp_138.hg19.vcf
bgzip -f --threads ${threads} /opt/ref/hg19/dbsnp_138.hg19.vcf > /opt/ref/hg19/dbsnp_138.hg19.vcf.gz
tabix -f /opt/ref/hg19/dbsnp_138.hg19.vcf.gz
fi
if [ ! -f "/opt/ref/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf.gz" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf.gz -d /opt/ref/hg19
else
if [ -f "/opt/ref/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf.gz.aria2" ]; then
echo 'download continue...'
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf.gz -c -d /opt/ref/hg19
fi
fi
if [ ! -f "/opt/ref/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf.gz.tbi" ]; then
gzip -k -f -d /opt/ref/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf.gz > /opt/ref/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf
bgzip -f --threads ${threads} /opt/ref/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf > /opt/ref/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf.gz
tabix -f /opt/ref/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf.gz
fi
if [ ! -f "/opt/ref/hg19/1000G_phase1.snps.high_confidence.hg19.sites.vcf.gz" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg19/1000G_phase1.snps.high_confidence.hg19.sites.vcf.gz -d /opt/ref/hg19
else
if [ -f "/opt/ref/hg19/1000G_phase1.snps.high_confidence.hg19.sites.vcf.gz.aria2" ]; then
echo 'download continue...'
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg19/1000G_phase1.snps.high_confidence.hg19.sites.vcf.gz -c -d /opt/ref/hg19
fi
fi
if [ ! -f "/opt/ref/hg19/1000G_phase1.snps.high_confidence.hg19.sites.vcf.gz.tbi" ]; then
gzip -k -f -d /opt/ref/hg19/1000G_phase1.snps.high_confidence.hg19.sites.vcf.gz > /opt/ref/hg19/1000G_phase1.snps.high_confidence.hg19.sites.vcf
bgzip -f --threads ${threads} /opt/ref/hg19/1000G_phase1.snps.high_confidence.hg19.sites.vcf > /opt/ref/hg19/1000G_phase1.snps.high_confidence.hg19.sites.vcf.gz
tabix -f /opt/ref/hg19/1000G_phase1.snps.high_confidence.hg19.sites.vcf.gz
fi
if [ ! -f "/opt/ref/hg19/1000G_phase1.indels.hg19.sites.vcf.gz" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg19/1000G_phase1.indels.hg19.sites.vcf.gz -d /opt/ref/
else
if [ -f "/opt/ref/hg19/1000G_phase1.indels.hg19.sites.vcf.gz.aria2" ]; then
echo 'download continue...'
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg19/1000G_phase1.indels.hg19.sites.vcf.gz -c -d /opt/ref/hg19
fi
fi
if [ ! -f "/opt/ref/hg19/1000G_phase1.indels.hg19.sites.vcf.gz.tbi" ]; then
gzip -k -f -d /opt/ref/hg19/1000G_phase1.indels.hg19.sites.vcf.gz > /opt/ref/hg19/1000G_phase1.indels.hg19.sites.vcf
bgzip -f --threads ${threads} /opt/ref/hg19/1000G_phase1.indels.hg19.sites.vcf > /opt/ref/hg19/1000G_phase1.indels.hg19.sites.vcf.gz
tabix -f /opt/ref/hg19/1000G_phase1.indels.hg19.sites.vcf.gz
fi
#Create the dict dictionary file for the hg19 reference sequence
if [ ! -f "/opt/ref/hg19/hg19.dict" ]; then
gatk CreateSequenceDictionary -R /opt/ref/hg19/hg19.fasta -O /opt/ref/hg19/hg19.dict
fi
if [ "${project_bed}" == "None" ]; then
if [ ! -f "${result}/${sn}/align/${sn}_merged.bed.interval_list" ]; then
gatk BedToIntervalList \
-I ${result}/${sn}/align/${sn}_merged.bed \
-SD /opt/ref/${version_reference}/${version_reference}.dict \
-O ${result}/${sn}/align/${sn}_merged.bed.interval_list
fi
mkdir -p ${result}/${sn}/recal
gatk BaseRecalibrator \
--known-sites /opt/ref/hg19/dbsnp_138.hg19.vcf.gz \
--known-sites /opt/ref/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf.gz \
--known-sites /opt/ref/hg19/1000G_phase1.indels.hg19.sites.vcf.gz \
-L ${result}/${sn}/align/${sn}_merged.bed.interval_list \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-I ${result}/${sn}/align/${sn}_marked.bam \
-O ${result}/${sn}/align/${sn}_recal.table
else
if [ ! -f "/opt/ref/${version_reference}/${project_bed}" ]; then
#Create the interval list file based on the downloaded Illumina_pt2.bed file, converting coordinates from 0-based to 1-based
#sed 's/chr//; s/\t/ /g' /opt/ref/hg19/Illumina_pt2.bed > /opt/ref/hg19/Illumina_pt2.processed.bed
mkdir -p /opt/ref/${version_reference}
aria2c https://raw.githubusercontent.com/doujiangbaozi/sliverworkspace-util/main/germline/projects/${project_bed} -d /opt/ref/${version_reference}
fi
if [ ! -f "/opt/ref/${version_reference}/${project_bed}.interval_list" ]; then
gatk BedToIntervalList \
-I /opt/ref/${version_reference}/${project_bed} \
-SD /opt/ref/${version_reference}/${version_reference}.dict \
-O /opt/ref/${version_reference}/${project_bed}.interval_list
fi
mkdir -p ${result}/${sn}/recal
gatk BaseRecalibrator \
--known-sites /opt/ref/hg19/dbsnp_138.hg19.vcf.gz \
--known-sites /opt/ref/hg19/Mills_and_1000G_gold_standard.indels.hg19.sites.vcf.gz \
--known-sites /opt/ref/hg19/1000G_phase1.indels.hg19.sites.vcf.gz \
-L /opt/ref/${version_reference}/${project_bed}.interval_list \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-I ${result}/${sn}/align/${sn}_marked.bam \
-O ${result}/${sn}/align/${sn}_recal.table
fi
elif [ "${version_reference}" == "hg38" ]; then
echo "USE reference Version : ${version_reference}"
if [ ! -f "/opt/ref/hg38/dbsnp_146.hg38.vcf.gz" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/dbsnp_146.hg38.vcf.gz -d /opt/ref/hg38
else
if [ -f "/opt/ref/hg38/dbsnp_146.hg38.vcf.gz.aria2" ]; then
echo 'download continue...'
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/dbsnp_146.hg38.vcf.gz -c -d /opt/ref/hg38
fi
fi
if [ ! -f "/opt/ref/hg38/dbsnp_146.hg38.vcf.gz.tbi" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/dbsnp_146.hg38.vcf.gz.tbi -d /opt/ref/hg38
else
if [ -f "/opt/ref/hg38/dbsnp_146.hg38.vcf.gz.tbi.aria2" ]; then
echo 'download continue...'
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/dbsnp_146.hg38.vcf.gz.tbi -c -d /opt/ref/hg38
fi
fi
if [ ! -f "/opt/ref/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz -d /opt/ref/hg38
else
if [ -f "/opt/ref/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz.aria2" ]; then
echo 'download continue...'
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz -c -d /opt/ref/hg38
fi
fi
if [ ! -f "/opt/ref/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz.tbi" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz.tbi -d /opt/ref/hg38
else
if [ -f "/opt/ref/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz.tbi.aria2" ]; then
echo 'download continue...'
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz.tbi -c -d /opt/ref/hg38
fi
fi
if [ ! -f "/opt/ref/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz -d /opt/ref/hg38
else
if [ -f "/opt/ref/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz.aria2" ]; then
echo 'download continue...'
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz -c -d /opt/ref/hg38
fi
fi
if [ ! -f "/opt/ref/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz.tbi" ]; then
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz.tbi -d /opt/ref/hg38
else
if [ -f "/opt/ref/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz.tbi.aria2" ]; then
echo 'download continue...'
aria2c -x 16 -s 32 ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz.tbi -c -d /opt/ref/hg38
fi
fi
#Create the dict dictionary file for the hg38 reference sequence
if [ ! -f "/opt/ref/hg38/hg38.dict" ]; then
gatk CreateSequenceDictionary -R /opt/ref/hg38/hg38.fasta -O /opt/ref/hg38/hg38.dict
fi
if [ "${project_bed}" == "None" ]; then
if [ ! -f "${result}/${sn}/align/${sn}_merged.bed.interval_list" ]; then
gatk BedToIntervalList \
-I ${result}/${sn}/align/${sn}_merged.bed \
-SD /opt/ref/${version_reference}/${version_reference}.dict \
-O ${result}/${sn}/align/${sn}_merged.bed.interval_list
fi
mkdir -p ${result}/${sn}/recal
gatk BaseRecalibrator \
--known-sites /opt/ref/hg38/dbsnp_146.hg38.vcf.gz \
--known-sites /opt/ref/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz \
--known-sites /opt/ref/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz \
-L ${result}/${sn}/align/${sn}_merged.bed.interval_list \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-I ${result}/${sn}/align/${sn}_marked.bam \
-O ${result}/${sn}/align/${sn}_recal.table
else
if [ ! -f "/opt/ref/${version_reference}/${project_bed}.interval_list" ]; then
gatk BedToIntervalList \
-I /opt/ref/${version_reference}/${project_bed} \
-SD /opt/ref/${version_reference}/${version_reference}.dict \
-O /opt/ref/${version_reference}/${project_bed}.interval_list
fi
mkdir -p ${result}/${sn}/recal
gatk BaseRecalibrator \
--known-sites /opt/ref/hg38/dbsnp_146.hg38.vcf.gz \
--known-sites /opt/ref/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz \
--known-sites /opt/ref/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz \
-L /opt/ref/${version_reference}/${project_bed}.interval_list \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-I ${result}/${sn}/align/${sn}_marked.bam \
-O ${result}/${sn}/align/${sn}_recal.table
fi
fi
mamba deactivate
4. GATK: apply base quality score recalibration and obtain insert size statistics
mamba activate ${pn}.gatk
if [ "${project_bed}" == "None" ]; then
gatk SplitIntervals \
-L ${result}/${sn}/align/${sn}_merged.bed.interval_list \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-O ${result}/${sn}/interval \
--scatter-count ${scatter} &
gatk ApplyBQSR \
--bqsr-recal-file ${result}/${sn}/align/${sn}_recal.table \
-L ${result}/${sn}/align/${sn}_merged.bed.interval_list \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-I ${result}/${sn}/align/${sn}_marked.bam \
-O ${result}/${sn}/align/${sn}_bqsr.bam &
gatk CollectInsertSizeMetrics \
-I ${result}/${sn}/align/${sn}_marked.bam \
-O ${result}/${sn}/qc/${sn}_insertsize_metrics.txt \
-H ${result}/${sn}/qc/${sn}_insertsize_histogram.pdf &
else
rm -f ${result}/${sn}/interval/*.interval_list
gatk SplitIntervals \
-L /opt/ref/${version_reference}/${project_bed}.interval_list \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-O ${result}/${sn}/interval \
--scatter-count ${scatter} &
gatk ApplyBQSR \
--bqsr-recal-file ${result}/${sn}/align/${sn}_recal.table \
-L /opt/ref/${version_reference}/${project_bed}.interval_list \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-I ${result}/${sn}/align/${sn}_marked.bam \
-O ${result}/${sn}/align/${sn}_bqsr.bam &
gatk CollectInsertSizeMetrics \
-I ${result}/${sn}/align/${sn}_marked.bam \
-O ${result}/${sn}/qc/${sn}_insertsize_metrics.txt \
-H ${result}/${sn}/qc/${sn}_insertsize_histogram.pdf &
fi
wait
mamba deactivate
5. GATK HaplotypeCaller to call SNP/indel variants:
mamba activate ${pn}.gatk
mkdir -p ${result}/${sn}/vcf
rm -f ${result}/${sn}/vcf/vcf-file.list
touch ${result}/${sn}/vcf/vcf-file.list
if [ "${version_reference}" == hg19 ]; then
for i in `ls ${result}/${sn}/interval/*.interval_list`;
do
rm -f ${i%.*}_bqsr.vcf.gz
gatk HaplotypeCaller \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-L $i \
-I ${result}/${sn}/align/${sn}_bqsr.bam \
-D /opt/ref/${version_reference}/dbsnp_138.hg19.vcf.gz \
-O ${i%.*}.vcf
echo ${i%.*}.vcf >> ${result}/${sn}/vcf/vcf-file.list
done
elif [ "${version_reference}" == "hg38" ]; then
for i in `ls ${result}/${sn}/interval/*.interval_list`;
do
rm -f ${i%.*}_bqsr.vcf.gz
gatk HaplotypeCaller \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-L $i \
-I ${result}/${sn}/align/${sn}_bqsr.bam \
-D /opt/ref/${version_reference}/dbsnp_146.hg38.vcf.gz \
-O ${i%.*}.vcf
echo ${i%.*}.vcf >> ${result}/${sn}/vcf/vcf-file.list
done
fi
wait
gatk MergeVcfs \
-I ${result}/${sn}/vcf/vcf-file.list \
-O ${result}/${sn}/vcf/${sn}_bqsr.vcf
mamba deactivate
6. A single sample does not provide enough data to run VQSR, so hard filtering is applied directly; see reference values at #https://gatk.broadinstitute.org/hc/en-us/articles/360035532412?id=11097
mamba activate ${pn}.gatk
#https://gatk.broadinstitute.org/hc/en-us/articles/360035532412?id=11097
gatk VariantFiltration \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-V ${result}/${sn}/vcf/${sn}.vcf \
-O ${result}/${sn}/vcf/${sn}_snp.vcf \
--filter-name "SNP_QD" \
--filter-expression "QD < 2.0" \
--filter-name "SNP_MQ" \
--filter-expression "MQ <40.0" \
--filter-name "SNP_FS" \
--filter-expression "FS > 60.0" \
--filter-name "SNP_SOR" \
--filter-expression "SOR > 3.0" \
--filter-name "SNP_MQRankSum" \
--filter-expression "MQRankSum < -12.5" \
--filter-name "SNP_ReadPosRankSum" \
--filter-expression "ReadPosRankSum < -8.0"
gatk VariantFiltration \
-R /opt/ref/${version_reference}/${version_reference}.fasta \
-V ${result}/${sn}/vcf/${sn}_snp.vcf \
-O ${result}/${sn}/vcf/${sn}_filtered.vcf \
--filter-name "INDEL_QD" \
--filter-expression "QD < 2.0" \
--filter-name "INDEL_FS" \
--filter-expression "FS > 200.0" \
--filter-name "INDEL_SOR" \
--filter-expression "SOR > 10.0" \
--filter-name "INDEL_ReadPosRankSum" \
--filter-expression "ReadPosRankSum < -20.0" \
--filter-name "INDEL_InbreedingCoeff" \
--filter-expression "InbreedingCoeff < -0.8"
mamba deactivate7. Annotate the variant results with VEP:
#conda checks whether the environment exists; on first run, if it does not exist, the environment is created and software installed
if [ ! -d "${envs}/${pn}.vep" ]; then
echo "Creating the environment ${pn}.vep"
mamba create -n ${pn}.vep -y ensembl-vep=${version_vep}
fi
mamba activate ${pn}.vep
mkdir -p /opt/result/${sn}/vcf
if [ "${version_reference}" == "hg19" ]; then
if [ ! -d "/opt/ref/vep-cache/homo_sapiens/${version_vep_cache}_GRCh37" ]; then
aria2c -x 16 -s 48 https://ftp.ensembl.org/pub/release-${version_vep_cache}/variation/indexed_vep_cache/homo_sapiens_vep_${version_vep_cache}_GRCh37.tar.gz -d /opt/ref/
tar -zxvf /opt/ref/homo_sapiens_vep_${version_vep_cache}_GRCh37.tar.gz -C /opt/ref/vep-cache/
elif [ -f "/opt/ref/homo_sapiens_vep_${version_vep_cache}_GRCh37.tar.gz.aria2" ]; then
aria2c -x 16 -s 48 https://ftp.ensembl.org/pub/release-${version_vep_cache}/variation/indexed_vep_cache/homo_sapiens_vep_${version_vep_cache}_GRCh37.tar.gz -c -d /opt/ref/
tar -zxvf /opt/ref/homo_sapiens_vep_${version_vep_cache}_GRCh37.tar.gz -C /opt/ref/vep-cache/
fi
vep \
-i ${result}/${sn}/vcf/${sn}_filtered.vcf \
-o ${result}/${sn}/vcf/${sn}_filtered_vep.tsv \
--offline \
--cache \
--cache_version ${version_vep_cache} \
--everything \
--dir_cache /opt/ref/vep-cache \
--dir_plugins /opt/ref/vep-cache/Plugins \
--species homo_sapiens \
--assembly GRCh37 \
--hgvs \
--fasta /opt/ref/${version_reference}/${version_reference}.fasta \
--force_overwrite \
--format vcf \
--tab \
--fork ${threads} \
--offline
elif [ "${version_reference}" == "hg38" ]; then
if [ ! -d "/opt/ref/vep-cache/homo_sapiens/${version_vep_cache}_GRCh38" ]; then
aria2c -x 16 -s 48 https://ftp.ensembl.org/pub/release-${version_vep_cache}/variation/indexed_vep_cache/homo_sapiens_vep_${version_vep_cache}_GRCh38.tar.gz -d /opt/ref/
tar -zxvf /opt/ref/homo_sapiens_vep_${version_vep_cache}_GRCh38.tar.gz -C /opt/ref/vep-cache/
elif [ -f "/opt/ref/homo_sapiens_vep_${version_vep_cache}_GRCh38.tar.gz.aria2" ]; then
aria2c -x 16 -s 48 https://ftp.ensembl.org/pub/release-${version_vep_cache}/variation/indexed_vep_cache/homo_sapiens_vep_${version_vep_cache}_GRCh38.tar.gz -c -d /opt/ref/
tar -zxvf /opt/ref/homo_sapiens_vep_${version_vep_cache}_GRCh38.tar.gz -C /opt/ref/vep-cache/
fi
vep \
-i ${result}/${sn}/vcf/${sn}_filtered.vcf \
-o ${result}/${sn}/vcf/${sn}_filtered_vep.tsv \
--offline \
--cache \
--cache_version ${version_vep_cache} \
--everything \
--dir_cache /opt/ref/vep-cache \
--dir_plugins /opt/ref/vep-cache/Plugins \
--species homo_sapiens \
--assembly GRCh38 \
--hgvs \
--fasta /opt/ref/${version_reference}/${version_reference}.fasta \
--force_overwrite \
--format vcf \
--tab \
--fork ${threads} \
--offline
fi
mamba deactivate8. Write a script to filter the variant VCF file (annotated with VEP) and obtain pathogenic variants with ClinVar annotation
mamba activate ${pn}.gatk
if [ ! -f "${envs}/GermlineVepAnnotationUtil.py" ]; then
aria2c https://raw.githubusercontent.com/doujiangbaozi/sliverworkspace-util/main/somatic/GermlineVepAnnotationUtil.py -d ${envs}/
chmod a+x ${envs}/GermlineVepAnnotationUtil.py
fi
${envs}/GermlineVepAnnotationUtil.py \
-v ${result}/${sn}/vcf/${sn}_filtered.vcf \
-a ${result}/${sn}/vcf/${sn}_filtered_vep.tsv \
-o ${result}/${sn}/${sn}.result.variants.tsv
mamba deactivate
9. Write a script to obtain QC information from the outputs of fastp, bamdst, and GATK CollectInsertSize
mamba activate ${pn}.gatk
if [ ! -f "${envs}/GermlineQcUtil.py" ]; then
aria2c https://raw.githubusercontent.com/doujiangbaozi/sliverworkspace-util/main/somatic/GermlineQcUtil.py -d ${envs}/
chmod a+x ${envs}/GermlineQcUtil.py
fi
python ${envs}/GermlineQcUtil.py \
--out=${result}/${sn}/${sn}.result.qc.tsv \
--sample-fastp=${result}/${sn}/qc/${sn}_fastp.json \
--sample-bamdst=${result}/${sn}/qc/coverage.report \
--sample-insertsize=${result}/${sn}/qc/${sn}_insertsize_metrics.txt
mamba deactivate
mamba activate ${pn}.fastp
multiqc ${result}/${sn}/ -f -o ${result}/${sn}/qc
mamba deactivateResult confirmation: bam file and variant positions in IGV:

Report generated from a Word docx template:

