Skip to content

Add ERAMER ERAP1-trimming predictor (fills the erap_trimming gap) - #246

Merged
iskandr merged 1 commit into
masterfrom
eramer
Jul 10, 2026
Merged

Add ERAMER ERAP1-trimming predictor (fills the erap_trimming gap)#246
iskandr merged 1 commit into
masterfrom
eramer

Conversation

@iskandr

@iskandr iskandr commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Second of the two native-reimplementation PRs (Calis ✅ → ERAMER). This one closes the last empty stage of the processing pathway: Kind.erap_trimming was "reserved, not yet used" — after this, every Kind in the taxonomy has at least one predictor.

ERAP1 trims the N-termini of 9–16mer precursor peptides in the ER down to the 8–10mers MHC-I presents — the step between TAP transport (DeepTAP) and MHC loading. Wraps ERAMER (Al-okaily et al., Comput. Biol. Med. 2024), which models ERAP1 specificity as a per-length position-weight matrix and scores a precursor by averaging the PWM specificity over each residue trimmed off as it is cut toward a target epitope length.

from mhctools import ERAMER

predictor = ERAMER(epitope_length=8)       # resolves ERAMER_HOME / ~/ERAMER
results = predictor.predict(["GGGGGVVVVVVAAAEE"])   # a 9-16mer precursor
results[0].erap_trimming.score

Licensing — nothing vendored (like TULIP/MixMHCpred/netMHC)

ERAMER is GPLv3 and its PWM lives in a GPL-licensed PWM.xlsx; mhctools is Apache-2.0 and vendors neither. This is a clean-room Python-3 reimplementation of the (Python-2.7) tool's trimming-cascade average that loads the PWM from a user-provided ERAMER checkout at runtime (ERAMER_HOME / eramer_home= / pwm_path=, via openpyxl) — exactly how the netMHC / MixMHCpred wrappers read user-provided model files. Reimplementing in py3 also avoids ERAMER's py2.7 toolchain.

Faithfulness / validation

  • The cascade (_specificity = per-position PWM mean; eramer_score = mean over the trimming steps) reproduces ERAMER v1.0's own sample outputs exactly: GGGGGVVVVVVAAAEE → 0.085322875, LLLLLLLLLLLAAAAA → 0.273310375. Cross-checked the upstream compute_specificty no-op length_weight term (never set → 0) so I don't carry it.
  • tests/test_eramer.py: cascade math tested binary-free with a synthetic PWM; construction/validation tests; e2e gated on ERAMER_HOME + openpyxl reproducing the reference values. Added to the public CI subset (the e2e skips cleanly in CI, which has no checkout).

Integration

  • Allele-independent (mhc_dependence: none, mhc_class: I) — one erap_trimming prediction per peptide, empty allele. New data model; adds the PeptideResult.erap_trimming accessor and a new erap_trimming annotate token so it composes with mhctools predict-table (--predictor eramer:col:erap_trimming). Verified end-to-end.
  • Registered eramer; openpyxl is a lazy import with a clear install hint (only needed to read the user's PWM.xlsx).

Caveat (documented)

ERAMER's evaluation is self-reported and ERAP1 trimming is intrinsically noisy — treat the score as a pathway prior, not a validated oracle.

Version 3.26.0 → 3.27.0.

https://claude.ai/code/session_01LZahFhBSCiehXTESCYQ7wG

ERAP1 trims the N-termini of 9-16mer precursor peptides in the ER down to the
8-10mers MHC-I presents — the processing step between TAP transport and MHC
loading, and previously the one empty Kind in mhctools (erap_trimming was
"reserved, not yet used"; every other kind now has a predictor). ERAMER
(Al-okaily 2024) models ERAP1 specificity as a per-length position-weight matrix
and scores a precursor by averaging the PWM specificity over each residue
trimmed off as it is cut toward a target epitope length.

Licensing: ERAMER is GPLv3 and its PWM ships in a GPL-licensed PWM.xlsx; mhctools
is Apache-2.0 and vendors neither. This is a clean-room Python-3 reimplementation
of the (Python-2.7) tool's trimming-cascade average that loads the PWM from a
user-provided ERAMER checkout at runtime (ERAMER_HOME / eramer_home= / pwm_path=)
via openpyxl — exactly how the netMHC / MixMHCpred wrappers read user-provided
model files.

- mhctools/eramer.py: _find_pwm_path (honors explicit paths, else env/home),
  load_pwm (openpyxl, lazy import), _specificity + eramer_score (the cascade),
  and the allele-free ERAMER predictor (predict() / predict_dataframe()).
- pred.py: PeptideResult.erap_trimming accessor.
- annotate.py: "erap_trimming" output-field token so predict-table can consume
  ERAMER (--predictor eramer:col:erap_trimming). Verified end-to-end.
- cli/args.py + __init__.py: registered/exported "eramer".
- tests/test_eramer.py: cascade math tested binary-free with a synthetic PWM;
  validation/support tests; e2e gated on ERAMER_HOME + openpyxl, reproducing
  ERAMER v1.0's own sample outputs exactly (0.085322875, 0.273310375). Added to
  the public CI subset.
- README: ERAP1 trimming section + kind_support row; erap_trimming kind is no
  longer "reserved". Every Kind in the taxonomy now has at least one predictor.

Note: ERAMER's evaluation is self-reported and ERAP1 trimming is intrinsically
noisy — treat the score as a pathway prior, not a validated oracle.

Version 3.26.0 -> 3.27.0.

Claude-Session: https://claude.ai/code/session_01LZahFhBSCiehXTESCYQ7wG
@iskandr
iskandr merged commit e51637b into master Jul 10, 2026
5 checks passed
@iskandr
iskandr deleted the eramer branch July 10, 2026 01:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant