A Nextflow pipeline for estimating effective population size (Ne) trajectories from whole-genome sequence data, supporting multiple demographic inference tools.
Note: The NeHub Docker image is currently private. It will be made public in a future release. If you wish to use Docker or Singularity, you can either build the image yourself (see Running with Docker / Singularity) or contact the author for access to pull the image directly.
Chromosome naming: The pipeline currently only recognises chromosomes in the format
chr1,chr2, ...,chrX. Chromosomes named1,2, etc. (without thechrprefix) will not be processed correctly. Please ensure your VCF files and reference genome use thechrprefix convention.
Docker vs Conda: If you are not familiar with Docker or Singularity, we recommend using the Conda-based installation described in the Installation section.
PSMCandMSMCare included inbasic_tools.yml.SMC++,PHLASH, andtsinfer/tsdate/tskiteach require a separate Conda environment as detailed below.Stairway Plot,Relate, andGONEare installed as standalone packages, with their installation paths specified in the pipeline configuration.
- Available Tools
- Configuration
- Data Processing
- Usage
- Cluster Usage
- Running with Docker / Singularity
- Installation
- VCF Header Fix
- Important Notes
| Tools | Input | Link | Install Approach | Available Now |
|---|---|---|---|---|
| GONE | plink file (.ped, .bim) | https://github.com/esrud/GONE | git clone | Yes |
| PSMC | fastq | https://github.com/lh3/psmc | conda install | Yes |
| MSMC | vcf | https://github.com/stschiff/msmc2 | conda install | Yes |
| SMC++ | vcf.gz | https://github.com/popgenmethods/smcpp | conda install | Yes |
| PHLASH | vcf.gz | https://github.com/jthlab/phlash | pip install | Yes |
| tsinfer & tsdate & tskit | ts | https://tskit.dev/ | conda install | Yes |
| Relate | haps and sample | https://myersgroup.github.io/relate/ | package | Yes |
| Stairway Plot | SFS | https://github.com/xiaoming-liu/stairway-plot-v2 | package | Yes |
- SMC++ requires at least 16 GB memory if use
singularity run docker://terhorst/smcpp:latest - PHLASH benefits from GPU acceleration
- Java memory settings:
export NXF_OPTS='-Xss256k -Xmx512m'- Nextflow >= 24.10.2
- Java >= 17
git clone https://github.com/HighlanderLab/NeHub.git
cd NeHubThe pipeline uses configuration files located in the conf/ directory, including global parameters and tool-specific configurations.
- Command Line Parameters: Direct input through the command line
nextflow -log ${workdir}/logs/nextflow_${task}_${replicate}.log run ${workdir}/main.nf \
--chromosomes 1 \
--population_file popLabel.txt \
--GONE.installation_path "/path/to/GONE/" \- JSON Configuration File: Partial parameter input through a JSON file
Detail see in ./conf/params.config.
{
"input_dir": "/test/",
"method": "GONE,PSMC,tskit,SMCpp,Relate,Phlash,stairway,MSMC",
"chromosomes": [1]
}3. Config file
Copy conf/params.config, edit it, and pass it with -c. Unlike JSON, a config file can hold comments, and can reuse values (e.g. params.option.ancestral_genome):
cp conf/params.config my_params.config # edit the values
nextflow run main.nf -profile local_singularity,small -c my_params.configTip: Keep the whole copied file rather than a few lines. Grouped settings such as
Relate = [ ... ]are replaced as a block, so a config file that only setsRelate = [ Relate_path: ... ]would drop the other Relate settings. To change a single nested value, use the command line or the JSON file instead.
Check the final values before a long run:
nextflow config -profile local_singularity,small -params-file params.json | grep -A15 "Relate"Note: If use
singularity, the reference genome, ancestral genome, and container image paths must all be absolute paths. Relative paths (e.g../tests/test_data/test.fa) will not work inside Singularity containers as the working directory differs from the host.
Note: Before starting, please install conda environment,
Stairway Plot 2,Relate, andGONE
module load nextflow
export NXF_OPTS='-Xss256k -Xmx512m'
# or make sure they are iin your environment
nextflow run main.nf -profile local_no_Nehub_docker \
-params-file params.json \
--input_dir /path/to/input \
--output_dir /path/to/outputNote: Before starting, please pull mirror and build
.sif. Replace path of.sifto container setting of local_singularity in nextflow.config
module load singulairty
module load nextflow
export NXF_OPTS='-Xss256k -Xmx512m'
# or make sure they are iin your environment
nextflow run main.nf -profile local_singularity \
-params-file params.json \
--input_dir /path/to/input \
--output_dir /path/to/outputParameter file refers to./conf/params.config, and ./conf/resources.config has two setting for large resource requirement (large) and small resource requirement (small). Here, large is used for real data, small is used for simulation data.
nextflow run main.nf -profile local_singularity,small \
-params-file params.json \
--input_dir /path/to/input \
--output_dir /path/to/output
# OR
nextflow run main.nf -profile local_singularity,large \
-params-file params.json \
--input_dir /path/to/input \
--output_dir /path/to/output| Profile | Recommended For | Samples | Chromosomes | Memory |
|---|---|---|---|---|
small |
Testing, small datasets, simulation | ≤ 100 | ≤ 2 | Reduced (e.g. 4–8 GB per process) |
large |
Production runs, large cohorts | > 100 | Many | Full (e.g. 16–160 GB per process) |
| (none) | Uses default resources defined inline in each module; resource requirements are similar to small |
— | — | — |
| Profile | Executor | Software from | Container | Concurrency | Error strategy | Intended use |
|---|---|---|---|---|---|---|
local_no_Nehub_docker |
local (queueSize 8, maxForks 9) |
Conda envs, activated per label | none | ≤ 8–9 parallel tasks in one job | ignore |
Eddie or local machine with all conda envs installed |
local_singularity |
local (queueSize 8, maxForks 9) |
NeHub Singularity image | same nehub.sif (--nv GPU flag) |
≤ 8–9 parallel tasks in one job | ignore |
Eddie, everything runs inside one interactive or array job |
sge_singularity |
SGE (queueSize 8) |
NeHub Singularity image | /exports/eddie/scratch/$USER/nehub.sif |
8 queued jobs | ignore |
Eddie, each process submitted as its own SGE job |
sge_no_singularity |
SGE (queueSize 20, 10 s submit rate) |
Conda envs (Eddie's central anaconda) + module load for plink |
none (but Singularity is enabled) | 20 queued jobs, maxForks 9 |
retry ×3 |
Eddie production runs; per-job h_vmem = task memory + 4 GB; PHLASH on the GPU queue |
github |
local | Conda envs created in CI | none | default | default (stop) | GitHub Actions CI; also loads conf/test.config |
The pipeline is set up for SGE clusters such as Eddie (University of Edinburgh). All cluster settings are in nextflow.config. On Eddie you can run it in one of two ways:
| Mode | Profiles | How it works | Best for |
|---|---|---|---|
| Local executor | local_singularity, local_no_Nehub_docker |
Submit one job; Nextflow runs every process inside it, sharing that job's CPUs and memory. | Simulations, small datasets, testing (real data also works if you limit how many processes run at once) |
| SGE executor | sge_singularity, sge_no_singularity |
Nextflow runs as a lightweight head process and submits each process as its own SGE job, with its own CPU and memory request. | Real data, large cohorts, many chromosomes ( Run Nextflow on a login node inside screen/tmux (so it keeps running after you log out) or on a node with submit rights.-resume.) |
All processes run inside a single job, so request enough CPUs and memory for everything.
Conda environments
#!/bin/bash
# submit_nextflow.sh
#$ -N nextflow_main
#$ -pe sharedmem 8
#$ -l h_vmem=16G # per slot: 8 x 16G = 128G in total
#$ -l h_rt=48:00:00
#$ -cwd
#$ -j y
module load java
module load nextflow
# Stop tools from sizing themselves to the whole node (Eddie limits virtual memory)
export NXF_OPTS='-Xms1g -Xmx4g'
export MALLOC_ARENA_MAX=2
export OMP_NUM_THREADS=${NSLOTS:-1} OPENBLAS_NUM_THREADS=${NSLOTS:-1} MKL_NUM_THREADS=${NSLOTS:-1}
nextflow run main.nf \
-profile local_no_Nehub_docker,large \
-params-file params.json \
--input_dir /path/to/input \
--output_dir /path/to/output \
--chromosomes 1 \
--population_file popLabel.txtSingularity image (.sif)
Same as above, but load Singularity, give it a scratch directory, and use the local_singularity profile. Set the .sif path in nextflow.config first.
#!/bin/bash
# submit_nextflow.sh
#$ -N nextflow_main
#$ -pe sharedmem 8
#$ -l h_vmem=16G
#$ -l h_rt=48:00:00
#$ -cwd
#$ -j y
module load singularity
module load java
module load nextflow
export NXF_OPTS='-Xms1g -Xmx4g'
export MALLOC_ARENA_MAX=2
export OMP_NUM_THREADS=${NSLOTS:-1} OPENBLAS_NUM_THREADS=${NSLOTS:-1} MKL_NUM_THREADS=${NSLOTS:-1}
export SINGULARITY_TMPDIR=/exports/eddie/scratch/$USER/tmp
export NXF_SINGULARITY_CACHEDIR=/exports/eddie/scratch/$USER/singularity_cache
mkdir -p "$SINGULARITY_TMPDIR" "$NXF_SINGULARITY_CACHEDIR"
nextflow run main.nf \
-profile local_singularity,large \
-params-file params.json \
--input_dir /path/to/input \
--output_dir /path/to/output \
--chromosomes 1 \
--population_file popLabel.txtSubmit with:
qsub submit_nextflow.shRun Nextflow on a node that can submit jobs (e.g. a login node), inside screen or tmux so it keeps running after you log out. Nextflow then submits every process with qsub.
screen -S nehub # reattach later with: screen -r nehub
module load java nextflow
export NXF_OPTS='-Xms1g -Xmx4g'
nextflow run main.nf \
-profile sge_no_singularity,large \
-params-file params.json \
--input_dir /path/to/input \
--output_dir /path/to/output \
--chromosomes 1 \
--population_file popLabel.txtqstat -u $USER # your running / queued jobs
tail -f .nextflow.log # Nextflow log in real time
qacct -j <job_id> # why a finished job stopped (check failed / exit_status / maxvmem)A job that disappears from
qstatwithfailed 46: execd enforced h_vmem limitinqacctran out of (virtual) memory. Increaseh_vmemor check the thread settings above.
Run the same command again from the same launch directory (where .nextflow/ and work/ are), with -resume added. Completed tasks are reused from the cache.
nextflow run main.nf \
-profile local_singularity,large \
-params-file params.json \
--input_dir /path/to/input \
--output_dir /path/to/output \
--chromosomes 1 \
--population_file popLabel.txt \
-resumeHere are two options: one is Docker based on mirrors, and the other is installation on the local machine.
Note: If you are not familiar with Docker or Singularity, skip this section and follow the Conda-based installation instead.
Pre-pull the image once to avoid multiple nodes downloading simultaneously.
Note: This step requires at least 16 GB memory. Request an interactive node first:
qlogin -l h_vmem=16G
Option 1: Pull from Docker Hub (requires access credentials)
module load singularity
export SINGULARITY_DOCKER_USERNAME=aprilyuzhang
export SINGULARITY_DOCKER_PASSWORD=${PASSWORD} # contact author if need
export SINGULARITY_TMPDIR=/exports/eddie/scratch/$USER/tmp
mkdir -p /exports/eddie/scratch/$USER/tmp
singularity pull \
--tmpdir /exports/eddie/scratch/$USER/tmp \
./nehub.sif \
docker://aprilyuzhang/nehub:latestOption 2: Build from Dockerfile (no credentials required)
# 1. Build Docker image locally on your machine
docker build --build-arg BUILDPLATFORM=linux/amd64 \
-t nehub:latest \
-f docker/Dockerfile .
# 2. Save as tar
docker save nehub:latest -o nehub.tar
gzip nehub.tar
# 3. Transfer to Eddie
scp nehub.tar.gz /path/to/image
# 4. On Eddie, convert to SIF
module load singularity
# set SINGULARITY_TMPDIR to avoid FATAL ERROR: Out of memory (cache_alloc)
export SINGULARITY_TMPDIR=/exports/eddie/scratch/$USER/tmp
mkdir -p $SINGULARITY_TMPDIR
gunzip /path/to/image/nehub.tar.gz
singularity build \
./nehub.sif \
docker-archive://path/to/image/nehub.tarOption 3: Build from Dockerfile and push to private repository (no credentials required)
# 1. Build Docker image locally on your machine
docker build --build-arg BUILDPLATFORM=linux/amd64 \
-t nehub:latest \
-f docker/Dockerfile .
docker tag nehub:latest aprilyuzhang/nehub:latest
docker push aprilyuzhang/nehub:latest
module load singularity
export SINGULARITY_DOCKER_USERNAME=aprilyuzhang
export SINGULARITY_DOCKER_PASSWORD=${PASSWORD}
export SINGULARITY_TMPDIR=/exports/eddie/scratch/$USER/tmp
mkdir -p /exports/eddie/scratch/$USER/tmp
singularity pull \
--tmpdir /exports/eddie/scratch/$USER/tmp \
$USER/nehub.sif \
docker://aprilyuzhang/nehub:latestRecommendation: If you are not familiar with Docker, use the Conda-based installation below. Each tool is installed into a separate Conda environment to avoid dependency conflicts.
- Conda (recommended: Miniconda)
Users can install all tools with install/install_all.sh, install only selected tools with the same script, or follow the manual commands in the sections below Install step by step.
The script runs the similar install commands as the CI workflow (.github/workflows/ci.yml), which is tested on every pull request.
bash install/install_all.shbash install/install_all.sh smcpp relate # only SMC++ and Relate
bash install/install_all.sh conda # all conda environments
bash install/install_all.sh standalone # GONE, Relate, Stairway Plot, easySFS
⚠️ Next step (important): Once installation succeeds, the standalone tools are in your tools folder (./toolsby default, or the folder given with--tools-dir). Their paths must be in your parameter file before the pipeline can run:
- Copy it and replace the remaining
/path/to/...entries (Install path,input, output, genomes, genetic maps):cp params_template.json params.json grep -n '/path/to' params.json # anything listed still needs editing- Run the pipeline:
nextflow run main.nf -profile <profile> -params-file params.json
| Conda env | YAML file | Main contents | Used by process label | Notes |
|---|---|---|---|---|
basic_Ne |
conf/envs/basic_tools.yml |
PSMC, MSMC2, plink, bcftools, other basic tools | basic_Ne, plink |
Core environment for most steps |
ts_tools |
conf/envs/ts_tools.yml |
tskit, tsinfer, tsdate, tszip, msprime | ts_tools |
Then run conda install -n ts_tools -y -c conda-forge tszip msprime |
bcftools |
conf/envs/bcftools.yml |
bcftools | bcftools |
VCF handling and consensus FASTA |
smcpp |
conf/envs/smcpp.yml |
SMC++ | smcpp |
Requires Python 3.10 (longintrepr.h was removed in Python 3.11+) |
phlash |
conf/envs/phlash.yml |
PHLASH | ne_pipe_phlash |
Works with both GPU and CPU builds |
Note: if smcpp Installation has issue, alternatively, use the Singularity image (no installation required and more stable)
Note: Ensure your VCF file header includes chromosome lengths before running SMC++. See VCF Header Fix below.
Note: If no GPU is detected, phlash automatically falls back to CPU. Installing the standard version (
pip install phlash) will use GPU if available, or CPU otherwise — no need to maintain two separate environments.
1. dinopy build failure:
If you encounter a Cython compilation error related to isinstance(seq, (int, long)):
# download dinopy source
pip download dinopy --no-deps -d ./dinopy_src
# unpack and edit processors.pyx:
# change: isinstance(seq, (int, long))
# to: isinstance(seq, int)
pip install ./dinopy-3.0.0/2. JAX >= 0.6.0 incompatibility:
If JAX version is >= 0.6.0, edit gpu.py in the phlash installation:
# change from:
return jax.pure_callback(
kern, result_shape_dtype, pp=params, index=index, grad=grad,
vmap_method='legacy_vectorized'
)
# to:
return jax.pure_callback(
kern, result_shape_dtype, pp=params, index=index, grad=grad,
)git clone https://github.com/esrud/GONE.git /path/to/GONE
chmod -R +x /path/to/GONE/Linux/PROGRAMMES/git clone https://github.com/isaacovercast/easySFS.git /path/to/easySFS
chmod +x /path/to/easySFS/easySFS.py
# Download stairway_plot_v2.1.3.zip from:
# https://github.com/xiaoming-liu/stairway-plot-v2
unzip stairway_plot_v2.1.3.zipDownload the pre-built binary from https://myersgroup.github.io/relate/:
tar -xvzf relate_v1.2.2_x86_64_dynamic.tgz -C /path/to/relate/Or build from source:
git clone --depth 1 https://github.com/MyersGroup/relate.git /path/to/relate_src
cd /path/to/relate_src
rm -rf build && mkdir build && cd build
cmake .. && make -j$(nproc)
cp /path/to/relate_src/bin/* /path/to/relate/Some tools (e.g. SMC++) require the VCF header to include chromosome lengths. Use the following script to add them:
i=chr_number
bcftools view -h chr${i}.vcf.gz > old_header.txt
awk 'BEGIN{while(getline < "ref.fa.fai"){len["chr"$1]=$2}}
/^##contig=<ID=/ {match($0,/ID=([^,>]+)/,a); chr=a[1];
if(chr in len){print "##contig=<ID="chr",length="len[chr]">"}
else {print $0}}
!/##contig=<ID=/ {print $0}' old_header.txt > new_header.txt
bcftools reheader -h new_header.txt -o chr${i}_new.vcf.gz chr${i}.vcf.gz
mv chr${i}.vcf.gz chr${i}_old.vcf.gz
mv chr${i}_new.vcf.gz chr${i}.vcf.gz- Chromosome naming: The pipeline currently only recognises chromosomes in the format
chr1,chr2, ...,chrX. Please ensure all input VCF files, reference genomes, and ancestral genomes use thechrprefix. Chromosomes named1,2, etc. will cause the pipeline to fail silently. - Docker image: The Docker image
aprilyuzhang/nehubis currently private. Conda-based installation is recommended for users without Docker Hub access. - GPU support: PHLASH benefits significantly from GPU acceleration. On Eddie, request a GPU node with
-q gpu -l gpu=1for pHlash jobs. - Refernece genome: Make sure
Refernece genomeis consistent with vcf REF