Skip to content

Move BART to Codeberg master with the rebased downstream stack - #104

Merged
mcencini merged 7 commits into
mainfrom
claude/bart-downstream-rebase-n4as96
Sep 29, 2026
Merged

mcencini merged 7 commits into
mainfrom
claude/bart-downstream-rebase-n4as96

Conversation

@mcencini

@mcencini mcencini commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Requested by Matteo · project thread

What changed

  • Submodule move. external/bart goes from 694ab5fe (on bartorch-v1.0.00, now also tagged downstream-20260929) to 7fab96d7 (on downstream). The new commit is Codeberg master 3beb5572 plus 22 downstream commits.
  • Build. The library now builds with C23, which is BART's -std=gnu2x. It defines USE_GPU beside USE_CUDA, since BART's device code now sits under USE_GPU. simu/gpu_bloch.cu is added to the CUDA sources.
  • Symbol visibility. Upstream's misc/dllspec.h now gives BARTLIB_API default visibility outside Windows. That put seq_*, num_rand_init and debug_printf in the dynamic table beside the bartorch_* ABI; the dry-run Linux wheel had 35 of them.
    • A compile definition of the header's guard leaves them hidden, as BARTLIB_STATIC already does on Windows.
    • The CUDA sources now take the same hidden preset as C and C++. Without it the CUDA build exported 124 of BART's cuda_*, eigenmapscu and wl3_cuda_* wrappers; that leak predates this PR, and the new test caught it.
    • tests/test_abi.py now holds the table's C names to the ABI. It fails on that wheel and passes on this build.
  • One OpenMP runtime on Linux too. The Linux wheels vendored their own libgomp, so a process with torch mapped two runtimes. They now carry none and bind to torch's, as macOS and Windows already did.
    • Both Linux repairs run auditwheel repair --exclude libgomp.so.1, and $ORIGIN/../torch/lib is on the library's runpath.
    • _lib._load imports torch before loading the library on every platform, so the copy torch loaded is the one bound.
    • torch carries torch/lib/libgomp.so.1 from 2.7.1 on (earlier releases use a hashed name), so Linux now requires torch>=2.7.1. macOS stays at 2.3.
    • tests/test_openmp.py now requires exactly one runtime, torch's, on every platform.
    • AGENTS.md, cmake/openmp.cmake, the FINUFFT design page, the installation and prerequisites pages and the license page are updated to match.
  • Field-map arguments. nufft_create2 and sense_nc_init now take a field map and a time map.
    • The substitutes take them too.
    • --nufft-conf dft (BART's explicit transform, the only one that uses a field map) is handed straight to BART.
    • A field map passed without dft is refused with a message that names the problem.
    • sense.c now includes sense/modelnc.h, so the compiler checks the substitute against BART's declaration. The previous copy compiled against the old signature without complaint.
  • Catalogue. _catalogue.py is regenerated. The reader now handles OPTL_FLVEC7 and a help string declared as a pointer (pulseq). Option help is escaped for | (mobafit's |M| broke the docs build).
  • New commands, all kept private:
    • pulseq reads and writes files.
    • sort is covered by torch.
    • bet and extractdc are not wrapped yet.
  • Changed commands:
    • unwrap now takes a set of axes; the wrapper passes one bit.
    • mobafit now requires its output, and raga refuses to run without one. The optional-output exception therefore moves from mobafit to raga.
  • A test fix from Build FINUFFT for x86-64-v2, v3 and v4 as well, and pick the level at run time #102. test_a_library_without_its_modules_transforms_at_the_baseline copied the library into an empty folder, which loses anything the wheel vendors beside it. It now keeps the wheel's layout.

Why

This moves the fork workflow onto Codeberg history: master equals Codeberg, and downstream is master plus the patch stack.

Validation

CI on this PR (Tests, Docs, Lint, Typos): green on 58b06cc0.

  • Tests cover Linux GCC 14 on 3.10 (MKL FINUFFT) and 3.14, macOS arm64 on 3.10 and 3.14, Windows clang on 3.10 and 3.14, and the CUDA build (nvcc, cuFINUFFT, run on the host).

Publish dry run: workflow_dispatch on 58b06cc0, run 36549695519, all green. Publish to PyPI and Attach the CUDA wheel to the release were skipped (they run only on tags), so nothing was published.

  • Wheels built: sdist, Linux x86-64, macOS arm64, Windows x86-64, Linux CUDA.
  • Every wheel ran the suite in cibuildwheel and passed the install tests on 3.10 and 3.14 per OS. The CUDA wheel loaded without a card on 3.10 and 3.14.

Wheel inspection (downloaded artifacts, auditwheel, readelf/nm/objdump, macholib, pefile). Linux and CUDA are from run 36549695519; macOS and Windows are from run 36541419983 on 87e42582, and nothing since changes what they link.

  • Linux CPU
    • Tag manylinux_2_28_x86_64. The highest GLIBC version any of its libraries references is 2.28.
      • auditwheel show on the runner reports 2_38. That comes from the runner's own libgomp, which it now resolves because the wheel no longer carries one (inferred; the wheel's own objects stop at 2.28).
    • NEEDED is libc, libm, libdl, libpthread, ld-linux and libgomp.so.1. There is no bartorch.libs, libstdc++ or libgcc_s. The runpath is $ORIGIN/../torch/lib.
    • Six FINUFFT modules: v2, v3 and v4, each on DUCC0 and on MKL. The _mkl modules link no MKL and import no FFTW symbols, and export only finufft* and bartorch_fftw_bind.
    • Installed beside torch 2.14 CPU here, one OpenMP runtime is mapped: torch/lib/libgomp.so.1. test_openmp.py and test_finufft.py pass against the extracted wheel (77 passed, 15 skipped).
  • Linux CUDA
    • NEEDED is libcudart.so.12, libcufft.so.11, libcublas(Lt).so.12 and libgomp.so.1, with no vendored libgomp.
    • The runpath is nvidia/*/lib and then $ORIGIN/../torch/lib.
  • macOS arm64
    • Loads /usr/lib/libSystem.B.dylib, @rpath/libomp.dylib and /usr/lib/libc++.1.dylib.
    • The only rpath is @loader_path/../torch/lib, so the libomp is torch's. No Homebrew, /usr/local or /opt/local path appears anywhere in the binary.
  • Windows x86-64
    • The library and the three FINUFFT modules import only KERNEL32.dll, the UCRT api-ms-win-crt-* set and libiomp5md.dll (torch's Intel OpenMP).
    • No MSYS2, winpthread, libgcc or libstdc++ name appears in them.

Local, Linux x86-64, GCC 14: pytest tests/ gave 1806 passed, 97 skipped and 20 failed on 40866e73. All 20 failures are packages missing from the container: torchsim, mrinufft, a torch/torchvision mismatch that breaks deepinv, and the MKL FINUFFT module, which needs mkl-include. Lint is clean. Every renamed BART symbol exists in both its bart_ and its substituted form.

Needs real hardware (not run; no results claimed)

  • NVIDIA card: python scripts/check_device.py with the CUDA wheel. It covers:

    • the device found, and a tool on device tensors
    • the NUFFT against an explicit DFT on the card
    • cuFINUFFT serving the trajectory
    • device against host
    • pics with and without Toeplitz
    • multiple streams, the memcache beside torch's allocator
    • -g being redundant

    Also run tests/test_cuda.py. CI only compiles the device code and loads it without a card; this bump moved it under USE_GPU and added simu/gpu_bloch.cu.

  • Intel and AMD x86-64 (Linux and Windows):

    • _finufft.simd() picks the newest level the CPU runs: v4 only where AVX-512 exists; AMD Zen 4 and later is v4, and earlier Zen is v3.
    • With pip install mkl, the _mkl module is preferred and agrees with DUCC0.
    • BARTORCH_FINUFFT_SIMD overrides the choice.
    • CI runners are one vendor and one level.
  • Clean Windows machine without MSYS2 on PATH:

    • pip install the wheel and torch, then import and run a tool and a NUFFT.
    • Confirm that only torch's libiomp5md.dll is loaded.
  • Apple Silicon outside CI: the wheel with a torch from PyPI, running a tool, a NUFFT and threaded torch in one process, with one libomp mapped.

Public API and documentation

  • Removed: bartorch.tools.pocsense, tools.sqpics and tools.rtnlinv, and bartorch pocsense on the command line. Upstream deleted these commands.
  • Kept: bartorch.apps.pocsense is still built from BART's pocs iteration. It is now tested against a fully sampled phantom being a fixed point and against its answer lying in the range of the coils, instead of against the command's bits.
  • Requirement: torch>=2.7.1 on Linux, for the libgomp above.
  • Updated: docs/api/tools.md, docs/api/apps.md, docs/explanation/non-cartesian.md, the OpenMP pages listed above, and AGENTS.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_014ok1jumatvU8YSzRCEaj8Q

The submodule moves from 694ab5fe on bartorch-v1.0.00 to 7fab96d7 on
downstream: Codeberg master 3beb5572 plus the 22-commit portability
stack.  What the library needs from that BART:

- C23, which BART now compiles as (bool is a keyword, stdbool.h is gone).
- USE_GPU beside USE_CUDA, the macro BART's device code is now under,
  and simu/gpu_bloch.cu in the CUDA sources.
- nufft_create2 and sense_nc_init take a field map and a time map.  Both
  are only served by BART's explicit transform (--nufft-conf dft), which
  is handed straight to BART; a field map without it is refused by name.
  sense.c includes modelnc.h so the compiler holds the substitute to the
  header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ok1jumatvU8YSzRCEaj8Q
BART no longer has pocsense, sqpics or rtnlinv, so their derived tools
go, with the CLI's pocsense adapter and the tests that ran them.
apps.pocsense stays, built as before from BART's pocs iteration, and is
held to a fully sampled phantom being its fixed point and to its answer
lying in the range of the coils.

New commands are private: pulseq reads and writes files, sort is an
array operation torch has, bet and extractdc are not wrapped yet.

unwrap takes a set of axes rather than one; mobafit now requires its
output and raga refuses to run without one, so the optional-output
exception moves from mobafit to raga.  The catalogue reader learns
OPTL_FLVEC7 and a help string declared as a pointer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ok1jumatvU8YSzRCEaj8Q
mobafit's -P help writes |M|, which reStructuredText reads as a
substitution, and the docs build treats that warning as an error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ok1jumatvU8YSzRCEaj8Q
…UFFT test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ok1jumatvU8YSzRCEaj8Q
@codecov

codecov Bot commented Sep 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

The new misc/dllspec.h gives BARTLIB_API default visibility outside
Windows, which put seq_*, num_rand_init and debug_printf in the
library's dynamic table beside the bartorch_* ABI.  Defining the
header's guard with BARTLIB_API empty leaves them hidden, as Windows
already has them through BARTLIB_STATIC, and a test holds the table's
C names to the ABI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ok1jumatvU8YSzRCEaj8Q
nvcc's host code took no visibility preset, so the CUDA build exported
BART's cuda_* wrappers, eigenmapscu and wl3_cuda_* beside the
bartorch_* ABI, which the dynamic-table test now catches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ok1jumatvU8YSzRCEaj8Q
The Linux wheels carried a libgomp of their own, so a process that
imported torch had two OpenMP runtimes.  torch carries libgomp.so.1 in
torch/lib from 2.7.1 on, which is the name the library's NEEDED entry
asks for: the library is loaded after torch on Linux as it already is
on macOS and Windows, the wheels are repaired with --exclude
libgomp.so.1, and $ORIGIN/../torch/lib is on the runpath.  Linux
requires torch 2.7.1, the first release whose copy has that name, and
the OpenMP test now holds every platform to one runtime, torch's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ok1jumatvU8YSzRCEaj8Q
@mcencini
mcencini marked this pull request as ready for review September 29, 2026 09:55
@mcencini
mcencini merged commit 6599961 into main Sep 29, 2026
28 checks passed
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.

2 participants