Ejemplos
Ejemplo: Descarga de secuencias de GenBank
Antes de ejecutar análisis más complejos, veremos tres formas de descargar secuencias de GenBank con Entrez Direct, Apptainer y Slurm.
Los tres ejemplos realizan prácticamente la misma tarea, pero muestran distintas formas de organizar el trabajo:
| Ejemplo | ¿Qué hace? | Ejecución |
|---|---|---|
| Una accesión | Descarga una secuencia | Un trabajo de Slurm |
Bucle while |
Recorre una lista de accesiones | Un trabajo; las descargas se realizan una tras otra |
| Array de Slurm | Asigna una accesión a cada tarea | Varias tareas pueden ejecutarse simultáneamente |
while no paraleliza
El bucle permite automatizar el procesamiento de varias muestras, pero las procesa secuencialmente dentro de un solo trabajo. El array es el ejemplo que realmente permite procesar varias accesiones al mismo tiempo.
Preparar la práctica
Crea una carpeta con subdirectorios para el contenedor, los scripts, los registros y las secuencias descargadas:
mkdir -p efetch_test/{sif,scripts,logs,fasta}
cd efetch_testLa carpeta logs/ debe existir antes de ejecutar sbatch. Slurm abre los archivos de salida y error antes de comenzar el script.
Descargar el contenedor
Para esta práctica utilizaremos la imagen de Entrez Direct disponible en BioContainers:
apptainer pull \
sif/entrez-direct_25.3.sif \
docker://quay.io/biocontainers/entrez-direct:25.3--he881be0_0Comprueba que efetch está disponible dentro del contenedor:
apptainer exec sif/entrez-direct_25.3.sif efetch -helpDescargar la imagen una sola vez evita que cada trabajo o cada tarea del array tenga que consultar nuevamente el registro de contenedores.
Ejemplo 1: descargar una secuencia
Este primer script descarga una sola secuencia de la base de datos nuccore de NCBI en formato FASTA.
Crea el archivo:
nano scripts/efetch_single.sbatchContenido:
#!/bin/bash
#SBATCH --job-name=efetch_single
#SBATCH --partition=ib
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=1
#SBATCH --mem=1G
#SBATCH --time=00:10:00
#SBATCH --output=logs/%x-%j.out
#SBATCH --error=logs/%x-%j.err
set -euo pipefail
cd "$SLURM_SUBMIT_DIR"
IMG="sif/entrez-direct_25.3.sif"
ACCESSION="KY293680.1"
OUTPUT="fasta/${ACCESSION}.fasta"
echo "Descargando: $ACCESSION"
apptainer exec "$IMG" \
efetch -db nuccore -id "$ACCESSION" -format fasta \
> "$OUTPUT"
echo "Archivo creado: $OUTPUT"Envía el trabajo:
sbatch scripts/efetch_single.sbatchRevisa el resultado cuando termine:
squeue -u "$USER"
head fasta/KY293680.1.fastaCrear una lista de accesiones
Para los siguientes ejemplos se necesita un archivo de texto con una accesión de GenBank por línea. En este contexto conviene llamarlas accesiones o identificadores de GenBank; un voucher es el ejemplar biológico de referencia y no necesariamente corresponde al identificador de la secuencia.
Crea list.txt:
NC_001477.1
NC_001498.1
NC_001542.1
NC_001802.1
NC_001806.2
NC_002549.1
NC_003977.2
NC_004102.1
NC_007605.1
NC_045512.2
Comprueba el número de accesiones:
wc -l list.txtPara el array, evita líneas vacías y espacios adicionales en esta lista.
Ejemplo 2: procesar una lista con while
Este script utiliza un bucle while para leer list.txt. Todas las accesiones forman parte de un solo trabajo y se descargan una después de otra.
Crea el archivo:
nano scripts/efetch_loop.sbatchContenido:
#!/bin/bash
#SBATCH --job-name=efetch_loop
#SBATCH --partition=ib
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=1
#SBATCH --mem=1G
#SBATCH --time=00:20:00
#SBATCH --output=logs/%x-%j.out
#SBATCH --error=logs/%x-%j.err
set -euo pipefail
cd "$SLURM_SUBMIT_DIR"
LIST="list.txt"
OUTPUT_DIR="fasta"
IMG="sif/entrez-direct_25.3.sif"
mkdir -p "$OUTPUT_DIR"
while IFS= read -r ACCESSION; do
[[ -z "$ACCESSION" ]] && continue
echo "Descargando: $ACCESSION"
apptainer exec "$IMG" \
efetch -db nuccore -id "$ACCESSION" -format fasta \
> "$OUTPUT_DIR/${ACCESSION}.fasta"
done < "$LIST"
echo "Todas las descargas terminaron"Envía el trabajo:
sbatch scripts/efetch_loop.sbatchCuando termine, revisa cuántos archivos se crearon:
find fasta -maxdepth 1 -name '*.fasta' | wc -lEjemplo 3: paralelizar con un array de Slurm
Un array crea varias tareas a partir del mismo script. La variable SLURM_ARRAY_TASK_ID indica qué línea de list.txt debe procesar cada tarea.
Primero obtén el número de accesiones:
N=$(wc -l < list.txt)
echo "$N"Crea el archivo:
nano scripts/efetch_array.sbatchContenido:
#!/bin/bash
#SBATCH --job-name=efetch_array
#SBATCH --partition=ib
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=1
#SBATCH --mem=1G
#SBATCH --time=00:10:00
#SBATCH --output=logs/%x-%A_%a.out
#SBATCH --error=logs/%x-%A_%a.err
set -euo pipefail
cd "$SLURM_SUBMIT_DIR"
LIST="list.txt"
OUTPUT_DIR="fasta"
IMG="sif/entrez-direct_25.3.sif"
mkdir -p "$OUTPUT_DIR"
ACCESSION=$(sed -n "${SLURM_ARRAY_TASK_ID}p" "$LIST")
if [[ -z "$ACCESSION" ]]; then
echo "No se encontró una accesión para la tarea ${SLURM_ARRAY_TASK_ID}" >&2
exit 1
fi
echo "Tarea ${SLURM_ARRAY_TASK_ID}: descargando $ACCESSION"
apptainer exec "$IMG" \
efetch -db nuccore -id "$ACCESSION" -format fasta \
> "$OUTPUT_DIR/${ACCESSION}.fasta"
echo "Tarea ${SLURM_ARRAY_TASK_ID}: terminó $ACCESSION"Envía una tarea por cada línea y permite ejecutar como máximo cinco al mismo tiempo:
N=$(wc -l < list.txt)
sbatch --array="1-${N}%5" scripts/efetch_array.sbatchEn 1-${N}%5:
1-${N}crea una tarea por cada línea de la lista.%5limita el array a un máximo de cinco tareas ejecutándose simultáneamente.- Cada tarea solicita 1 CPU y 1 GB de memoria.
- Por lo tanto, cinco tareas simultáneas pueden utilizar en conjunto hasta 5 CPU y 5 GB.
Revisa las tareas del array:
squeue -u "$USER"Al finalizar, revisa los archivos y los registros:
ls -lh fasta/
ls -lh logs/Comparación de los tres métodos
| Método | Trabajos o tareas | Orden de procesamiento | Uso recomendado |
|---|---|---|---|
| Una accesión | 1 | Una sola descarga | Probar el contenedor y el comando |
Bucle while |
1 | Secuencial | Listas pequeñas o tareas muy breves |
| Array | Una tarea por accesión | Paralelo, sujeto a los recursos disponibles | Muchas muestras independientes |
%5?
El límite evita enviar demasiadas descargas simultáneas a NCBI y reduce la presión sobre el clúster. Aumentarlo no garantiza que el trabajo termine antes: Slurm solamente iniciará tareas cuando existan recursos disponibles.
Ejemplo: Análisis filogenético con BEAST2
Esta sección utiliza imágenes públicas del repositorio de Docker Hub:
https://hub.docker.com/repositories/ccervantess
Estas imágenes fueron preparadas y probadas para BEAGLE, con el objetivo de facilitar el uso de software bioinformático sin compilar programas ni modificar el sistema principal del clúster.
Para esta práctica se usará únicamente el archivo testGTR.xml, una prueba pequeña de BEAST2 que permite verificar que Apptainer, Slurm y el contenedor funcionan correctamente en BEAGLE.
El objetivo no es hacer un análisis biológico final ni comparar formalmente CPU contra GPU. Debido a que testGTR.xml es pequeño, la GPU puede no ser más rápida.
Se recomienda descargar imágenes solo de repositorios confiables, como Docker Hub o Quay.io, usando etiquetas de versión específicas en lugar de latest.
Archivo de prueba
El archivo testGTR.xml está disponible en el repositorio oficial de BEAST2, dentro de la carpeta examples: https://github.com/CompEvol/beast2/blob/master/examples/testGTR.xml.
En esta práctica, el archivo se descargará dentro de la carpeta de trabajo beast2_testGTR/data/, para mantener juntos los datos, scripts, contenedores, logs y resultados del ejercicio.
Imágenes usadas en esta práctica
Las imágenes se descargan desde Docker Hub usando Apptainer. Para reproducibilidad, se recomienda usar etiquetas específicas y evitar latest.
| Uso | Imagen de Docker Hub | Etiqueta | Archivo .sif sugerido |
|---|---|---|---|
| BEAST2 en CPU | ccervantess/beast2 |
2.7.8 |
beast2_2.7.8.sif |
| BEAST2 + BEAGLE + CUDA para V100 | ccervantess/beast2-beagle-cuda |
2.7.8-gpu-v100 |
beast2-beagle-cuda_2.7.8-gpu-v100.sif |
Preparar la carpeta de trabajo
Desde la raíz del repositorio del manual, crea la carpeta de la práctica:
mkdir -p beast2_testGTR/{data,sif,scripts,logs,runs/cpu,runs/gpu}Después entra a la carpeta de la práctica:
cd beast2_testGTRDescarga el archivo testGTR.xml dentro de la carpeta data/ de la práctica:
wget -O data/testGTR.xml \
https://raw.githubusercontent.com/CompEvol/beast2/master/examples/testGTR.xmlVerifica que el archivo se descargó correctamente:
ls -lh data/testGTR.xmlCopia el archivo testGTR.xml a las carpetas de corrida:
cp data/testGTR.xml runs/cpu/
cp data/testGTR.xml runs/gpu/La estructura esperada será:
beast2_testGTR/
├── data/
│ └── testGTR.xml
├── logs/
├── runs/
│ ├── cpu/
│ │ └── testGTR.xml
│ └── gpu/
│ └── testGTR.xml
├── scripts/
└── sif/
BEAST2 escribirá archivos como primate-mtDNA.log, primate.trees y testGTR.xml.state. Si se ejecutan las pruebas CPU y GPU en la misma carpeta, una corrida puede sobrescribir los resultados de la otra.
Descargar la imagen de BEAST2 para CPU
Descarga la imagen de BEAST2 desde Docker Hub y conviértela a formato .sif:
apptainer pull \
sif/beast2_2.7.8.sif \
docker://ccervantess/beast2:2.7.8Revisa que el archivo se haya creado:
ls -lh sif/Prueba que el ejecutable beast está disponible dentro del contenedor:
apptainer exec sif/beast2_2.7.8.sif beast -helpEjecutar testGTR.xml en CPU con Slurm
Crea el script:
nano scripts/beast2_gtr_cpu.sbatchContenido:
#!/bin/bash
#SBATCH --job-name=beast2_gtr_cpu
#SBATCH --partition=ib
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=1
#SBATCH --mem=4G
#SBATCH --time=01:00:00
#SBATCH --output=logs/%x-%j.out
#SBATCH --error=logs/%x-%j.err
set -euo pipefail
cd "$SLURM_SUBMIT_DIR"
# Cargar token y chat_id de Telegram
if [[ -f "$HOME/.telegram" ]]; then
source "$HOME/.telegram"
fi
mkdir -p logs
send_telegram() {
local MESSAGE="$1"
if [[ -n "${TELEGRAM_BOT_TOKEN:-}" && -n "${TELEGRAM_CHAT_ID:-}" ]]; then
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d chat_id="${TELEGRAM_CHAT_ID}" \
-d text="${MESSAGE}" > /dev/null || true
fi
}
send_telegram "BEAST2 CPU inició. Job: ${SLURM_JOB_NAME} (${SLURM_JOB_ID}) en $(hostname)."
START_TIME=$(date +%s)
finish() {
EXIT_CODE=$?
END_TIME=$(date +%s)
ELAPSED=$((END_TIME - START_TIME))
if [[ "$EXIT_CODE" -eq 0 ]]; then
send_telegram "BEAST2 CPU terminó correctamente. Job: ${SLURM_JOB_NAME} (${SLURM_JOB_ID}). Tiempo: ${ELAPSED} s."
else
send_telegram "BEAST2 CPU terminó con error. Job: ${SLURM_JOB_NAME} (${SLURM_JOB_ID}). Código: ${EXIT_CODE}. Revisa logs/."
fi
exit "$EXIT_CODE"
}
trap finish EXIT
echo "===================================="
echo "Trabajo: $SLURM_JOB_NAME"
echo "Job ID: $SLURM_JOB_ID"
echo "Nodo: $(hostname)"
echo "Inicio: $(date)"
echo "Directorio: $SLURM_SUBMIT_DIR"
echo "===================================="
cd runs/cpu
/usr/bin/time -v apptainer exec \
../../sif/beast2_2.7.8.sif \
beast \
-overwrite \
testGTR.xml
echo "===================================="
echo "Fin: $(date)"
echo "===================================="Envía el trabajo:
sbatch scripts/beast2_gtr_cpu.sbatchRevisa si sigue en cola:
squeue -u $USERCuando termine, revisa los archivos de salida:
ls -lh logs/
ls -lh runs/cpu/Revisa el final del archivo .out:
tail -n 40 logs/beast2_gtr_cpu-*.outRevisa si hubo errores:
tail -n 40 logs/beast2_gtr_cpu-*.errTambién puedes revisar el log principal de BEAST2:
tail -n 20 runs/cpu/primate-mtDNA.logDescargar la imagen de BEAST2 con BEAGLE CUDA para GPU
Descarga la imagen preparada para usar BEAST2 con BEAGLE y CUDA en el nodo con GPU V100:
apptainer pull \
sif/beast2-beagle-cuda_2.7.8-gpu-v100.sif \
docker://ccervantess/beast2-beagle-cuda:2.7.8-gpu-v100Revisa que el archivo se haya creado:
ls -lh sif/Prueba que el contenedor abre correctamente:
apptainer exec sif/beast2-beagle-cuda_2.7.8-gpu-v100.sif beast -helpEjecutar testGTR.xml con GPU
Este ejercicio solicita una GPU con #SBATCH --gres=gpu:1 y usa apptainer exec --nv para que el contenedor tenga acceso a las bibliotecas NVIDIA del nodo.
Crea el script:
nano scripts/beast2_gtr_gpu.sbatchContenido:
#!/bin/bash
#SBATCH --job-name=beast2_gtr_gpu
#SBATCH --partition=gpu_V100
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=4
#SBATCH --mem=16G
#SBATCH --gres=gpu:1
#SBATCH --time=01:00:00
#SBATCH --output=logs/%x-%j.out
#SBATCH --error=logs/%x-%j.err
set -euo pipefail
cd "$SLURM_SUBMIT_DIR"
# Cargar token y chat_id de Telegram
if [[ -f "$HOME/.telegram" ]]; then
source "$HOME/.telegram"
fi
mkdir -p logs
send_telegram() {
local MESSAGE="$1"
if [[ -n "${TELEGRAM_BOT_TOKEN:-}" && -n "${TELEGRAM_CHAT_ID:-}" ]]; then
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d chat_id="${TELEGRAM_CHAT_ID}" \
-d text="${MESSAGE}" > /dev/null || true
fi
}
send_telegram "BEAST2 GPU inició. Job: ${SLURM_JOB_NAME} (${SLURM_JOB_ID}) en $(hostname)."
START_TIME=$(date +%s)
finish() {
EXIT_CODE=$?
END_TIME=$(date +%s)
ELAPSED=$((END_TIME - START_TIME))
if [[ "$EXIT_CODE" -eq 0 ]]; then
send_telegram "BEAST2 GPU terminó correctamente. Job: ${SLURM_JOB_NAME} (${SLURM_JOB_ID}). Tiempo: ${ELAPSED} s."
else
send_telegram "BEAST2 GPU terminó con error. Job: ${SLURM_JOB_NAME} (${SLURM_JOB_ID}). Código: ${EXIT_CODE}. Revisa logs/."
fi
exit "$EXIT_CODE"
}
trap finish EXIT
echo "===================================="
echo "Trabajo: $SLURM_JOB_NAME"
echo "Job ID: $SLURM_JOB_ID"
echo "Nodo: $(hostname)"
echo "Inicio: $(date)"
echo "Directorio: $SLURM_SUBMIT_DIR"
echo "CPUs asignadas: ${SLURM_CPUS_PER_TASK}"
echo "GPUs asignadas: ${SLURM_GPUS:-No disponible}"
echo "===================================="
echo "Revisando GPU asignada:"
nvidia-smi
cd runs/gpu
/usr/bin/time -v apptainer exec \
--nv \
../../sif/beast2-beagle-cuda_2.7.8-gpu-v100.sif \
beast \
-beagle \
-beagle_GPU \
-beagle_order 1 \
-overwrite \
testGTR.xml
echo "===================================="
echo "Fin: $(date)"
echo "===================================="Envía el trabajo:
sbatch scripts/beast2_gtr_gpu.sbatchRevisa si sigue en cola:
squeue -u $USERCuando termine, revisa los archivos generados:
ls -lh logs/
ls -lh runs/gpu/Revisa el archivo de salida:
tail -n 60 logs/beast2_gtr_gpu-*.outRevisa si hubo errores:
tail -n 60 logs/beast2_gtr_gpu-*.errRevisa el log principal de BEAST2:
tail -n 20 runs/gpu/primate-mtDNA.logUsar notificaciones por Telegram
Los scripts de esta práctica pueden enviar un mensaje por Telegram al iniciar y otro al terminar el trabajo.
Para no escribir el token directamente dentro del script .sbatch, se recomienda guardar las credenciales en un archivo oculto dentro del directorio personal del usuario.
Crea el archivo ~/.telegram:
nano ~/.telegramAgrega tus credenciales:
export TELEGRAM_BOT_TOKEN="TU_TOKEN_DEL_BOT"
export TELEGRAM_CHAT_ID="TU_CHAT_ID"Guarda el archivo y cambia sus permisos:
chmod 600 ~/.telegramDentro del script .sbatch, las credenciales se cargan con:
# Cargar credenciales de Telegram si existen
if [[ -f "$HOME/.telegram" ]]; then
source "$HOME/.telegram"
fiDe esta forma, el script puede usar las variables TELEGRAM_BOT_TOKEN y TELEGRAM_CHAT_ID sin que el token quede escrito dentro del archivo .sbatch.
La función para enviar mensajes puede definirse así:
send_telegram() {
local MESSAGE="$1"
if [[ -n "${TELEGRAM_BOT_TOKEN:-}" && -n "${TELEGRAM_CHAT_ID:-}" ]]; then
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d chat_id="${TELEGRAM_CHAT_ID}" \
-d text="${MESSAGE}" > /dev/null || true
fi
}Después se puede enviar un mensaje al iniciar el trabajo:
send_telegram "Inicia BEAST2 CPU | Job ${SLURM_JOB_ID} | Nodo $(hostname)"y otro al terminar:
send_telegram "Terminó BEAST2 CPU | Job ${SLURM_JOB_ID}"Si el archivo ~/.telegram no existe, el trabajo se ejecutará normalmente, pero no enviará notificaciones.
Revisar resultados
Revisa directamente los archivos .out, .err y los archivos generados por el programa.
Para esta práctica, los archivos importantes son:
logs/beast2_gtr_cpu-JOBID.out
logs/beast2_gtr_cpu-JOBID.err
logs/beast2_gtr_gpu-JOBID.out
logs/beast2_gtr_gpu-JOBID.err
runs/cpu/primate-mtDNA.log
runs/cpu/primate.trees
runs/gpu/primate-mtDNA.log
runs/gpu/primate.trees
Puedes buscar mensajes de error con:
grep -i "error\|exception\|failed" logs/*.out logs/*.errSi no aparece nada, revisa el final de los archivos .out:
tail -n 40 logs/*.outLimpiar resultados para repetir la prueba
Si quieres repetir la prueba desde cero, elimina solo los resultados generados dentro de las carpetas de corrida:
rm -f runs/cpu/primate-mtDNA.log runs/cpu/primate.trees runs/cpu/testGTR.xml.state
rm -f runs/gpu/primate-mtDNA.log runs/gpu/primate.trees runs/gpu/testGTR.xml.stateNo borres las imágenes .sif a menos que quieras descargarlas de nuevo.
rm
rm borra archivos de forma permanente. Antes de borrar, confirma tu ubicación con:
pwd
ls -lh