Skip to main content

Fast Mixed Model Association for GWAS

Project description

CI PyPI Python 3.11+ JAX NumPy Hypothesis License: GPL-3.0 Buy Me a Coffee

JAMMA

Fast Mixed Model Association — A modern Python reimplementation of GEMMA for genome-wide association studies (GWAS).

  • GEMMA-compatible: Drop-in replacement with identical CLI flags and output formats
  • Numerical equivalence: Validated against GEMMA — 100% significance agreement, 100% effect direction agreement
  • Fast: Up to 10x faster than GEMMA 0.98.5 at scale
  • Memory-safe: Pre-flight memory checks prevent OOM crashes before allocation
  • Cross-platform: Runs on Linux, macOS, and Windows — NumPy backend works everywhere, JAX adds batch acceleration on Linux and ARM Mac
  • Pure Python + optional C extension: NumPy + optional JAX stack; C extension with OpenMP for fast Wald tests, JAX for batch MLE optimization
  • Large-scale ready: Optional numpy-mkl ILP64 wheels (numpy 2.4.2) for >46k sample eigendecomposition

Installation

macOS (Intel or ARM)

pip install jamma          # NumPy backend
pip install jamma[jax]     # + JAX acceleration (ARM Mac only)

That's it. macOS Accelerate BLAS handles large matrices natively.

Linux / Windows / Intel Mac

For small datasets (<46k samples), the standard install works:

pip install jamma          # NumPy backend
pip install jamma[jax]     # + JAX acceleration

For large-scale GWAS (>46k samples) on Linux x86_64, install numpy-mkl first — standard numpy uses 32-bit BLAS integers which overflow at ~46k samples. MKL is x86_64-only; ARM Mac and Windows users are limited to <46k samples. Pre-built ILP64 wheels are available for Python 3.11–3.14:

NumPy backend only:

pip install numpy \
  --extra-index-url https://michael-denyer.github.io/numpy-mkl \
  --force-reinstall --upgrade
pip install jamma --no-deps
pip install psutil loguru threadpoolctl click progressbar2 bed-reader

With JAX acceleration:

pip install numpy \
  --extra-index-url https://michael-denyer.github.io/numpy-mkl \
  --force-reinstall --upgrade
pip install jamma[jax] --no-deps
pip install psutil loguru threadpoolctl click progressbar2 bed-reader \
  jax jaxlib jaxtyping

From Git (latest development version):

pip install numpy \
  --extra-index-url https://michael-denyer.github.io/numpy-mkl \
  --force-reinstall --upgrade
pip install git+https://github.com/michael-denyer/jamma.git --no-deps
pip install psutil loguru threadpoolctl click progressbar2 bed-reader

Why --no-deps? JAMMA depends on numpy>=2.0.0, so a normal pip install jamma will pull in standard numpy and overwrite the ILP64 build. --no-deps prevents this; you install the runtime dependencies manually instead.

See the User Guide for ILP64 verification steps.

Platform Support

Platform pip install jamma pip install jamma[jax] Notes
Linux x86_64 JAX (auto-included) Full support; ILP64 for >46k samples
ARM Mac (M1+) JAX (auto-included) Full support
Intel Mac NumPy only Not available JAX dropped Intel Mac support
Windows NumPy only Not available JAX dropped Windows support

JAX is auto-included on Linux and ARM Mac via platform markers. Force a specific backend with --backend numpy or --backend jax.

Quick Start

# Compute kinship matrix (centered relatedness)
jamma -gk 1 -bfile data/my_study -o output

# Run LMM association (Wald test)
jamma -lmm 1 -bfile data/my_study -k output/output.cXX.txt -o results

Output files match GEMMA format exactly:

  • output.cXX.txt — Kinship matrix
  • results.assoc.txt — Association results (chr, rs, ps, n_miss, allele1, allele0, af, beta, se, logl_H1, l_remle, p_wald)
  • results.log.txt — Run log

Python API

One-call GWAS (recommended)

from jamma import gwas

# Full pipeline: load data → kinship → eigendecomp → LMM → results
result = gwas("data/my_study", kinship_file="data/kinship.cXX.txt")
print(f"Tested {result.n_snps_tested} SNPs in {result.timing['total_s']:.1f}s")

# Compute kinship from scratch and save it
result = gwas("data/my_study", save_kinship=True, output_dir="output")

# With covariates and LRT test
result = gwas("data/my_study", kinship_file="k.txt", covariate_file="covars.txt", lmm_mode=2)

# LOCO analysis (leave-one-chromosome-out)
result = gwas("data/my_study", loco=True)

# Multi-phenotype with eigendecomp reuse
result = gwas("data/my_study", write_eigen=True, phenotype_column=1)
result = gwas("data/my_study", eigenvalue_file="output/result.eigenD.txt",
              eigenvector_file="output/result.eigenU.txt", phenotype_column=2)

# SNP filtering
result = gwas("data/my_study", kinship_file="k.txt", snps_file="snps.txt", hwe=0.001)

Low-level API (JAX backend)

import numpy as np

from jamma.io import load_plink_binary
from jamma.kinship import compute_centered_kinship
from jamma.lmm import run_lmm_association_streaming
from jamma.lmm.eigen import eigendecompose_kinship

# Load PLINK data and phenotypes
data = load_plink_binary("data/my_study")
phenotypes = np.loadtxt("data/my_study.pheno")  # loaded separately from .fam or phenotype file

# Compute kinship and eigendecompose (treat kinship as consumed after this)
kinship = compute_centered_kinship(data.genotypes)
eigenvalues, eigenvectors = eigendecompose_kinship(kinship)

# Run association (streaming from disk)
results, n_tested = run_lmm_association_streaming(
    bed_path="data/my_study",
    phenotypes=phenotypes,
    eigenvalues=eigenvalues,
    eigenvectors=eigenvectors,
    chunk_size=5000,
)

Low-level API (NumPy backend)

import numpy as np

from jamma.io import load_plink_binary
from jamma.kinship import compute_centered_kinship
from jamma.lmm import run_lmm_association_numpy
from jamma.lmm.eigen import eigendecompose_kinship

data = load_plink_binary("data/my_study")
phenotypes = np.loadtxt("data/my_study.pheno")
kinship = compute_centered_kinship(data.genotypes)
eigenvalues, eigenvectors = eigendecompose_kinship(kinship)

snp_info = [
    {"chr": str(data.chromosome[i]), "rs": data.sid[i],
     "pos": int(data.bp_position[i]), "a1": data.allele_1[i], "a0": data.allele_2[i]}
    for i in range(data.n_snps)
]

# Returns list[AssocResult] — write to disk via IncrementalAssocWriter
results = run_lmm_association_numpy(
    genotypes=data.genotypes,
    phenotypes=phenotypes,
    kinship=None,  # Not needed when eigenvalues/eigenvectors provided
    snp_info=snp_info,
    eigenvalues=eigenvalues,
    eigenvectors=eigenvectors,
    lmm_mode=1,
)

Memory Safety

Unlike GEMMA, JAMMA includes pre-flight memory checks that prevent out-of-memory crashes:

from jamma.core.memory import estimate_workflow_memory

# Check memory requirements BEFORE loading data
estimate = estimate_workflow_memory(n_samples=200_000, n_snps=95_000)
print(f"Peak memory: {estimate.total_gb:.1f}GB")
print(f"Available: {estimate.available_gb:.1f}GB")
print(f"Sufficient: {estimate.sufficient}")

Key features:

  • Pre-flight checks before large allocations (eigendecomposition, genotype loading)
  • RSS memory logging at workflow boundaries
  • Incremental result writing (no memory accumulation)
  • Safe chunk size defaults with hard caps

GEMMA will silently OOM and get killed by the OS. JAMMA fails fast with clear error messages.

Performance

Benchmark on mouse_hs1940 (1,940 samples × 12,226 SNPs), Apple M2, JAMMA v2.9.5, GEMMA 0.98.5. Median of 3 runs, end-to-end wall clock:

Operation GEMMA 0.98.5 JAMMA (NumPy) JAMMA (JAX) vs GEMMA
Kinship (-gk 1) 2.2s 1.5s 1.5s 1.5x
LMM (-lmm 1) 11.2s 1.0s 2.4s 11.2x
LMM (-lmm 4) 20.7s 5.1s 3.2s 6.5x

For Wald-only (-lmm 1), the C extension with OpenMP is fastest — REML-only optimization is compute-bound and parallelizes well across SNPs. For all-tests (-lmm 4), JAX pulls ahead because the additional MLE optimization per SNP benefits from jax.vmap batching.

Supported Features

Current

  • Kinship matrix computation — centered (-gk 1) and standardized (-gk 2)
  • Univariate LMM Wald test (-lmm 1)
  • Likelihood ratio test (-lmm 2)
  • Score test (-lmm 3)
  • All tests mode (-lmm 4)
  • LOCO kinship — leave-one-chromosome-out analysis (-loco)
  • Eigendecomposition reuse — multi-phenotype workflows (-d/-u/-eigen)
  • Phenotype column selection (-n)
  • SNP subset selection for association and kinship (-snps/-ksnps)
  • HWE QC filtering (-hwe)
  • Pre-computed kinship input (-k)
  • Covariate support (-c)
  • PLINK binary format (.bed/.bim/.fam) with input dimension validation
  • Large-scale streaming I/O (>100k samples via numpy-mkl ILP64 — numpy 2.4.2)
  • JAX acceleration (CPU) with automatic device sharding
  • XLA profiling traces (--profile-dir) for TensorBoard/Perfetto
  • Lambda optimization bounds (-lmin/-lmax)
  • Individual weights for kinship (-widv)
  • Categorical covariates with one-hot encoding (-cat)
  • Pre-flight memory checks (fail-fast before OOM)
  • RSS memory logging at workflow boundaries
  • Incremental result writing
  • Optional C extension with OpenMP for NumPy LMM acceleration (auto-fallback to pure Python)

Planned

  • Multivariate LMM (mvLMM)

Architecture

JAMMA uses NumPy for data loading, kinship, and eigendecomposition, then splits at LMM into a JAX backend (JIT, vmap, sharding) or a NumPy backend with an optional C extension for OpenMP-parallel Wald tests.

flowchart TD
    CLI["CLI / gwas()"] --> PIPE["PipelineRunner"]
    PIPE --> LOAD["Load PLINK + Phenotypes<br>(NumPy)"]
    LOAD --> KIN["Kinship<br>(NumPy matmul)"]
    KIN --> EIG["Eigendecomposition<br>(numpy.linalg.eigh)"]
    EIG --> DET{"detect_backend()"}
    DET -->|"jax"| JAX["JAX Streaming Runner<br>JIT + vmap + sharding"]
    DET -->|"numpy"| NP["NumPy Batch Runner"]
    NP --> CEXT{"C extension<br>available?"}
    CEXT -->|yes| C["C Extension<br>OpenMP + SIMD"]
    CEXT -->|no| PY["Pure Python<br>fallback"]
    JAX --> RES["AssocResult"]
    C --> RES
    PY --> RES

Both backends share the same core algorithms (likelihood.py, prepare_common.py) and produce identical results. Backend-specific files follow a naming convention: *_jax.py / *_numpy.py.

See Code Map for the full architecture diagram with source links.

Documentation

Requirements

  • Python 3.11+
  • NumPy 2.0+
  • JAX 0.8.0+ (optional, for batch acceleration: pip install jamma[jax])

License

GPL-3.0 (same as GEMMA)

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jamma-2.9.5.tar.gz (80.3 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

jamma-2.9.5-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (380.9 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

jamma-2.9.5-cp313-cp313-macosx_11_0_arm64.whl (254.5 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

jamma-2.9.5-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (380.9 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

jamma-2.9.5-cp312-cp312-macosx_11_0_arm64.whl (254.5 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

jamma-2.9.5-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (380.2 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

jamma-2.9.5-cp311-cp311-macosx_11_0_arm64.whl (254.6 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

File details

Details for the file jamma-2.9.5.tar.gz.

File metadata

  • Download URL: jamma-2.9.5.tar.gz
  • Upload date:
  • Size: 80.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for jamma-2.9.5.tar.gz
Algorithm Hash digest
SHA256 80f19b5df2cb8e07aabee4fa8caac2cd896095bcee03190ca5c9045485af1aa3
MD5 55085ff40720605e0ae4422814617711
BLAKE2b-256 0a8365e4d6c2e77ca56dc00c1b6ff8cc299c07260a7f41dca5a1f892568d944c

See more details on using hashes here.

Provenance

The following attestation bundles were made for jamma-2.9.5.tar.gz:

Publisher: build-wheels.yml on michael-denyer/jamma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jamma-2.9.5-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for jamma-2.9.5-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8e130fb481778b838e1da9499f65b9fa748330ed410b14e7624d27f4edafb0af
MD5 1a18b87ab20b43df4e7b30a073f9d097
BLAKE2b-256 c2b393d1cdc8a74f60f02576495e80f6f9db2141a04652dc2d102cd20705a8df

See more details on using hashes here.

Provenance

The following attestation bundles were made for jamma-2.9.5-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl:

Publisher: build-wheels.yml on michael-denyer/jamma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jamma-2.9.5-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for jamma-2.9.5-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 7edb666552045b8d8b01e43f0fe57d932cecc72c5e2c81d26ea55da2f9736dfb
MD5 4c5cd6e39b55a64d775278f848bcc6c9
BLAKE2b-256 76a4c3bb35beb9ca91d7ed72b6e6d33f6e68932f3bd8faed99413f9d7357fc55

See more details on using hashes here.

Provenance

The following attestation bundles were made for jamma-2.9.5-cp313-cp313-macosx_11_0_arm64.whl:

Publisher: build-wheels.yml on michael-denyer/jamma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jamma-2.9.5-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for jamma-2.9.5-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 e191a0b5162911fdce48412bee0641477def8dbf9d19579bc37c100b929878f4
MD5 9b4fa0e70c02fb6396139901d914c8f1
BLAKE2b-256 345f39c5a76253ed14794e083435b75eccc79875d22ed10c1163141494000dab

See more details on using hashes here.

Provenance

The following attestation bundles were made for jamma-2.9.5-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl:

Publisher: build-wheels.yml on michael-denyer/jamma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jamma-2.9.5-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for jamma-2.9.5-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 27d851be3dccaff20c52a3ce6dfb06110ac39898724bb3e2f72ddb1db16ddf77
MD5 43265b7fc020083c82717dab5353b887
BLAKE2b-256 3995879e7951cda59b66bd2a375199a6498e41d147a47e39918f020cb2960d60

See more details on using hashes here.

Provenance

The following attestation bundles were made for jamma-2.9.5-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: build-wheels.yml on michael-denyer/jamma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jamma-2.9.5-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for jamma-2.9.5-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ef474b11960f67d29942cf4d9dd605996442c1c1bda558825e4fae7f0295549d
MD5 cc0103736b6f17af864fe8112f60c48d
BLAKE2b-256 97b62f8f681f9e6680e0f92942cd1ebf5b79013706cee208e8d9ba06cee1ab8f

See more details on using hashes here.

Provenance

The following attestation bundles were made for jamma-2.9.5-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl:

Publisher: build-wheels.yml on michael-denyer/jamma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jamma-2.9.5-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for jamma-2.9.5-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 088606254b2b69fd2b4ce9f17bb3769524d32159b09745530c72f349f08fd341
MD5 9e5b32585073d36767134a38e3719914
BLAKE2b-256 85f3ac14f78c8e54cd943a97894e55e3027f56e9f5a093d56c0367a455aec777

See more details on using hashes here.

Provenance

The following attestation bundles were made for jamma-2.9.5-cp311-cp311-macosx_11_0_arm64.whl:

Publisher: build-wheels.yml on michael-denyer/jamma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page