[med-svn] [Git][med-team/bowtie2][upstream] New upstream version 2.5.5
Steffen Möller (@moeller)
gitlab at salsa.debian.org
Sun Feb 22 15:33:39 GMT 2026
Steffen Möller pushed to branch upstream at Debian Med / bowtie2
Commits:
ea626081 by Steffen Moeller at 2026-02-22T15:11:40+00:00
New upstream version 2.5.5
- - - - -
28 changed files:
- .github/workflows/random-tests.yml
- .github/workflows/simple-tests.yml
- BOWTIE2_VERSION
- CMakeLists.txt
- MANUAL
- MANUAL.markdown
- Makefile
- NEWS
- README.md
- aligner_seed.cpp
- aligner_seed.h
- aligner_seed2.h
- aligner_sw_driver.cpp
- aligner_sw_driver.h
- aln_sink.h
- bowtie2-build
- bowtie2-inspect
- bowtie_main.cpp
- bt2_search.cpp
- doc/manual.html
- doc/website/manual.ssi
- doc/website/recent_news.ssi
- doc/website/rhsidebar.ssi
- group_walk.h
- opts.h
- pat.cpp
- pat.h
- processor_support.h
Changes:
=====================================
.github/workflows/random-tests.yml
=====================================
@@ -45,14 +45,14 @@ jobs:
make clean; make -j4 allall
export NUM_CORES=1
make random-test
- linux-avx2:
+ linux-noavx2:
runs-on: ubuntu-latest
needs: linux
steps:
- uses: actions/checkout at v2
- - name: Run random tests using avx2
+ - name: Run random tests without using avx2
run: |
- export SSE_AVX2=1
+ export SSE_AVX2=0
make clean; make -j4 allall
export NUM_CORES=1
make random-test
=====================================
.github/workflows/simple-tests.yml
=====================================
@@ -44,14 +44,14 @@ jobs:
run: |
make clean; make -j4 allall
make simple-test
- linux-avx2:
+ linux-noavx2:
runs-on: ubuntu-latest
needs: linux
steps:
- uses: actions/checkout at v2
- - name: Run simple tests using AVX2
+ - name: Run simple tests without using AVX2
run: |
- export SSE_AVX2=1
+ export SSE_AVX2=0
make clean; make -j4 allall
make simple-test
macos:
=====================================
BOWTIE2_VERSION
=====================================
@@ -1 +1 @@
-2.5.4
+2.5.5
=====================================
CMakeLists.txt
=====================================
@@ -1,10 +1,10 @@
-cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
cmake_policy(SET CMP0048 NEW)
cmake_policy(SET CMP0005 NEW)
file(STRINGS ${CMAKE_SOURCE_DIR}/BOWTIE2_VERSION PROJECT_VERSION)
-project(bowtie2 LANGUAGES CXX VERSION ${PROJECT_VERSION})
+project(bowtie2 LANGUAGES C CXX VERSION ${PROJECT_VERSION})
enable_testing()
@@ -29,13 +29,14 @@ set(USE_SAIS ${USE_SAIS})
set(WITH_THREAD_PROFILING ${WITH_THREAD_PROFILING})
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -g3 -Wall")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -funroll-loops")
set(INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
-include_directories(${SOURCE_DIR}/third_party)
+include_directories(${CMAKE_SOURCE_DIR}/third_party)
+message("${CMAKE_SOURCE_DIR}/third_party")
if (MINGW)
option(BOWTIE_MM "Memory mapped files not supported on Windows" OFF)
option(BOWTIE_SHARED_MEM "Shared memory not supported on Windows" OFF)
@@ -194,22 +195,34 @@ if (USE_SRA)
find_package(Perl REQUIRED)
find_program(MAKE_EXE NAMES gmake nmake make)
+ # ExternalProject_add(ncbi_vdb_project
+ # URL https://github.com/ncbi/ncbi-vdb/archive/refs/tags/${NCBI_VDB_VER}.tar.gz
+ # PREFIX ${CMAKE_CURRENT_BINARY_DIR}/ncbi-vdb-${NCBI_VDB_VER}
+ # BUILD_IN_SOURCE 0
+ # # CONFIGURE_COMMAND ./configure --prefix=${THIRD_PARTY_LIBS} --without-debug
+ # BUILD_COMMAND cmake . -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${THIRD_PARTY_LIBS}
+ # # BUILD_COMMAND ${MAKE_EXE}
+ # INSTALL_COMMAND ${MAKE_EXE} install
+ # )
+
ExternalProject_add(ncbi_vdb_project
- URL https://github.com/ncbi/ncbi-vdb/archive/${NCBI_VDB_VER}.tar.gz
+ URL https://github.com/ncbi/ncbi-vdb/archive/refs/tags/${NCBI_VDB_VER}.tar.gz
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/ncbi-vdb-${NCBI_VDB_VER}
BUILD_IN_SOURCE 1
- CONFIGURE_COMMAND ./configure --prefix="${THIRD_PARTY_LIBS}" --without-debug
- BUILD_COMMAND ${MAKE_EXE}
- INSTALL_COMMAND ${MAKE_EXE} install
+ # CONFIGURE_COMMAND ./configure --prefix=${THIRD_PARTY_LIBS} --without-debug
+ CONFIGURE_COMMAND cd build && cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${THIRD_PARTY_LIBS}
+ BUILD_COMMAND cmake --build build
+ INSTALL_COMMAND cmake --install build
)
ExternalProject_add(ngs_project
- URL https://github.com/ncbi/sra-tools/archive/${SRA_TOOLS_VER}.tar.gz
+ URL https://github.com/ncbi/sra-tools/archive/refs/tags/${SRA_TOOLS_VER}.tar.gz
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/sra-tools-${SRA_TOOLS_VER}
BUILD_IN_SOURCE 1
- CONFIGURE_COMMAND ./configure --prefix=${THIRD_PARTY_LIBS} --with-ncbi-vdb-prefix=${THIRD_PARTY_LIBS} --enable-static --without-debug
- BUILD_COMMAND ${MAKE_EXE}
- INSTALL_COMMAND ${MAKE_EXE} install
+ CONFIGURE_COMMAND cd build && cmake .. -DCMAKE_BUILD_TYPE=Release -DVDB_INCDIR=${THIRD_PARTY_LIBS}/include -DVDB_LIBDIR=${THIRD_PARTY_LIBS}/lib64 -DCMAKE_INSTALL_PREFIX=${THIRD_PARTY_LIBS} -DBUILD_TOOLS_INTERNAL=ON -DBUILD_TOOLS_LOADERS=OFF -DBUILD_TOOLS_TEST_TOOLS=OFF
+ BUILD_COMMAND cmake --build build
+
+ INSTALL_COMMAND cmake --install build
DEPENDS ncbi_vdb_project
)
=====================================
MANUAL
=====================================
@@ -23,12 +23,12 @@ many other tools, some of which are listed here.
If you use Bowtie 2 for your published research, please cite our work.
Papers describing Bowtie 2 are:
-- Langmead B, Wilks C, Antonescu V, Charles R. Scaling read aligners
- to hundreds of threads on general-purpose processors.
- Bioinformatics. 2018 Jul 18. doi: 10.1093/bioinformatics/bty648.
+- Langmead B, Wilks C, Antonescu V, Charles R. Scaling read aligners to
+ hundreds of threads on general-purpose processors. Bioinformatics.
+ 2018 Jul 18. doi: 10.1093/bioinformatics/bty648.
-- Langmead B, Salzberg SL. Fast gapped-read alignment with Bowtie 2.
- Nature Methods. 2012 Mar 4;9(4):357-9. doi: 10.1038/nmeth.1923.
+- Langmead B, Salzberg SL. Fast gapped-read alignment with Bowtie 2.
+ Nature Methods. 2012 Mar 4;9(4):357-9. doi: 10.1038/nmeth.1923.
How is Bowtie 2 different from Bowtie 1?
@@ -155,15 +155,15 @@ and gzipped inputs.
To build bowtie2-build with libsais first make sure that the libsais
submodule is available. This can be done in one of the following ways:
-- first time cloning bowtie2 --
- git clone --recursive https://github.com/BenLangmead/bowtie2.git
-- existing checkout of bowtie2 --
- git submodule init && git submodule update
+- first time cloning bowtie2 --
+ git clone --recursive https://github.com/BenLangmead/bowtie2.git
+- existing checkout of bowtie2 --
+ git submodule init && git submodule update
Issue the following command line to build libsais:
-- with OpenMP support -- [g]make libsais USE_SAIS_OPENMP=1
-- without OpenMP support -- [g]make libsais USE_SAIS=1
+- with OpenMP support -- [g]make libsais USE_SAIS_OPENMP=1
+- without OpenMP support -- [g]make libsais USE_SAIS=1
The choice of using OpenMP will determine whether or not the algorithm
runs multithreaded. The [-p/--threads] argument to bowtie2-build will be
@@ -171,15 +171,15 @@ ignored when libsais is compiled without OpenMP support.
Finally, building the bowtie2-build executable:
-- with OpenMP support -- [g]make bowtie2-build-s USE_SAIS_OPENMP=1
-- without OpenMP support -- [g]make bowtie2-build-s USE_SAIS=1
+- with OpenMP support -- [g]make bowtie2-build-s USE_SAIS_OPENMP=1
+- without OpenMP support -- [g]make bowtie2-build-s USE_SAIS=1
Building with CMake
To build Bowtie2 with SRA and libsais support issue the following
command:
-- cmake . -D USE_SRA=1 -D USE_SAIS=1 && cmake --build .
+- cmake . -D USE_SRA=1 -D USE_SAIS=1 && cmake --build .
CMake will take care of building and linking against the specified
dependencies.
@@ -688,20 +688,20 @@ record for such a read, but no alignment will be reported and the YF:i
SAM optional field will be set to indicate the reason the read was
filtered.
-- YF:Z:LN: the read was filtered because it had length less than or
- equal to the number of seed mismatches set with the -N option.
-- YF:Z:NS: the read was filtered because it contains a number of
- ambiguous characters (usually N or .) greater than the ceiling
- specified with --n-ceil.
-- YF:Z:SC: the read was filtered because the read length and the match
- bonus (set with --ma) are such that the read can't possibly earn an
- alignment score greater than or equal to the threshold set with
- --score-min
-- YF:Z:QC: the read was filtered because it was marked as failing
- quality control and the user specified the --qc-filter option. This
- only happens when the input is in Illumina's QSEQ format (i.e. when
- --qseq is specified) and the last (11th) field of the read's QSEQ
- record contains 1.
+- YF:Z:LN: the read was filtered because it had length less than or
+ equal to the number of seed mismatches set with the -N option.
+- YF:Z:NS: the read was filtered because it contains a number of
+ ambiguous characters (usually N or .) greater than the ceiling
+ specified with --n-ceil.
+- YF:Z:SC: the read was filtered because the read length and the match
+ bonus (set with --ma) are such that the read can't possibly earn an
+ alignment score greater than or equal to the threshold set with
+ --score-min
+- YF:Z:QC: the read was filtered because it was marked as failing
+ quality control and the user specified the --qc-filter option. This
+ only happens when the input is in Illumina's QSEQ format (i.e. when
+ --qseq is specified) and the last (11th) field of the read's QSEQ
+ record contains 1.
If a read could be filtered for more than one reason, the value YF:Z
flag will reflect only one of those reasons.
@@ -1247,6 +1247,18 @@ offsets and searches for more alignments. A read is considered to have
repetitive seeds if the total number of seed hits divided by the number
of seeds that aligned at least once is greater than 300. Default: 2.
+ -d/--deterministic-seeds
+
+Consider all seeds in order (no subsampling). Can be used to augment -a
+or -k with deterministic behavior. This option significantly speeds up
+-a while also reducing memory consumption. It is not however always
+strictly better than standalone [-a] when considering the number of
+repeated alignments found.
+
+Note: In order to use this option exact upfront and 1mm upfront behavior
+have to be disabled using the following options: [--no-exact-upfront]
+and --no-1mm-upfront.
+
Paired-end options
-I/--minins <int>
=====================================
MANUAL.markdown
=====================================
@@ -1514,6 +1514,23 @@ searches for more alignments. A read is considered to have repetitive seeds if
the total number of seed hits divided by the number of seeds that aligned at
least once is greater than 300. Default: 2.
+</td></tr>
+<tr><td id="bowtie2-options-d">
+
+ -d/--deterministic-seeds
+
+</td><td>
+
+Consider all seeds in order (no subsampling). Can be used to augment
+[`-a`] or [`-k`] with deterministic behavior. This option
+significantly speeds up [`-a`] while also reducing memory consumption.
+It is not however always strictly better than standalone `[-a]` when
+considering the number of repeated alignments found.
+
+Note: In order to use this option exact upfront and 1mm upfront behavior
+have to be disabled using the following options: [`--no-exact-upfront`]
+and [`--no-1mm-upfront`].
+
</td></tr>
</table>
=====================================
Makefile
=====================================
@@ -59,6 +59,8 @@ endif
ifeq (1, $(WINDOWS))
BOWTIE_MM :=
BOWTIE_SHARED_MEM :=
+ # and no support for advanced vectorization either
+ SSE_AVX2 := 0
endif
MACOS :=
@@ -72,17 +74,21 @@ ifneq (,$(findstring Darwin,$(shell uname)))
endif
endif
+# do we have a 256-bit variant of the executable?
+ENABLE_V256 := 0
+
BITS := 32
ARCH ?= $(shell uname -m)
ifneq (,$(findstring $(ARCH), x86_64 amd64))
BITS := 64
- ifeq (1, $(SSE_AVX2))
- SSE_FLAG := -mavx2 -faligned-new -DSSE_AVX2
- else
- SSE_FLAG := -msse2
- endif
-
+ SSE_FLAG := -msse2
POPCNT_CAPABILITY ?= 1
+ ifneq (0, $(SSE_AVX2))
+ ENABLE_V256 := 1
+ V256_FLAG := -march=x86-64-v3 -mtune=znver3 -faligned-new -DSSE_AVX2 -DPOPCNT_CAPABILITY
+ # tell 128-bit version to check for v256 capability and use it, if found
+ SSE_FLAG += -DENABLE_x86_64_v3
+ endif
else ifneq (,$(findstring $(ARCH), aarch64 arm64 s390x powerpc64 powerpc64le ppc64 ppc64le))
BITS := 64
SSE_FLAG :=
@@ -229,29 +235,45 @@ else ifeq (0,$(shell $(CXX) -E -fsanitize=undefined btypes.h > /dev/null 2>&1; e
SANITIZER_FLAGS := -fsanitize=undefined
endif
-DEBUG_FLAGS := -O0 -g3 $(SSE_FLAG)
-RELEASE_FLAGS := -O3 $(SSE_FLAG) -funroll-loops -g3
+DEBUG_FLAGS := -O0 -g3
+RELEASE_FLAGS := -O3 -funroll-loops -g3
NOASSERT_FLAGS := -DNDEBUG
FILE_FLAGS := -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
DEBUG_DEFS = -DCOMPILER_OPTIONS="\"$(DEBUG_FLAGS) $(CXXFLAGS)\""
RELEASE_DEFS = -DCOMPILER_OPTIONS="\"$(RELEASE_FLAGS) $(CXXFLAGS)\""
-BOWTIE2_BIN_LIST := bowtie2-build-s \
+ifeq (1, $(ENABLE_V256))
+ V256_DEBUG_DEFS = -DCOMPILER_OPTIONS="\"$(DEBUG_FLAGS) $(CXXFLAGS) $(V256_FLAG)\""
+ V256_RELEASE_DEFS = -DCOMPILER_OPTIONS="\"$(RELEASE_FLAGS) $(CXXFLAGS) $(V256_FLAG)\""
+endif
+
+
+BOWTIE2_BIN_BOTH_LIST := bowtie2-build-s \
bowtie2-build-l \
bowtie2-align-s \
- bowtie2-align-l \
- bowtie2-inspect-s \
- bowtie2-inspect-l
-BOWTIE2_BIN_LIST_DBG := bowtie2-build-s-debug \
+ bowtie2-align-l
+BOWTIE2_BIN_BOTH_LIST_DBG := bowtie2-build-s-debug \
bowtie2-build-l-debug \
bowtie2-align-s-debug \
- bowtie2-align-l-debug \
- bowtie2-inspect-s-debug \
- bowtie2-inspect-l-debug
-BOWTIE2_BIN_LIST_SAN := bowtie2-build-s-sanitized \
+ bowtie2-align-l-debug
+BOWTIE2_BIN_BOTH_LIST_SAN := bowtie2-build-s-sanitized \
bowtie2-build-l-sanitized \
bowtie2-align-s-sanitized \
- bowtie2-align-l-sanitized \
+ bowtie2-align-l-sanitized
+
+ifeq (1, $(ENABLE_V256))
+ BOWTIE2_BIN_BOTH_LIST += bowtie2-align-s-v256 bowtie2-align-l-v256
+ BOWTIE2_BIN_BOTH_LIST_DBG += bowtie2-align-s-debug-v256 bowtie2-align-l-debug-v256
+ BOWTIE2_BIN_BOTH_LIST_SAN += bowtie2-align-s-sanitized-v256 bowtie2-align-l-sanitized-v256
+endif
+
+BOWTIE2_BIN_LIST := $(BOWTIE2_BIN_BOTH_LIST) \
+ bowtie2-inspect-s \
+ bowtie2-inspect-l
+BOWTIE2_BIN_LIST_DBG := $(BOWTIE2_BIN_BOTH_LIST_DBG) \
+ bowtie2-inspect-s-debug \
+ bowtie2-inspect-l-debug
+BOWTIE2_BIN_LIST_SAN := $(BOWTIE2_BIN_BOTH_LIST_SAN) \
bowtie2-inspect-s-sanitized \
bowtie2-inspect-l-sanitized
ifndef SANITIZER_FLAGS
@@ -309,9 +331,9 @@ endif
all: $(BOWTIE2_BIN_LIST) ;
allall: $(BOWTIE2_BIN_LIST) $(BOWTIE2_BIN_LIST_DBG) $(BOWTIE2_BIN_LIST_SAN) ;
-both: bowtie2-align-s bowtie2-build-s bowtie2-align-l bowtie2-build-l ;
-both-debug: bowtie2-align-s-debug bowtie2-build-s-debug bowtie2-align-l-debug bowtie2-build-l-debug ;
-both-sanitized: bowtie2-align-s-sanitized bowtie2-build-s-sanitized bowtie2-align-l-sanitized bowtie2-build-l-sanitized ;
+both: $(BOWTIE2_BIN_BOTH_LIST) ;
+both-debug: $(BOWTIE2_BIN_BOTH_LIST_DBG) ;
+both-sanitized: $(BOWTIE2_BIN_BOTH_LIST_SAN) ;
DEFS := -fno-strict-aliasing \
-DBOWTIE2_VERSION="\"`cat BOWTIE2_VERSION`\"" \
@@ -377,7 +399,7 @@ bowtie2-build-l-debug: bt2_build.cpp $(SHARED_CPPS) $(HEADERS)
bowtie2-align-s-sanitized bowtie2-align-s: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
$(CXX) $(RELEASE_FLAGS) $(RELEASE_DEFS) $(CXXFLAGS) \
$(DEFS) -DBOWTIE2 $(NOASSERT_FLAGS) \
- $(CPPFLAGS) \
+ $(CPPFLAGS) $(SSE_FLAG) \
-o $@ $< \
$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
$(LDFLAGS) $(LDLIBS)
@@ -385,7 +407,7 @@ bowtie2-align-s-sanitized bowtie2-align-s: bt2_search.cpp $(SEARCH_CPPS) $(SHARE
bowtie2-align-l-sanitized bowtie2-align-l: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
$(CXX) $(RELEASE_FLAGS) $(RELEASE_DEFS) $(CXXFLAGS) \
$(DEFS) -DBOWTIE2 -DBOWTIE_64BIT_INDEX $(NOASSERT_FLAGS) \
- $(CPPFLAGS) \
+ $(CPPFLAGS) $(SSE_FLAG) \
-o $@ $< \
$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
$(LDFLAGS) $(LDLIBS)
@@ -394,7 +416,7 @@ bowtie2-align-s-debug: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $
$(CXX) $(DEBUG_FLAGS) \
$(DEBUG_DEFS) $(CXXFLAGS) \
$(DEFS) -DBOWTIE2 \
- $(CPPFLAGS) \
+ $(CPPFLAGS) $(SSE_FLAG) \
-o $@ $< \
$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
$(LDFLAGS) $(LDLIBS)
@@ -403,11 +425,52 @@ bowtie2-align-l-debug: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $
$(CXX) $(DEBUG_FLAGS) \
$(DEBUG_DEFS) $(CXXFLAGS) \
$(DEFS) -DBOWTIE2 -DBOWTIE_64BIT_INDEX \
- $(CPPFLAGS) \
+ $(CPPFLAGS) $(SSE_FLAG) \
+ -o $@ $< \
+ $(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
+ $(LDFLAGS) $(LDLIBS)
+
+ifeq (1,$(ENABLE_V256))
+#
+# bowtie2-align v256 targets
+#
+
+bowtie2-align-s-sanitized-v256 bowtie2-align-s-v256: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
+ $(CXX) $(RELEASE_FLAGS) $(V256_RELEASE_DEFS) $(CXXFLAGS) \
+ $(DEFS) -DBOWTIE2 $(NOASSERT_FLAGS) \
+ $(CPPFLAGS) $(V256_FLAG) \
-o $@ $< \
$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
$(LDFLAGS) $(LDLIBS)
+bowtie2-align-l-sanitized-v256 bowtie2-align-l-v256: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
+ $(CXX) $(RELEASE_FLAGS) $(V256_RELEASE_DEFS) $(CXXFLAGS) \
+ $(DEFS) -DBOWTIE2 -DBOWTIE_64BIT_INDEX $(NOASSERT_FLAGS) \
+ $(CPPFLAGS) $(V256_FLAG) \
+ -o $@ $< \
+ $(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
+ $(LDFLAGS) $(LDLIBS)
+
+bowtie2-align-s-debug-v256: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
+ $(CXX) $(DEBUG_FLAGS) \
+ $(V256_DEBUG_DEFS) $(CXXFLAGS) \
+ $(DEFS) -DBOWTIE2 \
+ $(CPPFLAGS) $(V256_FLAG) \
+ -o $@ $< \
+ $(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
+ $(LDFLAGS) $(LDLIBS)
+
+bowtie2-align-l-debug-v256: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
+ $(CXX) $(DEBUG_FLAGS) \
+ $(V256_DEBUG_DEFS) $(CXXFLAGS) \
+ $(DEFS) -DBOWTIE2 -DBOWTIE_64BIT_INDEX \
+ $(CPPFLAGS) $(V256_FLAG) \
+ -o $@ $< \
+ $(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
+ $(LDFLAGS) $(LDLIBS)
+
+endif
+
#
# bowtie2-inspect targets
#
=====================================
NEWS
=====================================
@@ -18,6 +18,17 @@ Please report any issues to the Bowtie 2 Github page or using the Sourceforge bu
Version Release History
=======================
+## Version 2.5.5 - Feb 16, 2026 ##
+
+### bowtie2 ###
+ * Added `-d` command line option that makes `-a`/`-k`
+ deterministic in the way alignments are reported. This
+ deterministic mode runs much significantly faster than `-a` and
+ consumes less memory. It not yet strictly better than `-a` when
+ considering alignments found. (PR #520, 521)
+ * Add support for selecting AVX version at runtime on x86_64/amd64
+ CPUs. (PR #515)
+
## Version 2.5.4 - May 16, 2024 ##
=====================================
README.md
=====================================
@@ -2,7 +2,9 @@
<!-- badges: start -->


-[](https://shields.io/)
+[](https://shields.io/)
+[](https://usegalaxy.eu/root?tool_id=bowtie2)
+[](https://usegalaxy.org/root?tool_id=bowtie2)
<!-- [](https://travis-ci.org/BenLangmead/bowtie2) -->
[](https://www.gnu.org/licenses/gpl-3.0)
<!--badges: end -->
=====================================
aligner_seed.cpp
=====================================
@@ -600,6 +600,7 @@ void SeedAligner::searchAllSeeds(
const Ebwt* ebwtBw, // BWT' index
const Read& read, // read to align
const Scoring& pens, // scoring scheme
+ size_t ncut_f, // min seed quality for BWT
AlignmentCacheIface& cache, // local cache for seed alignments
SeedResults& sr, // holds all the seed hits
SeedSearchMetrics& met, // metrics
@@ -613,6 +614,7 @@ void SeedAligner::searchAllSeeds(
ebwtBw_ = ebwtBw;
sc_ = &pens;
read_ = &read;
+ ncut_f_ = ncut_f;
bwops_ = bwedits_ = 0;
uint64_t possearches = 0, seedsearches = 0, intrahits = 0, interhits = 0, ooms = 0;
@@ -1582,6 +1584,8 @@ SeedAligner::reportHit(
uint16_t len, // length of hit
DoublyLinkedList<Edit> *prevEdit) // previous edit
{
+ if ( (botf - topf) > ncut_f_) return; // low quality seed, just ignore
+
const BTDnaString& seq = cache.getSeq();
// Add information about the seed hit to AlignmentCache. This
=====================================
aligner_seed.h
=====================================
@@ -1688,6 +1688,7 @@ public:
const Ebwt* ebwtBw, // BWT' index
const Read& read, // read to align
const Scoring& pens, // scoring scheme
+ size_t ncut_f, // min seed quality for BWT
AlignmentCacheIface& cache, // local seed alignment cache
SeedResults& hits, // holds all the seed hits
SeedSearchMetrics& met, // metrics
@@ -1834,6 +1835,8 @@ protected:
const Read* read_; // read whose seeds are currently being aligned
+ size_t ncut_f_; // min seed quality for BWT
+
EList<Edit> edits_; // temporary place to sort edits
EList<uint32_t> offIdx2off_;// offset idx to read offset map, set up instantiateSeeds()
uint64_t bwops_; // Burrows-Wheeler operations
=====================================
aligner_seed2.h
=====================================
@@ -2158,7 +2158,7 @@ public:
for(size_t i = 0; i < sas_.size(); i++) {
size_t en = sink[i].botf - sink[i].topf;
sas_[i].init(sink[i].topf, EListSlice<TIndexOffU, 16>(offs_, ei, en));
- gws_[i].init(ebwtFw, ref, sas_[i], rnd, met);
+ gws_[i].init(ebwtFw, ref, sas_[i], met);
ei += en;
}
}
@@ -2509,7 +2509,7 @@ protected:
sas_.resize(1);
gws_.resize(1);
sas_[0].init(topf, EListSlice<TIndexOffU, 16>(offs_, 0, botf - topf));
- gws_[0].init(ebwtFw, ref, sas_[0], rnd, met);
+ gws_[0].init(ebwtFw, ref, sas_[0], met);
}
DescentPartialResolvedAlignmentSink palsink_;
=====================================
aligner_sw_driver.cpp
=====================================
@@ -68,6 +68,7 @@ bool SwDriver::eeSaTups(
SeedResults& sh, // seed hits to extend into full alignments
const Ebwt& ebwt, // BWT
const BitPairReference& ref, // Reference strings
+ bool deterministicSeeds, // Should I disable the random seed selection?
RandomSource& rnd, // pseudo-random generator
WalkMetrics& wlm, // group walk left metrics
SwMetrics& swmSeed, // metrics for seed extensions
@@ -88,6 +89,7 @@ bool SwDriver::eeSaTups(
nobj += sh.mm1EEHits().size();
nobj = min(nobj, maxelt);
gws_.ensure(nobj);
+ useCurrIdx = false;
rands_.ensure(nobj);
satpos_.ensure(nobj);
eehits_.ensure(nobj);
@@ -188,7 +190,6 @@ bool SwDriver::eeSaTups(
ebwt, // forward Bowtie index
ref, // reference sequences
sa, // SATuple
- rnd, // pseudo-random generator
wlm); // metrics
assert(gws_.back().repOk(sa));
nelt_out += width;
@@ -277,7 +278,6 @@ bool SwDriver::eeSaTups(
ebwt, // forward Bowtie index
ref, // reference sequences
sa, // SATuple
- rnd, // pseudo-random generator
wlm); // metrics
assert(gws_.back().repOk(sa));
nelt_out += width;
@@ -487,7 +487,9 @@ void SwDriver::extend(
* Given seed results, set up all of our state for resolving and keeping
* track of reference offsets for hits.
*/
-void SwDriver::prioritizeSATups(
+
+// non-deterministic, fill in rands_
+void SwDriver::prioritizeSATupsRands(
const Read& read, // read
SeedResults& sh, // seed hits to extend into full alignments
const Ebwt& ebwtFw, // BWT
@@ -510,6 +512,7 @@ void SwDriver::prioritizeSATups(
const int matei = (read.mate <= 1 ? 0 : 1);
satups_.clear();
gws_.clear();
+ useCurrIdx = false;
rands_.clear();
rands2_.clear();
satpos_.clear();
@@ -620,7 +623,6 @@ void SwDriver::prioritizeSATups(
ebwtFw, // forward Bowtie index
ref, // reference sequences
sa, // SA tuples: ref hit, salist range
- rnd, // pseudo-random generator
wlm); // metrics
assert(gws_.back().initialized());
rands_.expand();
@@ -665,7 +667,6 @@ void SwDriver::prioritizeSATups(
ebwtFw, // forward Bowtie index
ref, // reference sequences
sa, // SA tuples: ref hit, salist range
- rnd, // pseudo-random generator
wlm); // metrics
assert(gws_.back().initialized());
rands_.expand();
@@ -725,7 +726,6 @@ void SwDriver::prioritizeSATups(
ebwtFw, // forward Bowtie index
ref, // reference sequences
sa, // SA tuples: ref hit, salist range
- rnd, // pseudo-random generator
wlm); // metrics
assert(gws_.back().initialized());
// Initialize random selector
@@ -737,6 +737,172 @@ void SwDriver::prioritizeSATups(
return;
}
+// deterministic, use only a single gws element, will use just-in-time init later
+void SwDriver::prioritizeSATupsIdxs(
+ const Read& read, // read
+ SeedResults& sh, // seed hits to extend into full alignments
+ const Ebwt& ebwtFw, // BWT
+ const Ebwt* ebwtBw, // BWT
+ const BitPairReference& ref, // Reference strings
+ int seedmms, // # mismatches allowed in seed
+ size_t maxelt, // max elts we'll consider
+ bool doExtend, // do extension of seed hits?
+ AlignmentCacheIface& ca, // alignment cache for seed hits
+ WalkMetrics& wlm, // group walk left metrics
+ PerReadMetrics& prm, // per-read metrics
+ size_t& nelt_out) // out: # elements total
+{
+ const size_t nonz = sh.nonzeroOffsets(); // non-zero positions
+ const int matei = (read.mate <= 1 ? 0 : 1);
+ satups_.clear();
+ gws_.resize(1); // will use a single element in deterministic mode
+ useCurrIdx = true;
+ satpos_.clear();
+
+ size_t nrange = 0, nelt = 0;
+ for(size_t i = 0; i < nonz; i++) {
+ bool fw = true;
+ uint32_t offidx = 0, rdoff = 0, seedlen = 0;
+ QVal qv = sh.hitsByRank(i, offidx, rdoff, fw, seedlen);
+ assert(qv.valid());
+ assert(!qv.empty());
+ assert(qv.repOk(ca.current()));
+ ca.queryQval(qv, satups_, nrange, nelt);
+ for(size_t j = 0; j < satups_.size(); j++) {
+ const size_t sz = satups_[j].size();
+ // Check whether this hit occurs inside the extended boundaries of
+ // another hit we already processed for this read.
+ if(seedmms == 0) {
+ // See if we're covered by a previous extended seed hit
+ EList<ExtendRange>& range =
+ fw ? seedExRangeFw_[matei] : seedExRangeRc_[matei];
+ bool skip = false;
+ for(size_t k = 0; k < range.size(); k++) {
+ size_t p5 = range[k].off;
+ size_t len = range[k].len;
+ if(p5 <= rdoff && p5 + len >= (rdoff + seedlen)) {
+ if(sz <= range[k].sz) {
+ skip = true;
+ break;
+ }
+ }
+ }
+ if(skip) {
+ assert_gt(nrange, 0);
+ nrange--;
+ assert_geq(nelt, sz);
+ nelt -= sz;
+ continue; // Skip this seed
+ }
+ }
+ satpos_.expand();
+ SATupleAndPos& satpos = satpos_.back();
+ satpos.sat = satups_[j];
+ satpos.origSz = sz;
+ satpos.pos.init(fw, offidx, rdoff, seedlen);
+ satpos.nlex = satpos.nrex = 0;
+#ifndef NDEBUG
+ tmp_rdseq_.clear();
+ uint64_t key = satpos.sat.key.seq;
+ for(size_t k = 0; k < seedlen; k++) {
+ int c = (int)(key & 3);
+ tmp_rdseq_.append(c);
+ key >>= 2;
+ }
+ tmp_rdseq_.reverse();
+#endif
+ size_t nlex = 0, nrex = 0;
+ if(doExtend) {
+ extend(
+ read,
+ ebwtFw,
+ ebwtBw,
+ satpos.sat.topf,
+ (TIndexOffU)(satpos.sat.topf + sz),
+ satpos.sat.topb,
+ (TIndexOffU)(satpos.sat.topb + sz),
+ fw,
+ rdoff,
+ seedlen,
+ prm,
+ nlex,
+ nrex);
+ }
+ satpos.nlex = nlex;
+ satpos.nrex = nrex;
+ if(seedmms == 0 && (nlex > 0 || nrex > 0)) {
+ assert_geq(rdoff, (fw ? nlex : nrex));
+ size_t p5 = rdoff - (fw ? nlex : nrex);
+ EList<ExtendRange>& range =
+ fw ? seedExRangeFw_[matei] : seedExRangeRc_[matei];
+ range.expand();
+ range.back().off = p5;
+ range.back().len = seedlen + nlex + nrex;
+ range.back().sz = sz;
+ }
+ }
+ satups_.clear();
+ }
+ assert_eq(nrange, satpos_.size());
+ // sort satpos_, since we want to consider the high-quality (smaller size) seeds first
+ satpos_.sort();
+ gws_.ensure(nrange);
+
+ size_t nelt_added = 0;
+ // We may not want to keep all of the ranges
+ // so check if we hit max before we run of them
+ size_t sp_el = 0;
+ for(sp_el = 0; (sp_el < nrange) && (nelt_added < maxelt); sp_el++) {
+ const SATupleAndPos& satpos = satpos_[sp_el];
+ nelt_added += satpos.sat.size();
+#ifndef NDEBUG
+ for(size_t k = 0; k < sp_el; k++) {
+ assert(!(satpos_[k] == satpos_[sp_el]));
+ }
+#endif
+ }
+ if (sp_el < nrange) {
+ // did not use all elements, truncate
+ satpos_.resize(sp_el);
+ }
+
+ nelt_out = nelt_added;
+ return;
+}
+
+// just the selector
+void SwDriver::prioritizeSATups(
+ const Read& read, // read
+ SeedResults& sh, // seed hits to extend into full alignments
+ const Ebwt& ebwtFw, // BWT
+ const Ebwt* ebwtBw, // BWT
+ const BitPairReference& ref, // Reference strings
+ int seedmms, // # mismatches allowed in seed
+ size_t maxelt, // max elts we'll consider
+ bool doExtend, // do extension of seed hits?
+ bool deterministicSeeds, // Should I disable the random seed selection?
+ bool lensq, // square length in weight calculation
+ bool szsq, // square range size in weight calculation
+ size_t nsm, // if range as <= nsm elts, it's "small"
+ AlignmentCacheIface& ca, // alignment cache for seed hits
+ RandomSource& rnd, // pseudo-random generator
+ WalkMetrics& wlm, // group walk left metrics
+ PerReadMetrics& prm, // per-read metrics
+ size_t& nelt_out, // out: # elements total
+ bool all) // report all hits?
+{
+ if (deterministicSeeds) {
+ prioritizeSATupsIdxs(read, sh, ebwtFw, ebwtBw, ref,
+ seedmms, maxelt, doExtend,
+ ca, wlm, prm, nelt_out);
+ } else {
+ prioritizeSATupsRands(read, sh, ebwtFw, ebwtBw, ref,
+ seedmms, maxelt, doExtend, lensq, szsq, nsm,
+ ca, rnd, wlm, prm, nelt_out, all);
+ }
+ return;
+}
+
enum {
FOUND_NONE = 0,
FOUND_EE,
@@ -780,6 +946,7 @@ int SwDriver::extendSeeds(
size_t cpow2, // interval between diagonals to checkpoint
bool doTri, // triangular mini-fills?
int tighten, // -M score tightening mode
+ bool deterministicSeeds, // Should I disable the random seed selection?
AlignmentCacheIface& ca, // alignment cache for seed hits
RandomSource& rnd, // pseudo-random source
WalkMetrics& wlm, // group walk left metrics
@@ -831,13 +998,14 @@ int SwDriver::extendSeeds(
sh, // seed hits to extend into full alignments
ebwtFw, // BWT
ref, // Reference strings
+ deterministicSeeds, // Should I disable the random seed selection?
rnd, // pseudo-random generator
wlm, // group walk left metrics
swmSeed, // seed-extend metrics
nelt, // out: # elements total
maxIters, // max # to report
all); // report all hits?
- assert_eq(gws_.size(), rands_.size());
+ assert_eq(satpos_.size(), rands_.size());
assert_eq(gws_.size(), satpos_.size());
} else {
eeMode = false;
@@ -861,6 +1029,7 @@ int SwDriver::extendSeeds(
seedmms, // # seed mismatches allowed
maxIters, // max rows to consider per position
doExtend, // extend out seeds
+ deterministicSeeds, // Should I disable the random seed selection?
true, // square extended length
true, // square SA range size
nsm, // smallness threshold
@@ -870,8 +1039,10 @@ int SwDriver::extendSeeds(
prm, // per-read metrics
nelt, // out: # elements total
all); // report all hits?
- assert_eq(gws_.size(), rands_.size());
- assert_eq(gws_.size(), satpos_.size());
+ if (!useCurrIdx) {
+ assert_eq(satpos_.size(), rands_.size());
+ assert_eq(gws_.size(), satpos_.size());
+ }
neltLeft = nelt;
firstExtend = false;
}
@@ -880,33 +1051,57 @@ int SwDriver::extendSeeds(
break;
}
}
- for(size_t i = 0; i < gws_.size(); i++) {
+ const size_t maxi = satpos_.size();
+ for(size_t i = 0; i < maxi; i++) {
if(eeMode && eehits_[i].score < minsc) {
return EXTEND_PERFECT_SCORE;
}
- bool is_small = satpos_[i].sat.size() < nsm;
- bool fw = satpos_[i].pos.fw;
- uint32_t rdoff = satpos_[i].pos.rdoff;
- uint32_t seedhitlen = satpos_[i].pos.seedlen;
+ // In deterministic mode, we can reuse the same gws_ element
+ GroupWalk2S<TSlice, 16> &gws = gws_[useCurrIdx? 0 : i];
+
+ const SATupleAndPos& satpos = satpos_[i];
+ const size_t sat_size = satpos.sat.size();
+ // when we are not subsampling(useCurrIdx), treat them all as if they were small
+ const bool is_small = useCurrIdx ? true : (sat_size < nsm);
+ const bool fw = satpos.pos.fw;
+ uint32_t rdoff = satpos.pos.rdoff;
+ uint32_t seedhitlen = satpos.pos.seedlen;
if(!fw) {
// 'rdoff' and 'offidx' are with respect to the 5' end of
// the read. Here we convert rdoff to be with respect to
// the upstream (3') end of ther read.
rdoff = (uint32_t)(rdlen - rdoff - seedhitlen);
}
+ if (useCurrIdx) {
+ // since we are reusing the same element, just-in-time initialization
+ SARangeWithOffs<TSlice> sa;
+ sa.topf = satpos.sat.topf;
+ sa.len = satpos.sat.key.len;
+ sa.offs = satpos.sat.offs;
+ gws.reset();
+ gws.init(
+ ebwtFw, // forward Bowtie index
+ ref, // reference sequences
+ sa, // SA tuples: ref hit, salist range
+ wlm); // metrics
+ assert(gws.initialized());
+ }
bool first = true;
+ size_t currIdx = 0; // only used when useCurrIdx==true
// If the range is small, investigate all elements now. If the
// range is large, just investigate one and move on - we might come
// back to this range later.
size_t riter = 0;
- while(!rands_[i].done() && (first || is_small || eeMode)) {
- assert(!gws_[i].done());
+ while( (useCurrIdx? (currIdx<sat_size) : (!rands_[i].done()) ) &&
+ (first || is_small || eeMode) ) {
+ assert(!gws.done());
riter++;
if(minsc == perfectScore) {
if(!eeMode || eehits_[i].score < perfectScore) {
return EXTEND_PERFECT_SCORE;
}
} else if(eeMode && eehits_[i].score < minsc) {
+ assert(!useCurrIdx);
break;
}
if(prm.nExDps >= maxDp || prm.nMateDps >= maxDp) {
@@ -922,13 +1117,14 @@ int SwDriver::extendSeeds(
first = false;
// Resolve next element offset
WalkResult wr;
- size_t elt = rands_[i].next(rnd);
+ // auto-increment after use
+ size_t elt = useCurrIdx ? (currIdx++) : rands_[i].next(rnd);
//cerr << "elt=" << elt << endl;
SARangeWithOffs<TSlice> sa;
- sa.topf = satpos_[i].sat.topf;
- sa.len = satpos_[i].sat.key.len;
- sa.offs = satpos_[i].sat.offs;
- gws_[i].advanceElement((TIndexOffU)elt, ebwtFw, ref, sa, gwstate_, wr, wlm, prm);
+ sa.topf = satpos.sat.topf;
+ sa.len = satpos.sat.key.len;
+ sa.offs = satpos.sat.offs;
+ gws.advanceElement((TIndexOffU)elt, ebwtFw, ref, sa, gwstate_, wr, wlm, prm);
eltsDone++;
if(!eeMode) {
assert_gt(neltLeft, 0);
@@ -952,7 +1148,7 @@ int SwDriver::extendSeeds(
}
#ifndef NDEBUG
if(!eeMode && !straddled) { // Check that seed hit matches reference
- uint64_t key = satpos_[i].sat.key.seq;
+ uint64_t key = satpos.sat.key.seq;
for(size_t k = 0; k < wr.elt.len; k++) {
int c = ref.getBase(tidx, toff + wr.elt.len - k - 1);
assert_leq(c, 3);
@@ -1289,8 +1485,10 @@ int SwDriver::extendSeeds(
// At this point we know that we aren't bailing, and will
// continue to resolve seed hits.
- } // while(!gws_[i].done())
- }
+ } // while(!gws.done())
+ } // for maxi
+
+ if (useCurrIdx) break; // always one-pass, when using useCurrIdx
}
// Short-circuited because a limit, e.g. -k, -m or -M, was exceeded
return EXTEND_EXHAUSTED_CANDIDATES;
@@ -1419,6 +1617,7 @@ int SwDriver::extendSeedsPaired(
size_t cpow2, // interval between diagonals to checkpoint
bool doTri, // triangular mini-fills?
int tighten, // -M score tightening mode
+ bool deterministicSeeds, // Should I disable the random seed selection?
AlignmentCacheIface& ca, // alignment cache for seed hits
RandomSource& rnd, // pseudo-random source
WalkMetrics& wlm, // group walk left metrics
@@ -1511,18 +1710,19 @@ int SwDriver::extendSeedsPaired(
sh, // seed hits to extend into full alignments
ebwtFw, // BWT
ref, // Reference strings
+ deterministicSeeds, // Should I disable the random seed selection?
rnd, // pseudo-random generator
wlm, // group walk left metrics
swmSeed, // seed-extend metrics
nelt, // out: # elements total
maxIters, // max elts to report
all); // report all hits
- assert_eq(gws_.size(), rands_.size());
+ assert_eq(satpos_.size(), rands_.size());
assert_eq(gws_.size(), satpos_.size());
neltLeft = nelt;
// Initialize list that contains the mate-finding failure
// streak for each range
- mateStreaks_.resize(gws_.size());
+ mateStreaks_.resize(satpos_.size());
mateStreaks_.fill(0);
} else {
eeMode = false;
@@ -1548,6 +1748,7 @@ int SwDriver::extendSeedsPaired(
seedmms, // # seed mismatches allowed
maxIters, // max rows to consider per position
doExtend, // extend out seeds
+ deterministicSeeds, // Should I disable the random seed selection?
true, // square extended length
true, // square SA range size
nsm, // smallness threshold
@@ -1557,11 +1758,13 @@ int SwDriver::extendSeedsPaired(
prm, // per-read metrics
nelt, // out: # elements total
all); // report all hits?
- assert_eq(gws_.size(), rands_.size());
- assert_eq(gws_.size(), satpos_.size());
+ if (!useCurrIdx) {
+ assert_eq(satpos_.size(), rands_.size());
+ assert_eq(gws_.size(), satpos_.size());
+ }
neltLeft = nelt;
firstExtend = false;
- mateStreaks_.resize(gws_.size());
+ mateStreaks_.resize(satpos_.size());
mateStreaks_.fill(0);
}
if(neltLeft == 0) {
@@ -1569,30 +1772,55 @@ int SwDriver::extendSeedsPaired(
break;
}
}
- for(size_t i = 0; i < gws_.size(); i++) {
+ const size_t maxi = satpos_.size();
+ for(size_t i = 0; i < maxi; i++) {
if(eeMode && eehits_[i].score < minsc) {
return EXTEND_PERFECT_SCORE;
}
- bool is_small = satpos_[i].sat.size() < nsm;
- bool fw = satpos_[i].pos.fw;
- uint32_t rdoff = satpos_[i].pos.rdoff;
- uint32_t seedhitlen = satpos_[i].pos.seedlen;
+ // In deterministic mode, we can reuse the same gws_ element
+ GroupWalk2S<TSlice, 16> &gws = gws_[useCurrIdx? 0 : i];
+
+ const SATupleAndPos& satpos = satpos_[i];
+ const size_t sat_size = satpos.sat.size();
+ // when we are not subsampling(useCurrIdx), treat them all as if they were small
+ const bool is_small = useCurrIdx ? true : (sat_size < nsm);
+ const bool fw = satpos.pos.fw;
+ uint32_t rdoff = satpos.pos.rdoff;
+ uint32_t seedhitlen = satpos.pos.seedlen;
if(!fw) {
// 'rdoff' and 'offidx' are with respect to the 5' end of
// the read. Here we convert rdoff to be with respect to
// the upstream (3') end of ther read.
rdoff = (uint32_t)(rdlen - rdoff - seedhitlen);
}
+ if (useCurrIdx) {
+ // since we are reusing the same element, just-in-time initialization
+ SARangeWithOffs<TSlice> sa;
+ sa.topf = satpos.sat.topf;
+ sa.len = satpos.sat.key.len;
+ sa.offs = satpos.sat.offs;
+ gws.reset();
+ gws.init(
+ ebwtFw, // forward Bowtie index
+ ref, // reference sequences
+ sa, // SA tuples: ref hit, salist range
+ wlm); // metrics
+ assert(gws.initialized());
+ }
bool first = true;
+ size_t currIdx = 0; // only used when useCurrIdx==true
// If the range is small, investigate all elements now. If the
// range is large, just investigate one and move on - we might come
// back to this range later.
- while(!rands_[i].done() && (first || is_small || eeMode)) {
+ size_t riter = 0;
+ while( (useCurrIdx? (currIdx<sat_size) : (!rands_[i].done()) ) &&
+ (first || is_small || eeMode) ) {
if(minsc == perfectScore) {
if(!eeMode || eehits_[i].score < perfectScore) {
return EXTEND_PERFECT_SCORE;
}
} else if(eeMode && eehits_[i].score < minsc) {
+ assert(!useCurrIdx);
break;
}
if(prm.nExDps >= maxDp || prm.nMateDps >= maxDp) {
@@ -1615,21 +1843,26 @@ int SwDriver::extendSeedsPaired(
}
if(mateStreaks_[i] >= maxMateStreak) {
// Don't try this seed range anymore
- rands_[i].setDone();
- assert(rands_[i].done());
+ if (useCurrIdx) {
+ currIdx = sat_size;
+ } else {
+ rands_[i].setDone();
+ assert(rands_[i].done());
+ }
break;
}
prm.nExIters++;
first = false;
- assert(!gws_[i].done());
+ assert(!gws.done());
// Resolve next element offset
WalkResult wr;
- size_t elt = rands_[i].next(rnd);
+ // auto-increment after use
+ size_t elt = useCurrIdx ? (currIdx++) : rands_[i].next(rnd);
SARangeWithOffs<TSlice> sa;
- sa.topf = satpos_[i].sat.topf;
- sa.len = satpos_[i].sat.key.len;
- sa.offs = satpos_[i].sat.offs;
- gws_[i].advanceElement((TIndexOffU)elt, ebwtFw, ref, sa, gwstate_, wr, wlm, prm);
+ sa.topf = satpos.sat.topf;
+ sa.len = satpos.sat.key.len;
+ sa.offs = satpos.sat.offs;
+ gws.advanceElement((TIndexOffU)elt, ebwtFw, ref, sa, gwstate_, wr, wlm, prm);
eltsDone++;
assert_gt(neltLeft, 0);
neltLeft--;
@@ -1651,7 +1884,7 @@ int SwDriver::extendSeedsPaired(
}
#ifndef NDEBUG
if(!eeMode && !straddled) { // Check that seed hit matches reference
- uint64_t key = satpos_[i].sat.key.seq;
+ uint64_t key = satpos.sat.key.seq;
for(size_t k = 0; k < wr.elt.len; k++) {
int c = ref.getBase(tidx, toff + wr.elt.len - k - 1);
assert_leq(c, 3);
@@ -2396,7 +2629,9 @@ int SwDriver::extendSeedsPaired(
// At this point we know that we aren't bailing, and will continue to resolve seed hits.
} // while(!gw.done())
- } // for(size_t i = 0; i < gws_.size(); i++)
+ } // for(size_t i = 0; i < maxi; i++)
+
+ if (useCurrIdx) break; // always one-pass, when using useCurrIdx
}
return EXTEND_EXHAUSTED_CANDIDATES;
}
=====================================
aligner_sw_driver.h
=====================================
@@ -346,6 +346,7 @@ public:
size_t cpow2, // interval between diagonals to checkpoint
bool doTri, // triangular mini-fills
int tighten, // -M score tightening mode
+ bool deterministicSeeds, // Should I disable the random seed selection?
AlignmentCacheIface& ca, // alignment cache for seed hits
RandomSource& rnd, // pseudo-random source
WalkMetrics& wlm, // group walk left metrics
@@ -403,6 +404,7 @@ public:
size_t cpow2, // interval between diagonals to checkpoint
bool doTri, // triangular mini-fills
int tighten, // -M score tightening mode
+ bool deterministicSeeds, // Should I disable the random seed selection?
AlignmentCacheIface& cs, // alignment cache for seed hits
RandomSource& rnd, // pseudo-random source
WalkMetrics& wlm, // group walk left metrics
@@ -447,6 +449,7 @@ protected:
SeedResults& sh, // seed hits to extend into full alignments
const Ebwt& ebwt, // BWT
const BitPairReference& ref, // Reference strings
+ bool deterministicSeeds, // Should I disable the random seed selection?
RandomSource& rnd, // pseudo-random generator
WalkMetrics& wlm, // group walk left metrics
SwMetrics& swmSeed, // metrics for seed extensions
@@ -478,6 +481,7 @@ protected:
int seedmms, // # seed mismatches allowed
size_t maxelt, // max elts we'll consider
bool doExtend, // extend out seeds
+ bool deterministicSeeds, // Should I disable the random seed selection?
bool lensq, // square extended length
bool szsq, // square SA range size
size_t nsm, // if range as <= nsm elts, it's "small"
@@ -488,9 +492,45 @@ protected:
size_t& nelt_out, // out: # elements total
bool all); // report all hits?
+ void prioritizeSATupsRands(
+ const Read& rd, // read
+ SeedResults& sh, // seed hits to extend into full alignments
+ const Ebwt& ebwtFw, // BWT
+ const Ebwt* ebwtBw, // BWT'
+ const BitPairReference& ref, // Reference strings
+ int seedmms, // # seed mismatches allowed
+ size_t maxelt, // max elts we'll consider
+ bool doExtend, // extend out seeds
+ bool lensq, // square extended length
+ bool szsq, // square SA range size
+ size_t nsm, // if range as <= nsm elts, it's "small"
+ AlignmentCacheIface& ca, // alignment cache for seed hits
+ RandomSource& rnd, // pseudo-random generator
+ WalkMetrics& wlm, // group walk left metrics
+ PerReadMetrics& prm, // per-read metrics
+ size_t& nelt_out, // out: # elements total
+ bool all); // report all hits?
+
+ void prioritizeSATupsIdxs(
+ const Read& rd, // read
+ SeedResults& sh, // seed hits to extend into full alignments
+ const Ebwt& ebwtFw, // BWT
+ const Ebwt* ebwtBw, // BWT'
+ const BitPairReference& ref, // Reference strings
+ int seedmms, // # seed mismatches allowed
+ size_t maxelt, // max elts we'll consider
+ bool doExtend, // extend out seeds
+ AlignmentCacheIface& ca, // alignment cache for seed hits
+ WalkMetrics& wlm, // group walk left metrics
+ PerReadMetrics& prm, // per-read metrics
+ size_t& nelt_out); // out: # elements total
+
Random1toN rand_; // random number generators
- EList<Random1toN, 16> rands_; // random number generators
- EList<Random1toN, 16> rands2_; // random number generators
+
+ bool useCurrIdx; // use currIdx if true, rands_ else
+ EList<Random1toN, 16> rands_; // random number generators (needed when non-deterministic)
+
+ EList<Random1toN, 16> rands2_; // random number generators, internal temp
EList<EEHit, 16> eehits_; // holds end-to-end hits
EList<SATupleAndPos, 16> satpos_; // holds SATuple, SeedPos pairs
EList<SATupleAndPos, 16> satpos2_; // holds SATuple, SeedPos pairs
=====================================
aln_sink.h
=====================================
@@ -858,6 +858,10 @@ public:
return oq_;
}
+ /**
+ * Now many possible reference names do we handle
+ */
+ size_t num_refnames() const { return refnames_.size();}
protected:
OutputQueue& oq_; // output queue
=====================================
bowtie2-build
=====================================
@@ -25,6 +25,7 @@ import gzip
import inspect
import logging
import argparse
+import platform
import subprocess
@@ -115,6 +116,9 @@ def main():
if tot_size > small_index_max_size:
build_bin_spec = os.path.join(ex_path, build_bin_l)
+ if "Windows" in platform.platform():
+ build_bin_spec += '.exe'
+
if not os.path.exists(build_bin_spec):
sys.stderr.write(
"{0} does not exist, try running `[g]make {0}'\n".format(
=====================================
bowtie2-inspect
=====================================
@@ -26,6 +26,7 @@ import inspect
import logging
import argparse
import subprocess
+import platform
from collections import deque
def main():
@@ -61,7 +62,7 @@ def main():
inspect_bin_l += '-debug'
if script_options.sanitized:
- inpsect_bin_spec += '-sanitized'
+ inspect_bin_spec += '-sanitized'
inspect_bin_l += '-sanitized'
if script_options.large_index:
@@ -73,6 +74,9 @@ def main():
if large_idx_exists and not small_idx_exists:
inspect_bin_spec = os.path.join(ex_path,inspect_bin_l)
+ if "Windows" in platform.platform():
+ inspect_bin_spec += '.exe'
+
argv.appendleft('basic-0')
argv.appendleft('--wrapper')
argv.appendleft(inspect_bin_spec)
=====================================
bowtie_main.cpp
=====================================
@@ -24,12 +24,38 @@
#include "tokenize.h"
#include "ds.h"
+#ifdef ENABLE_x86_64_v3
+#include <unistd.h>
+#endif
+
using namespace std;
extern "C" {
int bowtie(int argc, const char **argv);
}
+#ifdef ENABLE_x86_64_v3
+void check_x86_64_v3(int argc, const char **argv) {
+ if (__builtin_cpu_supports ("x86-64-v3") && (argc<126)) {
+ const char* new_argv[128]; // should always be enough, but above check enforces it, too
+ const char * org_path = argv[0];
+ // Append -v256 to the original path
+ const int fn_len = strlen(org_path);
+ char *new_path = (char*) malloc(fn_len+16);
+ memcpy(new_path,org_path,fn_len);
+ strncpy(new_path+fn_len,"-v256",15);
+
+ for (int i=1; i<=argc; i++) new_argv[i] = argv[i]; // all but first the same, also copy final NULL
+ new_argv[0] = new_path;
+ // now replace the executable with new variant
+ // assuming the executable exists... execvp will gracefully fail else, which is OK
+ execvp(new_argv[0], (char *const *)new_argv);
+ // we should never get out of the above call
+ fprintf(stderr,"[WARNING] Failed to launch x86-64-v3 version, staying with default\n");
+ }
+}
+#endif
+
/**
* Bowtie main function. It is placed in a separate source file to
* make it slightly easier to compile Bowtie as a library.
@@ -40,6 +66,9 @@ extern "C" {
* bowtie.
*/
int main(int argc, const char **argv) {
+#ifdef ENABLE_x86_64_v3
+ check_x86_64_v3(argc, argv);
+#endif
if(argc > 2 && strcmp(argv[1], "-A") == 0) {
const char *file = argv[2];
ifstream in;
=====================================
bt2_search.cpp
=====================================
@@ -1,3 +1,4 @@
+
/*
* Copyright 2011, Ben Langmead <langmea at cs.jhu.edu>
*
@@ -85,6 +86,7 @@ static string metricsFile;// output file to put alignment metrics in
static bool metricsStderr;// output file to put alignment metrics in
static bool metricsPerRead; // report a metrics tuple for every read
static bool allHits; // for multihits, report just one
+static bool deterministicSeeds; // for low quality seeds, enable subsampling
static bool showVersion; // just print version and quit?
static int ipause; // pause before maching?
static uint64_t qUpto; // max # of queries to read
@@ -101,6 +103,8 @@ static string thread_stealing_dir; // keep track of pids in this directory
static bool thread_stealing;// true iff thread stealing is in use
static int outType; // style of output
static bool noRefNames; // true -> print reference indexes; not names
+static uint32_t lowseeds; // size of seed range above which a seed is considered low quality, and thus discarded (0 disables the cut)
+static uint32_t lowseedsDivider; // how much should I divide the lowseeds parameter by, if 0 use abs value
static uint32_t khits; // number of hits per read; >1 is much slower
static uint32_t mhits; // don't report any hits if there are > mhits
static int partitionSz; // output a partitioning key in first field
@@ -278,6 +282,24 @@ static void set_format(int ¤t_format, file_format format) {
}
}
+int set_default_thread_count() {
+ int num_threads = 1;
+ const char *omp_num_threads = NULL;
+ if ((omp_num_threads = getenv("OMP_NUM_THREADS")) != NULL) {
+ try {
+ num_threads = std::stoi(omp_num_threads);
+ } catch (std::invalid_argument const &ex) {
+ std::cerr << "Error: " << ex.what() << std::endl;
+ exit(EXIT_FAILURE);
+ } catch (std::out_of_range const &ex) {
+ std::cerr << "Error: " << ex.what() << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ return num_threads;
+}
+
static void resetOptions() {
mates1.clear();
mates2.clear();
@@ -297,6 +319,7 @@ static void resetOptions() {
metricsStderr = false; // print metrics to stderr (in addition to --metrics-file if it's specified
metricsPerRead = false; // report a metrics tuple for every read?
allHits = false; // for multihits, report just one
+ deterministicSeeds = false; // for low quality seeds, enable subsampling
showVersion = false; // just print version and quit?
ipause = 0; // pause before maching?
qUpto = 0xffffffffffffffff; // max # of queries to read
@@ -307,13 +330,15 @@ static void resetOptions() {
solexaQuals = false; // quality strings are solexa quals, not phred, and subtract 64 (not 33)
phred64Quals = false; // quality chars are phred, but must subtract 64 (not 33)
integerQuals = false; // quality strings are space-separated strings of integers, not ASCII
- nthreads = 1; // number of pthreads operating concurrently
+ nthreads = set_default_thread_count(); // number of pthreads operating concurrently
thread_ceiling = 0; // max # threads user asked for
thread_stealing_dir = ""; // keep track of pids in this directory
thread_stealing = false; // true iff thread stealing is in use
FNAME_SIZE = 4096;
outType = OUTPUT_SAM; // style of output
noRefNames = false; // true -> print reference indexes; not names
+ lowseeds = 0; // size of seed range above which a seed is considered low quality, and thus discarded (0 disables the cut)
+ lowseedsDivider = 0; // how much should I divide the lowseeds parameter by, if 0 use the abs value
khits = 1; // number of hits per read; >1 is much slower
mhits = 50; // stop after finding this many alignments+1
partitionSz = 0; // output a partitioning key in first field
@@ -476,7 +501,7 @@ static void resetOptions() {
#endif
}
-static const char *short_options = "bfF:qbzhcu:rv:s:aP:t3:5:w:p:k:M:1:2:I:X:CQ:N:i:L:U:x:S:g:O:D:R:";
+static const char *short_options = "bfF:qbzhcu:rv:s:adP:t3:5:w:p:k:l:M:1:2:I:X:CQ:N:i:L:U:x:S:g:O:D:R:";
static struct option long_options[] = {
{(char*)"verbose", no_argument, 0, ARG_VERBOSE},
@@ -509,6 +534,7 @@ static struct option long_options[] = {
{(char*)"help", no_argument, 0, 'h'},
{(char*)"threads", required_argument, 0, 'p'},
{(char*)"khits", required_argument, 0, 'k'},
+ {(char*)"lowseeds", required_argument, 0, 'l'},
{(char*)"minins", required_argument, 0, 'I'},
{(char*)"maxins", required_argument, 0, 'X'},
{(char*)"quals", required_argument, 0, 'Q'},
@@ -626,6 +652,8 @@ static struct option long_options[] = {
{(char*)"no-exact-upfront", no_argument, 0, ARG_EXACT_UPFRONT_NO},
{(char*)"no-1mm-upfront", no_argument, 0, ARG_1MM_UPFRONT_NO},
{(char*)"1mm-minlen", required_argument, 0, ARG_1MM_MINLEN},
+ {(char*)"deterministic-seeds", no_argument, 0, 'd'},
+ {(char*)"no-deterministic-seeds", no_argument, 0, ARG_DET_SEEDS_NO},
{(char*)"seed-off", required_argument, 0, 'O'},
{(char*)"seed-boost", required_argument, 0, ARG_SEED_BOOST_THRESH},
{(char*)"read-times", no_argument, 0, ARG_READ_TIMES},
@@ -824,11 +852,15 @@ static void printUsage(ostream& out) {
<< " OR" << endl
<< " -k <int> report up to <int> alns per read; MAPQ not meaningful" << endl
<< " OR" << endl
- << " -a/--all report all alignments; very slow, MAPQ not meaningful" << endl
+ << " -a/--all report all alignments; very slow without -l, MAPQ not meaningful" << endl
<< endl
<< " Effort:" << endl
+ << " -l/--lowseeds <n> ignore any low quality seeds with ranges over threshold" << endl
+ << " (0=no cut, if percentage, mili or nano, relative to idx size)" << endl
<< " -D <int> give up extending after <int> failed extends in a row (15)" << endl
<< " -R <int> for reads w/ repetitive seeds, try <int> sets of seeds (2)" << endl
+ << " -d/--deterministic-seeds" << endl
+ << " Consider all seeds in order (no subsampling, best with -a)" << endl
<< endl
<< " Paired-end:" << endl
<< " -I/--minins <int> minimum fragment length (0)" << endl
@@ -952,6 +984,19 @@ T parse(const char *s) {
return tmp;
}
+/**
+ * Parse a T string 'str',
+ * provide first char after the parse (\0 if all string consumed)
+ */
+template<typename T>
+T parse(const char *s, char &remainder) {
+ T tmp;
+ stringstream ss(s);
+ ss >> tmp;
+ ss >> remainder;
+ return tmp;
+}
+
/**
* Parse a pair of Ts from a string, 'str', delimited with 'delim'.
*/
@@ -1286,6 +1331,30 @@ static void parseOption(int next_option, const char *arg) {
saw_k = true;
break;
}
+ case 'l': {
+ char remainder = 0;
+ lowseedsDivider = 0;
+ lowseeds = parse<size_t>(arg, remainder);
+ if (remainder=='%') {
+ // User requested percentage of DB
+ lowseedsDivider = 100;
+ } else if (remainder=='m') {
+ // User requested mili of DB
+ lowseedsDivider = 1000;
+ } else if (remainder=='n') {
+ // User requested nano of DB
+ lowseedsDivider = 1000000;
+ } else if (remainder==0) {
+ // We got an absolute value
+ lowseedsDivider = 0;
+ } else {
+ cerr << "Warning: -l argument had training chars "
+ << "that were not parsed" << endl;
+ }
+ break;
+ }
+ case 'd': deterministicSeeds = true; break;
+ case ARG_DET_SEEDS_NO: deterministicSeeds = false; break;
case ARG_VERBOSE: gVerbose = 1; break;
case ARG_STARTVERBOSE: startVerbose = true; break;
case ARG_QUIET: gQuiet = true; break;
@@ -1706,6 +1775,16 @@ static void parseOptions(int argc, const char **argv) {
assert_gt(mhits, 0);
msample = true;
}
+ if (deterministicSeeds) {
+ if ( doExactUpFront || do1mmUpFront || (mhits!=0) ) {
+ cerr << "Warning: -d cannot be used with --exact-upfront, --1mm-upfront or -m." << endl;
+ throw 1;
+ }
+ if ( !allHits ) {
+ cerr << "Error: -d can only be used with -a." << endl;
+ throw 1;
+ }
+ }
if (format == UNKNOWN)
set_format(format, FASTQ);
if(mates1.size() != mates2.size()) {
@@ -1714,7 +1793,7 @@ static void parseOptions(int argc, const char **argv) {
<< "sequences must be specified with -1 and -2." << endl;
throw 1;
}
- if(interleaved && (format != FASTA && format != FASTQ)) {
+ if(interleaved && (format != FASTA && format != FASTQ && format != BAM)) {
cerr << "Error: --interleaved only works in combination with FASTA (-f) and FASTQ (-q) formats." << endl;
throw 1;
}
@@ -3022,6 +3101,12 @@ static void multiseedSearchWorker(void *vp) {
AlnSink& msink = *multiseed_msink;
OutFileBuf* metricsOfb = multiseed_metricsOfb;
+ const size_t lowseeds_ncut = (lowseeds>0) ?
+ ((lowseedsDivider!=0) ? ((msink.num_refnames() * lowseeds + (lowseedsDivider-1))/lowseedsDivider) // round up, avoid 0
+ : lowseeds
+ ) :
+ std::numeric_limits<size_t>::max(); // never filter by size
+
{
#ifdef PER_THREAD_TIMING
uint64_t ncpu_changeovers = 0;
@@ -3505,6 +3590,7 @@ static void multiseedSearchWorker(void *vp) {
cpow2, // checkpointer interval, log2
doTri, // triangular mini-fills?
tighten, // -M score tightening mode
+ deterministicSeeds, // Should I disable the random seed selection?
ca, // seed alignment cache
rnd, // pseudo-random source
wlm, // group walk left metrics
@@ -3547,6 +3633,7 @@ static void multiseedSearchWorker(void *vp) {
cpow2, // checkpointer interval, log2
doTri, // triangular mini-fills
tighten, // -M score tightening mode
+ deterministicSeeds, // Should I disable the random seed selection?
ca, // seed alignment cache
rnd, // pseudo-random source
wlm, // group walk left metrics
@@ -3687,6 +3774,7 @@ static void multiseedSearchWorker(void *vp) {
cpow2, // checkpointer interval, log2
doTri, // triangular mini-fills?
tighten, // -M score tightening mode
+ deterministicSeeds, // Should I disable the random seed selection?
ca, // seed alignment cache
rnd, // pseudo-random source
wlm, // group walk left metrics
@@ -3729,6 +3817,7 @@ static void multiseedSearchWorker(void *vp) {
cpow2, // checkpointer interval, log2
doTri, // triangular mini-fills?
tighten, // -M score tightening mode
+ deterministicSeeds, // Should I disable the random seed selection?
ca, // seed alignment cache
rnd, // pseudo-random source
wlm, // group walk left metrics
@@ -3865,6 +3954,7 @@ static void multiseedSearchWorker(void *vp) {
ebwtBw, // BWT' index
*rds[mate], // read
sc, // scoring scheme
+ lowseeds_ncut, // cut no seed quality
ca, // alignment cache
shs[mate], // store seed hits here
sdm, // metrics
@@ -3963,6 +4053,7 @@ static void multiseedSearchWorker(void *vp) {
cpow2, // checkpointer interval, log2
doTri, // triangular mini-fills?
tighten, // -M score tightening mode
+ deterministicSeeds, // Should I disable the random seed selection?
ca, // seed alignment cache
rnd, // pseudo-random source
wlm, // group walk left metrics
@@ -4005,6 +4096,7 @@ static void multiseedSearchWorker(void *vp) {
cpow2, // checkpointer interval, log2
doTri, // triangular mini-fills?
tighten, // -M score tightening mode
+ deterministicSeeds, // Should I disable the random seed selection?
ca, // seed alignment cache
rnd, // pseudo-random source
wlm, // group walk left metrics
@@ -4716,8 +4808,14 @@ static void multiseedSearch(
EList<int> tids;
EList<std::thread*> threads(nthreads);
EList<thread_tracking_pair> tps;
+ // The condition_variable synchronization can be problematic
+ // in certain situations.
+ // Disabling it and using the polling-based lock-free mechanism can help there
+ // The (relative) polling cost is much higher for low thread count, so use that as a treshold
+ bool readahead_useCVLocks = nthreads<=16; // Note: We may want to consider other factors, too
+
// Important: Need at least nthreads+1 elements, more is OK
- PatternSourceReadAheadFactory readahead_factory(patsrc,pp,4*nthreads+1);
+ PatternSourceReadAheadFactory readahead_factory(patsrc,pp,4*nthreads+1,readahead_useCVLocks);
multiseed_readahead_factory = &readahead_factory;
tps.resize(std::max(nthreads, thread_ceiling));
=====================================
doc/manual.html
=====================================
@@ -6,6 +6,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Bowtie 2 Manual</title>
<style>
+ /* Default styles provided by pandoc.
+ ** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
+ */
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
@@ -1778,6 +1781,25 @@ number of seed hits divided by the number of seeds that aligned at least
once is greater than 300. Default: 2.</p>
</td>
</tr>
+<tr>
+<td id="bowtie2-options-d">
+<pre><code>-d/--deterministic-seeds</code></pre>
+</td>
+<td>
+<p>Consider all seeds in order (no subsampling). Can be used to augment
+<a href="#bowtie2-options-a"><code>-a</code></a> or <a
+href="#bowtie2-options-k"><code>-k</code></a> with deterministic
+behavior. This option significantly speeds up <a
+href="#bowtie2-options-a"><code>-a</code></a> while also reducing memory
+consumption. It is not however always strictly better than standalone
+<code>[-a]</code> when considering the number of repeated alignments
+found.</p>
+<p>Note: In order to use this option exact upfront and 1mm upfront
+behavior have to be disabled using the following options:
+[<code>--no-exact-upfront</code>] and <a
+href="#bowtie2-options-no-1mm-upfront"><code>--no-1mm-upfront</code></a>.</p>
+</td>
+</tr>
</table>
<h4 id="paired-end-options">Paired-end options</h4>
<table>
=====================================
doc/website/manual.ssi
=====================================
@@ -1747,6 +1747,25 @@ number of seed hits divided by the number of seeds that aligned at least
once is greater than 300. Default: 2.</p>
</td>
</tr>
+<tr>
+<td id="bowtie2-options-d">
+<pre><code>-d/--deterministic-seeds</code></pre>
+</td>
+<td>
+<p>Consider all seeds in order (no subsampling). Can be used to augment
+<a href="#bowtie2-options-a"><code>-a</code></a> or <a
+href="#bowtie2-options-k"><code>-k</code></a> with deterministic
+behavior. This option significantly speeds up <a
+href="#bowtie2-options-a"><code>-a</code></a> while also reducing memory
+consumption. It is not however always strictly better than standalone
+<code>[-a]</code> when considering the number of repeated alignments
+found.</p>
+<p>Note: In order to use this option exact upfront and 1mm upfront
+behavior have to be disabled using the following options:
+[<code>--no-exact-upfront</code>] and <a
+href="#bowtie2-options-no-1mm-upfront"><code>--no-1mm-upfront</code></a>.</p>
+</td>
+</tr>
</table>
<h4 id="paired-end-options">Paired-end options</h4>
<table>
@@ -3087,5 +3106,3 @@ format, run:</p>
href="http://samtools.sourceforge.net/mpileup.shtml">Calling SNPs/INDELs
with SAMtools/BCFtools</a> for more details and variations on this
process.</p>
-<!-- fasta-continuous option does not exist but was added to prevent
-warnings due to the case insensitive nature of markdown URLs -->
=====================================
doc/website/recent_news.ssi
=====================================
@@ -1,3 +1,19 @@
+<h2 id="version-2.5.5---feb-16-2026">Version 2.5.5 - Feb 16, 2026</h2>
+<h3 id="bowtie2">bowtie2</h3>
+<ul>
+ <li>Added <code><a href="manual.shtml#bowtie2-options-d">-d/--deterministic-mode</a></code>command
+ line option that
+ makes <code><a href="manual.shtml#bowtie2-options-a">-a</a>/<a href="manual.shtml#bowtie2-options-k">-k</a></code>
+ deterministic in the way alignments are reported. This
+ deterministic mode runs much significantly faster
+ than <a href="manual.shtml#bowtie2-options-a">-a</a> and
+ consumes less memory. It not yet strictly better
+ than <a href="manual.shtml#bowtie2-options-a">-a</a> when
+ considering alignments found. (PR #520, 521)</li>
+ <li>Add support for selecting AVX version at runtime on x86_64/amd64
+ CPUs. (PR #515)</li>
+</ul>
+
<h2 id="version-2.5.4---may-16-2024">Version 2.5.4 - May 16, 2024</h2>
<h3 id="bowtie2">bowtie2</h3>
<ul>
=====================================
doc/website/rhsidebar.ssi
=====================================
@@ -18,10 +18,10 @@
</tr>
<tr>
<td>
- <a href="https://sourceforge.net/projects/bowtie-bio/files/bowtie2/2.5.4">Bowtie2 v2.5.4</a>
+ <a href="https://sourceforge.net/projects/bowtie-bio/files/bowtie2/2.5.4">Bowtie2 v2.5.5</a>
</td>
<td align="right">
- 05/16/24
+ 02/16/26
</td>
</tr>
<tr>
=====================================
group_walk.h
=====================================
@@ -1106,7 +1106,6 @@ public:
const Ebwt& ebwtFw, // forward Bowtie index for walking left
const BitPairReference& ref,// bitpair-encoded reference
SARangeWithOffs<T>& sa, // SA range with offsets
- RandomSource& rnd, // pseudo-random generator for sampling rows
WalkMetrics& met) // update metrics here
{
reset();
=====================================
opts.h
=====================================
@@ -163,6 +163,7 @@ enum {
ARG_SRA_ACC, // --sra-acc
ARG_SAM_APPEND_COMMENT, // --sam-append-comment
ARG_SAM_OPT_CONFIG, // --sam-opt-config
+ ARG_DET_SEEDS_NO, // --no-deterministic-seeds
};
#endif
=====================================
pat.cpp
=====================================
@@ -55,7 +55,7 @@ static uint32_t genRandSeed(
size_t qlen = qry.length();
// Throw all the characters of the read into the random seed
for(size_t i = 0; i < qlen; i++) {
- int p = (int)qry[i];
+ int p = (int)qry[i];
assert_leq(p, 4);
size_t off = ((i & 15) << 1);
rseed ^= ((uint32_t)p << off);
@@ -302,20 +302,28 @@ pair<bool, int> DualPatternComposer::nextBatch(PerThreadReadBuf& pt) {
* the read and quality input, create a list of pattern sources to
* dispense them.
*/
-PatternComposer* PatternComposer::setupPatternComposer(
- const EList<string>& si, // singles, from argv
- const EList<string>& m1, // mate1's, from -1 arg
- const EList<string>& m2, // mate2's, from -2 arg
- const EList<string>& m12, // both mates on each line, from --12 arg
- const EList<string>& q, // qualities associated with singles
- const EList<string>& q1, // qualities associated with m1
- const EList<string>& q2, // qualities associated with m2
+PatternComposer *PatternComposer::setupPatternComposer(
+ const EList<string> &si, // singles, from argv
+ const EList<string> &m1, // mate1's, from -1 arg
+ const EList<string> &m2, // mate2's, from -2 arg
+ const EList<string> &m12, // both mates on each line, from --12 arg
+ const EList<string> &q, // qualities associated with singles
+ const EList<string> &q1, // qualities associated with m1
+ const EList<string> &q2, // qualities associated with m2
#ifdef USE_SRA
- const EList<string>& sra_accs, // SRA accessions
+ const EList<string> &sra_accs, // SRA accessions
#endif
- PatternParams& p, // read-in parameters
- bool verbose) // be talkative?
+ PatternParams &p, // read-in parameters
+ bool verbose) // be talkative?
{
+ // We save the value of PatternParams::align_paired_reads
+ // so that `--align-paired-reads` works as expected.
+ bool align_paired_reads = p.align_paired_reads;
+ // This serves as an indicator to the BAM pattern source
+ // that we intend on parsing paired reads from separate files
+ p.align_paired_reads = true;
+
+
EList<PatternSource*>* a = new EList<PatternSource*>();
EList<PatternSource*>* b = new EList<PatternSource*>();
// Create list of pattern sources for paired reads appearing
@@ -331,11 +339,11 @@ PatternComposer* PatternComposer::setupPatternComposer(
}
a->push_back(PatternSource::patsrcFromStrings(p, *qs));
b->push_back(NULL);
- p.interleaved = false;
if(!p.fileParallel) {
break;
}
- }
+ }
+ p.interleaved = false;
#ifdef USE_SRA
for(size_t i = 0; i < sra_accs.size(); i++) {
@@ -354,8 +362,7 @@ PatternComposer* PatternComposer::setupPatternComposer(
}
}
#endif
-
- // Create list of pattern sources for paired reads
+ // Create list of pattern sources for paired reads
for(size_t i = 0; i < m1.size(); i++) {
const EList<string>* qs = &m1;
EList<string> tmpSeq;
@@ -391,7 +398,11 @@ PatternComposer* PatternComposer::setupPatternComposer(
// All mates/mate files must be paired
assert_eq(a->size(), b->size());
- // Create list of pattern sources for the unpaired reads
+ // Create list of pattern sources for the unpaired reads
+ p.align_paired_reads = align_paired_reads;
+ if (p.align_paired_reads) {
+ p.interleaved = true;
+ }
for(size_t i = 0; i < si.size(); i++) {
const EList<string>* qs = &si;
PatternSource* patsrc = NULL;
@@ -1370,7 +1381,8 @@ std::pair<bool, int> BAMPatternSource::get_alignments(PerThreadReadBuf& pt, bool
i = i + sizeof(l_name) + l_name + sizeof(uint32_t);
}
first_ = false;
- }
+ }
+
while (readi < pt.max_buf_) {
if (i >= alignment_batch.size()) {
return make_pair(false, readi);
@@ -1397,19 +1409,26 @@ std::pair<bool, int> BAMPatternSource::get_alignments(PerThreadReadBuf& pt, bool
i += sizeof(block_size);
memcpy(&flag, &alignment_batch[0] + i + offset[BAMField::flag], sizeof(flag));
if (currentlyBigEndian())
- flag = endianSwapU16(flag);
- EList<Read>& readbuf = (pp_.align_paired_reads && (flag & 0x80)) != 0 ? pt.bufb_ : pt.bufa_;
+ flag = endianSwapU16(flag);
+
+ if (interleaved_) {
+ batch_a = (flag & 0x80) != 0 ? false : true;
+ }
+
+ EList<Read> &readbuf = batch_a ? pt.bufa_ : pt.bufb_;
+
if ((flag & 0x4) == 0) {
readbuf[readi].readOrigBuf.clear();
i += block_size;
continue;
}
- if (!pp_.align_paired_reads && ((flag & 0x40) != 0 || (flag & 0x80) != 0)) {
+ if (!align_paired_reads_ && (flag & 0x1) != 0) {
readbuf[readi].readOrigBuf.clear();
i += block_size;
continue;
}
- if (pp_.align_paired_reads && ((flag & 0x40) == 0 && (flag & 0x80) == 0)) {
+ if (align_paired_reads_ &&
+ ((batch_a && ((flag & 0x40) == 0)) || (!batch_a && (flag & 0x80) == 0))) {
readbuf[readi].readOrigBuf.clear();
i += block_size;
continue;
@@ -1418,7 +1437,7 @@ std::pair<bool, int> BAMPatternSource::get_alignments(PerThreadReadBuf& pt, bool
readbuf[readi].readOrigBuf.resize(block_size);
memcpy(readbuf[readi].readOrigBuf.wbuf(), &alignment_batch[0] + i, block_size);
i += block_size;
- readi += (pp_.align_paired_reads &&
+ readi += (interleaved_ &&
pt.bufb_[readi].readOrigBuf.length() == 0) ? 0 : 1;
}
=====================================
pat.h
=====================================
@@ -851,22 +851,16 @@ class BAMPatternSource : public CFilePatternSource {
};
public:
-
- BAMPatternSource(
- const EList<std::string>& infiles,
- const PatternParams& p) :
- CFilePatternSource(infiles, p),
- first_(true),
- alignment_batch(0),
- alignment_offset(0),
- delta_(0),
- pp_(p)
- {
- stream.zalloc = Z_NULL;
- stream.zfree = Z_NULL;
- stream.opaque = Z_NULL;
- alignment_batch.reserve(1 << 16);
- }
+ BAMPatternSource(const EList<std::string> &infiles, const PatternParams &p)
+ : CFilePatternSource(infiles, p), first_(true), alignment_batch(0),
+ alignment_offset(0), delta_(0), pp_(p), interleaved_(pp_.interleaved),
+ align_paired_reads_(pp_.align_paired_reads)
+ {
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+ stream.opaque = Z_NULL;
+ alignment_batch.reserve(1 << 16);
+ }
virtual void reset() {
first_ = true;
@@ -913,7 +907,9 @@ private:
size_t delta_;
z_stream stream;
- PatternParams pp_;
+ PatternParams pp_;
+ bool interleaved_;
+ bool align_paired_reads_;
};
/**
@@ -1298,10 +1294,10 @@ public:
PatternSourceReadAheadFactory(
PatternComposer& composer,
- const PatternParams& pp, size_t n) :
+ const PatternParams& pp, size_t n, bool useCV) :
psfact_(composer,pp),
- psq_ready_(),
- psq_idle_(psfact_,n),
+ psq_ready_(useCV),
+ psq_idle_(useCV,psfact_,n),
asynct_(readAsync, this) {}
~PatternSourceReadAheadFactory() {
@@ -1325,9 +1321,75 @@ public:
private:
template <typename T>
- class LockedQueue {
+ class LockedQueueCV {
public:
- virtual ~LockedQueue() {}
+ virtual ~LockedQueueCV() {}
+
+ bool empty() {
+ bool ret = false;
+ {
+ std::unique_lock<std::mutex> lk(m_);
+ ret = q_.empty();
+ }
+ return ret;
+ }
+
+ void push(T& ps) {
+ std::unique_lock<std::mutex> lk(m_);
+ q_.push(ps);
+ cv_.notify_all();
+ }
+
+ // wait for data, if none in the queue
+ T pop() {
+ T ret;
+ {
+ std::unique_lock<std::mutex> lk(m_);
+ cv_.wait(lk, [this] { return !q_.empty();});
+ ret = q_.front();
+ q_.pop();
+ }
+ return ret;
+ }
+
+ protected:
+ std::mutex m_;
+ std::condition_variable cv_;
+ std::queue<T> q_;
+ };
+
+ class LockedPSQueueCV : public LockedQueueCV<PatternSourcePerThread*> {
+ public:
+ LockedPSQueueCV(PatternSourcePerThreadFactory& psfact, size_t n) :
+ LockedQueueCV<PatternSourcePerThread*>() {
+ for (size_t i=0; i<n; i++) {
+ q_.push(psfact.create());
+ }
+ }
+
+ virtual ~LockedPSQueueCV() {
+ while (!q_.empty()) {
+ delete q_.front();
+ q_.pop();
+ }
+ }
+ };
+
+ class LockedREQueueCV : public LockedQueueCV<ReadElement> {
+ public:
+ virtual ~LockedREQueueCV() {
+ // we actually own ps while in the queue
+ while (!q_.empty()) {
+ delete q_.front().ps;
+ q_.pop();
+ }
+ }
+ };
+
+ template <typename T>
+ class LockedQueueMC {
+ public:
+ virtual ~LockedQueueMC() {}
bool empty() {
return q_.size_approx() == 0;
@@ -1346,21 +1408,19 @@ private:
}
protected:
- // std::mutex m_;
- // std::condition_variable cv_;
ConcurrentQueue<T> q_;
};
- class LockedPSQueue: public LockedQueue<PatternSourcePerThread*> {
+ class LockedPSQueueMC: public LockedQueueMC<PatternSourcePerThread*> {
public:
- LockedPSQueue(PatternSourcePerThreadFactory& psfact, size_t n) :
- LockedQueue<PatternSourcePerThread*>() {
+ LockedPSQueueMC(PatternSourcePerThreadFactory& psfact, size_t n) :
+ LockedQueueMC<PatternSourcePerThread*>() {
for (size_t i=0; i<n; i++) {
q_.enqueue(psfact.create());
}
}
- virtual ~LockedPSQueue() {
+ virtual ~LockedPSQueueMC() {
PatternSourcePerThread *item;
while (q_.size_approx() != 0) {
@@ -1371,9 +1431,9 @@ private:
};
- class LockedREQueue : public LockedQueue<ReadElement> {
+ class LockedREQueueMC : public LockedQueueMC<ReadElement> {
public:
- virtual ~LockedREQueue() {
+ virtual ~LockedREQueueMC() {
// we actually own ps while in the queue
ReadElement item;
@@ -1385,6 +1445,60 @@ private:
}
};
+ template <typename T, typename Q1, typename Q2>
+ class LockedQueueDuo {
+ public:
+ LockedQueueDuo(Q1 *pq1, Q2 *pq2)
+ : pq1_(pq1), pq2_(pq2)
+ {
+ assert( (pq1_!=NULL) || (pq2_!=NULL) );
+ }
+
+ virtual ~LockedQueueDuo() {
+ if (pq1_!=NULL) delete pq1_;
+ if (pq2_!=NULL) delete pq2_;
+ }
+
+ bool empty() {
+ return (pq1_!=NULL) ? pq1_->empty() : pq2_->empty();
+ }
+
+ void push(T& ps) {
+ if (pq1_!=NULL) {
+ pq1_->push(ps);
+ } else {
+ pq2_->push(ps);
+ }
+ }
+
+ T pop() {
+ return (pq1_!=NULL) ? pq1_->pop() : pq2_->pop();
+ }
+
+ protected:
+ // owned, and exactly one should be not NULL
+ Q1 *pq1_;
+ Q2 *pq2_;
+ };
+
+ class LockedPSQueue: public LockedQueueDuo<PatternSourcePerThread*, LockedPSQueueCV, LockedPSQueueMC> {
+ public:
+ LockedPSQueue(bool useCV, PatternSourcePerThreadFactory& psfact, size_t n) :
+ LockedQueueDuo<PatternSourcePerThread*, LockedPSQueueCV, LockedPSQueueMC>(
+ useCV ? new LockedPSQueueCV(psfact,n) : NULL,
+ useCV ? NULL : new LockedPSQueueMC(psfact,n)
+ ) {}
+ };
+
+ class LockedREQueue: public LockedQueueDuo<ReadElement, LockedREQueueCV, LockedREQueueMC> {
+ public:
+ LockedREQueue(bool useCV) :
+ LockedQueueDuo<ReadElement, LockedREQueueCV, LockedREQueueMC>(
+ useCV ? new LockedREQueueCV() : NULL,
+ useCV ? NULL : new LockedREQueueMC()
+ ) {}
+ };
+
static void readAsync(PatternSourceReadAheadFactory *obj) {
LockedREQueue &psq_ready = obj->psq_ready_;
LockedPSQueue &psq_idle = obj->psq_idle_;
=====================================
processor_support.h
=====================================
@@ -31,6 +31,9 @@ public:
ProcessorSupport() { }
bool POPCNTenabled()
{
+#if defined(SSE_AVX2)
+ return true; // POPCNT is part of AVX2, so always present; no need to check
+#else
// from: Intel® 64 and IA-32 Architectures Software Developer’s Manual, 325462-036US,March 2013
//Before an application attempts to use the POPCNT instruction, it must check that the
//processor supports SSE4.2
@@ -58,6 +61,7 @@ public:
return false;
}
return true;
+#endif
}
#endif // POPCNT_CAPABILITY
View it on GitLab: https://salsa.debian.org/med-team/bowtie2/-/commit/ea62608187cc1b15ab7a2fc42d537fcaa06f0efe
--
View it on GitLab: https://salsa.debian.org/med-team/bowtie2/-/commit/ea62608187cc1b15ab7a2fc42d537fcaa06f0efe
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20260222/6785aa93/attachment-0001.htm>
More information about the debian-med-commit
mailing list