BBMap and the Human Reference Problem: Why Your Database Choice Matters as Much as Your Tool — Day 3 of 5
🧬 Day 3 of 5 — Benchmarking Host-Read Removal for High-Host-Content Metagenomes Day 1 framed the benchmark. Day 2 showed that two well-known alignment tools — BMTagger and Bowtie2 — produce noticeably different removal rates even when both use GRCh38 as the reference. The natural next question was: how much of that difference is the algorithm, and how much is the reference?
Today’s post answers that directly. I ran BBMap twice — same samples, same mapping parameters, same tool — against two different human references: the standard GRCh38.p12 and a repeat-masked hg19. The only thing that changed between the two runs was the database.
The result was a 3–5 percentage point difference in host removal across the high-host samples.
This is the most important lesson in the entire benchmark series: the reference is part of the method. Writing “human reads were removed with BBMap” in a Methods section is not a complete description. Stating the reference genome, the masking strategy, and the key alignment parameters is what makes a host-removal workflow reproducible.
What BBMap is and why it is used here
BBMap is a splice-aware short- and long-read aligner developed at the Joint Genome Institute. For host removal it offers a useful combination: a k-mer-seeded hybrid mapping strategy that is highly sensitive, configurable alignment thresholds that let you tune the sensitivity/specificity balance, and output flags that directly separate unmapped (retained microbial) reads from mapped (human) reads in a single command.
The key output flags are:
-
outu1/outu2— reads that did not map to the human reference → your retained microbial reads -
outm1/outm2— reads that did map → your discarded human reads
This direct separation in a single pass is operationally cleaner than tools that require a post-processing extraction step.
The benchmark design for Day 3
The same fastp-preprocessed paired-end reads used on Days 1 and 2 were passed to BBMap twice, with only the path= argument changed between runs:
| Run | Reference | All other parameters |
|---|---|---|
| BBMap GRCh38 | GRCh38.p12 (standard) | Identical |
| BBMap masked hg19 | Repeat-masked hg19 | Identical |
This is the controlled comparison that isolates the reference effect from the algorithm effect. When the only variable between two runs is the database, any difference in output is a reference effect.
BBMap: full command
Both runs used these parameters:
/usr/bin/time -v -o ${SAMPLE}_bbmap_${REF_NAME}.time.txt \
bbmap.sh \
minid=0.95 \
maxindel=3 \
bwr=0.16 \
bw=12 \
quickmatch \
fast \
minhits=2 \
qtrim=rl \
trimq=10 \
untrim \
path=${REF_DIR} \
in1=${SAMPLE}_R1.fastp.fastq.gz \
in2=${SAMPLE}_R2.fastp.fastq.gz \
outu1=${OUTDIR}/${SAMPLE}_nonhuman_R1.fastq.gz \
outu2=${OUTDIR}/${SAMPLE}_nonhuman_R2.fastq.gz \
outm1=${OUTDIR}/${SAMPLE}_human_R1.fastq.gz \
outm2=${OUTDIR}/${SAMPLE}_human_R2.fastq.gz \
threads=16 \
-Xmx48g
Key parameters explained:
| Parameter | Value | What it does |
|---|---|---|
minid=0.95 | 95% identity threshold | Only classify a read as human if ≥95% identity to the reference — reduces false positives |
maxindel=3 | Max 3 indels | Appropriate for short reads; reduces misalignments |
bwr=0.16 | Bandwidth ratio | Controls alignment band width; affects sensitivity/speed tradeoff |
quickmatch | — | Uses faster approximate matching before full alignment |
fast | — | Increases speed at slight sensitivity cost |
minhits=2 | Min 2 k-mer hits | A read must share at least 2 k-mer seeds with the reference before full alignment — reduces spurious mappings |
qtrim=rl trimq=10 | Quality trim both ends | Trim low-quality bases before alignment |
untrim | — | Restore original read length in output after alignment |
-Xmx48g | 48 GB heap | Critical — BBMap loads the reference into memory; undersizing this causes crashes |
The -Xmx48g flag deserves attention. BBMap stores the reference index in Java heap memory. For a full human genome reference, this requires tens of gigabytes. If you run BBMap without setting this appropriately for your reference size, it will fail mid-run with an out-of-memory error — sometimes after hours of processing. Always set this flag explicitly and allocate enough memory in your SLURM job request.
Building the BBMap reference database
For GRCh38:
bbmap.sh ref=GRCh38.p12.fa path=GRCh38_BBMap_DB -Xmx48g
For masked hg19:
bbmap.sh ref=hg19_masked.fa path=masked_hg19_DB -Xmx48g
The path= directory stores the pre-built index. Building the index from a full human genome takes 30–60 minutes and substantial memory, but it only needs to be done once. Store the index in a shared project location so all samples use the same database.
What masking actually does
Before looking at the results, it is worth understanding what a masked reference is and why someone would use one.
The human genome contains large amounts of:
- Repetitive sequence — transposable elements, satellite repeats, tandem repeats
- Low-complexity regions — homopolymers, simple sequence repeats
- Conserved sequence — regions similar to genes found in bacteria, archaea, or other eukaryotes
When a short read maps to one of these regions, the alignment may be ambiguous: the read matches the human reference, but it might equally match a microbial sequence. An aggressive mapper will classify it as human and remove it. A more conservative approach would leave it unclassified.
A repeat-masked reference replaces these problematic regions with N characters before indexing. A read that would have mapped to a repetitive or low-complexity human region can no longer map — because that region has been masked out. The mapper therefore retains reads it would otherwise have classified as human.
The trade-off is explicit:
Standard reference (GRCh38):
Higher sensitivity for human reads
Risk: some ambiguous/microbial reads classified as human
Masked reference:
Lower sensitivity for human reads in repetitive regions
Benefit: reduced false-positive removal of microbial reads
Neither is universally correct. The right choice depends on what matters most for your biological question.
Benchmark results
Across the five samples:
| Sample | BBMap GRCh38 | BBMap masked hg19 | Difference |
|---|---|---|---|
| Sample 1 | 89.85% | 85.57% | −4.28% |
| Sample 2 | 93.26% | 88.44% | −4.82% |
| Sample 3 | 21.25% | 20.19% | −1.06% |
| Sample 4 | 9.83% | 9.30% | −0.53% |
| Sample 5 | 82.19% | 78.71% | −3.48% |
| Mean | 59.28% | 56.44% | −2.84% |
The masked reference consistently removed fewer reads. The difference is largest in high-host samples (Samples 1, 2, and 5) and smallest in the low-host sample (Sample 4) — which makes intuitive sense. In high-host samples, a larger fraction of reads are genuinely human, so the effect of masking out repetitive regions is proportionally larger.
The tempting but wrong conclusion
Looking at this table, a natural reaction is:
“GRCh38 removes more reads, so it is better.”
This is the wrong conclusion — or at least, it is an incomplete one. The additional reads removed by GRCh38 could represent:
- True human reads that the masked reference missed — in which case GRCh38 is more sensitive and the additional removals are correct
- Ambiguous reads that map to repetitive regions shared between human and microbial genomes — in which case both references are removing something real, but the GRCh38 run is removing more of the microbial co-mapping reads
- Microbial false positives — reads from vaginal community members that share short regions of sequence similarity with unmasked repetitive elements
The removal percentage alone cannot distinguish between these three possibilities. That requires the read-level discordance analysis coming on Day 5, where I map discordant reads back to taxonomic databases and ask what organisms they actually come from.
Computational performance
Approximate mean performance across all five samples:
| Configuration | Mean wall-clock runtime | Approximate peak RAM |
|---|---|---|
| BBMap GRCh38 | ~77 minutes | ~45.5 GB |
| BBMap masked hg19 | ~56 minutes | ~44.3 GB |
Two things stand out here.
First, BBMap required substantially more RAM than any other tool in this benchmark. BMTagger used ~8 GB, Bowtie2 used ~4 GB, and BBMap needed ~45 GB. This is the most practically significant limitation of BBMap for host removal: on a shared HPC cluster, allocating 45–50 GB per sample limits how many simultaneous jobs you can run on a given node. At scale — 100 samples — this becomes a scheduling bottleneck.
Second, the masked reference was ~27% faster than GRCh38. Since the masked reference has fewer indexable positions (the N-masked regions are ignored), the mapper processes fewer potential alignment targets per read. Faster runtime with lower sensitivity in repetitive regions — a consistent package.
Why the reference is part of the method
This benchmark illustrates a principle that applies well beyond host removal:
The output of a bioinformatics tool is a joint product of the algorithm, the database, the parameters, and the preprocessing. Naming only the tool is an incomplete description.
For host removal specifically, a reproducible Methods section should include:
✓ Tool name and version
✓ Human reference genome (GRCh38, hg19, T2T, etc.)
✓ Whether the reference was masked, and how
✓ Key alignment parameters (identity threshold, minhits, etc.)
✓ How paired-end reads were handled
✓ How unmapped reads were retained
A Methods section that says only “Human reads were removed using BBMap” does not contain enough information for another researcher to reproduce the analysis — or to understand why their results differ if they attempt to.
A complete description would read more like:
Human reads were removed using BBMap (v39.x) mapped against GRCh38.p12, requiring ≥95% nucleotide identity (minid=0.95) and a minimum of 2 k-mer seed hits (minhits=2). Unmapped read pairs were retained for downstream analysis.
That is a reproducible methods statement.
A framework for thinking about host removal
The benchmark has now tested four configurations across three tools. A useful way to organize them:
Host-removal result =
f(algorithm, reference, parameters, preprocessing)
To isolate algorithm effects:
→ keep reference and parameters constant, vary the tool
To isolate reference effects:
→ keep algorithm and parameters constant, vary the database
(this is what Day 3 tested)
To evaluate end-to-end performance:
→ use each tool's recommended reference and parameters,
compare realistic production configurations
All three comparisons answer different questions. A benchmark that only runs each tool with its default settings on a single reference is measuring something, but it is conflating algorithm, reference, and parameter effects in a way that makes it hard to interpret differences.
What comes tomorrow
Day 4 introduces Cleanifier — the newest method in this benchmark and the one that most changed my thinking about the tradeoffs involved.
In the benchmark, Cleanifier produced host-removal percentages close to BMTagger while running in approximately 1.5 minutes per sample. That is not a typo. Where BBMap takes 77 minutes and requires 45 GB of RAM, Cleanifier finished the same sample in under two minutes.
That result was interesting enough that I did not stop at the runtime table. I asked the more important question: what exactly are the reads that Cleanifier removes that the alignment-based tools miss — and vice versa? That read-level investigation became the most analytically interesting part of the benchmark, and it is the focus of Day 4.

| Previous posts: Day 1 — Benchmark design and why host removal matters | Day 2 — BMTagger vs Bowtie2. |