# rust-ise
Fast, Rust-native **ISEScan-equivalent** insertion-sequence (IS) scanner for bacterial
genomes and metagenome assemblies. Reports IS family (ISfinder taxonomy), genomic
coordinates, terminal inverted repeats (TIR), and complete/partial status — much faster
than ISEScan, with concordant results.
## Pipeline
1. **ORF prediction** — `rustygal` (a Rust port of Prodigal) META gene-finding, linked as a
library (no external binary), plus strand-aware edge-ORF recovery.
2. **Homology search** — MMseqs2 profile search against a union IS database
(ISOSDB ∪ ISfinder), calling the system `mmseqs`.
3. **Classification** — 4-tier family call (plain / `-like` / `-chimera` / novel).
4. **TIR** — native affine Smith-Waterman-Gotoh on the flanks; boundary + complete/partial.
5. **Output** — `isscan.tsv`, `isscan.gff` (GFF3), `isscan.sum` (per-family summary).
Output is deterministic across runs.
## Prerequisites (NOT installed by cargo)
- **MMseqs2** — `mmseqs` must be on your `PATH` (conda: `conda install -c bioconda mmseqs2`).
- **IS database** — the union profile DB (ISOSDB ∪ ISfinder MMseqs2 profiles) is external data,
released as a prebuilt artifact paired with the matching per-profile thresholds the binary embeds.
Download it, then point rust-ise at it via `--db <dir>` or `$ISSCAN_DB`. The dir must contain
`mmdb_union/profileDb*` and `manifest_union.tsv`.
## Database
The profile DB is distributed as a versioned download (it is calibrated together with the thresholds
baked into the matching binary release — the two are a locked pair, so use the DB that ships with
your binary version):
```sh
export ISSCAN_DB=/path/to/isscan_db # extracted DB directory
```
## Install
```sh
# from a local checkout (path build):
cargo install --path rust-ise
# or from git:
cargo install --git https://github.com/necoli1822/rust-ise rust-ise
```
`RUSTFLAGS="-C target-cpu=native"` is optional (~few % faster, stays result-identical).
> `rustygal` resolves from crates.io (`>= 0.2.0`); no local checkout is needed. For
> side-by-side local development, override it with `[patch.crates-io]` in your workspace.
## Usage
```sh
export ISSCAN_DB=/path/to/isscan_db # or pass --db each run
rust-ise -i contigs.fasta -o out_dir -t 16
```
| `-i, --seqfile` | input contigs FASTA (required) |
| `-o, --output` | output directory (required) |
| `-t, --threads` | CPU threads (default 16) |
| `--db <dir>` | IS database dir (else `$ISSCAN_DB`) |
| `--gpu` | use MMseqs2 GPU acceleration |
| `--keep` | keep intermediate files |
| `--strict` | drop `fpFlag=host` calls (host-lineage false positives) from the output |
## Output columns (`isscan.tsv`)
`seqID family tier isBegin isEnd isLen ncopy4is orfBegin orfEnd strand E-value
qcov pident type irLen irId start2 end2 tir fpFlag`
Coordinates are 1-based inclusive. `type` is `c` (complete) or `p` (partial).
### `fpFlag` — nucleotide false-positive control
The HTH/DDE/ATPase folds of IS transposases are shared with host proteins (transcriptional regulators,
recombinases, IstB-like ATPases), so the protein-profile search alone mis-calls them as IS
(e.g. *marA*/*soxS* → IS4, *dnaA* → IS21). `fpFlag` runs a **nucleotide** neg-pos discriminator per call —
the call's DNA is compared to an IS-lineage reference and a host-lineage reference — and reports which
lineage it resembles:
The verdict combines the nt homology signal with two homology-**independent** structural signals — a
terminal inverted repeat (**TIR**) and a target-site duplication (**TSD**, the short direct repeat an
IS leaves flanking itself on insertion). Structure lets a divergent/novel IS (nt homology silent) still
be recognized, and protects a structurally-supported call from being dropped as a false positive:
| `IS` | call DNA matches the IS reference — homology-confirmed |
| `putative` | no nt homology either way, but a TIR/TSD is present — structure suggests IS (e.g. a divergent IS) |
| `shared` | nt leans host (matches both, host closer), or structure-vs-nt conflict — borderline, kept |
| `host` | matches host reference only, no IS or structural support — likely false positive |
| `unresolved` | no nt match and no structure — IS-vs-host undecided (keep; divergent IS or off-reference host gene) |
`fpFlag` is advisory (all calls are retained); use `--strict` to drop `host` calls (the only tier with
no IS support of any kind). The `.sum` file carries an `#fpControl` count line. Requires the
`fpc/refset` DB (see below); if absent the module is skipped and every call is flagged `IS`.
### FP-control database
The `fpc/refset` reference ships inside the released DB. It is (re)built by the
`build-db` subcommand (see below), which also assembles the union IS profile DB.
## Rebuilding the database (`build-db`)
`rust-ise build-db` rebuilds the union IS profile DB (`mmdb_union/` + `manifest_union.tsv`)
and, with a host pool, the `fpc/refset` FP-control reference — reproducibly from source.
The five source files can be supplied locally or **auto-downloaded** (each pinned by commit
SHA and verified by sha256, so every rebuild starts from byte-identical inputs):
```sh
# fully auto: download+verify all sources (and the host negative pool) then build
rust-ise build-db --fetch-sources --fetch-host --out isscan_db
# or supply sources locally (offline / local-first — explicit paths override fetched):
rust-ise build-db --isosdb-fna ISOSDB.V3.fna --fam-annot IS_fam_annot.txt \
--isfinder-faa IS.faa --isfinder-csv IS.csv --isfinder-fna IS.fna \
--host host_neg.fna --out isscan_db
```
`build-db` shells out to `mmseqs` (and `curl` for `--fetch-sources`); the ISOSDB `.zip`
is extracted in-process. The IS-lineage `P|` pool is derived automatically (ISOSDB per-ORF
CDS + ISfinder transposase CDS located in `IS.fna` by 6-frame translation, pure Rust). The
host `N|` pool is the `--host` FASTA (or `--fetch-host`). Without a host pool, `fpc/refset`
is skipped and the scanner's FP-control no-ops.
**Data sources / copyright.** `--fetch-sources` downloads, from their upstream origin
(not redistributed by this crate): the **ISfinder** sequences (`IS.faa`/`IS.csv`/`IS.fna`,
© the ISfinder team, isfinder.biotoul.fr; via the `thanhleviet/ISfinder-sequences` mirror)
and the **ISOSDB**/`IS_fam_annot.txt` (from `joshuakirsch/pseudoR`, Kirsch et al.). See
[`NOTICE`](NOTICE) for citations and licensing; cite ISfinder and ISOSDB when you use the DB.
## Testing
```sh
cargo test --release # hermetic unit tests: fpFlag 5-tier verdict, TSD, codon/revcomp, E-value fmt
./tests/golden_e2e.sh /path/to/isscan_db # end-to-end golden: 17-contig fixture -> diff vs tests/golden/expected.tsv
```
The golden test locks the whole pipeline (ORF → search → family call → TIR → dedup/merge → TSD → fpFlag)
including all five `fpFlag` tiers; it needs `mmseqs` + the DB, so it is a shell test rather than
`cargo test`. rust-ise output is byte-stable across runs.
## Changelog
### 0.2.3
- **`build-db` now ships in the published crate** (previously dev-tree only): rebuild the
union IS profile DB + `fpc/refset` reproducibly from source, with in-process poasta MSAs.
- **Source auto-download (`--fetch-sources` / `--fetch-host`).** Every build-db source is
pinned by commit SHA and verified by sha256, so a rebuild starts from byte-identical inputs
and reproduces the same DB for every user. Downloads use system `curl`; the ISOSDB `.zip`
is extracted in-process. A local source cache is reused across runs.
- **fpc `P|` pool fully auto-derived in pure Rust.** The ISfinder half of the IS-lineage
positive pool is now located directly from `IS.fna` by 6-frame translation (no external
intermediate), matching the shipped pool byte-for-byte; `--fpc-pos-extra` is now an optional
escape hatch rather than a requirement.
- Scanner engine (`rust_ise::run`) is unchanged from 0.2.2 (`SIG_EVALUE`/`SIG_QCOV` intact).
### 0.2.2
- **Tightened the significance gate for higher precision.** The primary E-value
floor (`SIG_EVALUE`) in `family_call` was tightened `1e-10 → 1e-30` — the
empirical knee on the E. coli MG1655 vs RefSeq truth set (removes ~5
low-significance false positives while retaining every true IS element:
precision 0.72 → 0.76, recall unchanged at 0.98). Added a conservative
query-coverage floor (`SIG_QCOV = 0.35`) that trims only extreme fragmentary
hits without harming recall. Both gates are covered by new unit tests.
### 0.2.1
- **New IS profile DB + recalibrated thresholds.** Per-profile percent-identity
thresholds (`data/rep_thresholds.tsv`, compiled into the binary via `phf`)
were recalibrated on GTDB and matched to a new poasta-MSA-built IS profile
database, with false-positive control tightened against a GTDB regression set.
The DB itself is built/distributed separately and supplied at runtime via
`--db` / `$ISSCAN_DB`.
- `rustygal` now resolves from crates.io (`>= 0.2.0`, the `meta_api` ORF finder)
rather than a local path.
### 0.2.0 / 0.1.x
- Earlier crates.io releases: the pure-Rust ISEScan-equivalent IS scanner
(rustygal ORFs + MMseqs2 profile search + native affine-SW terminal inverted
repeats) with the in-process `rust_ise::run` library API and the `rust-ise` CLI.
## License
GPL-3.0-or-later (same as the bundled `rustygal`). See [LICENSE](LICENSE).