Hola,
para romper con mis últimas entradas, donde hablaba de código fuente, hoy quisiera discutir un tema recurrente cuando planeamos experimentos de secuenciación masiva.
Cuál es el problema? Pues que a menudo se nos ocurren experimentos pero no sabemos dónde podemos llevarlos a cabo, porque no tenemos en casa un HiSeq, ni cuánto nos costarán. El mapamundi NGS, del que hablaba Carlos P Cantalapiedra en 2011, y que ahora vive en http://omicsmaps.com, nos puede ayudar a buscar proveedores cercanos, lo cual puede ser importante para no mandar muestras difíciles de obtener y facilísimas de estropearse, a la otra punta del munco.
Sin embargo, otra cuestión es el precio y el plazo de entrega, y si ofrecen apoyo bioinformático básico. Nosotros mismos hemos tenido que tirar de teléfono y llamar a proveedores variopintos para tener unos cuantos presupuestos en la mano y decidirnos por el mejor. Hasta la fecha, dentro de España hemos contratado con el Parque Científico de Madrid y con el CNAG. Pero también hemos contactado con proveedores europeos y norteamericanos, y aquí es donde viene a cuento https://genohub.com, al que no quiero dar publicidad gratuita, pero es que es la única herramienta de este tipo que conozco, y que puede ahorrarnos mucho esfuerzo en la elaboración de presupuestos y la preparación de experimentos. Si conocéis otros recursos similares por favor ponedlos como comentarios,
un saludo,
Bruno
Ideas y código para problemas de genómica de plantas, biología computacional y estructural
30 de julio de 2013
17 de julio de 2013
C++ STL en paralelo
Hola,
como contábamos en una entrada anterior, últimamente hemos estado liados trabajando con archivos FASTQ de varios GBs, con decenas de millones de lecturas o reads. Para algunas de las tareas que hemos tenido que realizar, como ordenar o renombrar, nos hemos dado cuenta que lenguajes interpretados como Perl o Python son varias veces más lentos que caballos de carreras compilados como C/C++, como también comenta el autor de readfq, por ejemplo.
Por eso he estado refrescando la Standard Template Library (STL) de C++, que para alguien acostumbrado a programar en lenguajes de alto nivel es esencial, como recurso para crear estructuras de datos flexibles y eficientes en programas escritos en C/C++. Como dice Scott Meyers en su libro Effective STL, probablemente los contenedores más populares de la STL sonvectores y strings. Sólo por estas dos estructuras dinámicas, a las que yo añado también las tablas asociativas (maps), vale la pena aprender a usar la STL. Sin embargo, hay mucho más que esto, y por eso escribo esta entrada, porque la STL implementada en el compilador GNU gcc (libstdc++) incluye una biblioteca de algoritmos en paralelo de propósito general, que podemos usar fácilmente en nuestros programas para sacarle el jugo a los procesadores multicore y resolver de manera más eficiente múltiples problemas. Entre otros, la versión actual de libstdc++ paraleliza los siguientes algoritmos de la STL, todos ellos útiles para tareas habituales en programación:
El siguiente ejemplo de sort en paralelo, que depende de la librería OpenMP, se compila con $ g++ -O3 -fopenmp -o testP testP.cc para generar un ejecutable que empleará 4 cores para ordenar un millón de palabras de 25 caracteres de longitud:
Referencias más avanzadas:
[1] http://algo2.iti.kit.edu/singler/mcstl/parallelmode_se.pdf
[2] http://ls11-www.cs.uni-dortmund.de/people/gutweng/AD08/VO11_parallel_mode_overview.pdf
Hasta luego,
Bruno
como contábamos en una entrada anterior, últimamente hemos estado liados trabajando con archivos FASTQ de varios GBs, con decenas de millones de lecturas o reads. Para algunas de las tareas que hemos tenido que realizar, como ordenar o renombrar, nos hemos dado cuenta que lenguajes interpretados como Perl o Python son varias veces más lentos que caballos de carreras compilados como C/C++, como también comenta el autor de readfq, por ejemplo.
Por eso he estado refrescando la Standard Template Library (STL) de C++, que para alguien acostumbrado a programar en lenguajes de alto nivel es esencial, como recurso para crear estructuras de datos flexibles y eficientes en programas escritos en C/C++. Como dice Scott Meyers en su libro Effective STL, probablemente los contenedores más populares de la STL son
std::count
std::find
std::search
std::replace
std::max_element
std::merge
std::min_element
std::nth_element
std::set_union
std::set_intersection
std::sort
![]() | |
Esquema de sort parelelo y merge posterior, tomado de http://javaero.org/tag/parallel-merge-sort |
El siguiente ejemplo de sort en paralelo, que depende de la librería OpenMP, se compila con $ g++ -O3 -fopenmp -o testP testP.cc para generar un ejecutable que empleará 4 cores para ordenar un millón de palabras de 25 caracteres de longitud:
#include <stdlib.h>
#include <omp.h>
#include <vector>
#include <parallel/algorithm>
using namespace std;
// g++ -O3 -fopenmp -o testP testP.cc
// http://gcc.gnu.org/onlinedocs/libstdc++/manual/parallel_mode.html
#define MAXTHREADS 4;
string randomStrGen(int length)
{
//http://stackoverflow.com/questions/2146792/how-do-you-generate-random-strings-in-c
static string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890;:|.@";
string result;
result.resize(length);
for (int i = 0; i < length; i++) result[i] = charset[rand() % charset.length()];
return result;
}
int main()
{
unsigned threads = MAXTHREADS;
omp_set_dynamic(false);
omp_set_num_threads(threads);
srand(time(NULL));
std::vector<string> data(1000000);
for(int i=0;i<data.size();i++) data[i] = randomStrGen(25);
__gnu_parallel::sort(data.begin(), data.end()); //std::less<string>() , std::smaller<string>() );
printf("%s\n%s\n%s\n%s\n",data[0].c_str(),data[1].c_str(),data[2].c_str(),data[data.size()-1].c_str());
return 0;
}
Referencias más avanzadas:
[1] http://algo2.iti.kit.edu/singler/mcstl/parallelmode_se.pdf
[2] http://ls11-www.cs.uni-dortmund.de/people/gutweng/AD08/VO11_parallel_mode_overview.pdf
Hasta luego,
Bruno
29 de junio de 2013
Potenciando el entorno Python I: webapps con CherryPy
Buenas!
Todos necesitamos utilizar distintos lenguajes de programación y distintas sintaxis y convenciones para muy diversas tareas. A saber: bash scripting, sed, awk, C, Perl, Python, PHP, Java, XML, HTML, JavaScript, JSON, AJAX, etcetc
Yo soy partidario de tratar de evitar esto lo máximo posible. Así que últimamente estoy tratando de potenciar mi entorno de trabajo Python y moverme a otros lenguajes sólo cuando sea realmente necesario. He hecho algunas nuevas adquisiciones a mi repertorio últimamente, aunque todavía sin mucho dominio de ellas. A pesar de esto, los resultados me han parecido muy satisfactorios. Aquí voy a hablar de un Framework para aplicaciones web en Python, CherryPy (a minimalist python web framework).
Cuales son las claves para que me haya decidido por utilizar CherryPy:
- Python no incorpora las utilidades de aplicación web que vienen incluídas en, por ejemplo, PHP. En mi caso, especialmente, control de sesión HTTP.
- Necesitaba trabajar tras un servidor Apache y tanto el módulo CGI de Python, como el mod_python de Apache son desaconsejados.
- Una aplicación CherryPy es un servidor HTTP en sí mismo, por lo que puede trabajarse muy cómodamente sobre la aplicación sin necesidad de involucrar otros sistemas en un principio.
- Permite trabajar única y exclusivamente en Python. Incluso la configuración se puede realizar con diccionarios de Python y decorators, si se prefiere esto a tener ficheros de configuración externos. La petición HTTP (la request) y sus parámetros se manejan directamente desde métodos Python.
- Es una Framework ligera, que no se inmiscuye en creación de vistas, control de usuarios, etc. Si bien permite la creación y utilización de herramientas y plugins complementarios. Siempre me han atraido las pequeñas cosas modulares, por encima de las grandes aplicaciones todo en uno. Las primeras me sugieren versatilidad y claridad; las segundas dependencia.
Quizás la parte más complicada para tirarse a trabajar con CherryPy es la configuración. Aunque más que por su complejidad, es debido a la errática documentación existente y los ligeros cambios entre versiones de la framework que para un novicio pueden ser difíciles de atribuir a una u otra versión*. En mi caso, lo mejor ha sido obviar a menudo la documentación de la página principal y trabajar directamente con el libro CherryPy Essentials y apoyándome en la lista de usuarios de CherryPy.
Sin embargo, ya digo que no es muy complicado. Una vez uno se tira a escribir sobre la aplicación y va viendo que las cosas funcionan, en seguida se pasa a trabajar con la aplicación en Python y se olvida de lo que hay detrás. Eso hasta que ejecutamos la aplicación y voilá! Ya podemos hacer peticiones desde un navegador directamente a nuestros métodos Python. Pero ¿cómo se hace una aplicación con CherryPy?
Lo primero es descargar e instalar CherryPy, para lo cual hay información detallada y fácil de llevar a cabo en la documentación oficial.
Lo segundo es crear nuestro fichero principal de Python que hará las veces de servidor. En mi caso "server.py".
A éste fichero le añadimos el import de cherrypy:
import cherrypy
Luego hacemos el diseño de las clases y métodos que serán dianas de las distintas URLs. Por ejemplo, para:
http://mysite/myapp/exec
con un parámetro "myparam" que viene por ejemplo de un submit en HTML o en un GET:
class NameOfMyClass(Base):
@cherrypy.expose
def exec(self, myparam):
# tratar los datos de la request, por ejemplo añadirlos a sesión
cherrypy.session['param_01'] = myparam
# realizar operaciones
result = mymodel.mymethod(myparam)
# devolver una respuesta, por ejemplo en formato HTML
return html_generator(result)
Especialmente fijarse en que el decorator (@cherrypy.expose) hace al método exec visible para el mapeador de URLs, es decir, para el cliente HTTP en definitiva.
El nombre de la clase no tiene que coincidir con el de la aplicación en éste caso, precisamente por ser la clase de la aplicación, cuyo mapeo desde URL definiremos a continuación:
Faltaría añadir aquí el contenido de las variables "conf" y "app_conf". En ambos casos pueden ser rutas a ficheros de configuración o diccionarios de Python. Sobre la configuración mejor consultar aquí o el libro que ya hemos comentado. Pero un ejemplo con diccionarios podría ser:
conf = {
'global': {
'server.socket_host': '127.0.0.1',
'server.socket_port': 9091,
},
}
app_conf = {
'/style.css': {
'tools.staticfile.on': True,
'tools.staticfile.filename': os.path.join(_curdir,
'/mydeploydir/css/style.css'),
}
}
Y con esto sería suficiente. Ejecutamos:
python server.py
Y ya deberíamos poder hacer peticiones desde un navegador a:
http://127.0.0.1:9091/myapp/exec?myparam=eead
Por último, tocaba desplegar la aplicación tras el servidor Apache, de forma que este siguiera sirviendo otras aplicaciones (escritas en PHP, Perl, etc.) y CherryPy sirviera mi aplicación Python. Hay muchos ejemplos sobre como desplegar CherryPy tras Apache en el libro, y también en algunas páginas en caché de Google ;) pero para un profano de Apache no quedaba claro cuál de ellas era mejor para que ambos sirvieran páginas, ni cómo modificar los ejemplos para ello. Finalmente, para el esquema que muestro a continuación, añadiendo 2 líneas a la configuración de Apache fue suficiente.
ProxyPass /myapp http://127.0.0.1:9091/myapp/
ProxyPassReverse /myapp http://127.0.0.1:9091/myapp/
Esto es, un proxy reverso para la aplicación creada en CherryPy con script_name en el método cherrypy.tree.mount a "/myapp".
Y esto es todo lo que quería contar sobre CherryPy y servir aplicaciones web escritas en Python. Pythonic uh? :)
Todos necesitamos utilizar distintos lenguajes de programación y distintas sintaxis y convenciones para muy diversas tareas. A saber: bash scripting, sed, awk, C, Perl, Python, PHP, Java, XML, HTML, JavaScript, JSON, AJAX, etcetc
Yo soy partidario de tratar de evitar esto lo máximo posible. Así que últimamente estoy tratando de potenciar mi entorno de trabajo Python y moverme a otros lenguajes sólo cuando sea realmente necesario. He hecho algunas nuevas adquisiciones a mi repertorio últimamente, aunque todavía sin mucho dominio de ellas. A pesar de esto, los resultados me han parecido muy satisfactorios. Aquí voy a hablar de un Framework para aplicaciones web en Python, CherryPy (a minimalist python web framework).
Cuales son las claves para que me haya decidido por utilizar CherryPy:
- Python no incorpora las utilidades de aplicación web que vienen incluídas en, por ejemplo, PHP. En mi caso, especialmente, control de sesión HTTP.
- Necesitaba trabajar tras un servidor Apache y tanto el módulo CGI de Python, como el mod_python de Apache son desaconsejados.
- Una aplicación CherryPy es un servidor HTTP en sí mismo, por lo que puede trabajarse muy cómodamente sobre la aplicación sin necesidad de involucrar otros sistemas en un principio.
- Permite trabajar única y exclusivamente en Python. Incluso la configuración se puede realizar con diccionarios de Python y decorators, si se prefiere esto a tener ficheros de configuración externos. La petición HTTP (la request) y sus parámetros se manejan directamente desde métodos Python.
- Es una Framework ligera, que no se inmiscuye en creación de vistas, control de usuarios, etc. Si bien permite la creación y utilización de herramientas y plugins complementarios. Siempre me han atraido las pequeñas cosas modulares, por encima de las grandes aplicaciones todo en uno. Las primeras me sugieren versatilidad y claridad; las segundas dependencia.
Quizás la parte más complicada para tirarse a trabajar con CherryPy es la configuración. Aunque más que por su complejidad, es debido a la errática documentación existente y los ligeros cambios entre versiones de la framework que para un novicio pueden ser difíciles de atribuir a una u otra versión*. En mi caso, lo mejor ha sido obviar a menudo la documentación de la página principal y trabajar directamente con el libro CherryPy Essentials y apoyándome en la lista de usuarios de CherryPy.
Sin embargo, ya digo que no es muy complicado. Una vez uno se tira a escribir sobre la aplicación y va viendo que las cosas funcionan, en seguida se pasa a trabajar con la aplicación en Python y se olvida de lo que hay detrás. Eso hasta que ejecutamos la aplicación y voilá! Ya podemos hacer peticiones desde un navegador directamente a nuestros métodos Python. Pero ¿cómo se hace una aplicación con CherryPy?
Lo primero es descargar e instalar CherryPy, para lo cual hay información detallada y fácil de llevar a cabo en la documentación oficial.
Lo segundo es crear nuestro fichero principal de Python que hará las veces de servidor. En mi caso "server.py".
A éste fichero le añadimos el import de cherrypy:
import cherrypy
Luego hacemos el diseño de las clases y métodos que serán dianas de las distintas URLs. Por ejemplo, para:
http://mysite/myapp/exec
con un parámetro "myparam" que viene por ejemplo de un submit en HTML o en un GET:
class NameOfMyClass(Base):
@cherrypy.expose
def exec(self, myparam):
# tratar los datos de la request, por ejemplo añadirlos a sesión
cherrypy.session['param_01'] = myparam
# realizar operaciones
result = mymodel.mymethod(myparam)
# devolver una respuesta, por ejemplo en formato HTML
return html_generator(result)
Especialmente fijarse en que el decorator (@cherrypy.expose) hace al método exec visible para el mapeador de URLs, es decir, para el cliente HTTP en definitiva.
El nombre de la clase no tiene que coincidir con el de la aplicación en éste caso, precisamente por ser la clase de la aplicación, cuyo mapeo desde URL definiremos a continuación:
cherrypy.config.update(conf)
cherrypy.tree.mount(NameOfMyClass(), script_name='/myapp', app_conf)
cherrypy.engine.start()
cherrypy.engine.block()
Faltaría añadir aquí el contenido de las variables "conf" y "app_conf". En ambos casos pueden ser rutas a ficheros de configuración o diccionarios de Python. Sobre la configuración mejor consultar aquí o el libro que ya hemos comentado. Pero un ejemplo con diccionarios podría ser:
conf = {
'global': {
'server.socket_host': '127.0.0.1',
'server.socket_port': 9091,
},
}
app_conf = {
'/style.css': {
'tools.staticfile.on': True,
'tools.staticfile.filename': os.path.join(_curdir,
'/mydeploydir/css/style.css'),
}
}
Y con esto sería suficiente. Ejecutamos:
python server.py
Y ya deberíamos poder hacer peticiones desde un navegador a:
http://127.0.0.1:9091/myapp/exec?myparam=eead
Por último, tocaba desplegar la aplicación tras el servidor Apache, de forma que este siguiera sirviendo otras aplicaciones (escritas en PHP, Perl, etc.) y CherryPy sirviera mi aplicación Python. Hay muchos ejemplos sobre como desplegar CherryPy tras Apache en el libro, y también en algunas páginas en caché de Google ;) pero para un profano de Apache no quedaba claro cuál de ellas era mejor para que ambos sirvieran páginas, ni cómo modificar los ejemplos para ello. Finalmente, para el esquema que muestro a continuación, añadiendo 2 líneas a la configuración de Apache fue suficiente.
ProxyPass /myapp http://127.0.0.1:9091/myapp/
ProxyPassReverse /myapp http://127.0.0.1:9091/myapp/
Esto es, un proxy reverso para la aplicación creada en CherryPy con script_name en el método cherrypy.tree.mount a "/myapp".
Y esto es todo lo que quería contar sobre CherryPy y servir aplicaciones web escritas en Python. Pythonic uh? :)
13 de junio de 2013
oferta de empleo en Bioinformática
Puesto de Postdoc en laboratorio de Genética de Plantas del CRAG. Se trata del grupo de genómica de melón del Dr. Jordi García-Mas:
Funciones: análisis bioinformático de datos de secuenciación de RNA de melón, en el marco de un proyecto PLANT-KBBE (SAFQIM: Sugar and Fruit Quality in Melon). Además, participará en la mejora de una base de datos de genómica de melón.
· Requisitos: PhD en Biología o similar. Gran experiencia en bioinformática y Linux.
· Se ofrece: contrato de 6 meses, renovable por 6 meses más. 37’5h semanales.
· Inscripción: CRAG, Ref 18/2013 (antes del 30 de junio de 2013)
Funciones: análisis bioinformático de datos de secuenciación de RNA de melón, en el marco de un proyecto PLANT-KBBE (SAFQIM: Sugar and Fruit Quality in Melon). Además, participará en la mejora de una base de datos de genómica de melón.
· Requisitos: PhD en Biología o similar. Gran experiencia en bioinformática y Linux.
· Se ofrece: contrato de 6 meses, renovable por 6 meses más. 37’5h semanales.
· Inscripción: CRAG, Ref 18/2013 (antes del 30 de junio de 2013)
5 de junio de 2013
FASTQ sort + parallel
Buenas,
recientemente en el laboratorio hemos estado manipulando archivos de pares de secuencias (pair-end reads) en formato FASTQ. Una de las tareas habituales ha sido limpiar los archivos de secuencias de baja calidad, ya sea recortando o eliminando directamente, para luego volver a definir parejas entre las secuencias que superaron el corte. Una estrategia posible para esta tarea es simplemente linearizar las secuencias, de manera que cada una ocupe ahora una sola línea, separando con tabuladores la cabecera, la secuencia, el separador y las calidades. Por ejemplo, la siguiente secuencia:
Tras esta transformación ya sí es posible ordenar un archivo FASTQ con GNU sort, que viene instalado en cualquier sistema linux (y se puede instalar en Windows). GNU sort es ideal para ordenar conjuntos de datos que no caben en memoria (M), como a menudo ocurre con los archivos FASTQ, porque de manera implícita divide el problema inicial, de tamaño N, en N/M trozos que luego mezcla (merge) de manera externa.
En nuestra experiencia GNU sort es significativemente más eficiente que nuestros scripts para este tipo de problemas, puesto que ya trae de fábrica toda la lógica para partir el problema en trozos y luego mezclar las soluciones parciales. Sólo hay que tener cuidado de asignar la variable de ambiente LC_ALL, por ejemplo con:
recientemente en el laboratorio hemos estado manipulando archivos de pares de secuencias (pair-end reads) en formato FASTQ. Una de las tareas habituales ha sido limpiar los archivos de secuencias de baja calidad, ya sea recortando o eliminando directamente, para luego volver a definir parejas entre las secuencias que superaron el corte. Una estrategia posible para esta tarea es simplemente linearizar las secuencias, de manera que cada una ocupe ahora una sola línea, separando con tabuladores la cabecera, la secuencia, el separador y las calidades. Por ejemplo, la siguiente secuencia:
@SEQ_ID GATTTGGGGTTCAAAGCAGTA... + !''*((((***+))%%%++)(...
quedaría así:
@SEQ_ID GATTTGGGGTTCAAAGCAGTA... + !''*((((***+))%%%++)(...
Tras esta transformación ya sí es posible ordenar un archivo FASTQ con GNU sort, que viene instalado en cualquier sistema linux (y se puede instalar en Windows). GNU sort es ideal para ordenar conjuntos de datos que no caben en memoria (M), como a menudo ocurre con los archivos FASTQ, porque de manera implícita divide el problema inicial, de tamaño N, en N/M trozos que luego mezcla (merge) de manera externa.
En nuestra experiencia GNU sort es significativemente más eficiente que nuestros scripts para este tipo de problemas, puesto que ya trae de fábrica toda la lógica para partir el problema en trozos y luego mezclar las soluciones parciales. Sólo hay que tener cuidado de asignar la variable de ambiente LC_ALL, por ejemplo con:
$ export LC_ALL=POSIX
y echar a andar. Muy bien. Pero te quedas con la duda de si estás sacando el máximo partido a tu CPU multicore, podremos optimizar sort en paralelo? Y si invocamos a GNU parallel (mira el vídeo)?
Nos ponemos manos a la obra y hacemos pruebas con un archivo FASTQ linearizado real, de 576Mb:
Nos ponemos manos a la obra y hacemos pruebas con un archivo FASTQ linearizado real, de 576Mb:
$ ls -lh /tmp/unsortedXXpJ6CaB -rw-------. 1 576M Jun 5 10:15 /tmp/unsortedXXpJ6CaB
Ahora lo ordenamos con GNU sort, dándole un máximo de 500Mb de área en RAM para trabajar (la M de antes):
$ time sort -k 1,1 -u -S 500M /tmp/unsortedXXpJ6CaB > /tmp/unsortedXXpJ6CaB.S real 0m7.628s user 0m5.143s sys 0m2.373s
Finalmente probamos ahora con parallel, agrupando las secuencias en grupos de 100.000 elementos (ojo con esto, puedes llegar a obtener resultados parcialmente desordenados porque la segunda llamada a parallel puede recibir más argumentos de los que el shell soporta). Cambiando este valor a 10000 o a 10E6 los resultados son similares:
$ time cat /tmp/unsortedXXpJ6CaB | parallel -N 100000 --pipe --files sort -k 1,1 |
parallel -Xj1 sort -k 1,1 -u -m {} ';' rm {} > /tmp/unsortedXXpJ6CaB.P real 0m15.451s user 0m9.919s sys 0m8.371s
Comprobamos que los resultados son idénticos:
$ diff /tmp/unsortedXXpJ6CaB.S /tmp/unsortedXXpJ6CaB.P
Conclusión de estas pruebas: no vale la pena complicarse con parallel para ordenar grandes archivos FASTQ, ya que probablemente el cuello de botella sea el merge final, y eso parece resolverlo mejor directamente GNU sort. De todos modos es posible que haya otras maneras de invocar a parallel más ventajosas
Si en vuestras pruebas obtenéis resultados distintos por favor escribid,
Si en vuestras pruebas obtenéis resultados distintos por favor escribid,
un saludo,
Bruno
Suscribirse a:
Entradas (Atom)