infernal-gpu 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ build/
2
+ dist/
3
+ *.egg-info/
4
+ __pycache__/
5
+ *.pyc
6
+ .venv/
7
+ venv/
@@ -0,0 +1,27 @@
1
+ # Builds the two GPU programs and installs them into the infernal_gpu package (pip install .).
2
+ # CUDA architectures: the local GPU by default; override with e.g.
3
+ # CMAKE_ARGS="-DCMAKE_CUDA_ARCHITECTURES=80;86;89" pip install .
4
+ cmake_minimum_required(VERSION 3.24)
5
+ if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
6
+ set(CMAKE_CUDA_ARCHITECTURES native)
7
+ endif()
8
+ project(infernal_gpu LANGUAGES CXX CUDA)
9
+ set(CMAKE_CUDA_STANDARD 14)
10
+ set(CMAKE_CXX_STANDARD 14)
11
+ find_package(Threads REQUIRED)
12
+
13
+ set(ENGINE_SOURCES src/cyk_kernel.cu src/inside_kernel.cu src/gpu_transfer.cu src/gpu_batch_scan.cu src/scan.cu)
14
+ set(ENGINE_DEFS IL_PARALLEL_SCAN IL_ZERO_EMISSION_SCAN BIF_RING_INDEX ROOT_STATE_FUSED INSIDE_MIN_BLOCKS_256=4)
15
+
16
+ function(engine_program name)
17
+ add_executable(${name} ${ENGINE_SOURCES})
18
+ target_include_directories(${name} PRIVATE src)
19
+ target_compile_definitions(${name} PRIVATE ${ENGINE_DEFS} ${ARGN})
20
+ target_compile_options(${name} PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:-O2 -Xcompiler=-O2>)
21
+ set_target_properties(${name} PROPERTIES CUDA_SEPARABLE_COMPILATION ON CUDA_RESOLVE_DEVICE_SYMBOLS ON)
22
+ target_link_libraries(${name} PRIVATE Threads::Threads)
23
+ install(TARGETS ${name} RUNTIME DESTINATION infernal_gpu/bin)
24
+ endfunction()
25
+
26
+ engine_program(infernal-gpu-scan) # search
27
+ engine_program(infernal-gpu-calibrate-scan CALIB_RECORDS) # calibration (record emission)
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, the Infernal-GPU authors
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.4
2
+ Name: infernal-gpu
3
+ Version: 0.1.0
4
+ Summary: GPU covariance-model calibration and search for Infernal, with results matching Infernal
5
+ Author: Infernal-GPU authors
6
+ License-Expression: BSD-3-Clause
7
+ License-File: LICENSE
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: C++
10
+ Classifier: Environment :: GPU :: NVIDIA CUDA
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
13
+ Project-URL: Homepage, https://github.com/void-echo/infernal-gpu
14
+ Project-URL: Source, https://github.com/void-echo/infernal-gpu
15
+ Requires-Python: >=3.8
16
+ Description-Content-Type: text/markdown
17
+
18
+ # Infernal-GPU
19
+
20
+ Infernal-GPU is a GPU implementation of the covariance-model (CM) dynamic programming of
21
+ [Infernal](http://eddylab.org/infernal/) 1.1.5. It provides a replacement for `cmcalibrate` that
22
+ follows the same protocol and writes the same model file, and a CM search in which the GPU scores
23
+ every model against every sequence while Infernal's own `cmsearch` computes the final hits, so
24
+ scores, E-values and coordinates are Infernal's.
25
+
26
+ ## Requirements
27
+
28
+ - Linux with an NVIDIA GPU and the CUDA toolkit (`nvcc`)
29
+ - CMake ≥ 3.24 (fetched by pip if missing) and Python ≥ 3.8
30
+ - Infernal 1.1.5 (`cmsearch`, `cmfetch`) for `search` and `hybrid`
31
+
32
+ ## Install
33
+
34
+ pip install infernal-gpu # from PyPI; compiles the GPU programs
35
+ pip install git+https://github.com/void-echo/infernal-gpu # or from GitHub (or `pip install .` in a clone)
36
+
37
+ The GPU programs are compiled for the GPU of the build machine. To build for other or several
38
+ architectures (A100 = 80, RTX 30xx = 86, RTX 40xx = 89 with CUDA ≥ 11.8), name them; if CMake
39
+ does not find `nvcc`, also set `CUDACXX=/usr/local/cuda/bin/nvcc`:
40
+
41
+ CMAKE_ARGS="-DCMAKE_CUDA_ARCHITECTURES=80;86" pip install .
42
+
43
+ ## Usage
44
+
45
+ Calibrate E-values of a model or library from `cmbuild`:
46
+
47
+ infernal-gpu calibrate model.cm model.calibrated.cm --gpu 0
48
+
49
+ Calibrations on more random sequence are more accurate (sampling error falls with the square root of its
50
+ length). To calibrate on 16 Mb, ten times the default, compile cmcalibrate's sequence generator once
51
+ against an Infernal 1.1.5 source build and pass its output with `--seqs`:
52
+
53
+ I=infernal-1.1.5
54
+ cc -O2 -I$I/src -I$I/hmmer/src -I$I/easel tools/gen_calib_seqs.c $I/src/libinfernal.a \
55
+ $I/hmmer/src/libhmmer.a $I/easel/libeasel.a -lm -lpthread -o gen_calib_seqs
56
+ ./gen_calib_seqs 181 1600 10000 > random16Mb.fa # seed, chunks, chunk length
57
+ infernal-gpu calibrate model.cm model.calibrated.cm --seqs random16Mb.fa --gpu 0
58
+
59
+ Filter-free search of calibrated models (the hits of `cmsearch --nohmm`). E-values cover the
60
+ `--n-models` models of the library, as in `cmscan`; the GPU is chosen with `CUDA_VISIBLE_DEVICES`:
61
+
62
+ infernal-gpu search --cm-lib Rfam.cm --n-models 4227 --fasta genome.fa \
63
+ --infernal-bin infernal-1.1.5/src --out-dir run1
64
+
65
+ Sensitive search behind Infernal's HMM filters, with the CM stages on the GPU. It needs a second
66
+ copy of Infernal 1.1.5, patched once so that it writes out the envelopes that pass the filters:
67
+
68
+ curl -LO http://eddylab.org/infernal/infernal-1.1.5.tar.gz
69
+ tar xf infernal-1.1.5.tar.gz && mv infernal-1.1.5 infernal-envdump
70
+ infernal-gpu patch-infernal infernal-envdump
71
+ (cd infernal-envdump && ./configure && make)
72
+ infernal-gpu hybrid --cm models.cm --fasta targets.fa --filter relaxed --gpu 0 --out-dir run2 \
73
+ --envdump-cmsearch infernal-envdump/src/cmsearch --infernal-bin infernal-1.1.5/src
74
+
75
+ `--filter` is `default`, `mid` or `relaxed` (`--mid --Fmid 0.1`). Every command lists its options
76
+ with `--help`.
77
+
78
+ ## Outputs
79
+
80
+ `calibrate` writes the model file with new `ECM` lines and everything else unchanged; it works with
81
+ `cmsearch` and `cmscan`. `search` and `hybrid` write `hits.tbl` in `cmsearch --tblout` format on the
82
+ original sequences, the same hits as `refined_hits.tsv`, the GPU candidate regions, the native
83
+ per-model `cmsearch` outputs and `summary.json`.
84
+
85
+ ## Test
86
+
87
+ INFERNAL_BIN=infernal-1.1.5/src python tests/test_infernal_gpu.py
88
+
89
+ The test (about a minute; `pytest tests` also works) calibrates two models and compares their
90
+ E-value thresholds with `cmcalibrate`, then searches a genome slice and compares every hit with
91
+ `cmsearch --nohmm`. Its data are files from the Infernal 1.1.5 tutorial.
92
+
93
+ ## Citation and license
94
+
95
+ Please cite: [to be added]. Infernal-GPU is distributed under the BSD 3-Clause license (`LICENSE`).
@@ -0,0 +1,78 @@
1
+ # Infernal-GPU
2
+
3
+ Infernal-GPU is a GPU implementation of the covariance-model (CM) dynamic programming of
4
+ [Infernal](http://eddylab.org/infernal/) 1.1.5. It provides a replacement for `cmcalibrate` that
5
+ follows the same protocol and writes the same model file, and a CM search in which the GPU scores
6
+ every model against every sequence while Infernal's own `cmsearch` computes the final hits, so
7
+ scores, E-values and coordinates are Infernal's.
8
+
9
+ ## Requirements
10
+
11
+ - Linux with an NVIDIA GPU and the CUDA toolkit (`nvcc`)
12
+ - CMake ≥ 3.24 (fetched by pip if missing) and Python ≥ 3.8
13
+ - Infernal 1.1.5 (`cmsearch`, `cmfetch`) for `search` and `hybrid`
14
+
15
+ ## Install
16
+
17
+ pip install infernal-gpu # from PyPI; compiles the GPU programs
18
+ pip install git+https://github.com/void-echo/infernal-gpu # or from GitHub (or `pip install .` in a clone)
19
+
20
+ The GPU programs are compiled for the GPU of the build machine. To build for other or several
21
+ architectures (A100 = 80, RTX 30xx = 86, RTX 40xx = 89 with CUDA ≥ 11.8), name them; if CMake
22
+ does not find `nvcc`, also set `CUDACXX=/usr/local/cuda/bin/nvcc`:
23
+
24
+ CMAKE_ARGS="-DCMAKE_CUDA_ARCHITECTURES=80;86" pip install .
25
+
26
+ ## Usage
27
+
28
+ Calibrate E-values of a model or library from `cmbuild`:
29
+
30
+ infernal-gpu calibrate model.cm model.calibrated.cm --gpu 0
31
+
32
+ Calibrations on more random sequence are more accurate (sampling error falls with the square root of its
33
+ length). To calibrate on 16 Mb, ten times the default, compile cmcalibrate's sequence generator once
34
+ against an Infernal 1.1.5 source build and pass its output with `--seqs`:
35
+
36
+ I=infernal-1.1.5
37
+ cc -O2 -I$I/src -I$I/hmmer/src -I$I/easel tools/gen_calib_seqs.c $I/src/libinfernal.a \
38
+ $I/hmmer/src/libhmmer.a $I/easel/libeasel.a -lm -lpthread -o gen_calib_seqs
39
+ ./gen_calib_seqs 181 1600 10000 > random16Mb.fa # seed, chunks, chunk length
40
+ infernal-gpu calibrate model.cm model.calibrated.cm --seqs random16Mb.fa --gpu 0
41
+
42
+ Filter-free search of calibrated models (the hits of `cmsearch --nohmm`). E-values cover the
43
+ `--n-models` models of the library, as in `cmscan`; the GPU is chosen with `CUDA_VISIBLE_DEVICES`:
44
+
45
+ infernal-gpu search --cm-lib Rfam.cm --n-models 4227 --fasta genome.fa \
46
+ --infernal-bin infernal-1.1.5/src --out-dir run1
47
+
48
+ Sensitive search behind Infernal's HMM filters, with the CM stages on the GPU. It needs a second
49
+ copy of Infernal 1.1.5, patched once so that it writes out the envelopes that pass the filters:
50
+
51
+ curl -LO http://eddylab.org/infernal/infernal-1.1.5.tar.gz
52
+ tar xf infernal-1.1.5.tar.gz && mv infernal-1.1.5 infernal-envdump
53
+ infernal-gpu patch-infernal infernal-envdump
54
+ (cd infernal-envdump && ./configure && make)
55
+ infernal-gpu hybrid --cm models.cm --fasta targets.fa --filter relaxed --gpu 0 --out-dir run2 \
56
+ --envdump-cmsearch infernal-envdump/src/cmsearch --infernal-bin infernal-1.1.5/src
57
+
58
+ `--filter` is `default`, `mid` or `relaxed` (`--mid --Fmid 0.1`). Every command lists its options
59
+ with `--help`.
60
+
61
+ ## Outputs
62
+
63
+ `calibrate` writes the model file with new `ECM` lines and everything else unchanged; it works with
64
+ `cmsearch` and `cmscan`. `search` and `hybrid` write `hits.tbl` in `cmsearch --tblout` format on the
65
+ original sequences, the same hits as `refined_hits.tsv`, the GPU candidate regions, the native
66
+ per-model `cmsearch` outputs and `summary.json`.
67
+
68
+ ## Test
69
+
70
+ INFERNAL_BIN=infernal-1.1.5/src python tests/test_infernal_gpu.py
71
+
72
+ The test (about a minute; `pytest tests` also works) calibrates two models and compares their
73
+ E-value thresholds with `cmcalibrate`, then searches a genome slice and compares every hit with
74
+ `cmsearch --nohmm`. Its data are files from the Infernal 1.1.5 tutorial.
75
+
76
+ ## Citation and license
77
+
78
+ Please cite: [to be added]. Infernal-GPU is distributed under the BSD 3-Clause license (`LICENSE`).
@@ -0,0 +1,2 @@
1
+ """infernal-gpu: GPU-accelerated covariance-model calibration and search for Infernal."""
2
+ __version__ = "0.1.0"
@@ -0,0 +1,69 @@
1
+ """GPU replacement for `cmcalibrate` (default protocol): calibrate CM E-values and write a model file.
2
+
3
+ infernal-gpu calibrate IN.cm OUT.cm [--gpu 0]
4
+
5
+ IN.cm is a model or library from cmbuild (with or without ECM lines). The scanner is the bundled
6
+ infernal-gpu-calibrate-scan (built with -DCALIB_RECORDS). Every model is calibrated in cmcalibrate's
7
+ four modes on cmcalibrate's own default random sequences (data/cmcalibrate_default_seed181.fa in
8
+ this package: 160 x 10 kb from Infernal's genomic HMM, seed 181), and the four ECM lines are written
9
+ into OUT.cm in Infernal's format; everything else in the file is copied unchanged. OUT.cm can be used
10
+ directly by cmsearch/cmscan. --seqs selects other random sequences (e.g. longer ones for a more
11
+ precise calibration; dbsize is taken from their total length). Python 3.8+, standard library.
12
+ """
13
+ import argparse, os, subprocess, sys, tempfile, time
14
+ from pathlib import Path
15
+
16
+ HERE = Path(__file__).resolve().parent
17
+ MODES = ('ECMLC', 'ECMGC', 'ECMLI', 'ECMGI') # cm_file.c write order
18
+
19
+
20
+ def main():
21
+ ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
22
+ ap.add_argument('cm_in'); ap.add_argument('cm_out')
23
+ ap.add_argument('--scanner', default=str(HERE / 'bin' / 'infernal-gpu-calibrate-scan'),
24
+ help='GPU scanner built with -DCALIB_RECORDS (default: the bundled one)')
25
+ ap.add_argument('--gpu', default=os.environ.get('CUDA_VISIBLE_DEVICES', '0'))
26
+ ap.add_argument('--seqs', default=str(HERE / 'data' / 'cmcalibrate_default_seed181.fa'))
27
+ ap.add_argument('--keep-tsv', help='also keep the per-mode calibration table here')
28
+ ap.add_argument('--gtailn', type=int, default=250, help='hits/Mb fitted in glocal modes (cmcalibrate --gtailn)')
29
+ ap.add_argument('--ltailn', type=int, default=750, help='hits/Mb fitted in local modes (cmcalibrate --ltailn)')
30
+ a = ap.parse_args()
31
+
32
+ env = dict(os.environ, CUDA_DEVICE_ORDER='PCI_BUS_ID', CUDA_VISIBLE_DEVICES=str(a.gpu),
33
+ GPU_TILE_POLICY='wave', GPU_PACKED_BEGL='auto', GPU_PACK_ALL='auto')
34
+ with tempfile.TemporaryDirectory() as td:
35
+ tsv = a.keep_tsv or str(Path(td) / 'calib.tsv')
36
+ t0 = time.time()
37
+ r = subprocess.run([a.scanner, a.cm_in, a.seqs, '--calibrate', tsv,
38
+ '--gtailn', str(a.gtailn), '--ltailn', str(a.ltailn)], env=env,
39
+ stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True)
40
+ wall = time.time() - t0
41
+ if r.returncode != 0:
42
+ sys.exit('calibration failed:\n' + '\n'.join(l for l in r.stderr.splitlines() if 'FATAL' in l or 'ERR' in l))
43
+ calib = {}
44
+ for line in open(tsv):
45
+ if line.startswith('#'): continue
46
+ f = line.rstrip('\n').split('\t')
47
+ # cm_name cm_acc mode lambda mu_extrap mu_orig dbsize nrandhits tailp ...
48
+ calib.setdefault(f[0], {})[f[2]] = (float(f[3]), float(f[4]), float(f[5]), int(float(f[6]) + 0.5), int(f[7]), float(f[8]))
49
+
50
+ out, in_header, name, n = [], False, None, 0
51
+ for line in open(a.cm_in):
52
+ if line.startswith('INFERNAL1'):
53
+ in_header, name = True, None
54
+ if in_header:
55
+ if line.startswith('NAME') and name is None: name = line.split()[1]
56
+ if line.startswith('ECM'): continue
57
+ if line.rstrip('\n') == 'CM':
58
+ c = calib.get(name, {})
59
+ if len(c) != 4: sys.exit(f'{name}: calibration incomplete')
60
+ out += [f'{m} {c[m][0]:.5f} {c[m][1]:10.5f} {c[m][2]:10.5f} {c[m][3]:10d} {c[m][4]:10d} {c[m][5]:.6f}\n'
61
+ for m in MODES]
62
+ in_header = False; n += 1
63
+ out.append(line)
64
+ Path(a.cm_out).write_text(''.join(out))
65
+ print(f'{n} model(s) calibrated in {wall:.1f} s -> {a.cm_out}', file=sys.stderr)
66
+
67
+
68
+ if __name__ == '__main__':
69
+ main()
@@ -0,0 +1,56 @@
1
+ """infernal-gpu command line: one entry point for the package's commands.
2
+
3
+ infernal-gpu calibrate IN.cm OUT.cm [--gpu N] GPU replacement for cmcalibrate
4
+ infernal-gpu search --out-dir D --cm-lib LIB --fasta F --infernal-bin DIR --n-models N [-- scanner options]
5
+ filter-free search, streamed native refinement
6
+ infernal-gpu hybrid --cm LIB --fasta F --out-dir D --envdump-cmsearch X --infernal-bin DIR [--filter relaxed]
7
+ native HMM filters + GPU CM stages
8
+ infernal-gpu tblout --run-dir D --out hits.tbl export standard cmsearch tblout
9
+ infernal-gpu refine --hits C --fasta F --cm-lib LIB --infernal-bin DIR --n-models N --out-dir D
10
+ native rescan of candidate regions
11
+ infernal-gpu patch-infernal INFERNAL_SOURCE_DIR add the opt-in envelope output (for hybrid)
12
+
13
+ The bundled GPU programs are used unless --scanner is given. Each command prints its own --help.
14
+ Native Infernal 1.1.5 (cmsearch, cmfetch) must be installed; search and hybrid take its bin directory.
15
+ """
16
+ import importlib, os, sys
17
+
18
+ from . import __version__
19
+
20
+ COMMANDS = {'calibrate': 'calibrate', 'search': 'search', 'hybrid': 'hybrid', 'tblout': 'tblout',
21
+ 'refine': 'refine', 'patch-infernal': 'patch_infernal'}
22
+ # Measured production configuration of the GPU engine (callers' settings take precedence).
23
+ ENGINE_ENV = dict(CUDA_DEVICE_ORDER='PCI_BUS_ID', GPU_TILE_POLICY='wave', GPU_PACKED_BEGL='auto',
24
+ GPU_PACK_ALL='auto', GPU_BLOCK_SIZE='128')
25
+ # Default scanner options for filter-free search (calibrated CYK filter, NULL3 gates, 0.25-bit margin).
26
+ SEARCH_DEFAULTS = ['--candidate-evalue', '1', '--cascade-cyk-p', '1e-4', '--null3-gate', '--cyk-margin', '0.25']
27
+
28
+
29
+ def main(argv=None):
30
+ argv = list(sys.argv[1:] if argv is None else argv)
31
+ if argv and argv[0] == '--version':
32
+ print('infernal-gpu', __version__)
33
+ return 0
34
+ if not argv or argv[0] in ('-h', '--help', 'help') or argv[0] not in COMMANDS:
35
+ print(__doc__.strip())
36
+ return 0 if not argv or argv[0] in ('-h', '--help', 'help') else 2
37
+ cmd, rest = argv[0], argv[1:]
38
+ for k, v in ENGINE_ENV.items():
39
+ os.environ.setdefault(k, v)
40
+ if cmd == 'search' and not any(a in ('-h', '--help') for a in rest):
41
+ # scanner options follow '--'; add each default the caller did not set
42
+ head, tail = (rest[:rest.index('--')], rest[rest.index('--') + 1:]) if '--' in rest else (rest, [])
43
+ extra, i = [], 0
44
+ while i < len(SEARCH_DEFAULTS):
45
+ flag = SEARCH_DEFAULTS[i]
46
+ takes_value = i + 1 < len(SEARCH_DEFAULTS) and not SEARCH_DEFAULTS[i + 1].startswith('--')
47
+ if flag not in tail:
48
+ extra += SEARCH_DEFAULTS[i:i + 1 + takes_value]
49
+ i += 1 + takes_value
50
+ rest = head + ['--'] + extra + tail
51
+ sys.argv = ['infernal-gpu ' + cmd] + rest
52
+ return importlib.import_module('.' + COMMANDS[cmd], __package__).main()
53
+
54
+
55
+ if __name__ == '__main__':
56
+ sys.exit(main())