Skip to main content

Stransverse mass computation as a numpy ufunc.

Project description


This package may be used to evaluate MT2 in all its variants. This includes both symmetric and asymmetric MT2. MT2 is also known as the “stransverse mass”.

This package provides an interface to the bisection algorithm of, via an implementation detailed below. The variable MT2 itself is described here. Related information may be found in papers relating to MT2 linked from here.

Getting started

Install from pip:

pip install mt2

One can then compute MT2 as follows; here for the “symmetric” case, where both invisible particles have the same mass:

from mt2 import mt2

# The units of all quantities are the same, e.g. GeV
val = mt2(
    100, 410, 20,  # Visible 1: mass, px, py
    150, -210, -300,  # Visible 2: mass, px, py
    -200, 280,  # Missing transverse momentum: x, y
    100, 100)  # Invisible 1 mass, invisible 2 mass
print("Expected mT2 = 412.628.  Computed mT2 = ", val)



The mt2 function supports broadcasting over its arguments if they are array-like. For example, one could scan over a grid of invisible particle masses like so:

n1 = 20
n2 = 20
mass_1 = numpy.linspace(10, 200, n1).reshape((-1, 1))
mass_2 = numpy.linspace(10, 200, n2).reshape((1, -1))

# `val` has shape (n1, n2)
val = mt2(
    100, 410, 20,  # Visible 1: mass, px, py
    150, -210, -300,  # Visible 2: mass, px, py
    -200, 280,  # Missing transverse momentum: x, y
    mass_1, mass_2)  # Invisible 1 mass, invisible 2 mass
Note on performance

With full precision, the main reason to use vectorisation as above is convenience. The time spent in the C++ MT2 calculation is somewhat larger than the overhead introduced by a Python for loop. Vectorising can give a runtime reduction of ⪅30% in this case.

However, the benefit can be more significant when using a lower precision. This corresponds to a larger value for the desired_precision_on_mt2 argument. This is because less time is spent in C++, so proportionally the Python overhead of a for loop is more significant.

Toy MC

A fun example using a toy Monte-Carlo simulation can be viewed in this notebook

Other notes

For further information, see the documentation:


Also exported is mt2_ufunc. This is the raw implementation as a numpy ufunc. Usage is the same as for mt2, but it supports some additional arguments, like where. The reader should refer to the numpy documentation for a description of these.


The underlying implementation of the Lester-Nachman algorithm used in this package is by Rupert Tombs, found in src/mt2_bisect.h. It provides results consistent with the implementation provided with, but is 3x to 4x faster. Note that this does not implement the “deci-sectioning” described in the paper, since it is found to provide a more significant performance penalty in the majority of cases. Our version is also scale invariant, and is suitable for large ranges of input magnitude.

The legacy implementation, as it appears on arXiv, is also wrapped and exposed as mt2_arxiv for those that wish to independently cross-check the re-implementation. If you find any discrepancies, please file a bug report! We strongly encourage all users to use the primary mt2 method, due to the higher performance and scale invariance.


The default installation method via pip uses a precompiled wheel for your platform. If you wish to compile from source for your platform, you could instead install like so:

pip install mt2 --no-binary :all:

Since this can allow use of newer compilers, and code more optimised for your architecture, this can give a small speedup. On the author’s computer, there was 1% runtime reduction as measured with examples/


Please cite:

All files other than src/lester_mt2_bisect_v7.h and src/mt2_Lallyver2.h are released under the MIT license.

Other implementations

A list of alternative implementations of the MT2 calculation can be found here:

In Python, the other wrapper of the same algorithm known to the authors is by Nikolai Hartmann, here:


1.2.0 (2021-05-05)

  • Add mt2_arxiv public API for using (slower) implementation as published on arXiv, which may be wanted for independent testing.

1.1.0 (2021-04-18)

  • Re-implementation of the core algorithm, giving 3x-4x speedup overall.

1.0.0 (2021-02-14)

  • First non-beta release
  • Minor formatting alterations
  • Improved README

0.2.0 (2021-02-13)

  • Fix numpy build dependencies to use oldest possible version, so that wheels are maximally compatible.
  • Don’t support Python 3.5

0.1.6 (2021-02-11)

  • Fix build for numpy versions prior to 1.19

0.1.5 (2021-02-10)

  • Migrate to preliminary v7 of C file
  • Disable copyright message printing on run
  • Move away from pybind11 in favour of raw numpy C API

0.1.4 (2021-02-09)

  • Actually fix the build, maybe

0.1.3 (2021-02-09)

  • Fix the build

0.1.2 (2021-02-09)

  • Attempt C++ build

0.1.1 (2021-02-09)

  • Trivial change to test updating package on PyPI.

0.1.0 (2021-02-09)

  • First release on PyPI.

Project details

Download files

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

Source Distribution

mt2-1.2.0.tar.gz (36.8 kB view hashes)

Uploaded source

Built Distributions

mt2-1.2.0-cp39-cp39-win_amd64.whl (29.4 kB view hashes)

Uploaded cp39

mt2-1.2.0-cp39-cp39-win32.whl (28.3 kB view hashes)

Uploaded cp39

mt2-1.2.0-cp39-cp39-manylinux2010_i686.whl (89.7 kB view hashes)

Uploaded cp39

mt2-1.2.0-cp39-cp39-manylinux1_x86_64.whl (87.0 kB view hashes)

Uploaded cp39

mt2-1.2.0-cp39-cp39-manylinux1_i686.whl (78.9 kB view hashes)

Uploaded cp39

mt2-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl (29.3 kB view hashes)

Uploaded cp39

mt2-1.2.0-cp38-cp38-win_amd64.whl (29.7 kB view hashes)

Uploaded cp38

mt2-1.2.0-cp38-cp38-win32.whl (28.6 kB view hashes)

Uploaded cp38

mt2-1.2.0-cp38-cp38-manylinux2010_i686.whl (90.6 kB view hashes)

Uploaded cp38

mt2-1.2.0-cp38-cp38-manylinux1_x86_64.whl (87.8 kB view hashes)

Uploaded cp38

mt2-1.2.0-cp38-cp38-manylinux1_i686.whl (79.5 kB view hashes)

Uploaded cp38

mt2-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl (29.3 kB view hashes)

Uploaded cp38

mt2-1.2.0-cp37-cp37m-win_amd64.whl (29.4 kB view hashes)

Uploaded cp37

mt2-1.2.0-cp37-cp37m-win32.whl (28.3 kB view hashes)

Uploaded cp37

mt2-1.2.0-cp37-cp37m-manylinux1_x86_64.whl (87.0 kB view hashes)

Uploaded cp37

mt2-1.2.0-cp37-cp37m-manylinux1_i686.whl (78.7 kB view hashes)

Uploaded cp37

mt2-1.2.0-cp36-cp36m-win_amd64.whl (29.4 kB view hashes)

Uploaded cp36

mt2-1.2.0-cp36-cp36m-win32.whl (28.3 kB view hashes)

Uploaded cp36

mt2-1.2.0-cp36-cp36m-manylinux1_x86_64.whl (86.8 kB view hashes)

Uploaded cp36

mt2-1.2.0-cp36-cp36m-manylinux1_i686.whl (78.5 kB view hashes)

Uploaded cp36

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Huawei Huawei PSF Sponsor Microsoft Microsoft PSF Sponsor NVIDIA NVIDIA PSF Sponsor Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page