Mostrando entradas con la etiqueta blast. Mostrar todas las entradas
Mostrando entradas con la etiqueta blast. Mostrar todas las entradas

5 de febrero de 2020

Recursos y presentaciones del NCBI en PAG2020

Hola,
para empezar el año la gente genómica a menudo se cita en una de las conferencias más importantes del año, PAG . Allí se juntan los consorcios que producen los genomas último modelo de animales y plantas, las empresas que fabrican los instrumentos y reactivos, y los grupos que desarrollan los algoritmos y herramientas que lo sostienen todo, como el EBI o el NCBI.

Precisamente de éstos últimos hablo hoy, para compartir con vosotros los recursos y presentaciones que este año hicieron en PAG, entre los que destacaría:
https://github.com/NCBI-Hackathons/TheHumanPangenome

Que aproveche y hasta pronto,
Bruno

5 de marzo de 2019

Unión de varios ficheros ordenados (sort merge)

Hola,
en entradas pasadas, como ésta de 2010, ya hemos hablado de cómo ordenar resultados tabulares de BLAST con GNU sort. Entre tanto sort ha ido evolucionando y las versiones actuales, por ejemplo la que viene instalada por ejemplo en Ubuntu 18, ahora permite distribuir el trabajo en varias hebras:

--parallel=N    change the number of sorts run concurrently to N

Sin embargo, cuando queremos ordenar de manera global tablas numéricas distribuidas en varios ficheros internamente ordenados seguiremos usando una opción que ya teníamos en 2010:

-m, --merge     merge already sorted files; do not sort

A pesar de ahorrarse ordenar los ficheros internamente, cuando el número de ficheros es grande esta tarea se vuelve muy lenta. En el ejemplo ordenamos 100 ficheros separados por tabuladores (TSV) por las columnas numéricas 1 y 11:

time sort -S500M -s -k1g -k11g -m ficheros*.sorted > all.sorted

real 20m15.793s
user 19m46.045s
sys 0m18.724s

La clave para mejorar es eliminar el uso de ficheros temporales, leyendo de los 100 ficheros a la vez:

time sort --batch-size=100 -S500M -s -k1g -k11g -m ficheros*.sorted > all.sorted

real 13m49.672s
user 13m29.370s
sys 0m9.972s
 
De esta manera cuesta aproximadamente un tercio menos, y como se ve en el último ejemplo no sirve de nada aumentar la memoria del proceso de 500MB a 5 GB. De la misma manera, en mis pruebas no merece la pena aumentar el números de hebras concurrentes:

time sort --batch-size=100 S5G -s -k1g -k11g -m ficheros*.sorted > all.sorted

real 14m9.339s
user 13m49.315s
sys 0m10.705s

Hasta luego,
Bruno

2 de enero de 2019

BLAST+ actualizado a versión 2.8.1

Hola, espero que estéis bien.
En esta primera entrada del año solamente quería señalar que BLAST+ fue actualizado a la versión 2.8.1+ hace un par de semanas a causa de un error encontrado al usar la opción -max_target_seqs, tal como se publicó en https://doi.org/10.1093/bioinformatics/bty833 y se discutió en https://www.biostars.org/p/340129 .

En respuesta a este error, tres autores del NCBI (Madden, Busby y Ye) escribieron una carta donde explican que el error detectado tiene menor impacto del esperado porque afecta a alineamientos con un número "muy elevado" de indels. Sin embargo, sí reconocen que el uso del parámetro -max_target_seqs con valores M pequeños puede causar confusión porque secuencias con igual puntuación se seleccionarían en base a su posición en el fichero FASTA de partida. Para abordar esto la versión actualizada avisa al usuario cuando use M < 5.

La explicación detallada de los autores de BLAST y los cambios introducidos en la versión actual se explican en https://www.ncbi.nlm.nih.gov/books/NBK131777 y https://doi.org/10.1093/bioinformatics/bty1026 .

Un saludo,
Bruno

25 de septiembre de 2018

SequenceServer: nice local blast

Hi,
today I wanted to let you know about a tool that we discovered recently that has been very useful for us. Its name is SequenceServer (http://www.sequenceserver.com). It is simply a wrapper to let your collaborators run NCBI BLAST searches on your local sequence databases.
All you need is a copy of the NCBI folder with some BLAST+ release and a Linux distribution. Here we had ncbi-blast-2.7.1+ already in place but had to install the application, which is a ruby application, as recommended by the authors:

$ sudo gem install sequenceserver

Due to dependencies during installation I could not manage to install it in Centos5, but instead it was easy in CentOS release 7.5 (sudo yum install ruby-devel). Once this is done, and the appropriate port is open in the host, all that remains is to let the application know where the sequence databases are. You can do that with these commands:

$ sequenceserver -d /path/to/dbs  # add new databases
$ sequenceserver -l               # list installed dbs
$ sequenceserver &                # launch web application 
 

Now you are ready to go. Your users need to type the URL:port of your host in their browser and they can now run their searches. This is the way it looks in our server:


Cheers, Bruno

PS I will be moving to the EMBL-EBI so there might be a break in this blog, but please keep in touch

23 de octubre de 2017

BLASTP: diferentes versiones dan diferentes alineamientos de secuencias de baja complejidad



El alineamiento de secuencias repetitivas o regiones de baja complejidad en la version ncbi-blast-2.2.27+ muestra diferentes "Best hits" en los alineamientos comparado con las versiones más recientes de blast como la version ncbi-blast-2.2.30+ y la versión ncbi-blast-2.6.0+ a pesar de mantener los mismos parámetros en ambos casos y la misma base de datos.

Ejemplo de query: proteína de la familia PE de Mycobacterium tuberculosis asociada con virulencia y caracterizada por presentar regiones de baja complejidad.

>UT08
MSLVIATPQLLATAALDLASIGSQVSAANAAAAMPTTEVVAAAADEVSAAIAGLFGAHARQYQALSVQVAAFHEQFVQALTAAAGRYASTEAA

VERSLLGAVNAPTEALLGRPLIGNGADGTAPGQPGAAGGLLFGNGGNGAAGGFGQTGGSGGAAGLIGNGGNGGAGGTGAAGGAGGNG
GWLWGNGGNGGVGGTSVAAGIGGAGGNGGNAGLFGHGGAGGTGGAGLAGANGVNPTPGPAASTGDSPADVSGIGDQTGGDGGTGGH
GTAGTPTGGTGGDGATATAGSGKATGGAGGDGGTAAAGGGGGNGGDGGVAQGDIASAFGGDGGNGSDGVAAGSGGGSGGAGGGAFVHI
ATATSTGGSGGFGGNGAASAASGADGGAGGAGGNGGAGGLLFGDGGNGGAGGAGGIGGDGATGGPGGSGGNAGIARFDSPDPEAEPDV
VGGKGGDGGKGGSGLGVGGAGGLLFGNGGNGGNAGAGGDGGAGVAGGVGGNGGGGGTATFHEDPVAGVWAVGGVGGDGGSGGSSLG
VGGVGGAGGVGGKGGASGMLIGNGGNGGSGGVGGAGGVGGAGGDGGNGGSGGNASTFGDENSIGGAGGTGGNGGNGANGGNGGAG
GIAGGAGGSGGFLSGAAGVSGADGIGGAGGAGGAGGAGGSGGEAGAGGLTNGPGSPGVSGTEGMAGAPG


Versión ncbi-blast-2.2.27+:
Empleando los parametros por defecto para enmascarar las secuencias de baja complejidad:

Linea de ejecución:

~ncbi-blast-2.2.27+/bin/blastp -query UT08.fasta -db UT105.fa -outfmt 7 -max_target_seqs 5 -seg yes -soft_masking true

Alineamiento:

Fields: query id, subject id, % identity, alignment length, mismatches, gap opens, q. start, q. end, s. start, s. end, evalue, bit score
# 5 hits found

UT08    BNAKEEDD_03025    65.12    129    42    1    1    126    1    129    4e-45     167
UT08    BNAKEEDD_02663    72.80    125    31    1    1    122    1    125    2e-43     166
UT08    BNAKEEDD_01601    61.48    122    40    1    1    115    1    122    8e-36     141
UT08    BNAKEEDD_02274    63.89    144    49    3    1    141    1    144    5e-34     130
UT08    BNAKEEDD_00693    64.75    122    41    2    1    121    1    121    4e-33     134


Versión ncbi-blast-2.2.30+

 Linea de ejecución:

~ncbi-blast-2.2.30+/bin/blastp -query UT08.fasta -db UT105.fa -outfmt 7 -max_target_seqs 5 -seg yes -soft_masking true


Alineamiento:
Fields: query id, subject id, % identity, alignment length, mismatches, gap opens, q. start, q. end, s. start, s. end, evalue, bit score
# 5 hits found
UT08    BNAKEEDD_02661    98.27    694    0    1    1    682    1    694    0.0     1116

UT08    BNAKEEDD_03025    65.12    129    42    1    1    126    1    129    4e-45      167
UT08    BNAKEEDD_02663    74.82    139    32    1    1    136    1    139    1e-40      157
UT08    BNAKEEDD_01601    61.48    122    40    1    1    115    1    122    8e-36      141
UT08    BNAKEEDD_02274    63.89    144    49    3    1    141    1    144    5e-34      130



Versión ncbi-blast-2.6.0+

 Linea de ejecución:

~ncbi-blast-2.6.0+/bin/blastp -query UT08.fasta -db UT105.fa -outfmt 7 -max_target_seqs 5 -seg yes -soft_masking true


Alineamiento:

Fields: query id, subject id, % identity, alignment length, mismatches, gap opens, q. start, q. end, s. start, s. end, evalue, bit score
# 5 hits found
UT08    BNAKEEDD_02661    98.271    694    0    1    1    682    1    694    0.0    1116
UT08   BNAKEEDD_03025    65.116    129    42    1    1    126    1    129    3.79e-45    167
UT08    BNAKEEDD_02663    74.820    139    32    1    1    136    1    139    1.34e-40    157
UT08    BNAKEEDD_01601    61.475    122    40    1    1    115    1    122    7.24e-36    141
UT08    BNAKEEDD_02274    63.889    144    49    3    1    141    1    144    1.85e-34    130
 

 

Al realizar el alineamiento de la proteína query UT08 con la versión de blast 2.2.30 o 2.6.0 toma como segundo mejor hit el alineamiento que es el hit número uno para la versión 2.2.27. Sin embargo, al realizar la busqueda, para el alineamiento de UT08 usando en la versión 2.2.27 no fue posible identificar el hit número uno (BNAKEEDD_02661) de las versiónes 2.2.30 o 2.6.0 en los primeros 20 hits, siendo las que tuvieron el mayor procentaje de identidad (98.27%), mejor evalue y bit score para estas dos ultimas versiones.

Lo anterior indica que el alineamiento de secuencias en regiones de baja complejidad fue optimizado a partir de la versión ncbi-blast-2.2.30+ (ver Bug fixed https://www.ncbi.nlm.nih.gov/books/NBK131777/) .  Esta es una de las varias razónes que dan importancia a realizar periodicamente las actualizaciónes a las versiones más recientes de software para análisis de datos biológicos como Blast, sobre todo para corregir los posibles errores que traen las antiguas versiones, como en este caso paticular asociado a los alineamientos en secuencias repetitivas o de baja complejidad.








25 de abril de 2017

rendimiento multihebra de BLAST+ 2.6.0

Hola,
hace unas semanas descubrí gracias a mi colega Pablo Vinuesa que BLAST+ del NCBI iba ya por la versión 2.6.0. Cuando miré el resumen de cambios me llamó la atención que ya desde la versión 2.4 soporta un algoritmo multihebra para la fase reconstrucción hacia atrás del alineamiento, que en la literatura de programación dinámica se llama traceback. Dado que nosotros usamos con mucha frecuencia BLAST quise probar en qué se traducían estas novedades en tiempo de cálculo, dado que ya habíamos observado que BLASTP no paralelizaba bien, razón por la cual desarrollamos split_blast.pl, que recientemente comparamos contra DIAMOND.

El experimento consistió en buscar alineamientos locales de 48.588 secuencias de la variedad de cebada Haruna Nijo entre los 7.927 factores de transcripción de nuestra colección http://floresta.eead.csic.es/footprintdb:

$ ncbi-blast-2.2.30+/bin/makeblastdb -in footprintdb.18042017.tf.fasta -dbtype prot

$ time ~/soft/ncbi-blast-2.2.30+/bin/blastp -query HarunaNijo_proteins.fa \
  -db footprintdb.18042017.tf.fasta -outfmt 6 -max_target_seqs 10 \
  -num_threads 8 > HarunaNijo_proteins.2.2.30.blast

real  53m47.482s
user  122m2.375s
sys 0m9.749s

$ perl split_blast.pl 8 1000 ncbi-blast-2.2.30+/bin/blastp \
  -query HarunaNijo_proteins.fa -db footprintdb.18042017.tf.fasta -outfmt 6 \
  -max_target_seqs 10 -output HarunaNijo_proteins.split.blast

# runtime: 836 wallclock secs ( 0.71 usr  0.20 sys + 6391.38 cusr  5.54 csys = 6397.83 CPU)
# this is ~14m

$ ncbi-blast-2.6.0+/bin/makeblastdb -in footprintdb.18042017.tf.fasta -dbtype prot

$ time ncbi-blast-2.6.0+/bin/blastp -query HarunaNijo_proteins.fa \
  -db footprintdb.18042017.tf.fasta -outfmt 6 -max_target_seqs 10 \
  -num_threads 8 >   HarunaNijo_proteins.2.6.0.blast
 
real  20m35.969s
user  194m1.715s
sys 2m41.827s

Como podéis ver, al menos para BLASTP esta versión de BLAST+ supone una ganancia clara en procesadores multicore (8 en esta prueba), a costa de un aumento de tamaño del binario, que pasa de 31MB a 38MB, pero sigue siendo más lento que split_blast.pl,
hasta pronto,
Bruno



19 de diciembre de 2016

DIAMOND as alternative to BLASTP

Hi,
in a recent post I discussed the performance of DIAMOND when aligning nucleotide sequences against a peptide database. However, as this tool can also do protein similarity searches, I wanted to test that too. Here I summarize those results.

We used all protein sequences encoded in ecotype Bur-0 of Arabidopsis thaliana (n=53,027) and the proteome of Mycobacterium tuberculosis strain H37Rv (n=3,906). We scanned these against Swissprot, downloaded from ftp.uniprot.org and formatted as follows:

$ makeblastdb -in uniprot_sprot.fasta -dbtype prot                   
$ diamond makedb --in uniprot_sprot.fasta --db uniprot_sprot.fasta  

As earlier, we used v0.8.25, obtained from https://github.com/bbuchfink/diamond.

The actual sequence similarity searches were performed as follows:

$ diamond blastp -p 30 -d swissprot -q bur-0.faa -o bur-0.diamond.tsv \
  --max-target-seqs 1000 --evalue 0.00001 \
  --outfmt 6 qseqid sseqid pident length mismatch gapopen qstart qend \
  sstart send evalue bitscore qcovhsp sseq 

$ diamond blastp -p 30 -d swissprot -q bur-0.faa -o bur-0.diamond.sensitive.tsv \
  --sensitive ...

$ diamond blastp -p 30 -d swissprot -q bur-0.faa -o bur-0.diamond.more.tsv \
  --more-sensitive ...

$ time ncbi-blast-2.2.30+/bin/blastp -num_threads 30 -db swissprot \
  -query bur-0.faa -out bur-0.blastp.tsv 
  -max_target_seqs 1000 -evalue 0.00001 -outfmt '6 std qcovhsp sseq' 
 
# calling _split_blast.pl as used in get_homologues
$ get_homologues-est/_split_blast.pl 30 250 ncbi-blast-2.2.30+/bin/blastp \
  -db swissprot -query bur-0.faa -out bur-0.split.blastp.tsv \
  -max_target_seqs 1000 -evalue 0.00001 -outfmt \'6 std qcovhsp sseq\' 

Those commands were then run replacing bur-0.faa with Mtuberculosis_H37Rv.faa and using 8 CPU cores instead of 30. The obtained alignments were compared with a script (available upon request). Wall-clock time and matched hits are computed in relation to BLASTP (control). Alignment comparisons were performed with all BLASTP hits (red) and the subset of hits with identity >= 50% (blue).

The take home message is that DIAMOND "more sensitive" is 20x to 100x faster than BLASTP in these tests, with roughly 15% less sensitive overall, which is reduced to 5-9% when more remote homologues matter.

     search_strategy    time(s) matched =length longer shorter matched =length longer shorter

control (NCBI BLASTP)     16440  [         all hits          ]  [       IDENTITY:50%        ]
bur-0.diamond                55   0.402   0.804  0.109   0.088   0.848   0.916  0.063   0.021
bur-0.diamond.sensitive     192   0.774   0.794  0.116   0.090   0.906   0.916  0.062   0.022
bur-0.diamond.more          263   0.832   0.797  0.115   0.088   0.910   0.916  0.062   0.022
bur-0.split.blastp         6915   1.000    
                                          
control (NCBI BLASTP)      2657  [         all hits          ]  [       IDENTITY:50%        ]
Mtub.diamond                 34   0.483   0.853  0.075   0.072   0.930   0.932  0.051   0.017
Mtub.diamond.sensitive      124   0.832   0.823  0.091   0.087   0.957   0.931  0.052   0.017
Mtub.diamond.more           141   0.853   0.821  0.092   0.086   0.958   0.930  0.052   0.017
Mtub.split.blastp          2334   1.000 

Bruno

PS I post another test done by David A Wilkinson, from Massey University, New Zealand:

"I ran get homologues in conjunction with blastp, diamond in "standard mode" and diamond in "more-precise mode" for a small dataset.The dataset includes 20 genomes from the genus Leptospira - importantly, they are not all from the same "species", and for some pairwise comparisons will have relatively distant genomes and gene identities...

I used the ORTHOMCL algorithm in get-homologues for clustering. My numbers are in total agreement with published literature.Here are the comparative results:
#clusters
#core
#softcore
#shell
#cloud
BLASTP
10398
1523
2197
2269
5932
DIAMOND_STANDARD
10829
1421
2146
2328
6355
DIAMOND_MORE_PRECISE
10410
1535
2215
2269
5926
%clusters
%core
%softcore
%shell
%cloud
BLASTP
100%
100%
100%
100%
100%
DIAMOND_STANDARD
104%
93%
98%
103%
107%
DIAMOND_MORE_PRECISE
100%
101%
101%
100%
100%
"

26 de septiembre de 2016

PHMMER como alternativa a BLASTP

Hola,
hoy quería hablar de herramientas de búsqueda de secuencias de proteína, uno de los caballos de batalla en nuestro trabajo. Es un tema ya tocado en este blog, por ejemplo cuando hablamos de deltablast y cs-blast, pero que sigue siendo de actualidad.

En esta ocasión ha sido un artículo de Saripella et al el que me lo ha vuelto a recordar, comparando algoritmos que usan perfiles de secuencia (CS-BLAST, HHSEARCH and PHMMER) con algoritmos convencionales (BLASTP, USEARCH, UBLAST and FASTA). Es uno de esos artículos aburridos pero necesarios, donde se compara por vía independiente la validez de los mejores algoritmos para esta tarea, y se guardan los tiempos de cálculo empleados por cada uno de ellos (usando un core de CPU), para anotar dominios conocidos de secuencias de SwissProt extraídos de 3 repositorios complementarios (Pfam, Superfamily y CATH):

Figura original de http://bioinformatics.oxfordjournals.org/content/32/17/2636.full.

En el artículo se calculan áreas bajo curvas ROC para caracterizar a los diferentes algoritmos. De todos ellos destacaría dos:

1) BLASTP por ser muy rápido y muy preciso, con áreas de 0.908, 0.857 y 0.878 para las 3 colecciones de dominios y el tiempo que se muestra en la gráfica para buscar 100 secuencias al azar.

2) PHMMER por ser marginalmente más lento que BLASTP pero con una ganancia en área de aproximadamente el 3% (0.922,0.903,0.903).

Además, PHMMER es muy fácil de usar. Lo descargas de http://eddylab.org/software/hmmer3/CURRENT/ y solamente necesitas un archivo FASTA con la(s) secuencia(s) problema y otro con un repositorio de secuencias como SwissProt:

$ hmmer-3.1b1-linux-intel-x86_64/src/phmmer problema.faa uniprot_sprot.fasta

Hasta pronto,
Bruno


10 de octubre de 2014

Apuntes de genómica microbiana

Hola,
esta semana hemos participado en un taller de 6 días organizado por Mirko Rossi (Universidad de Helsinki, Finlandia) donde hemos repasado los principales aspectos de la genómica comparativa de bacterias. Todo esto desde un punto de vista muy aplicado, dado que la mayor parte de los alumnos eran investigadores de la esfera veterinaria. Nuestra aportación fue una sesión de tres horas y media dedicada a la determinación del pangenoma de un grupo de bacterias de interés, con la ayuda de nuestro software GET_HOMOLOGUES.

Estimación de las dimensiones del core-genoma (izq) y pan-genoma (der)
de una colección de 12 plásmidos plncA/C, genomas de ejemplo en el capítulo
"Robust identification of orthologues and paralogues for microbial pan-genomics
using GET_HOMOLOGUES: a case study of pIncA/C plasmids
", parte del libro

http://www.springer.com/biomed/medical+microbiology/book/978-1-4939-1719-8 .





A parte de esto, en esta entrada quería sobre todo contar algunas de las cosas que otros profesores a los que pude escuchar contaron, por si os pueden ayudar en vuestros proyectos:
  • Con Andrey Prjibelski, del Algorithmic Biology Lab de San Petersburgo, aprendimos a ensamblar genomas bacterianos con el software SPAdes, y luego a comparar y a evaluar distintos ensamblajes con ayuda de QUAST. Nos recomendó http://nucleotid.es para comparar de una manera objetiva las virtudes y defectos de distintos ensambladores disponibles ahora mismo, aunque comentó que dada la variedad de escenarios de los usuarios y de los tipos de lecturas/reads existentes no hay ahora mismo ninguno claramente superior a los demás. Sí remarcó que algunos están mal documentados y son por tanto más difíciles de utilizar. Me quedé un poco con la idea de que Velvet y SPAdes son los mejores para genomas bacterianos. Del primero menciona que es muy estable, de calidad moderada, pero muy limitado con lecturas del tipo mate pair. El segundo es el que desarrollan ellos y fue el que usamos en la sesión. SPAdes trabaja siempre sobre una base de lecturas Illumina/IonTorrent, que por defecto se corrigen antes de ser utilizadas, pero puede hacer ensamblajes híbridos con secuencias de otras plataformas, incluso Sanger, útiles para resolver secuencias repetidas, como mate pairs convencionales o Nextera (hqmp, de alta calidad). El programa tiene además un módulo (--careful) para corregir por mapeo errores (indels,mismatches) en los contigs generados al ensamblar. Su mayor ventaja respecto a Velvet es probablemente que ensambla iterativamente con K-meros diferentes para superar las limitaciones de K pequeños (ciclos) con los grandes y viceversa (falta de solapamientos cortos, ver este blog y este otro para una comparación más amplia).  
  • Bastien Chevreux, de DSM Nutritional Products AG, filosofó acerca de distintos problemas y estrategias para secuenciar y ensamblar genomas bacterianos con su software MIRA. La diferencia fundamental de este ensamblador respecto a los anteriores es que no se basa en grafos de De Bruijn, como Velvet o SPAdes, si no en la acumulación y alineamiento de lecturas solapantes, razón por la que es menos escalable y por tanto más lento que ellos. Este software a mi me parece sin duda más complejo de usar que SPAdes, pero tiene a su favor una lista de correo muy activa y documentación extensa. MIRA se ejecuta simplemente sobre un fichero manifiesto, editado por el usuario, que puede tener una sintaxis bastante compleja, pero que para un mapeo es algo sencillo, como por ejemplo:
    project= nombre_de_proyecto
    job= mapping,genome,accurate
    
    #input data comes next
    readgroup
    is_reference
    data= /path/to/file.gbk
    strain= Ecoli_strainA
    
    readgroup
    technology= solexa
    autopairing # busca PEs por ti
    data= /path/to/reads?.fastq
    strain= Ecoli_strainK12
     
  • Rauni Kivistö, de la Universidad de Helsinki, nosexplicó el uso de los programas ACT y BRIG para visualizar datos de comparación de genomas basados en BLAST.
  •  Veronika Vonstein y Ross  Overbeek, de la Fellowship for the Integration of Genomes, presentaron su plataforma para la anotación automática de genomas RAST que se construye sobre SEED, una colección de componentes, algo parecido a operones o trozos de rutas metabólicas, que llevan curando a mano desde hace dos décadas y que les permiten proyectar en tiempo real, según se van secuenciando nuevos genomas, anotaciones de alta calidad, que tienen en cuenta el contexto genómico y no se basan en BLAST, sino en eficientes búsquedas de K-meros específicos de familias de proteínas prealineadas que llaman FIGFams. Me sorprendió que un trabajo de esta envergadura no tuviera más repercusión, de hecho yo no lo conocía, pero se explica porque durante mucho tiempo trabajaron en el sector privado. Ahora mismo tienen financiación pública y se apoyan en hardware del Argonne National Laboratory.
Creo que esto es todo, un saludo y hasta la próxima,
Bruno



11 de julio de 2014

blast eficiente con alias de nr

Hola,
en esta entrada quisiera mostraros una manera de buscar secuencias de proteínas dentro de la base de datos estrictamente no redundante nr del NCBI, restringiendo la búsqueda a grupos taxonómicos arbitrarios, sin necesidad de duplicar secuencias en otros archivos. De hecho, por su gran tamaño, 45 millones de secuencias a dia de hoy, desde hace tiempo nosotros ya no trabajamos con el archivo FASTA de nr, si no con la base de datos ya formateada para blast que descargamos regularmente con update_blastdb.pl desde ftp://ftp.ncbi.nlm.nih.gov/blast/db .

La receta para realizar búsquedas sobre subconjuntos de nr la hemos sacado de https://www.biostars.org/p/6528, y aquí os mostraré un ejemplo con secuencias de plantas:

1) Si no la tienes ya descárgate con el script update_blastdb.pl una copia de nr. Ojo, son una serie de archivos que en total ocupan 42G:
$ perl update_blastdb.pl nr


2) Encontrar el identificador taxonómico que mejor represente al subconjunto de nr que quieres definir, en nuestro caso Viridiplantae:
http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?id=33090


3) Buscar todas las proteínas de plantas anotadas en el NCBI y exportar (Send to File => GI List) sus identificadores de GenBank (GIs) a un archivo, por ejemplo 'Viridiplantae_protein.gi.txt':
http://www.ncbi.nlm.nih.gov/protein/?term=txid33090[ORGN]



4) Hacer un alias de nr que contenga sólo proteínas de plantas:
$ ncbi-blast-2.2.29+/bin/blastdb_aliastool -gilist Viridiplantae_protein.gi.txt -db nr -out nr_plants -title nr_plants

En mi ejemplo produce el siguiente output:

Converted 3741334 GIs from Viridiplantae_protein.gi.txt to binary format in nr_plants.p.gil
Created protein BLAST (alias) database nr_plants with 2041649 sequences


Ahora veamos qué diferencias y ventajas tiene usar este subconjunto de nr en comparación con la base de datos completa:

[ NR ]
$ time ncbi-blast-2.2.29+/bin/blastx -query test.fna -db nr

 Database: All non-redundant GenBank CDS translations+PDB+SwissProt+PIR+PRF
excluding environmental samples from WGS projects
           45,360,603 sequences; 16,206,973,370 total letters

Query= test

Length=312
                                                                      Score     E
Sequences producing significant alignments:                          (Bits)  Value

dbj|BAK07057.1|  predicted protein [Hordeum vulgare subsp. vulgare]    156    8e-47
dbj|BAJ89957.1|  predicted protein [Hordeum vulgare subsp. vulgar...  62.0    5e-10
ref|WP_014745933.1|  asparagine synthase [Tistrella mobilis] >ref  42.7    0.020
ref|WP_006720063.1|  hypothetical protein [Collinsella stercoris]...  35.0    5.0 
ref|XP_001817163.2|  hypothetical protein AOR_1_2924174 [Aspergil...  35.0    5.3 
dbj|BAE55161.1|  unnamed protein product [Aspergillus oryzae RIB40]   35.0    6.9 
ref|WP_021178774.1|  Phosphate transport system permease protein ...  34.7    7.6 
ref|WP_021807128.1|  Phosphate transport system permease protein ...  34.7    7.9 
ref|WP_026166948.1|  glucan biosynthesis protein D [Novosphingobi...  34.3    8.8

[...]

real    5m28.923s
user    5m24.564s
sys    0m3.596s

[ NR_plants ]

$ time ncbi-blast-2.2.29+/bin/blastx -query test.fna -db nr_plants

Database: nr_plants

           2,041,649 sequences; 772,729,335 total letters

Query= test

Length=312
                                                                      Score     E

Sequences producing significant alignments:                          (Bits)  Value

dbj|BAK07057.1|  predicted protein [Hordeum vulgare subsp. vulgare]    156    4e-48
dbj|BAJ89957.1|  predicted protein [Hordeum vulgare subsp. vulgar...  62.0    2e-11
gb|EMS57556.1|  hypothetical protein TRIUR3_28581 [Triticum urartu]   33.1    0.95 
ref|XP_002311179.2|  hypothetical protein POPTR_0008s05850g [Popu...  33.5    1.1  
ref|XP_004509944.1|  PREDICTED: uncharacterized protein LOC101513...  32.0    3.0  
ref|XP_004509945.1|  PREDICTED: uncharacterized protein LOC101513...  32.0    3.0  
gb|EMT15944.1|  hypothetical protein F775_17477 [Aegilops tauschii]   32.0    3.3  
dbj|BAK00277.1|  predicted protein [Hordeum vulgare subsp. vulgare]   32.0    3.7  
ref|XP_004234300.1|  PREDICTED: uncharacterized protein LOC101244...  31.2    4.7  
ref|XP_006358717.1|  PREDICTED: LRR receptor-like serine/threonin...  31.2    5.2  
ref|XP_002316273.2|  hypothetical protein POPTR_0010s20870g [Popu...  31.2    6.6  
ref|XP_003571199.1|  PREDICTED: probable tocopherol cyclase, chlo...  30.8    8.4  
ref|XP_008451998.1|  PREDICTED: respiratory burst oxidase homolog...  30.4    9.9

[...]

real    0m16.805s
user    0m16.332s
sys    0m0.372s

Como se puede ver en ambos casos las dos primeras secuencias encontradas son las mismas, con la misma puntuación en bits y distinto E-valor, al ser universos de búsqueda de tamaños  distintos.

Además,  el tiempo de búsqueda con un sólo procesador es del orden de 20x más rápido con el alias nr_plants, y a la vez el consumo de RAM en tiempo real mucho menor.

Hasta luego,
Bruno

15 de mayo de 2014

Cuando Blastn no es Blastn


BLAST cambió hace ya algún tiempo a mejor con su versión BLAST+ pero por el camino se olvidó de algún detalle que puede confundir a más de uno.

El antiguo BLAST se ejecutaba con el comando 'blastall':

Blastall
--------

Blastall may be used to perform all five flavors of blast comparison. One
may obtain the blastall options by executing 'blastall -' (note the dash). A
typical use of blastall would be to perform a blastn search (nucl. vs. nucl.) 
of a file called QUERY would be:

blastall -p blastn -d nr -i QUERY -o out.QUERY

The output is placed into the output file out.QUERY and the search is performed
against the 'nr' database.  If a protein vs. protein search is desired,
then 'blastn' should be replaced with 'blastp' etc.

De esta forma un alineamiento de proteínas comenzaría como 'blastall -p blastp' y uno de ácidos nucleicos como 'blastall -p blastn' y si queremos usar MEGABLAST tenemos el comando diferente 'megablast'.

Sin embargo en la 'nueva' versión BLAST+, se separaron el alineamiento de proteínas y el de ácidos nucleicos en dos comandos: 'blastp' y 'blastn' (ver manual). Hasta aquí todo parece lógico y normal, lo que no todo el mundo sabe es que LA OPCIÓN POR DEFECTO DE BLASTN ES MEGABLAST, si ejecutamos 'blastn -help' encontraremos lo siguiente:


 *** General search options
 -task                 'megablast' 'rmblastn' >
   Task to execute
   Default = `megablast'

Y es que no todo el mundo está interesado en la velocidad de búsqueda de alineamientos, muchos de los que todavía usamos Blastn es porque apreciamos su gran sensibilidad para detectar alineamientos. En la actualidad usamos Blast para alinear miles de secuencias en tiempos muy razonables de minutos e incluso segundos. Para ganar velocidad en alineamientos de millones de secuencias existen otras mejores alternativas como Bowtie2.

La CONCLUSIÓN de todo esto, si usamos Blastn y nos interesa la sensibilidad deberemos ejecutarlo como:

 blastn -task blastn

Si lo hacemos sin añadir esta opción estaremos ejecutando MEGABLAST y correremos el peligro de perder una gran sensibilidad y no encontrar los alineamientos que deseamos. Por ejemplo, busquemos homología entre la 2'beta microglobulina humana (NM_004048.2) y la de ratón (NM_009735.3) usando la herramienta online de Blastn con las opciones por defecto ('Highly similar sequences (megablast)'):


Sin embargo si cambiamos la opción de búsqueda a 'Somewhat similar sequences (blastn)':


La diferencia es considerable, ¿no creéis? pasamos de no encontrar similaritud a un alineamiento con E-valor de 1.5E-56!!!!






21 de noviembre de 2013

GET_HOMOLOGUES for pan-genome analysis

Hola,
en el último número de Applied and Environmental Microbiology mi colega Pablo Vinuesa y yo publicamos un artículo describiendo el software GET_HOMOLOGUES, que tiene como abstract:
GET_HOMOLOGUES is an open source software package that builds upon popular orthology-calling approaches making highly customizable and detailed pan-genome analyses of microorganisms accessible to non-bioinformaticians. It can cluster homologous gene families using the bidirectional best-hit, COGtriangles or OrthoMCL clustering algorithms. Clustering stringency can be adjusted by scanning the domain-composition of proteins using the HMMER3 package, by imposing desired pair-wise alignment coverage cut-offs or by selecting only syntenic genes. Resulting homologous gene families can be made even more robust by computing consensus clusters from those generated by any combination of the clustering algorithms and filtering criteria. Auxiliary scripts make the construction, interrogation and graphical display of core and pan-genome sets easy to perform. Exponential and binomial mixture models can be fitted to the data to estimate theoretical core and pan-genome sizes, and high quality graphics generated. Furthermore, pan-genome trees can be easily computed and basic comparative genomics performed to identify lineage-specific genes or gene family expansions. The software is designed to take advantage of modern multiprocessor personal computers as well as computer clusters to parallelize time-consuming tasks. To demonstrate some of these capabilities, we survey a set of 50 Streptococcus genomes annotated in the Orthologous Matrix Browser as a benchmark case.
El  software  se puede descargar de http://www.eead.csic.es/compbio/soft/gethoms.php y también de http://maya.ccg.unam.mx/soft/gethoms.php y está escrito mayoritariamente en Perl, aunque contiene también trozos en R.
El manual del programa describe en detalle ejemplos de uso y está disponible en http://www.eead.csic.es/compbio/soft/manual.pdf .

Este paquete de programas se diseñó para el estudio de los pan y core-genomas de grupos de microorganismos, que es con lo que trabaja el grupo de Pablo fundamentalmente, y permite generar figuras como éstas:


Un saludo,
Bruno

23 de abril de 2013

Multicore Blast con Python

El otro día Bruno publicó en una entrada del blog un script en Perl para optimizar el tiempo de cálculo de Blast en ordenadores con procesadores multicore. Un gran script, pero creo que se puede hacer más sencillo usando el módulo subprocess de Python.

Bruno usó el módulo Parallel::ForkManager de Perl. en el pasado ya habíamos mostrado en otra entrada las ventajas y peligros de paralelizar procesos con Perl con el módulo threads.

La solución con Python creo que es la más sencilla, consiste en usar el módulo subprocess. Otro módulo de Python que podríamos usar sería multiprocessing, pero no es muy sencillo retornar el standard output de programas externos como Blast para un procesamiento posterior de los resultados.

En el siguiente ejemplo se paraleliza la ejecución del comando 'blastp -version' que retorna un texto con la versión instalada de blastp. Dicho comando se puede cambiar por cualquier otro, así como añadir código al script para procesar los resultados. En el ejemplo se ejecuta el comando 10 veces con 4 procesos simultáneos, chequeando si han terminado cada 2 segundos.

 #!/usr/bin/python  
 # -*- coding: utf-8 -*-   
 #  
   
 # Importar módulos  
 import time  
 import os, sys  
 import subprocess  
 from pprint import pprint  
   
 maximum_process_number = 4 # Número máximo de procesos simultáneos  
 checking_processes_interval = 2 # (segundos) Tiempo de espera para checkear si han terminado los procesos  
 data_to_process = range(10) # Datos a procesar, como ejemplo una lista de números del 0 al 9  
   
 # El proceso a ejecutar (como ejemplo se muestran los datos de la version de Blastp)  
 # Se puede cambiar por cualquier otro programa y comando que no sea Blast  
 def run_process(processes) :  
      print "Running process"  
      processes.append(subprocess.Popen("blastp -version", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE))  
   
 # Programa principal  
 if __name__ == '__main__':  

      # Definir variables  
      count_processes = 0  
      finished_processes = []  
      processes = []  
      results = {}

      # Procesar múltiples datos  
      for i in data_to_process:

           # Chequear si los procesos han terminado (cuando hay tantos procesos como el máximo permitido)  
           while count_processes == maximum_process_number:  
                for p in processes:  
                     p.wait()  
                     if p.returncode == 0:  
                          results[p.pid] = "\n".join(p.stdout)  
                          processes.remove(p)  
                          count_processes -= 1  
                          print "Process finished"  
                     else:   
                          results[p.pid] = "\n".join(p.stdout)  
                          processes.remove(p)  
                          count_processes -= 1  
                          print "Process failed"  
                # Si no han terminado, esperar el tiempo establecido  
                if count_processes == maximum_process_number:  
                     print "Waiting for finished processes"  
                     time.sleep(checking_processes_interval)  

           # Añadir procesos a la cola de ejecución  
           run_process(processes)  
           count_processes += 1  
           print "Process started", i, count_processes  

      # Chequear si los procesos han terminado los últimos procesos  
      while count_processes != 0:  
           for p in processes:  
                p.wait()  
                if p.returncode == 0:  
                     results[p.pid] = "\n".join(p.stdout)  
                     processes.remove(p)  
                     count_processes -= 1  
                     print "Last processes finishing"  
                else:   
                     results[p.pid] = "\n".join(p.stdout)  
                     processes.remove(p)  
                     count_processes -= 1  
                     print "Process failed"  
           if count_processes == maximum_process_number:  
                print count_processes,maximum_process_number  
                print "Waiting for last finished processes"  
                time.sleep(checking_processes_interval) 
 
      # Imprimir resultados  
      print "Output from the processes:"  
      pprint(results)  

9 de abril de 2013

split_blast.pl : real multicore BLAST

Hola,
sin duda BLAST es una de las herramientas esenciales para cualquiera que se dedique a la bioinformática. En una entrada anterior ya comentábamos que actualmente está vigente la rama BLAST+ del software, que ahora mismo va por la versión 2.2.28, con nuevas funcionalidades y una interfaz más fácil de usar. Sin embargo, como comentan algunos usuarios de SEQanswers o Biostar,  las versiones actuales de BLAST no permiten aprovechar al máximo la capacidad de los actuales procesadores multicore, ya que sólo parte de la búsqueda de secuencias similares está paralelizada en el código. Esta es posiblemente una de las razones por las que han sido tan habituales los clusters de cálculo en los laboratorios de bioinformática, que sí permiten hacer en paralelo este tipo de cálculos. Estos son algunos ejemplos de artículos que discuten este tema: http://bioinformatics.oxfordjournals.org/content/19/14/1865 ,
http://bioinformatics.oxfordjournals.org/content/27/2/182 ,
http://www.korilog.com/index.php/KLAST-high-performance-sequence-similarity-search-tool.html .

A lo que iba, ahora mismo cualquiera tiene delante una máquina multicore (en Linux comprueba /proc/cpuinfo) y con ella podremos acelerar significativamente nuestras búsquedas con BLAST si se cumple una condición:

1) la memoria RAM de tu hardware debe superar con creces el tamaño de la base de secuencias que queremos rastrear

Si esta condición se cumple en tu caso, sigue leyendo. El siguiente código Perl, que gestiona procesos con fork por medio del módulo Parallel-ForkManager, te permitirá exprimir tú máquina, partiendo el problema inicial en pedazos de tamaño igual que serán enviados de manera eficiente a procesar a los cores disponibles de tu máquina. En mis pruebas, el tamaño óptimo de pedazo es de 100 secuencias, y el número de cores óptimo es el físico de la máquina en cuestión.


El script se ejecuta modificando el comando nativo de BLAST, por ejemplo con 8 cores y trabajos de 250 secuencias:

$ split_blast.pl 8 250 blastp -query input.faa -db uniprot.fasta -outfmt 6 

Para más detalles guarda el código en un archivo y ejecútalo en el terminal:

 #!/usr/bin/perl -w  
   
 # Mar2013 Bruno Contreras http://www.eead.csic.es/compbio/  
 # Script to take advantage of multicore machines when running BLAST,  
 # which seems to scale up to the number of physical cores in our tests.  
 # Supports old BLAST (blastall) and new BLAST+ binaries.  
 #   
 # The gain in speed is proportional to the number of physical cores allocated,   
 # at the cost of proportionaly increasing the allocated memory. For this reason probably is not  
 # a good idea to use it in searches against huge databases such as nr or nt, unless your RAM allows it.  
 #  
 # Requires module Parallel::ForkManager (http://search.cpan.org/perldoc?Parallel%3A%3AForkManager)  
   
 use strict;  
   
 if(eval{ require Parallel::ForkManager }){ import Parallel::ForkManager; }  
 else  
 {  
    die "\n# Failed to locale required module Parallel::ForkManager\n".  
       "# Please install it by running in your terminal (as a root, preferably with sudo):\n\$ cpan -i Parallel::ForkManager\n\n";  
 }  
   
 my $VERBOSE = 1;  
 my $DEFAULTBATCHSIZE = 100;  
 my $BLASTDBVARNAME = 'BLASTDB';  
   
 # constant as indices to access read_FASTA_file_arrays  
 use constant NAME => 0;  
 use constant SEQ => 1;  
   
 my ($n_of_cores,$batchsize,$raw_command,$command) = (1,$DEFAULTBATCHSIZE,'','');  
 my ($outfileOK,$blastplusOK,$input_seqfile,$output_file,$db_file) = (0,0,'','','');  
 my $start_time;  
   
 if(!$ARGV[2])  
 {  
   print "\nScript to take advantage of multicore machines when running BLAST.\n\n";  
   print "Usage: perl split_blast.pl <number of processors/cores> <batch size> <blast command>\n\n";  
   print "<number of processors/cores> : while 1 is accepted, at least 2 should be requested\n";  
   print "<batch size> : is the number of sequences to be blasted in each batch, $DEFAULTBATCHSIZE works well in our tests\n";  
   print "<blast command> : is the explicit blast command that you would run in your terminal, either BLAST+ or old BLAST\n\n";  
   print "Example: split_blast.pl 8 250 blastp -query input.faa -db uniprot.fasta -outfmt 6 -out out.blast\n\n";  
   print "Please escape any quotes in your BLAST command. For instance:\n\n";  
   print "blastall -p blastp -i input.faa -d nr.fasta -m 8 -F 'm S' -o out.blast\n\n";  
   print "should be escaped like this:\n\n";  
   die "blastall -p blastp -i input.faa -d nr.fasta -m 8 -F \\'m\\ S\\' -o out.blast\n";  
 }  
 else ## parse command-line arguments  
 {  
   $n_of_cores = shift(@ARGV);  
   if($n_of_cores < 0){ $n_of_cores = 1 }  
   
   $batchsize = shift(@ARGV);  
   if($batchsize < 0){ $batchsize = $DEFAULTBATCHSIZE } # optimal in our tests  
   
   $raw_command = join(' ',@ARGV);  
   
   if($raw_command =~ /\-i (\S+)/)  
   {  
     $input_seqfile = $1;  
     if($raw_command =~ /\-o (\S+)/){ $output_file = $1 }  
     if($raw_command =~ /\-d (\S+)/){ $db_file = $1 }  
   }  
   elsif($raw_command =~ /\-query (\S+)/)  
   {  
     $blastplusOK = 1;  
     $input_seqfile = $1;  
     if($raw_command =~ /\-out (\S+)/){ $output_file = $1 }  
     if($raw_command =~ /\-db (\S+)/){ $db_file = $1 }  
   }  
   else{ die "# ERROR: BLAST command must include an input file [-i,-query]\n" }  
   
   if(!-s $input_seqfile){ die "# ERROR: cannot find input file $input_seqfile\n" }  
   elsif(!-s $db_file &&  
     ($ENV{$BLASTDBVARNAME} && !-s $ENV{$BLASTDBVARNAME}.'/'.$db_file) )  
   {  
     die "# ERROR: cannot find BLAST database file $db_file\n"  
   }  
   
   # remove BLAST threads commands  
   $command = $raw_command;  
   $command =~ s/\-num_threads \d+//;  
   $command =~ s/\-a \d+//;  
   
   if(!$output_file)  
   {  
    import File::Temp qw/tempfile/;  
     my ($fh, $filename) = tempfile();  
     $output_file = $filename;  
     if($blastplusOK){ $command .= " -out $output_file " }  
     else{ $command .= " -o $output_file " } #print "$command\n";  
   }  
   else{ $outfileOK = 1 }  
   
   print "# parameters: max number of processors=$n_of_cores ".  
    "batchsize=$batchsize \$VERBOSE=$VERBOSE\n";  
   print "# raw BLAST command: $raw_command\n\n";  
 }  
   
 if($outfileOK)  
 {   
    use Benchmark;     
    $start_time = new Benchmark();   
 }  
   
   
 ## parse sequences  
 my $fasta_ref = read_FASTA_file_array($input_seqfile);  
 if(!@$fasta_ref)  
 {  
   die "# ERROR: could not extract sequences from file $input_seqfile\n";  
 }  
   
 ## split input in batches of max $BLASTBATCHSIZE sequences  
 my ($batch,$batch_command,$fasta_file,$blast_file,@batches,@tmpfiles);  
 my $lastseq = scalar(@$fasta_ref)-1;  
 my $total_seqs_batch = $batch = 0;  
   
 $fasta_file = $input_seqfile . $batch;  
 $blast_file = $input_seqfile . $batch . '.blast';  
 $batch_command = $command;  
 if($batch_command =~ /\-i (\S+)/){ $batch_command =~ s/-i \Q$1\E/-i $fasta_file/ }  
 if($batch_command =~ /\-query (\S+)/){ $batch_command =~ s/-query \Q$1\E/-query $fasta_file/ }  
 $batch_command =~ s/$output_file/$blast_file/;  
 push(@batches,$batch_command);  
 push(@tmpfiles,[$fasta_file,$blast_file,$batch_command]);  
   
 open(BATCH,">$fasta_file") || die "# EXIT : cannot create batch file $fasta_file : $!\n";  
   
 foreach my $seq (0 .. $#{$fasta_ref})  
 {  
   $total_seqs_batch++;  
   print BATCH ">$fasta_ref->[$seq][NAME]\n$fasta_ref->[$seq][SEQ]\n";  
   if($seq == $lastseq || ($batchsize && $total_seqs_batch == $batchsize))  
   {  
     close(BATCH);  
   
     if($seq < $lastseq) # take care of remaining sequences/batches  
     {  
       $total_seqs_batch = 0;  
       $batch++;  
       $fasta_file = $input_seqfile . $batch;  
       $blast_file = $input_seqfile . $batch . '.blast';  
       $batch_command = $command;  
       if($batch_command =~ /\-i (\S+)/){ $batch_command =~ s/-i \Q$1\E/-i $fasta_file/ }  
       if($batch_command =~ /\-query (\S+)/){ $batch_command =~ s/-query \Q$1\E/-query $fasta_file/ }  
       $batch_command =~ s/$output_file/$blast_file/;  
       push(@batches,$batch_command);  
       push(@tmpfiles,[$fasta_file,$blast_file,$batch_command]);  
   
       open(BATCH,">$fasta_file") ||  
        die "# ERROR : cannot create batch file $fasta_file : $!\n";  
     }  
   }  
 }  
   
 undef($fasta_ref);  
   
 ## create requested number of threads  
 if($batch < $n_of_cores)  
 {  
   $n_of_cores = $batch;  
   print "# WARNING: using only $n_of_cores cores\n";  
 }  
 my $pm = Parallel::ForkManager->new($n_of_cores);  
   
 ## submit batches to allocated threads  
 foreach $batch_command (@batches)  
 {  
   $pm->start($batch_command) and next; # fork  
   
   print "# running $batch_command in child process $$\n" if($VERBOSE);  
   open(BATCHJOB,"$batch_command 2>&1 |");  
   while(<BATCHJOB>)  
   {  
     if(/Error/){ print; last }  
     elsif($VERBOSE){ print }  
   }  
   close(BATCHJOB);  
   
   if($VERBOSE)  
   {  
     printf("# memory footprint of child process %d is %s\n",  
       $$,calc_memory_footprint($$));  
   }  
   
   $pm->finish(); # exit the child process  
 }  
   
 $pm->wait_all_children();  
   
 ## put together BLAST results, no sort needed  
 my $blastOK = 1;  
 unlink($output_file) if(-s $output_file && $outfileOK);  
   
 foreach my $file (@tmpfiles)  
 {  
   ($fasta_file,$blast_file,$batch_command) = @$file;  
   if(!-e $blast_file)  
   {  
     unlink($output_file) if(-e $output_file);  
   
    if($blastOK)  
    {  
        print "# ERROR : did not produced BLAST file $blast_file ,".  
            " probably job failed: $batch_command\n";  
    }  
    $blastOK = 0;  
   }  
   else  
   {  
     print "# adding $blast_file results to $output_file\n" if($VERBOSE);  
     system("cat $blast_file >> $output_file"); # efficient, less portable  
   }  
   unlink($fasta_file,$blast_file);  
 }  
   
 exit if(!$blastOK);  
   
 if(!$outfileOK)  
 {  
   open(OUTBLAST,$output_file) || die "# ERROR : cannot read temporary outfile $output_file : $!\n";  
   while(<OUTBLAST>)  
   {  
     print;  
   }  
   close(OUTBLAST);  
   
   unlink($output_file);  
 }  
 else  
 {  
    my $end_time = new Benchmark();  
    print "\n# runtime: ".timestr(timediff($end_time,$start_time),'all')."\n";  
 }  
   
 if($VERBOSE)  
 {  
   printf("# memory footprint of parent process %d is %s\n",  
     $$,calc_memory_footprint($$));  
 }  
   
 ####################################################  
   
 sub read_FASTA_file_array  
 {  
    # in FASTA format  
    # returns a reference to a 2D array for 4 secondary keys: NAME,SEQ  
    # first valid index (first sequence) is '0'  
   my ( $infile ) = @_;  
   my (@FASTA,$name,$seq,$n_of_sequences);  
   $n_of_sequences = -1;  
   open(FASTA,"<$infile") || die "# read_FASTA_sequence: cannot read $infile $!:\n";  
   while(<FASTA>)  
   {  
     next if(/^$/);  
     next if(/^#/);  
     if(/^\>(.*?)[\n\r]/)  
     {  
       $n_of_sequences++; # first sequence ID is 0  
       $name = $1; #print "# $n_of_sequences $name\n";  
       $FASTA[$n_of_sequences][NAME] = $name;  
     }  
     elsif($n_of_sequences>-1)  
     {  
       $_ =~ s/[\s|\n|\-|\.]//g;  
       $FASTA[$n_of_sequences][SEQ] .= $_; # conserve case  
     }  
   }  
   close(FASTA);  
     
   return \@FASTA;  
 }  
   
 sub calc_memory_footprint  
 {  
   my ($pid) = @_;  
   my $KB = 0;  
   my $ps = `ps -o rss $pid 2>&1`;  
   while($ps =~ /(\d+)/g){ $KB += $1 }  
   return sprintf("%3.1f MB",$KB/1024);  
 }  
   
 
Si prefieres hacerlo en Python prueba estas soluciones:
http://qiime.org/scripts/parallel_blast.html ,
http://www.ruffus.org.uk/examples/bioinformatics/

Hasta luego,
Bruno

Actualización 17/04/2013
Unos días después de compartir este código descubro GNU parallel (http://www.gnu.org/software/parallel), todavía no instalado por defecto en los Linux que tengo a mi alcance, que generaliza y simplifica hasta el extremo la tarea que hacíamos con Perl, con algo como:

$ cat input.faa | parallel --block 100k --recstart '>' --pipe blastp -outfmt 6 -db uniprot.fasta -query - 

Estos dos comandos concatenados por una tubería 1) parten el archivo de secuencias en bloques de 100Kbytes, separando las entradas por medio del carácter '>',  y 2) envían cada bloque a CPUs/cores disponibles en ese momento. Esencialmente es lo mismo que hace el código Perl. En mis pruebas tiene una ganancia en tiempo de cálculo muy similar, con un consumo de memoria también similar.


22 de febrero de 2013

Probando deltablast

Hola,
hace tiempo que tenía pendiente escribir sobre una de las ramas más recientes de la familia de programas BLAST, que se llama deltablast, publicada el año pasado. La lectura del artículo original sugiere que este programa se desarrolló a partir de la publicación del algoritmo CS-BLAST (context specific BLAST).
Pero realmente la historia no comienza aquí.
Todo empezó con el algoritmo PSI-BLAST, una versión iterativa de BLASTP, que en vez comparar una secuencia de proteína contra una librería de secuencias, construye un perfil de la secuencia problema y ése es el que compara contra la librería, ganando en sensibilidad. Todo esto con un coste en tiempo de cálculo modesto.
Qué problema tiene esto? Pues que el perfil se construye en tiempo real con los homólogos encontrados en iteraciones previas de manera automática y en ocasiones se pueden contaminar y producir resultados no idóneos.

(tomada de http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2645910)
CS-BLAST, que en realidad es como un preprocesamiento de BLAST, logró superar estos problemas precalculando los perfiles, que capturan información del contexto, y de hecho mejoró la sensibilidad a la hora de detectar homólogos remotos, que han perdido claramente la similitud de secuencia.

Pues bien, deltablast es un programa del NCBI que se inspira en estas experiencias para superar a capacidad de búsqueda de CS-BLAST, apoyándose en la colección de dominios Conserved Domains Database (CDD):
(tomada de http://www.biology-direct.com/content/7/1/12)
El programa es muy sencillo de usar en la web, aquí os explico como probarlo localmente en vuestra máquina:
1) descarga la última versión de BLAST+ para tu arquitectura de
ftp://ftp.ncbi.nih.gov/blast/executables/LATEST
 
2) descomprime el software en una carpeta, por ejemplo soft/

3) descarga una copia de CDD de ftp://ftp.ncbi.nih.gov/blast/db/cdd_delta.tar.gz

4) descomprime la base de dominios en un carpeta, de nuevo por ejemplo en  soft/

5) elige una colección de secuencias protéicas contra la que buscar, por ejemplo soft/nr.faa y formatéala con:
 $ soft/ncbi-blast-2.2.27+/bin/makeblastdb nr.faa
 
6) Ya puedes buscar una secuencia de proteína, como ejemplo.faa, contra tu colección de secuencias:
$ soft/ncbi-blast-2.2.27+/bin/deltablast -query ejemplo.faa -db soft/nr.faa -rpsdb soft/cdd_delta

7) Puedes utilizar prácticamente los mismos parámetros que con BLASTP, que puedes consultar haciendo:
$ soft/ncbi-blast-2.2.27+/bin/deltablast -help

Suerte!
Bruno

11 de enero de 2013

Indexando archivos FASTA

Hola y feliz año nuevo con retraso!
Recientemente me he visto en la necesidad de acceder de maneara aleatoria a secuencias de un archivo FASTA de gran tamaño, en mi caso cercano a los 2 Gb,
con las secuencias formateadas en una sola línea.

Primero probé con las herramientas de BLAST+, en concreto:
$ makeblastdb -in archivo.fasta -parse_seqid

Con la idea de posteriormente consultar las secuencias con algo como (más ejemplos aquí):

$ blastdbcmd -query -db archivo.fasta

Sin embargo, la generación del índice se hizo eterna y de hecho la aborté, por problemas que desconozco y no he seguido mirando.

Posteriormente, tras buscar en Google encontré dos caminos en Perl:

1)  con ayuda de scripts de Bioperl: bp_index.pl y bp_fetch.pl

2) con ayuda del módulo core Tie::File, como muestro en el ejemplo a continuación, mi solución preferida, un saludo:

 #!/usr/bin/perl -w  
 use strict;  
 use Tie::File;  
   
 my $fasta_file = '/path/to/file.fasta';  
   
 my (%index_fasta,@fasta_array);  
 open(FASTA,$fasta_file) ||   
    die "# cannot open $fasta_file\n";  
 while(<FASTA>)  
 {  
    if(/^> any typical marker in header, such as gi (\S+)/)  
    {  
       $index_fasta{$1} = $.;   
    }  
 }  
 close(FASTA);   
 printf("# indexed %d sequences in file %s\n\n",  
    scalar(keys(%index_fasta)),$fasta_file);  
   
 tie(@fasta_array,'Tie::File',$fasta_file) ||   
    die "# cannot tie file $fasta_file\n";  
   
 print "ejemplo: secuencia con identificador 'id12':\n";  
 print "$fasta_array[$index_fasta{'id12'}-1]\n".  
    "$fasta_array[$index_fasta{'id12'}]\n";