# TIRL, the Tensor Image Registration Library (FMRIB/Oxford; Python + two Cython extensions). FMRIB's FSL installer ships it (conda package # fsl-tirl 3.6.3); not in Fedora. # # VERSION CAVEAT: this is 3.6.2, the newest tag FMRIB publishes (git.fmrib.ox.ac.uk/fsl/tirl). The installer's 3.6.3 has no public source: the # GitHub repo that FMRIB's page points to (tirlworks/tirl) is not reachable and there is no PyPI project. Morgan chose 3.6.2 (2026-10-09). # 3.6.2 predates NumPy 2 and does not work on it; Patch0 ports it (see the changelog). Licence is Apache-2.0 (the LICENSE file in the source and in # FMRIB's own install), though the conda metadata says "FSL"; the extensions link only LAPACK/BLAS, so this lives in the FREE project. %global pypi_name tirl %global tirl_requires python3-numpy python3-scipy python3-attrdict3 python3-dask python3-dill python3-imagecodecs python3-imageio python3-joblib python3-matplotlib python3-nibabel python3-nlopt python3-numba python3-opencv python3-openslide python3-pillow python3-psutil python3-pygments python3-dateutil python3-pyyaml python3-scikit-image python3-scikit-learn python3-simpleitk python3-threadpoolctl python3-tifffile Name: python-%{pypi_name} Version: 3.6.2 Release: 1%{?dist} Summary: TIRL - Tensor Image Registration Library License: Apache-2.0 URL: https://git.fmrib.ox.ac.uk/fsl/tirl Source0: https://git.fmrib.ox.ac.uk/fsl/tirl/-/archive/%{version}/tirl-%{version}.tar.gz Patch0: python-tirl-numpy2.patch BuildRequires: python3-devel BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: gcc-gfortran BuildRequires: lapack-devel BuildRequires: blas-devel BuildRequires: python3-Cython BuildRequires: %{tirl_requires} %global _description %{expand: TIRL registers images in arbitrary dimensions with linear and nonlinear transformations (including displacement fields and their inversion), tensor and scalar images, many cost functions and optimisers, with a TImage/TField data model. Includes FSLInterpolator, a Cython port of FLIRT's trilinear interpolation, and a field-inversion extension.} %description %_description %package -n python3-%{pypi_name} Summary: %{summary} Requires: %{tirl_requires} %description -n python3-%{pypi_name} %_description %prep %autosetup -p1 -n tirl-%{version} head -1 tirl/tirl | grep -q '^#!' %py3_shebang_fix tirl/tirl %generate_buildrequires %pyproject_buildrequires %build %pyproject_wheel %install %pyproject_install %pyproject_save_files tirl %check %pyproject_check_import # upstream ships no tests. Known-answer checks of what the NumPy 2 port touches, against the installed tree. export PYTHONPATH=%{buildroot}%{python3_sitearch} %{python3} -sP - <<'PY' import numpy as np, warnings, pkgutil, importlib warnings.simplefilter("ignore") import tirl # 1. FSLInterpolator: trilinear interpolation of a linear function is exact in the interior (it returns 0 on the last voxel index, like FLIRT) from tirl.cmodules.fslinterpolator import fslinterpolator i, j, k = np.meshgrid(np.arange(4), np.arange(5), np.arange(6), indexing="ij"); d = (2*i + 3*j + 5*k + 1).astype(np.float32) c = np.array([[1.5, 2.25, 3.75], [0, 0, 0], [2.9, 3.1, 4.2]], np.float32) got = np.asarray(fslinterpolator(d, c)); want = 2*c[:, 0] + 3*c[:, 1] + 5*c[:, 2] + 1 assert np.allclose(got, want, atol=1e-3), (got, want) # 2. field inversion: the inverse of a constant displacement (1, 0.5) is (-1, -0.5) (np.product in finv.pyx broke this on NumPy 2) from tirl.cmodules.finv import invert n = 8; g = np.stack(np.meshgrid(np.arange(n), np.arange(n), indexing="ij")).reshape(2, -1).T.astype(float) field = np.zeros((2, n, n)); field[0] = 1.0; field[1] = 0.5 out = np.asarray(invert(np.array([[3.0, 3.0], [4.0, 2.0]]), field, g)) assert np.allclose(out, [[-1, -1], [-0.5, -0.5]], atol=1e-6), out # 3. image construction and round trip (np.float_ default dtype and can_cast on a Python int broke this on NumPy 2) from tirl.timage import TImage a = np.arange(20, dtype=np.float32).reshape(4, 5); im = TImage(a) assert np.array_equal(np.asarray(im.data), a) and tuple(im.vshape) == (4, 5) # 4. every module imports bad = [] for m in pkgutil.walk_packages(tirl.__path__, "tirl."): try: importlib.import_module(m.name) except BaseException as e: bad.append((m.name, repr(e)[:80])) assert not bad, bad print("tirl known-answer checks passed;", len(list(pkgutil.walk_packages(tirl.__path__, "tirl."))), "modules import") PY %files -n python3-%{pypi_name} -f %{pyproject_files} %license LICENSE NOTICE %doc README.md CHANGELOG.md %{_bindir}/tirl %changelog * Fri Oct 09 2026 Morgan Hough - 3.6.2-1 - Initial package: TIRL 3.6.2 from FMRIB's GitLab, NOT the 3.6.3 that FMRIB's FSL installer ships (no public source for 3.6.3). - Patch0 ports 3.6.2 to NumPy 2 (Fedora 44 has 2.4): np.product -> np.prod (10 sites incl. finv.pyx), np.float_ -> np.float64, np.complex -> complex, np.bool -> bool, np.in1d -> np.isin, and domain.py's can_cast(python int, dtype) -> an iinfo bound. Mechanical and behaviour-preserving, 9 files. Unpatched on NumPy 2.4.6 (scratch chroot): finv.invert raises AttributeError (np.product) and TImage(np.zeros((4,4))) raises TypeError (can_cast); patched: both work, field inversion returns the exact negative of a constant displacement, 85 of 85 modules import. - No upstream tests; %%check carries known-answer checks (interpolation exact, field inversion, TImage round trip, all modules import). No registration has been run end to end, so the optimisers and cost functions beyond import are untested.