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

4 de abril de 2022

Dominios de función desconocida (DUF) en proteínas

Hola,

como ya hemos mencionado en otras ocasiones aquí, las proteínas habitualmente tienen uno o más dominios con determinadas funciones. Por eso cuando analizas secuencias de proteínas recursos como Pfam (incluída en Interpro) o CDD son muy útiles.

El crecimiento de las colecciones de secuencias es tan rápido que a veces se definen dominios o familias de proteínas sin saber realmente qué función tienen. Sabemos que existen, porque sus secuencias están conservadas en los genomas de diferentes organismos y se pueden alinear, pero todavía no hay evidencias de en qué procesos bioquímicos participan. Son los llamados Domains of Unknown Function (DUF).

Hace unos unos años Carlos Cantalapiedra y yo descubrimos tránscritos en cebada y en Arabidopsis thaliana que contenían dominios DUF. Entre ellos está por ejemplo DUF3615, pero todavía no sabemos si son importantes o no:

https://www.frontiersin.org/files/Articles/238135/fpls-08-00184-HTML/image_m/fpls-08-00184-g005.jpg

Figura 1. Dominios de Pfam encontrados en tránscritos accesorios de Arabidopsis thaliana (izq) y cebada (der). Fuente: https://doi.org/10.3389/fpls.2017.00184

La continuación de esta historia la encontramos en un artículo muy reciente, donde los autores descubren una pareja de proteínas, una de ellas DUF1644, que tanto en arroz como maiz interaccionan entre ellas y, al hacerlo, afectan al número de granos producidos, un caracter de enorme interés en la agricultura:

Figura 2. Interacción entre KRN2 y DUF1644 confirmada en ensayos Y1H (A) y ensayos de complementación con luciferasa en hojas de tabaco(B). Adaptada de https://doi.org/10.1126/science.abg7985

 

Queda claro que los dominios DUF son una fuente interesante por explorar. Lo lógico sería que con el tiempo se vayan convirtiendo en familias de función conocida, pero la verdad es que este ejemplo tampoco nos dice mucho de la  función de DUF1644, solamente que interacciona con otras proteínas.

Hasta pronto,

Bruno

24 de enero de 2022

nuevo modo paralelo en BLAST+ 2.12.0

Hola,

BLAST+ es una de las pocas herramientas esenciales para cualquier persona que haga biología computacional, todos la hemos usado alguna vez. Simplificando, creo que el secreto es que hace una sola cosa (alinear localmente secuencias) y la hace bien. Eso, y que BLAST evoluciona, y de vez en cuando introduce novedades interesantes, que podemos repasar en las notas de publicación periódicas disponibles en https://www.ncbi.nlm.nih.gov/books/NBK131777

La versión 2.12.0 (28 de junio de 2021) incluye un nuevo modo de paralelización por lotes de secuencias input que beneficia entre otros a los algoritmos clásicos BLASTN, BLASTP y BLASTX. Los detalles puedes verlos en  https://www.ncbi.nlm.nih.gov/books/NBK571452 , aquí comparto un ejemplo de invocación, que requiere el argumento -mt_mode 1:

 
$ blastp –db swissprot -query BIGFASTA.fsa –out test.out -num_threads 32 -mt_mode 1


La siguiente figura muestra la ganancia en tiempo de cálculo en función del número de cores y hebras empleado:

Image ckbk_ThreadByQuery-Image001.jpg


Espero que os sea útil, hasta pronto,

Bruno

23 de julio de 2021

Alphafold2: estructuras de proteínas para todos los públicos

Hola,

el jueves pasado escribía aquí sobre RoseTTAFold, que ponía al alcance de los programadores una potente herramienta para predecir la estructura de cualquier proteína que tenga suficientes secuencias parecidas en los archivos. Unas horas más tarde me enteré de que su principal competidor, AlphaFold2, del que hemos escrito aquí, aquí y aquí , había hecho también sus deberes y publicaba sus modelos neuronales para predecir el plegamiento de secuencias de aminoácidos. Hay muchos hilos en Twitter, como éstos: 1 y 2 .

En un artículo en Nature repasan sus resultados en CASP14, como su notable precisión de 1.5 Å de RMSD para todos los átomos modelados, y muestran que esos resultados excelentes se sostienen en gran medida en un conjunto de 3144 estructuras recientemente publicadas en el Protein Data Bank tras descartar las estructuras conocidas con % identidad de secuencia > 40. El siguiente vídeo resume el proceso de predicción de una secuencia con múltiples dominios y 863 aminoácidos. Recuerdo que la única información de partida es la secuencia de aminoácidos y un alineamiento múltiple de esa secuencia con otras secuencias no redundantes de proteínas homólogas:

 

Fuente: https://www.nature.com/articles/s41586-021-03819-2

Alphafold2 no es perfecto, ya que en la validación contra el PDB hay un en torno a un 25% de predicciones con valores de RMSD elevados, pero en la mayor parte de los casos es excelente:

Una de las fortalezas del método es que es capaz de estimar bien la calidad los modelos que genera (ver Figura 2b de https://www.nature.com/articles/s41586-021-03828-1). Entre las limitaciones reseñadas por los autores del trabajo, destacan:

1) La calidad de las predicciones cae de manera significativa si el alineamiento múltiple de secuencias homólogas a la de interés tiene una profundidad < 30 (leer más aquí). 

2) Las estructuas de Alphafold son de menor calidad para dominios poco compactos, con pocos contactos, como los dominios puente. Esto contrasta con las buenas prestaciones observadas (3) para predecir estructuras cuaternarias de homómeros.

Para los que queráis probarlo hay varias opciones:

i) El contenedor Docker descrito en https://github.com/deepmind/alphafold que ojo, requiere 2.2TB de espacio si instalas todas las bases de datos. 

ii) Un cuaderno Colab con un predictor simplificado en https://colab.research.google.com/github/deepmind/alphafold/blob/main/notebooks/AlphaFold.ipynb

iii) Las predicciones ya disponibles en UniProt para un total de 21 especies (https://alphafold.ebi.ac.uk/download), incluyendo 4 plantas (Arabidopsis thaliana, soja, arroz y maíz). Puedes leer más en 4, 5 y 6 y 7.

Hasta pronto,

Bruno

12 de septiembre de 2020

Alineamiento global con el algoritmo Wavefront (WFA)

Hola, en esta entrada vuelvo a una de las piedras angulares de la biología computacional, el alineamiento de secuencias. Este problema tiene múltiples caras, algunas ya discutidas en este blog, pero desde el algoritmo de Needleman-Wunsch su formulación fundamental es el alineamiento global de dos secuencias q y t de longitudes n y m, desde el principio hasta el final. 

La última vuelta de tuerca la acaban de publicar Santiago Marco Sola y colaboradores en Bioinformatics, donde describen su algoritmo de alineamiento llamado wavefront (WFA). En el artículo los autores muestran como WFA y su variante heurística WFA-Adapt son más eficientes tanto en tiempo de cálculo como en consumo de memoria que las alternativas del estado del arte, incluyendo los algoritmos de la librería KSW2, empleada por  minimap2 (visto en este blog).

Recomiendo la lectura del artículo porque es muy didáctico y está escrito en un estilo sencillo, dada la naturaleza del problema. A continuación resumo aquí las ideas principales. 

El problema que resuelve WFA es un alineamiento global entre dos secuencias usando el modelo affine-gap como función coste. Esto significa que para cada par de posiciones alineadas el coste del alineamiento aumenta en 0 puntos en caso de ser idénticas (a), en x puntos en caso de ser diferentes (x=6 en BWA-MEM) o con un coste lineal para las inserciones que se calcula como g(n) = o + e n  donde o es el coste de abrir un indel y e el de extenderlo n bases. WFA es un algoritmo exacto que calcula el alineamiento óptimo como aquel que termina en la celda (n,m) de la matriz de programación dinámica (Figura 1, izquierda) con un coste total más pequeño. Hasta aquí nada nuevo, es un algoritmo que busca diagonales que alinean las dos secuencias.

La novedad de WFA es que define furthest-reaching points (fr), vectores  Fs,k que indican para una diagonal k el punto más lejano donde se alcanza un coste s (ver Figura 1 izquierda, vectores M0, M4 y M8 desde el origen, donde M=matches, de la misms manera que I=indel y D=deletion). En su algoritmo reformulan el alineamiento por programación dinámica calculando vectores fr para un coste s en base a los vectores fr calculados para costes menores, pero de manera que sólo una fracción de los fr se llegan a calcular. El algoritmo descrito en la Figura 2 recibe su nombre porque para cada coste s se define el frente de onda WFs como el conjunto de todos los vectores fr con coste total s. El alineamiento optimo se corresponde a la secuencia de frentes de onda desde WF0 a WFs que alcanzan la coordenada (n, m) con el menor coste s. En el ejemplo de la Figura 1 solamente es necesario guardar en memoria 3 WF (0, 4 y 8) para calcular el alineamiento óptimo y luego reconstruirlo. A diferencia de otros algoritmos de alineamiento, WFA es más eficiente cuánto más se parecen las secuencias a alinear y sus operaciones son fácilmente paralelizables de manera portable con instrucciones SIMD.

 
Figura 1. Alineamiento global de dos secuencias en una matriz de programación dinámica (izq) y su representación en forma de vectores fr (furthest-reaching points, dcha). En la matriz las celdas (0,0) y (6,6) marcan respectivamente el principio y el final del alineamiento. Tomada de Bioinformatics


Figura 2. Pseudocódigo para el algoritmo WFA, tomado de Bioinformatics.

Para terminar esta entrada, el código de WFA está escrito en C y se compila fácilmente con gcc si lo clonas desde el repositorio https://github.com/smarco/WFA . Allí encontrarás ejemplos sencillos de cómo llamar a las funciones de alineamiento, un saludo,

Bruno

 

17 de abril de 2020

sobre el origen sospechoso de SARS-CoV-2

Buenas,
interrumpiendo la serie de entradas sobre redes neuronales no he podido resistirme a pegar aquí esta historia, en inglés, sobre el origen del virus SARS-CoV-2, o nCOV2019 en este artículo: http://virological.org/t/tackling-rumors-of-a-suspicious-origin-of-ncov2019/384

El tema es oportuno para este blog, porque la principal figura es un alineamiento pareado al estilo de BLASTN donde se observan hasta 19 mutaciones, todas en las terceras posiciones de sus codones:





En el artículo original usan datos de gripe para datar esta serie de mutaciones, y les salen 1950 años,

hasta pronto,
Bruno

9 de septiembre de 2019

modelos de proteínas a partir de alineamientos múltiples

Hola,
desde hace unos meses he estado hablando aquí (1, 2, 3) de los nuevos métodos de predicción de estructura de proteínas basados en estimar distancias entre resíduos a partir de los alineamientos múltiples de sus secuencias (MSA). Hoy traigo aquí uno de esos métodos, que a diferencia de alphaFold, podéis probar en vuestro propio ordenador: DMPfold. Este algoritmo es producto del grupo de David T. Jones, bien conocido por herramientas muy populares como PSIPRED y usa la información evolutiva capturada en un MSA para calcular distancias entre C-betas, puentes de hidrógeno del esqueleto peptídico y ángulos diedros (leer aquí y aquí).


Diagrama de flujo de DMPfold, tomado de https://www.nature.com/articles/s41467-019-11994-0


La lista de dependencia es larga, como explican en su repositorio https://github.com/psipred/DMPfold, pero os permitirá modelar vuestras propias secuencias, incluso proteínas de membrana, y tener el control sobre el proceso,
hasta pronto,
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

10 de agosto de 2018

minimap2 vs BLASTN

Hola,
recientemente Heng Li publicó un trabajo (https://doi.org/10.1093/bioinformatics/bty191) describiendo un nuevo alineador genérico de nucleótidos que se llama minimap2, que podéis descargar en https://github.com/lh3/minimap2.

Figura tomada de https://doi.org/10.1093/bioinformatics/bty191

En el artículo se compara minimap2 en diferentes escenarios contra otros softwares alternativos, incluyendo su antecesor BWA mem y se destaca su velocidad y su versatilidad, ya que es capaz de alinear lecturas cortas, secuencias largas e incluso también puede alinear saltando intrones.

Yo lo que he hecho ha sido una prueba rápida para compararlo con BLASTN en el escenario habitual de GET_HOMOLOGUES-EST, donde se comparan por ejemplo todos los genes de una planta (Brachypodium distachyon) contra todos los genes de otra especie cercana (Oryza sativa). Esto es lo que he hecho:

# how many sequences
$ grep -c "^>" *fna
Bdistachyon.fna:36647
Osativa.fna:42189

# index and BLASTN search
$ ncbi-blast-2.6.0+/bin/makeblastdb -in Osativa.fna -dbtype nucl
$ ncbi-blast-2.6.0+/bin/blastn -query Bdistachyon.fna -db Osativa.fna \
   -out Bdistachyon.Osativa.blastn.tsv -dbsize 100000000 -evalue 1e-5 -outfmt 6
real	0m40.937s
user	0m40.280s
sys	0m0.636s

# index [assuming up 80% sequence identity] and minimap2 search
$ minimap2/minimap2 -x asm20 -d Oryza.mmi Osativa.fna
$ time minimap2/minimap2 Oryza.mmi Bdistachyon.fna > Bdistachyon.Osativa.minimap.paf
real	0m2.084s
user	0m3.360s
sys	0m0.300s

Ahora echemos un ojo a los alineamientos resultantes. Selecciono un par de secuencias, primero de BLASTN:

BdiBd21-3.2G0760100.1   LOC_Os01g70090.1        87.839  847     95      5       31      876     37      876     0.0     987
BdiBd21-3.2G0521100.1   LOC_Os01g37510.1        85.652  683     92      3       91      773     103     779     0.0     713

y ahora de minimap2, en formato PAF:

BdiBd21-3.2G0760100.1	876	155	776	+	LOC_Os01g70090.1	876	161	776	181	621	60	tp:A:P	cm:i:16	s
1:i:179	s2:i:0	dv:f:0.0980
BdiBd21-3.2G0521100.1	777	110	653	+	LOC_Os01g37510.1	783	122	659	87	543	60	tp:A:P	cm:i:10	s
1:i:85	s2:i:0	dv:f:0.1196

Al maneo para estos dos ejemplos podemos observar que:
i) el mejor hit de BLASTN y minimap coinciden
ii) los alineamiento de BLASTN son más largos


Hasta pronto, buenas vacaciones,
Bruno

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.








24 de marzo de 2017

Apuntes sobre ensamblaje de genomas de plantas

Buenas, ayer asistimos Ernesto Igartua y yo al 6th CNAG Symposium on Genome Research: Agrigenomics, organizado por el Centro Nacional de Análisis Genómico en Barcelona, donde a menudo contratamos servicios de secuenciación.


Allí presentamos nuestro trabajo con cebada, junto a otros colegas que trabajan en ganadería, piscicultura y agricultura y utilizan herramientas de la genómica contemporánea.

Como curiosidades me apunté que André Eggen, de Illumina, mencionó que comparando razas bovinas habían imputado SNPs mezclando genotipos de baja densidad (chips de ~10K SNPs), con genomas completos, alcanzando millones de SNPs. Por cierto, habían usado el software propietario DeNovoMAGIC para ensamblar genomas bovinos.

Otra cosa fue que los peces que estudian Franscesc Piferrer y su grupo tienen un mecanismo de metilación en función de la temperatura para controlar la producción de hormonas sexuales, algo que me recordó mucho a la memoria de vernalización en las plantas.

Pero además de estas charlas, y de visitar las salas de secuenciación y de servidores del CNAG, tuvimos dos sesiones casi seguidas donde repasamos los últimos métodos de ensamblaje y validación de genomas de plantas de la mano de Tyler Alioto y Gareth Linsmith. Éstas son mis notas:

Detección de contaminantes en las lecturas/reads
kraken : https://ccb.jhu.edu/software/kraken

Ensamblajes híbridos y diploides, combinando lecturas cortas y largas y estrategias más complejas para genomas de individuos heterocigotos.
  • reads cortos, generalmente Illumina, de entre 100 y 300b, para alcanzar profunidades de al menos 30X en cada tipo de librería: 
    • paired-end (PE) con insertos de por ejemplo 400 y 730pb 
    • mate-pair (MP) con insertos de 4 y 8Kb para superar la longitud de la mayoría de secuencias repetidas
  • reads largos, generalmente PacBio o de Oxford Nanopore. EN CNAG usan secuenciadores minIon para producir lecturas de 11.5Kb de media, alcanzando longitudes máximas > 100kb. Gareth comentó que en manzano necesitaron 60x, y eso que era material doble haploide. Este tipo de reads requieren consensos calculados con software como Sparc, Racon o Nanopolish.
En cuanto a ensambladores, Tyler destacó DISCOVAR de novo y Platanus, más adecuado para individuos con moderadas tasas de sitios heterocigotos. Pero advirtió del efecto negativo que tiene la heterocigosis sobre N50. En cambio, Gareth mencionó que primero ensambla las lecturas cortas con SOAPdenovo sin resolver las burbujas de Bruijn para luego luego combinar los reads largos con DBG2OLC y CANU.

Estrategias complementarias de ensamblaje
Datos de RNAseq para scaffolding con AGOUTI y Rascaf.

Pools de fósmidos como los empleados en el genoma de la ostra.
Mapas ópticos con enzimas nickasas que cortan cada 10Kb, con Bionano.
Dovetail genomics, aproximación basada en Hi-C.

Herramientas para corregir y finalizar genomas
PILON : https://github.com/broadinstitute/pilon/wiki
BESST : https://github.com/ksahlin/BESST

Estrategias para evaluar y validar genomas
Aparte del criterio clásico de sintenia respecto a especies cercanas, ambos mencionaron los problemas de evaluar un ensamblaje solamente por su N50 sin mirar por ejemplo los genes core anotados, por ejemplo con BUSCO, el sucesor de CEGMA. Gareth mencionó ALE para calcular la verosimilitud de un ensamblaje dadas las librerías de secuencias y KAT para comparar los k-meros originales de los reads con los del ensamblaje, que deberían coincidir, o para determinar la fracción de sitios heterocigotos:

Frecuencias de k-meros de los genotipos B73 y Mo17 de maíz, tomada de http://www.nature.com/articles/srep42444.

Casi se me olvida mencionar la comparación entre el mapa físico y el genético como criterio de calidad, muy útil en el genoma de manzano o en el de la cebada:

Comparación entre las posiciones de marcadores en una población de mapeo en cebada y sus posiciones en los mapas físico IBSC y POPSEQ de cebada, tomada de http://link.springer.com/article/10.1007%2Fs11032-015-0253-1.


Hasta  pronto,
Bruno















17 de junio de 2016

pseudoalineamientos y conteos de tránscritos

Hola,
durante el análisis de unos experimentos de RNAseq mi colega Carlos Cantalapiedra y yo nos desesperábamos al calcular los valores de expresión de cada transcrito en una serie de condiciones, dado que para cada una de ellas era necesario alinear las lecturas/reads originales (en formato FASTQ) contra los transcritos ensamblados. Al menos éste era el protocolo habitual antes de aparecer el algoritmo genérico de pseudoalineamiento, que se describe en la siguiente figura:
Pseudoalineamiento de reads a partir de su composición en k-meros (k=3 en el ejemplo) y un  vector de sufijos de un transcriptoma. Figura tomada de http://bioinformatics.oxfordjournals.org/content/32/12/i192.full.  

Este tipo de algoritmos, implementados en software como kalllisto o RapMap (éste último con licencia GPL), permiten estimar de manera muy eficiente y precisa con qué transcritos son compatibles las lecturas de un archivo FASTQ, es decir, a qué secuencias de un transcriptoma mapean, sin necesidad de alinear base a base los reads. Los alineamientos se pueden calcular, si fuera preciso, después del mapeo. 

Hasta la fecha se han propuesto al menos dos implementaciones del algoritmo genérico de pseudoalineamiento, que se diferencian fundamentalmente en las estructuras de datos utilizadas, como se explica en estos blogs (1 , 2) [en el segundo se hace un repaso a la evolución de este tipo de algoritmos y a su nomenclatura].

En los próximos párrafos muestro dos aplicaciones usando ejecutables de RapMap y como datos un fichero (tr.fna) con 67K transcritos de Arabidopsis thaliana, ensamblados de novo con trinity, y otro (1.f1) con 89M de lecturas Illumina SE en formato FASTQ.

1. Mapeo de reads (20 cores, fichero de salida SAM)


          operación   tiempo   comando      
BWAmem       índice    1m28s   bwa-0.7.12/bwa index tr.fna    
BWAmem        mapeo    9m57s   bwa-0.7.12/bwa mem -t 20 tr.fna 1.fq > 1.sam 
RapMap       índice      58s   RapMap-0.2.2/bin/rapmap quasiindex -t tr.fna -i ./ 
RapMap        mapeo    5m56s   RapMap-0.2.2/bin/rapmap quasimap -t 20 -i ./ -r 1.fq \
                                 -o 1.sam 

Por comparación con BWA queda claro que incluso generando alineamientos SAM estos algoritmos son mucho más rápidos. 


2. Conteo de transcritos (20 cores, implementación Sailfish)

          operación   tiempo   comando      
Sailfish     índice    1m06s   SailfishBeta-0.10.0/bin/sailfish index -t tr.fna -o qindex \
                                  -p 20   
Sailfish      mapeo    1m09s   SailfishBeta-0.10.0/bin/sailfish quant -i qindex/ -r 1.fq \
                                  -p 20 -o 1.bur-0.sf --auxDir tmpsf --dumpEq --libType SF
  
Como se muestra en la tabla, la estimación de valores de expresión de transcritos por pseudoalineamiento y conteo de reads es muy eficiente. En este ejemplo se genera un archivo de salida (quant.sf) con este contenido:

Name      Length EffectiveLength TPM NumReads
TR1|c0_g1_i1 517 316.623      5.3984 214.782
TR2|c0_g1_i1 390 191.501     3.36608     81
TR3|c0_g1_i1 699 498.611      10.502 658
...

Entre las opciones del program está la posibilidad de calcular los conteos con bootstraping, como hace kallisto, aunque en la versión que yo he probado es experimental.

En la siguiente entrada veremos más aplicaciones,
un saludo,
Bruno

29 de abril de 2016

clustal one-liner con parallel

Hola,
hoy comparto un comando que a veces utilizo cuando necesito calcular muchos alineamientos múltiples a partir de una colección de ficheros de secuencias en formato FASTA. Como mi máquina, igual que la de casi todos, tiene amplia RAM y muchos cores, es un trabajo ideal para parallel. Supongamos que los archivos de salida están en la carpeta 'entrada' y queremos guardar los ficheros de salida en la carpeta 'path/to/salida', y que tenemos 20 cores disponibles:

$ mkdir /path/to/salida/
$ cd entrada
$ ls -1 *fasta | parallel --gnu -j 20 ~/soft/clustal-omega-1.2.1/src/clustalo \
--threads=1 -i {} -o /path/to/salida/{} :::

Este comando pondrá a trabajar 20 cores del sistema hasta que todos los archivos FASTA de la carpeta entrada estén alineados, con ganancias de tiempo de ejecución importantes en un experimento con 100 ficheros:

| cores (-j) | time(real) | time(user) | time(sys) |
|   1        | 4m34.440s  | 4m5.180s   | 0m2.168s  |
|  10        | 0m29.358s  | 3m57.768s  | 0m2.400s  |
|  20        | 0m23.248s  | 5m6.204s   | 0m3.364s  |

Un saludo,
Bruno

13 de febrero de 2016

Expresión regular de la familia de las O-fucosiltransferasas



Hola, 
el pasado 8 de febrero se publicó en la revista Nature Chemical Biology  (http://dx.doi.org/10.1038/nchembio.2019) un artículo donde se  describen las bases moleculares de la reacción de O-fucosilación. Ésta es una modificación postraduccional poco frecuente, que realizan las enzimas O-fucosiltransferasas, como nos explica la investigadora de nuestro grupo Inmaculada Yruela, una de las autoras del trabajo [reseña completa en www.eead.csic.es]:

"Esta reacción resulta esencial en algunas rutas metabólicas de los organismos eucariotas, incluidas las plantas, para mantener las funciones básicas de las células. El artículo describe el mecanismo por el cual la enzima O-fucosiltransferasa 2 (POFUT2) reconoce sin errores una secuencia de aminoácidos (TSR) de la proteína receptora y le transfiere una molécula de azúcar tipo fucosa –así resulta fucosilada–. Hasta la fecha no se conocía cómo estas enzimas reconocen y se unen a sus sustratos proteicos. La O-fucosilación es esencial para el correcto plegamiento y estabilidad del dominio TSR y el reconocimiento molecular de POFUT2."
Como se ve en el alineamiento, el dominio TSR contiene tres puentes disulfuro y una secuencia consenso en torno a los dos primeras cisteínas CX{2,3}[S|T]CX{2}G , lo que se llama un motivo, como los del repositorio Prosite:
Fragmento de un alineamiento múltiple de dominios TSR, tomado de http://dx.doi.org/10.1038/nchembio.2019

Tras alinear algunas secuencias de ejemplo y perfeccionar la expresión regular, ésta se empleó para identificar todas las secuencias con dominios TSR en los proteomas de Homo sapiens y Caenorhabditis elegans. Más generalmente, el siguiente trozo de código permite localizar dentro de un fichero FASTA todas las secuencias reconocidas por una expresión regular:
 #!/usr/bin/perl  
 use strict;  
   
 # script that takes a FASTA file(s) and scans all protein sequences   
 # looking for matches of a chosen motif expressed as a regular expression  
 # 11042015: edited following comments by JF
   
 # constant as indices to access read_FASTA_file arrays  
 use constant NAME => 0;   
 use constant SEQ => 1;  
   
 #my $motifRE = '.*C[^C]{0,21}.C[^C]{2,6}[S|T].C[^C]{4,75}C[^C]C[^C]{4,15}C.*'; 
 my $motifRE = 'C[^C]{0,21}.C[^C]{2,6}[ST].C[^C]{4,75}C[^C]C[^C]{4,15}C';
   
 if(!@ARGV){ die "# usage: $0  ... \n"; }  
 else{ print "# motif: $motifRE\n"; }  
   
 my ($n_of_matches,@matches) = (0);  
 foreach my $infile (@ARGV)  
 {  
   next if($infile !~ /.fa/);  
   my (@FASTA,$start,$end,$l);  
   my $n_of_sequences = -1;  
   open(FASTA,"<$infile") || die "# cannot read $infile $!:\n";  
   while()  
   {  
    next if(/^$/);  
    if(/^\>(.*?)[\n\r]/)  
    {  
      $n_of_sequences++;   
      $FASTA[$n_of_sequences][NAME] = $1;  
    }                
    else  
    {  
      s/[-\s\n.]//g; #s/[\s|\n|\-|\.]//g;  
      $FASTA[$n_of_sequences][SEQ] .= $_;  
    }  
   }  
   close(FASTA);  
   
   foreach my $seq ( 0 .. $n_of_sequences )  
   {  
    while($FASTA[$seq][SEQ] =~ m/($motifRE)/gi)   
    {  
      #$start=length($`);  
      #$l=length($1);  
      #$end=$start+$l;  

      $start = $-[1];
      $end   = $+[1];
      $l     = $end - $start + 1;

      print ">$FASTA[$seq][NAME] match=($start,$end,$l)\n$1\n";           
    }  
   }  
 }  

Un saludo,
Inma y Bruno

6 de julio de 2015

Alineamiento de secuencias de proteína y filogenias

Hola,
como anunciábamos hace unas semanas, esta semana participamos en un curso de verano de la Universidad de Zaragoza que empieza hoy en la ciudad de Jaca, al pie mismo del Pirineo. Por esta razón hemos preparado un material sobre Alineamiento de secuencias de proteína y filogenias que hoy colgamos en la Red para que podáis consultarlo si a alguien le interesa:

http://eead.csic.es/compbio/material/alineafilog

y que también podés descargar en formato PDF en:

http://digital.csic.es/handle/10261/117608


El índice del curso es el siguiente:
  •  Análisis jerárquico de la estructura de proteínas
    • Estructura primaria
    • Estructura secundaria
    • Estructura terciaria y cuaternaria
      • Demarcación de dominios en proteínas

Un saludo,
hasta pronto,
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!!!!






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.