Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@
[submodule "packages/ig-sw"]
path = packages/ig-sw
url = https://github.com/matsengrp/ig-sw.git
[submodule "zig-backend/partis-zig-core"]
path = zig-backend/partis-zig-core
url = https://github.com/matsengrp/partis-zig-core.git
117 changes: 117 additions & 0 deletions bin/install-zig-backend.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env bash
# Install the partis-zig-core Zig backend (drop-in replacements for bcrham and ig-sw).
#
# Usage:
# bin/install-zig-backend.sh [--install-dir DIR]
#
# After running, pass these flags to partis:
# --bcrham-binary <install-dir>/partis-zig-core/zig-out/bin/partis-zig-core
# --ig-sw-binary <install-dir>/partis-zig-core/zig-out/bin/partis-zig-igsw
#
# The Zig backend requires no external libraries (GSL, OpenBLAS, etc.) and
# produces bit-for-bit identical annotations to the C++ bcrham and C ig-sw binaries.
set -euo pipefail

ZIG_VERSION="0.15.2"
ZIG_REPO="https://github.com/matsengrp/partis-zig-core.git"
DEFAULT_INSTALL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/zig-backend"

INSTALL_DIR="$DEFAULT_INSTALL_DIR"
while [[ $# -gt 0 ]]; do
case "$1" in
--install-dir) INSTALL_DIR="$2"; shift 2 ;;
*) echo "Unknown argument: $1" >&2; exit 1 ;;
esac
done

ZIG_CORE_DIR="$INSTALL_DIR/partis-zig-core"
ZIG_EXE_FINAL="$ZIG_CORE_DIR/zig-out/bin/partis-zig-core"

echo "==> Installing partis Zig backend to: $INSTALL_DIR"
mkdir -p "$INSTALL_DIR"

# ── 1. Ensure Zig is available ──────────────────────────────────────────────

find_zig() {
# Prefer a zig in PATH that matches the required version
if command -v zig &>/dev/null; then
local v
v=$(zig version 2>/dev/null || echo "")
if [[ "$v" == "$ZIG_VERSION" ]]; then
echo "zig"
return
fi
fi
# Check if we already downloaded it
local downloaded="$INSTALL_DIR/zig-$ZIG_VERSION/zig"
if [[ -x "$downloaded" ]]; then
echo "$downloaded"
return
fi
echo ""
}

ZIG=$(find_zig)
if [[ -z "$ZIG" ]]; then
echo "==> Downloading Zig $ZIG_VERSION..."
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
# Normalize arch names
case "$ARCH" in
x86_64) ARCH="x86_64" ;;
aarch64|arm64) ARCH="aarch64" ;;
*) echo "ERROR: Unsupported architecture: $ARCH" >&2; exit 1 ;;
esac
case "$OS" in
linux) OS_TAG="linux" ;;
darwin) OS_TAG="macos" ;;
*) echo "ERROR: Unsupported OS: $OS" >&2; exit 1 ;;
esac
ZIG_TARBALL="zig-${OS_TAG}-${ARCH}-${ZIG_VERSION}.tar.xz"
ZIG_URL="https://ziglang.org/download/${ZIG_VERSION}/${ZIG_TARBALL}"
ZIG_DIR="$INSTALL_DIR/zig-${ZIG_VERSION}"
mkdir -p "$ZIG_DIR"
curl -fsSL "$ZIG_URL" | tar -xJ -C "$ZIG_DIR" --strip-components=1
ZIG="$ZIG_DIR/zig"
echo " Zig $ZIG_VERSION installed at: $ZIG"
else
echo "==> Using Zig: $ZIG ($(zig version 2>/dev/null || $ZIG version))"
fi

# ── 2. Clone or update partis-zig-core ──────────────────────────────────────

if [[ -d "$ZIG_CORE_DIR/.git" ]]; then
echo "==> Updating partis-zig-core..."
git -C "$ZIG_CORE_DIR" pull --ff-only
else
echo "==> Cloning partis-zig-core..."
git clone "$ZIG_REPO" "$ZIG_CORE_DIR"
fi

# ── 3. Build ─────────────────────────────────────────────────────────────────

# build.zig references ig-sw sources inside the partis repo.
# Set PARTIS_DIR so build.zig can find them.
PARTIS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
export PARTIS_DIR

echo "==> Building partis-zig-core (this takes ~30s)..."
(cd "$ZIG_CORE_DIR" && "$ZIG" build -Doptimize=ReleaseFast)

if [[ ! -x "$ZIG_EXE_FINAL" ]]; then
echo "ERROR: build succeeded but executable not found at $ZIG_EXE_FINAL" >&2
exit 1
fi

ZIG_IGSW_EXE_FINAL="$ZIG_CORE_DIR/zig-out/bin/partis-zig-igsw"

echo ""
echo "Build complete:"
echo " $ZIG_EXE_FINAL"
echo " $ZIG_IGSW_EXE_FINAL"
echo ""
echo "To use the Zig backend, pass these flags to partis:"
echo " --bcrham-binary $ZIG_EXE_FINAL"
echo " --ig-sw-binary $ZIG_IGSW_EXE_FINAL"
echo ""
echo "Omit these flags to use the default C++ bcrham and C ig-sw binaries."
1 change: 1 addition & 0 deletions bin/partis
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,7 @@ parent_args.append({'name' : '--count-correlations', 'kwargs' : {'action' : 'sto
parent_args.append({'name' : '--dont-write-parameters', 'kwargs' : {'action' : 'store_true', 'help' : 'don\'t write parameters to disk even if you\'ve counted them (mostly for use in conjunction with --only-smith-waterman, so you can avoid cluttering up your file system)'}})
parent_args.append({'name' : '--partis-dir', 'kwargs' : {'default' : partis_dir, 'help' : 'for internal use only'}})
parent_args.append({'name' : '--ig-sw-binary', 'kwargs' : {'default' : partis_dir + '/packages/ig-sw/src/ig_align/ig-sw', 'help' : 'Path to ig-sw executable.'}})
parent_args.append({'name' : '--bcrham-binary', 'kwargs' : {'default' : partis_dir + '/packages/ham/bcrham', 'help' : 'Path to bcrham executable.'}})
parent_args.append({'name' : '--vsearch-binary', 'kwargs' : { 'help' : 'Path to vsearch binary (vsearch binaries for linux and darwin are pre-installed in bin/, but for other systems you need to get your own)'}})
parent_args.append({'name' : '--is-simu', 'kwargs' : {'action' : 'store_true', 'help' : 'Set if running on simulated sequences'}})
parent_args.append({'name' : '--skip-unproductive', 'kwargs' : {'action' : 'store_true', 'help' : 'Skip sequences which Smith-Waterman determines to be unproductive (i.e. if they have stop codons, out of frame cdr3, or mutated cyst/tryp/phen)'}})
Expand Down
6 changes: 3 additions & 3 deletions partis/partitiondriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ def get_n_calculated_per_process(self):

total = 0. # sum over each process
for procinfo in self.bcrham_proc_info:
if 'vtb' not in procinfo['calcd'] or 'fwd' not in procinfo['calcd']:
print('%s couldn\'t find vtb/fwd in:\n%s' % (utils.color('red', 'warning'), procinfo['calcd'])) # may as well not fail, it probably just means we lost some stdout somewhere. Which, ok, is bad, but let's say it shouldn't be fatal.
if procinfo['calcd'].get('vtb') is None or procinfo['calcd'].get('fwd') is None:
print('%s couldn\'t find vtb/fwd in:\n%s' % (utils.color('red', 'warning'), procinfo['calcd'])) # may as well not fail, it probably just means we lost some stdout somewhere (or are using the Zig backend which doesn't emit calcd debug strings). Which, ok, is bad, but let's say it shouldn't be fatal.
return 1. # er, or something?
if self.args.naive_hamming_cluster: # make sure we didn't accidentally calculate some fwds
assert procinfo['calcd']['fwd'] == 0.
Expand Down Expand Up @@ -1263,7 +1263,7 @@ def dbgstr():
# ----------------------------------------------------------------------------------------
def get_hmm_cmd_str(self, algorithm, csv_infname, csv_outfname, parameter_dir, precache_all_naive_seqs, n_procs):
""" Return the appropriate bcrham command string """
cmd_str = self.args.partis_dir + '/packages/ham/bcrham'
cmd_str = self.args.bcrham_binary
cmd_str += ' --algorithm ' + algorithm
if self.args.debug > 0:
cmd_str += ' --debug ' + str(self.args.debug)
Expand Down
6 changes: 6 additions & 0 deletions test/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ def run(self, args):
if tkey in info:
cmd_str += ' --%s %s' % (tkey if tkey != 'inpath' else self.astr('in', dt=idt), info[tkey])
cmd_str += ' %s' % ' '.join(info['extras'] + self.common_extras)
if args.bcrham_binary is not None:
cmd_str += ' --bcrham-binary %s' % args.bcrham_binary
if args.ig_sw_binary is not None:
cmd_str += ' --ig-sw-binary %s' % args.ig_sw_binary

if name == 'simulate':
cmd_str += ' --%s %s' % (self.astr('out'), self.inpath('new', 'simu'))
Expand Down Expand Up @@ -941,6 +945,8 @@ def compare_files(fname):

parser.add_argument('--glfo-dir', default='data/germlines/human')
parser.add_argument('--locus', default='igh')
parser.add_argument('--bcrham-binary', default=None, help='override default bcrham binary path (e.g. Zig drop-in replacement)')
parser.add_argument('--ig-sw-binary', default=None, help='override default ig-sw binary path (e.g. Zig drop-in replacement)')
args = parser.parse_args()
assert not (args.quick and args.slow) # it just doesn't make sense
assert not (args.quick and args.paired) # --quick ignores --paired, which is confusing
Expand Down
1 change: 1 addition & 0 deletions zig-backend/partis-zig-core
Submodule partis-zig-core added at 6c51ef