Tuesday, August 19, 2014

bamsplitter

#!/bin/bash

#split the BAM file by chromosome on NameNode's local disk
pathSamtools=$1 #the full path to samtools. e.g /X/Y/Z/samtoools
bamInputFile=$2 #input BAM file name. e.g. /A/B/C/d.bam
bamOutputDir=$3 #output folder for splitted BAM file. The full path will be /A/B/C/E/


#bamInputFile="/A/B/C/d.bam"

#/A/B/C/
bamOutputPath=${bamInputFile%/*}"/"${bamOutputDir}

#"d.bam"
bamFileName=$(basename "$bamInputFile")

#"d"
bamFileNameNoExt=${bamFileName%%.*}

#"/A/B/C/d.bam.bai"
bamFileIndex=${bamInputFile}."bai"

#"/A/B/C/d"
bamFilePathNoExt=${bamInputFile%%.*}

#"bam"
#bamFileNameExt="${bam##*.}"

bam=${bamInputFile}

numCPU=$(grep -c ^processor /proc/cpuinfo)

sorted=$(samtools view -H ${bamInputFile} | grep SO:coordinate)
if [ -z "$sorted" ];then
        #unsorted
        ${pathSamtools} sort ${bamInputFile} ${bamFilePathNoExt}".sort"
        #create BAM index
bam=${bamFilePathNoExt}".sort.bam"
        ${pathSamtools} index ${bam}
else #sorted
        if [ ! -f "${bamFileIndex}" ];then #create BAM index if not exist
        ${pathSamtools} index ${bam}
        fi
fi

#create output folder if not exist
if [ ! -d "${bamOutputPath}" ]; then
        mkdir -p ${bamOutputPath}
fi

#split the BAM by chromosome
for i in `${pathSamtools} view -H ${bam} | awk -F"\t" '/@SQ/{print $2}' |  cut -d":" -f2`
do
${pathSamtools} view -@ ${numCPU} -h -F 0x4 -q 10 ${bam} $i  | \
awk '{if(/^@SQ/ && !/^@SQ\tSN:'$i'/) next} {if(/^@/) print $0}{if ($3~/^'$i'/) print $0}' | \
${pathSamtools} view -@ ${numCPU} -hbS - > ${bamOutputPath}/${bamFileNameNoExt}.$i.bam 2>/dev/null
done

Friday, August 1, 2014

Size of container

In Hadoop YARN, a container is a sub unit of a physical data node. The size of a container affect the performance of MapReduce greatly especially when the application itself supports multiple threads.

Let us say we have one DataNode with 4 cores and 8 GB memory, now we want to run BWA with input "A_1.fastq", what are the options? 

1) 1 container per DataNode. This container has all 4 cores and 6.4 GB memory (we do not want to starve the host DataNode). So we have only one BWA process running like "bwa mem -t 4 ... A_1.fastq" with 6.4GB available memory per BWA process. 

2) 4 container, each container has 1 core and 1.6 GB memory. so we have to split the "A_1.fastq" into "A_1_1.fastq" ... "A_4_1.fastq", then start 4 parallel BWA processes running like "bwa mem -t 1 ... A_1_1.fastq" and "bwa mem -t 1 ... A_2_1.fastq", etc. with 1.6GB available memory per process. 

Finally we have to merge the resulting SAM files. Since our goal is to optimize the execution, so the question is "Which one is faster?" 

Before jumping to the answer, now we have to consider: 

1) Smaller available memory means the input FASTQ files must be small, otherwise the process will fail. 

2) The overhead. splitting and merging will add some time to the overall running time and every BWA process has to load genome index into memory before mapping the reads. 

Since BWA itself supports multiple threads, it seems like the best way is option (1) - one container per DataNode. Is it the best solution? No! Why? Because the ApplicationMaster itself will occupy one container. 

Assume we have 5 DataNodes, each DataNode has one container. When we start a YARN-based MapReduce application, the ResourceManager will find a container to host the ApplicationMaster, 
subsequently the ApplicationMaster will start computing containers. ApplicationMaster itself will occupy a full container. As a result, we only have 4 computing containers. It is a waste of computing resource since we know ApplicationMaster does not need that much resource (4 cores and 7G memory). This figure shows a node in red box, is running ApplicationMaster without doing the "real computation"







If we "ssh" into that "ApplicationMaster" node, we can see it is running a process named "MRAppMaster".














In another word we wasted 20% of the computing resource. It is not a problem if you are running a 100-node cluster in that case only 1% resource was "wasted". However we do not need a big boss if we are a small team. 

Considering two containers per DataNode? As a result we will have 2*5 = 10 containers in total with 10% of the containers were wasted. But we come into the multiple container problem again - the overhead... 

This is just one the of tradeoff or balancing problems that we have encountered here and there.


Monday, July 28, 2014

Split the BAM file by chromosome then process it with GATK's UnifiedGenotyper

To parallel the execution of genotyping, one possible solution is to split the BAM files by chromosome (the safe method). For example, we have one big BAM file named "A.bam". Now we want to use GATK's UnifiedGenotyper to call variants on "A.bam". The command may looks like this:

time java -jar /home/hadoop/app/gatk/3.1-1/GenomeAnalysisTK.jar -T UnifiedGenotyper 
-R /home/hadoop/data/fasta/hg19/hg19.fa -I A.bam -o A.vcf
It may take hours to get above command completed. #The 1st improvement As an improvement, we can split the "A.bam" by chromosome, then process splitted BAM files in paralle. so we can do:


for i in `samtools view -H A.bam | awk -F"\t" '/@SQ/{print $2}' |  cut -d":" -f2`
do
    samtools view -h -F 0x4 -q 10 A.bam $i | samtools view -hbS - > A.$i.bam
done
Now we have generated 20+ files named "A.chr1.bam", "A.chr2.bam", ... Now call GATK's UnifiedGenotyper:

time java -jar /home/hadoop/app/gatk/3.1-1/GenomeAnalysisTK.jar -T UnifiedGenotyper \
-R /home/hadoop/data/fasta/hg19/hg19.fa -I A.chr1.bam -o A.chr1.vcf

real    32m
It takes 32 mins to complete. If you look at the outputs of above command you may find that UnifiedGenotyper does not stop after iterating "chr1". Since A.chr1.bam only contains alignments on chr1, it make no sense to waste time on other chromosomes. Let us make another improvement #The 2nd improvement This time, we split the reference FASTA file as well. supposedly we have "hg19.chr1.fa", "hg19.chr2.fa" under a folder.

for i in *.fa  
do  
   j=$(echo $i | cut -d"." -f1)  
   echo $j  
   java -jar ~/app/picard/1.114/CreateSequenceDictionary.jar R=$j.fa O=$j.dict  
   ~/app/samtools/0.1.19/samtools faidx $j.fa  
done  
Now call GATK's UnifiedGenotyper:


time java -jar /home/hadoop/bio/app/gatk/3.1-1/GenomeAnalysisTK.jar -T UnifiedGenotyper \
-R /home/hadoop/bio/data/fasta/hg19/hg19.chr1.fa -I A.chr1.bam -o A1.vcf

Let us see how much time it use ... Again, UnifiedGenotyper does not stop after iterating "chr1", it continue goes to "chr2" then throw an error message and terminate the process. What's wrong here? The header of splitted BAM files let us have a look at the header of "A.bam"


$samtools view -h A.bam | less

@HD     VN:1.3  SO:coordinate
@SQ     SN:chr1 LN:249250621
@SQ     SN:chr2 LN:243199373
@SQ     SN:chr3 LN:198022430
@SQ     SN:chr4 LN:191154276
@SQ     SN:chr5 LN:180915260
@SQ     SN:chr6 LN:162008842
...
@RG     ID:HELLO        LB:L01  PL:illumina     PU:barcode      SM:001
@PG     ID:bwa  PN:bwa  VN:0.7.9a-r786 
...

let us have a look at the header of "A.chr1.bam"


$samtools view -h A.chr1.bam | less

@HD     VN:1.3  SO:coordinate
@SQ     SN:chr1 LN:249250621
@SQ     SN:chr2 LN:243199373
@SQ     SN:chr3 LN:198022430
@SQ     SN:chr4 LN:191154276
@SQ     SN:chr5 LN:180915260
@SQ     SN:chr6 LN:162008842
...
@RG     ID:HELLO        LB:L01  PL:illumina     PU:barcode      SM:001
@PG     ID:bwa  PN:bwa  VN:0.7.9a-r786 
...

They are the same. Since "A.chr1.bam" only has the mappings on chr1, we do not need information on other chromosomes like "@SQ SN:chr2 LN:243199373" Unfortunately, both "samtools view" and "bamtools split" are unable to process the header file directly, we have to do it manually. Here is a script to do so


#!/bin/bash
#usage   

SAMTOOLS=$1
BAM_INPUT=$2
PATH_OUTPUT=$3
BAMTOOLS=~/bio/app/bamtools/bin/bamtools/2.3.0/bamtools
#create the target directory
mkdir -p ${PATH_OUTPUT}

if [ -f $BAMTOOLS ];
then

 cd ${PATH_OUTPUT} && ~/bio/app/bamtools/bin/bamtools split -in ${BAM_INPUT} -refPrefix "" -reference
 for i in *.chr*bam 
 do 
  sampleName=${i%.bam}
  chrName=${sampleName#*.}
  ${SAMTOOLS} view -h -F 0x4 -q 10 ${i} | awk '{if(/^@SQ/ && !/^@SQ\tSN:'$chrName'/) next} {if(/^@/) print $0}{if ($3~/^'$chrName'/) print $0}' | ${SAMTOOLS} view -hbS - > ${PATH_OUTPUT}/${sampleName}.tmp
  mv ${PATH_OUTPUT}/${sampleName}.tmp ${PATH_OUTPUT}/${sampleName}.bam
 done
else
 fileName=$(basename "$BAM_INPUT")
 #extension="${fileName##*.}"
 sampleName="${fileName%.*}"
 #split the bam
 for i in `${SAMTOOLS} view -H ${BAM_INPUT} | awk -F"\t" '/@SQ/{print $2}' |  cut -d":" -f2`
 do
  ${SAMTOOLS} view -h -F 0x4 -q 10 ${BAM_INPUT} $i | awk '{if(/^@SQ/ && !/^@SQ\tSN:'$i'/) next} {if(/^@/) print $0}{if ($3~/^'$i'/) print $0}' | $1 view -hbS - > ${PATH_OUTPUT}/${sampleName}.$i.tmp
  mv ${PATH_OUTPUT}/${sampleName}.$i.tmp ${PATH_OUTPUT}/${sampleName}.$i.bam
 done
fi

Save above script as "bam_split_by_chr.sh". #split


$chmod +x bam_split_by_chr.sh

$./bam_split_by_chr.sh /home/hadoop/samtools /home/hadoop/A.bam 
/home/hadoop/output

now under /home/hadoop/output you will see "A.chr1.bam".


$samtools view -h A.chr1.bam | less
@HD     VN:1.3  SO:coordinate
@SQ     SN:chr1 LN:249250621
@RG     ID:HELLO        LB:L01  PL:illumina     PU:barcode      SM:001
@PG     ID:bwa  PN:bwa  VN:0.7.9a-r786 
...

OK with this cleaned BAM file let us run UnifiedGenotyper again.


time java -jar /home/hadoop/bio/app/gatk/3.1-1/GenomeAnalysisTK.jar -T UnifiedGenotyper \
-R /home/hadoop/bio/data/fasta/hg19/hg19.chr1.fa -I A.chr1.bam -o A1.vcf

real:   7m

Now it only takes 7 mins to process the "A.chr1.bam". Finally, as a side effect, you will not be able to merge the splitted BAM files into the original "A.bam" again by using "samtools merge"


$samtools merge A.bam A.chr*.bam
[bam_merge_core] different target sequence name: 'chr1' != 'chr2' in file 'A.chr2.bam'

It does not matter, anyway. We do not need to do that.

Thursday, July 24, 2014

Counting lines in "fastq.gz"

Before splitting the "fastq.gz" into fragments, we need to counting how many lines in the raw file, then we can calculate how many lines per fragment.

If the raw file is quite big, the counting itself will take a long time to process because the file has to be decompressed firstly.

The common approach is using "zcat" with "wc". Is it the fastest?



#1. use zcat - 9.381s 
$time zcat A_R1.fq.gz | wc -l
 20000000

 real    0m9.381s
 user    0m7.423s
 sys     0m1.919s


#2. use zgrep - 16.258s
 $time zgrep -Ec "$" A_R1.fq.gz
 20000000

 real    0m16.258s
 user    0m13.109s
 sys     0m0.490s


#3. use pigz - 7.227s
 $sudo apt-get install pigz
 $time pigz -d -p 1 -c A_R1.fq.gz  | wc -l
 20000000

 real    0m7.227s
 user    0m5.544s
 sys     0m0.386s

#4. use pigz with 4 threads - 5.973s
 $time pigz -d -p 4 -c A_R1.fq.gz  | wc -l
 20000000

 real    0m5.973s
 user    0m5.599s
 sys     0m2.200s

By default, pigz will use all available processors so "-p" is not necessary. The above command can be simplified as 

 $pigz -dc A_R1.fq.gz  | wc -l


Clearly, our winner is pigz.

I am going to write another blog on splitting the "fastq.gz" file with only one goal - as fast as possible. 

 1. Count lines
 2. Determine how many lines per splitted fastq file
 3. Unzip and split the paired "fastq.gz" files
 4. Zip splitted "fastq" files again.


Reference:
http://superuser.com/questions/135329/count-lines-in-a-compressed-file



Build hadoop-2.4.1-src

1. http://apache.cs.utah.edu/hadoop/common/hadoop-2.4.1/hadoop-2.4.1-src.tar.gz

2. http://protobuf.googlecode.com/files/protobuf-2.5.0.tar.bz2

./configure && make && sudo make install && sudo ldconfig
mvn compile && mvn package


Monday, June 9, 2014

VirtualBox 4.3.12 configuration

File->"Preferences"->Click "Network" in left panel -> Add a new NAT network

Name -> "MyNAT"
CIDR: 192.168.0.0/24
Click the "Port forwarding" add port "22" in Ipv4.
Name "SSH"
Protocol "TCP"
Host IP "10.2.2.72" (run "cmd"->"ipconfig" to get it)
Host Port "22"
Guest IP "192.168.0.4" (The IP of the primary virtual machine)
Guest Port "22"


For each virtual machine, in "Settings"->"network"->"Adapter1"->"NAT Network" choose "MyNAT"

Wednesday, May 21, 2014

Windows+VirtualBox+Ubuntu+Xen+Ubuntu


What we have:

    Native machine installed with Windows 7.

Now I want to play with some virtual machines:

    1. Install VirtualBox into Windows 7, as a VM
    2. Install Ubuntu(1) into VirtualBox, as a guest OS
    3. Install Xen into Ubuntu, as a VM
    4. Install Ubuntu(2) into Xen, as a guest OS

Versions:
    VirtualBox 4.3.10 r93012
    Ubuntu 14.04 Server 
    Xen 4.4


It is quite easy to install Ubuntu into VirtualBox (step1 and step2). One thing to remember: "Do not assign all allocated space to Ubuntu(1)". Supposedly we decide to give 100GB disk space to VMs inside the VirtualBox, then the Ubuntu(1), as a dom0 OS, should use as less space as possible, say, 2GB. The remaining 98GB disk space should be reserved for one or more guest Ubuntu(2) guest OS. Otherwise your Xen will hang up when trying to "brought up CPU".


#1. get the Xen package
$sudo apt-get install xen-hypervisor-4.4-amd64

#2. Set Xen as the default loading OS
$sudo sed -i 's/GRUB_DEFAULT=.*\+/GRUB_DEFAULT="Xen 4.4-amd64"/' /etc/default/grub
sudo update-grub

#3. use xl as toolstack
$sudo sed -i 's/TOOLSTACK=.*\+/TOOLSTACK="xl"/' /etc/default/xen
$sudo reboot

$sudo xl list

#4. Create primary partition on remaining disk space
sudo fdisk /dev/sda

... /dev/sda3

#5. restart 

sudo reboot

#6. create physical storage

sudo pvcreate /dev/sda3

#7. create volume group "xen-vg" on /dev/sda3

sudo vgcreate xen-vg /dev/sda3

#8. take a look at PVs. 

sudo pvs

  PV         VG     Fmt  Attr PSize  PFree

  /dev/sda3  xen-vg lvm2 a--  51.62g 51.62g

#9. create logical volume "ubuntu" guest OS with 10G disk space
sudo lvcreate -L 10G -n ubuntu /dev/xen-vg


#10. Tell it where to get the image - Ubuntu 14.40 (a.k.a utopic)
sudo mkdir -p /var/lib/xen/images/ubuntu-netboot
$cd /var/lib/xen/images/ubuntu-netboot
$sudo wget http://ubuntu.cs.utah.edu/ubuntu/dists/utopic/main/installer-amd64/current/images/netboot/xen/initrd.gz
$sudo wget http://ubuntu.cs.utah.edu/ubuntu/dists/utopic/main/installer-amd64/current/images/netboot/xen/vmlinuz

#11. Configuration
$sudo vim /etc/xen/ubuntu.cfg

name = "ubuntu"
memory = 512
disk = ['phy:/dev/xen-vg/ubuntu,xvda,w']
vif = [' ']
kernel = "/var/lib/xen/images/ubuntu-netboot/vmlinuz"
ramdisk = "/var/lib/xen/images/ubuntu-netboot/initrd.gz"
extra = "debian-installer/exit/always_halt=true -- console=hvc0"

#12. Start installing the Ubuntu(2) 
sudo xl create /etc/xen/ubuntu.cfg -c  




Reference 

https://help.ubuntu.com/community/Xen