%define debug_package %{nil} Name: simnibs Version: 4.6.0 Release: 17%{?dist} Summary: Simulation of Non-Invasive Brain Stimulation License: GPL-3.0-only URL: http://simnibs.org Source0: https://github.com/simnibs/simnibs/archive/v%{version}/simnibs-%{version}.tar.gz # charm's mesher writes a MEDIT .mesh via CGAL, then reads it back with # simnibs' own read_medit(), which rejects it: CGAL emits a comment line # ("# CGAL::Mesh_complex_3_in_triangulation_3") between the Dimension and # Vertices keywords, and the reader requires the next line to be exactly # "Vertices". MEDIT permits comments. Without this, `charm --mesh` dies with # OSError: invalid mesh format after ~4 minutes of meshing work, and no head # model is ever produced. Patch0: simnibs-medit-skip-comment-lines.patch Patch1: simnibs-mmg-disable-scotch-renumbering.patch # path2bin constructs a path and never checks it, so a missing external # binary is silent until something executes it -- minutes into a run. Patch2: simnibs-path2bin-name-the-missing-binary.patch BuildRequires: gcc-c++ BuildRequires: python3-devel BuildRequires: python3-setuptools >= 68 BuildRequires: python3-setuptools_scm >= 8 BuildRequires: python3-Cython BuildRequires: python3-numpy BuildRequires: python3-pip BuildRequires: python3-wheel BuildRequires: python3-build # For CGAL mesh extensions BuildRequires: CGAL-devel BuildRequires: gmp-devel BuildRequires: mpfr-devel BuildRequires: zlib-devel BuildRequires: tbb-devel BuildRequires: eigen3-devel # Not needed to compile anything. They are here so %%check can follow the two # symlinks it installs into external/bin/linux and confirm they resolve. # Without them the targets do not exist in the buildroot, `test -x` fails on # a link that will be perfectly good once the package is installed, and -14 # failed its own assertion. Build-time presence also catches the case the # runtime Requires cannot: upstream renaming the binary, which would leave a # satisfied dependency and a dangling link. BuildRequires: mmg3d BuildRequires: meshfix %description SimNIBS is a software package for the simulation of non-invasive brain stimulation (NIBS). It enables realistic calculations of the electric field induced by transcranial magnetic stimulation (TMS) and transcranial direct current stimulation (tDCS). %package -n python3-simnibs Summary: Python 3 module for SimNIBS Requires: python3-numpy Requires: python3-scipy Requires: python3-h5py Requires: python3-nibabel Requires: python3-pillow Requires: python3-requests Requires: python3-jsonschema Requires: python3-numba Requires: python3-fmm3dpy Requires: python3-pygpc # A FLOOR, deliberately, and not the kind that failed us before. # # The floor that did NOT work was samseg's own `InsightToolkit5 >= 5.4.7-13`: # it tried to guard an ABI, and a layout change at an unchanged soname # satisfies any floor. This one states something different and checkable -- # "samseg builds before 0.5a0-8 are known broken against ITK -23/-24" -- # and the ABI work is done one hop down by samseg's own # `itk(abi) = 5.4-legacy` equality. simnibs links no ITK itself, so an # itk(abi) Requires here would be wrong in kind. # # Measured locally, same reproducer, same ITK 5.4.7-24, only samseg changed: # samseg 0.5a0-7 RED exit 1, "Zero-valued spacing is not supported" # raised inside KvlRigidRegistration.register() # samseg 0.5a0-8 GREEN exit 0, corr(fixed,out) 0.9986 # Without this line dnf installs the RED combination happily and charm # fails 19 seconds into a run. Requires: python3-samseg >= 0.5a0-8 Requires: python3-petsc4py Requires: python3-qt5 # The resources are not optional: coil models, head templates and the MNI # electrode caps live in the data subpackage, and every TMS/tDCS simulation # reads them. Without this the module imports and then fails at the point of # use, which is worse than not installing. Requires: %{name}-data = %{version}-%{release} # Meshing and mesh visualisation. Fedora ships gmsh 4.15 with its Python # bindings, so there is no reason to strip this dependency (see %%prep). Requires: python3-gmsh # The GUI is a separate subpackage but is how most people drive SimNIBS. Recommends: %{name}-gui = %{version}-%{release} # Cortical layer placement and analysis. NOT optional despite the name # suggesting a side feature: simnibs/__init__.py reaches it through the # import chain, so without it `import simnibs` raises # ModuleNotFoundError: No module named 'cortech' # and every entry point fails. It was a Recommends in -5, which is exactly # why the package installed cleanly and then did not work. Requires: python3-cortech # The MUMPS sparse direct solver binding. simnibs/simulation/fem.py does # `import mumps` at module scope, so this is not optional either. Upstream # leaves it out of pyproject.toml on purpose -- the comment there reads # "python-mumps - only works automatically via conda" -- which means a pip # install of SimNIBS has the same broken import we had. It is packaged now # (python-mumps), so on Fedora it simply works. Requires: python3-mumps # Head model creation from a subject's own MRI. simnibs/segmentation/ # brain_surface.py does `import brainnet` at module scope (line 13) and calls # brainnet.helpers.trega / brainnet.helpers.topofit to reconstruct the cortical # surfaces, so without this `charm --help` itself fails and # simnibs.mesh_tools.meshing and simnibs.optimization.opt_struct are # unimportable. Upstream declares brainnet>=0.2 in pyproject.toml; we used to # strip that line because the package did not exist. It does now. Requires: python3-brainnet >= 0.2 # torch is needed by simnibs/segmentation/brain_surface.py, which # mesh_tools/meshing.py and optimization/opt_struct.py both import -- so # without it charm cannot even print its help, and meshing and optimization # are unimportable. Upstream does not declare it in pyproject.toml at all, # the same omission as python-mumps. Fedora has torch 2.9.1. Requires: python3-torch # EEG forward modelling (simnibs/eeg/forward.py, eeg/utils_mne.py) reads and # writes MNE-Python structures. Not needed to import simnibs, so Recommends. Recommends: python3-mne # FSL and FreeSurfer are nonfree (mhough/neurofedora-nonfree); SimNIBS uses # them for some segmentation paths but works without them via charm/samseg. Suggests: fsl %description -n python3-simnibs Python 3 module for SimNIBS. %package data Summary: Data files for SimNIBS %description data Data files for SimNIBS including templates and coil models. %package gui Summary: Graphical User Interface for SimNIBS Requires: python3-simnibs = %{version}-%{release} Requires: python3-qt5 Requires: python3-pyopengl # charm's meshing stage shells out to these. Upstream bundles prebuilt # copies under simnibs/external/bin/linux, which %prep removes; Fedora has # both, so they are symlinked back into the path simnibs looks in. Requires: mmg3d Requires: meshfix %description gui Graphical User Interface for SimNIBS based on PyQt5. %prep %autosetup -n simnibs-%{version} -p1 # Remove bundled binaries and wheels rm -rf simnibs/external/bin/* rm -rf simnibs/external/wheels/* # Relax pinned version requirements sed -i 's/fmm3dpy==1.0.4/fmm3dpy>=1.0.0/' pyproject.toml sed -i 's/pygpc>=0.4.1/pygpc>=0.4.1/' pyproject.toml # Remove conda-only deps that are system libs on Fedora sed -i '/mkl ;/d' pyproject.toml sed -i '/tbb ;/d' pyproject.toml # Nothing is stripped from [project] dependencies any more. cortech went first # (-6) and brainnet is the last of them (-8): both are packaged now, so the # wheel metadata should say what `import simnibs` genuinely needs. # # Assert that, rather than leaving a comment that could go stale. The # dependency must be PRESENT in pyproject.toml, because the auto-generated # python3.14dist(brainnet) >= 0.2 requirement comes from there, and the # explicit Requires above is the belt to that brace. A positive test: if the # line vanished on a version bump this fails loudly instead of silently # shipping a simnibs that does not pull in brainnet. grep -q '"brainnet>=0.2"' pyproject.toml || { echo "ERROR: pyproject.toml no longer declares brainnet>=0.2." echo "Re-check the Requires on python3-simnibs before building." exit 1 } # The other two removals below stay, and are NOT the same case: mkl and tbb are # conda-only names for libraries Fedora provides as system packages, so there # is nothing to require. petsc4py is removed from the BUILD deps only and is a # hard runtime Requires above. # gmsh is NOT stripped: Fedora ships python3-gmsh 4.15 and SimNIBS's meshing # and .msh visualisation paths use it. # Remove petsc4py from build deps (not yet packaged, only needed at runtime) sed -i '/"petsc4py"/d' pyproject.toml # Relax numpy version (upstream requires >=2, system may have 1.x) sed -i 's/"numpy>=2"/"numpy"/' pyproject.toml sed -i "s/'numpy>=2'/'numpy'/" pyproject.toml # ---- Patch setup.py for system (non-conda) build ---- # Remove conda requirement check sed -i '/is_conda/d; /No conda/d; /Cannot run setup without conda/d' setup.py # Replace CONDA_PREFIX library/include paths with system paths (Linux block) sed -i "s|os.path.join(os.environ\['CONDA_PREFIX'\], 'lib')|'/usr/%{_lib}'|g" setup.py sed -i "s|os.path.join(os.environ\['CONDA_PREFIX'\], 'include','eigen3')|'/usr/include/eigen3'|g" setup.py # Fix C++ standard from gnu++14 to gnu++17 (CGAL 5.x / GCC 15) sed -i "s/-std=gnu++14/-std=gnu++17/" setup.py # Remove distutils import (removed in Python 3.12+) sed -i '/from distutils.dep_util import newer_group/d' setup.py # Remove the changed_meshing block that used newer_group (assigned but never used) sed -i '/changed_meshing = (/,/^ )$/d' setup.py # ---- Port _cgal_intersect.cpp from CGAL 5 to CGAL 6 ---- # CGAL 6 replaced boost::optional with std::optional sed -i 's/boost::optional/std::optional/g' simnibs/mesh_tools/cgal/_cgal_intersect.cpp # In CGAL 6, inter->second is directly SM_Face_index (not a variant) sed -i 's/boost::get(inter->second)/(std::size_t)inter->second/g' \ simnibs/mesh_tools/cgal/_cgal_intersect.cpp # In CGAL 6, inter->first is std::variant; use std::get_if for pointer access sed -i 's/boost::get(\&(inter->first))/std::get_if(\&(inter->first))/g' \ simnibs/mesh_tools/cgal/_cgal_intersect.cpp sed -i 's/boost::get(\&(inter->first))/std::get_if(\&(inter->first))/g' \ simnibs/mesh_tools/cgal/_cgal_intersect.cpp # ---- CGAL 6: create_labeled_image_mesh_domain takes named parameters ---- # Old form (CGAL 5): ::create_labeled_image_mesh_domain(image, relative_error_bound) # New form (CGAL 6): ::create_labeled_image_mesh_domain( # CGAL::parameters::image(image) # .relative_error_bound(relative_error_bound)) # Both _cgal_intersect.cpp (already patched above) and _mesh_volumes.cpp # use this; rawhide build 10505996 failed on the latter. sed -i 's|::create_labeled_image_mesh_domain(image, *1e-10)|::create_labeled_image_mesh_domain(CGAL::parameters::image(image).relative_error_bound(1e-10))|g' \ simnibs/mesh_tools/cgal/_mesh_volumes.cpp # ---- Default the FEM solver to MUMPS rather than hypre ---- # simnibs defaults to solver_options="hypre", i.e. PETSc's BoomerAMG # preconditioner. Fedora's petsc is NOT built with hypre, so every simulation # dies after assembling the matrix with # petsc4py.PETSc.Error: error code 86 ... Unable to find requested PC type hypre # MUMPS is one of simnibs's own VALID_SOLVER_OPTIONS and its branch uses # python-mumps directly rather than going through PETSc, so it works with what # Fedora ships (and is why simnibs imports mumps at all). Users can still ask # for any other option explicitly; this only changes the default. sed -i 's/solver_options: None | str = "hypre",/solver_options: None | str = "mumps",/' \ simnibs/simulation/fem.py sed -i 's/solver_options = "hypre" if solver_options is None else solver_options/solver_options = "mumps" if solver_options is None else solver_options/' \ simnibs/simulation/fem.py grep -q 'str = "mumps"' simnibs/simulation/fem.py || \ { echo "solver default patch did not apply"; exit 1; } # ---- Fix CGAL 6 const-correctness bug ---- # CGAL 6.0.3 Add_features_in_domain::operator() takes Image_3& (non-const) # but Labeled_mesh_domain_3 passes const Image_3 weights_. Create local patched copy. mkdir -p cgal_fix/CGAL cp /usr/include/CGAL/Labeled_mesh_domain_3.h cgal_fix/CGAL/ sed -i 's/void operator()(const CGAL::Image_3&, CGAL::Image_3&,/void operator()(const CGAL::Image_3\&, const CGAL::Image_3\&,/' \ cgal_fix/CGAL/Labeled_mesh_domain_3.h %build export SETUPTOOLS_SCM_PRETEND_VERSION=%{version} export CXXFLAGS="%{optflags} -std=c++17 -include cstdint -I$PWD/cgal_fix" export CFLAGS="%{optflags} -Wno-error=implicit-function-declaration -Wno-error=incompatible-pointer-types" %pyproject_wheel %install %pyproject_install # simnibs_python: upstream ships this as the interpreter from the Miniconda # instance its installer downloads, and the entire scripting tutorial invokes # scripts as `simnibs_python foo.py`. Here SimNIBS is installed into the # system Python, so the equivalent interpreter is simply python3 -- but the # name has to exist or every documented example fails with "command not # found". A three-line shim is the difference between the tutorials working # and not. install -d %{buildroot}%{_bindir} cat > %{buildroot}%{_bindir}/simnibs_python <<'SHIM' #!/bin/sh # SimNIBS on Fedora is installed into the system Python, so the interpreter # upstream ships as simnibs_python (a bundled Miniconda) is just python3. exec %{__python3} "$@" SHIM chmod 0755 %{buildroot}%{_bindir}/simnibs_python # Upstream wheel installs a top-level `tools/` package at site-packages root # (collides with Python global namespace; not part of `simnibs`). Drop it. rm -rf %{buildroot}%{python3_sitearch}/tools # --- external binaries: symlink Fedora's in place of the bundled ones --- # # %%prep deletes simnibs/external/bin/*, which is right -- they are prebuilt # x86_64 binaries plus a bundled libstdc++.so.6. But nothing replaced them, # and simnibs resolves them by PATH CONSTRUCTION, not by $PATH lookup: # file_finder.path2bin() returns SIMNIBSDIR/external/bin/linux/ # with no fallback. So charm died after ten minutes of meshing with # FileNotFoundError: .../simnibs/external/bin/linux/mmg3d_O3 # having already relabelled 100,204 tetrahedra. # # Fedora's mmg3d installs /usr/bin/mmg3d_O3 under exactly the name simnibs # wants, and meshfix is in this repo. Upstream also bundles two CAT12 tools # for spherical registration (charm --surfaces), CAT_Surf2Sphere and # CAT_WarpSurf. # # CAT_Surf2Sphere: the COPR's cat-surface 1.0.30-1 installs # /usr/bin/CAT_Surf2Sphere, but simnibs never looks on $PATH, so it went # unused (neurospark, aarch64, 2026-10-07: "not installed at # .../external/bin/linux/CAT_Surf2Sphere" with cat-surface installed; with # the link added by hand, it ran on a real 61,442-vertex white surface in # 18.7 s). So link it. The link is deliberately soft: there is no Requires # and no Recommends. Without cat-surface it dangles, os.path.exists is # False, and Patch2's path2bin raises naming the program and CAT12, exactly # as before. Recommends is held until cat-surface's spec is in this repo: # build 11091377 was an uploaded SRPM with no spec in git, and a Recommends # would install it by default with every simnibs. # # CAT_WarpSurf: no package provides it, so it is still missing, and # charm --surfaces still stops there. install -d %{buildroot}%{python3_sitearch}/simnibs/external/bin/linux ln -s %{_bindir}/mmg3d_O3 %{buildroot}%{python3_sitearch}/simnibs/external/bin/linux/mmg3d_O3 ln -s %{_bindir}/meshfix %{buildroot}%{python3_sitearch}/simnibs/external/bin/linux/meshfix ln -s %{_bindir}/CAT_Surf2Sphere %{buildroot}%{python3_sitearch}/simnibs/external/bin/linux/CAT_Surf2Sphere # --- charm atlases: put back the data upstream's wheel leaves out ------- # # charm cannot build a head model without these. A fresh install fails on the # very first stage: # # charm sub T1 T2 --initatlas # RuntimeError: itkImageFileReader.hxx:135: Could not create IO object for # reading file .../charm_atlas_mni_v1-1/template.nii -- The file doesn't exist # # Cause is upstream's MANIFEST.in. It has # global-include *.md *.txt *.ini # graft simnibs/segmentation/atlases/charm_atlas_mni # but the directories are charm_atlas_mni_v1-0 and charm_atlas_mni_v1-1, so # the graft matches nothing. The three small files that DO ship are there by # accident, caught by the *.txt/*.ini global-include; template.nii and the # three atlas_*.gz are not, and atlas_level1.txt.gz does not match *.txt # either. # # This bites US and not upstream, which is worth being precise about: the # build uses setuptools-scm, whose file finder enumerates GIT-TRACKED files, # so a wheel built from a checkout contains everything -- verified by reading # the central directory of their released # simnibs-4.6.0-cp311-cp311-linux_x86_64.whl, which has all 14 files. A # tarball has no .git, that finder returns nothing, and MANIFEST.in alone # decides. Distributions build from tarballs. See # docs/upstream/simnibs-manifest-charm-atlas.md # # The files are in the GitHub tarball this package builds from, so they are # simply copied in. 229 MB across the two atlases, which is why they go in # the -data subpackage. for atlas in charm_atlas_mni_v1-0 charm_atlas_mni_v1-1; do src=simnibs/segmentation/atlases/$atlas dst=%{buildroot}%{python3_sitearch}/simnibs/segmentation/atlases/$atlas install -d "$dst" for f in template.nii affine_no_neck.txt.gz atlas_level1.txt.gz atlas_level2.txt.gz; do test -f "$src/$f" || { echo "MISSING FROM SOURCE TARBALL: $src/$f" >&2; exit 1; } install -pm 0644 "$src/$f" "$dst/$f" done done %pyproject_save_files simnibs %check # The external binaries charm shells out to must resolve. A dangling symlink # costs the user ten minutes of meshing before it is noticed. # # Both halves are checked, because they fail for different reasons: -L says # we created a link, and -x says it points at something that exists and runs. # The second needs the targets in the buildroot, which is what the # BuildRequires above are for. for _b in mmg3d_O3 meshfix; do _l=%{buildroot}%{python3_sitearch}/simnibs/external/bin/linux/$_b test -L "$_l" || { echo "$_b: not a symlink" >&2; exit 1; } test -x "$_l" || { echo "$_b: symlink dangles -> $(readlink "$_l")" >&2; exit 1; } done # CAT_Surf2Sphere is linked but cat-surface is not a BuildRequires, so only # its shape can be checked here: a link, to exactly /usr/bin. _l=%{buildroot}%{python3_sitearch}/simnibs/external/bin/linux/CAT_Surf2Sphere test -L "$_l" && test "$(readlink "$_l")" = %{_bindir}/CAT_Surf2Sphere # Patch1 must have reached every mmg3d call site. %%autosetup applies patches # with -p1, but a hunk that does not match is reported as "ignored" and does # NOT fail the build -- release 11 shipped green with its only patch silently # skipped. Count the call sites instead of trusting the apply. # Patch2: a missing external binary must be named where it is looked up, # not minutes later by subprocess. Exercised against a fake SIMNIBSDIR so # it does not depend on the buildroot being installable. %{python3} -c " import os, re, sys src = open('%{buildroot}%{python3_sitearch}/simnibs/utils/file_finder.py', newline='').read() m = re.search(r'def path2bin\(program\):.*?return path_to_binary', src, re.S) assert m, 'path2bin not found' ns = {'os': os, 'sys': sys, 'SIMNIBSDIR': '/nonexistent-for-check'} exec(m.group(0).replace(chr(13), ''), ns) for prog, want in (('CAT_Surf2Sphere', 'CAT12'), ('mmg3d_O3', 'mmg3d_O3')): try: ns['path2bin'](prog) except FileNotFoundError as e: assert want in str(e), (prog, 'message does not mention %s: %s' % (want, e)) else: raise SystemExit('path2bin(%r) did not raise for a missing binary' % prog) print('path2bin names a missing binary, and names CAT12 for the CAT tools') " mt=%{buildroot}%{python3_sitearch}/simnibs/mesh_tools sites=$(cat $mt/meshing.py $mt/mesh_io.py | grep -c 'path2bin("mmg3d_O3")') rn=$(cat $mt/meshing.py $mt/mesh_io.py | grep -c '"-rn",') test "$sites" -eq 4 || { echo "expected 4 mmg3d call sites, found $sites" >&2; exit 1; } test "$rn" -eq "$sites" || { echo "Patch1 reached $rn of $sites call sites" >&2; exit 1; } # The atlas data above is what makes charm work at all, and its absence is # invisible until someone runs a real head model -- our 27 BATS tests and # every import check passed for months with it missing. Assert it here. for atlas in charm_atlas_mni_v1-0 charm_atlas_mni_v1-1; do t=%{buildroot}%{python3_sitearch}/simnibs/segmentation/atlases/$atlas/template.nii test -s "$t" # a real template is tens of MB; a truncated or placeholder file is not sz=$(stat -c%s "$t") test "$sz" -gt 40000000 || { echo "$atlas/template.nii is only $sz bytes" >&2; exit 1; } done # Full import requires scipy, numba, h5py, etc. -- just verify extensions built cd / %{python3} -c " import os, struct site = '%{buildroot}%{python3_sitearch}/simnibs' so_files = [] for root, dirs, files in os.walk(site): for f in files: if f.endswith('.so'): path = os.path.join(root, f) with open(path, 'rb') as fh: assert fh.read(4) == b'\x7fELF', f'{f} is not a valid ELF' so_files.append(f) assert len(so_files) >= 4, f'Expected at least 4 .so files, found {len(so_files)}' print(f'Found {len(so_files)} extension modules: {so_files}') " %files -n python3-simnibs -f %{pyproject_files} %license LICENSE.txt # The interpreter shim; see %%install for why it exists. %{_bindir}/simnibs_python %{_bindir}/add_tissues_to_upsampled %{_bindir}/calc_B %{_bindir}/charm %{_bindir}/charm_tms %{_bindir}/coil2nifti %{_bindir}/convert_3_to_4 %{_bindir}/download_coils %{_bindir}/eeg_positions %{_bindir}/expand_to_center_surround %{_bindir}/get_eeg_positions %{_bindir}/get_fields_at_coordinates %{_bindir}/maskmesh %{_bindir}/meshmesh %{_bindir}/mni2subject %{_bindir}/mni2subject_coords %{_bindir}/msh2cortex %{_bindir}/msh2nii %{_bindir}/nii2msh %{_bindir}/postinstall_simnibs %{_bindir}/prepare_eeg_forward %{_bindir}/prepare_eeg_montage %{_bindir}/prepare_tdcs_leadfield %{_bindir}/register %{_bindir}/simnibs %{_bindir}/subject2mni %{_bindir}/subject2mni_coords %{_bindir}/subject_atlas %exclude %{python3_sitearch}/simnibs/resources/ %exclude %{python3_sitearch}/simnibs/_internal_resources/ %exclude %{python3_sitearch}/simnibs/examples/ %exclude %{python3_sitearch}/simnibs/GUI/ %files data %{python3_sitearch}/simnibs/segmentation/atlases/ %{python3_sitearch}/simnibs/external/bin/linux/mmg3d_O3 %{python3_sitearch}/simnibs/external/bin/linux/meshfix %{python3_sitearch}/simnibs/external/bin/linux/CAT_Surf2Sphere %{python3_sitearch}/simnibs/resources/ %{python3_sitearch}/simnibs/_internal_resources/ %{python3_sitearch}/simnibs/examples/ %files gui %{python3_sitearch}/simnibs/GUI/ %{_bindir}/simnibs_gui %changelog * Wed Oct 07 2026 Morgan Hough - 4.6.0-17 - Link external/bin/linux/CAT_Surf2Sphere to /usr/bin/CAT_Surf2Sphere, so charm --surfaces uses cat-surface when it is installed. simnibs resolves external binaries by constructing a path, never via $PATH, so an installed cat-surface was ignored. Reported by neurospark on aarch64, where it ran on a real surface with the link added by hand. - Soft on purpose: no Requires or Recommends, and without cat-surface the link dangles and path2bin raises the same named error as before. Recommends waits for cat-surface's spec to be in the repo. - Still missing: CAT_WarpSurf, which no package provides. * Tue Oct 06 2026 Morgan Hough - 4.6.0-16 - Requires: python3-samseg >= 0.5a0-8. Until now dnf would happily install simnibs alongside a samseg built against the removed ITK layout, and charm then failed in T2->T1 registration 19 seconds in with "Zero-valued spacing is not supported ... Refusing to change spacing from [1, 1] to [0, 0]". Installable and working were different things, and nothing in the metadata said so. - Verified by reproducing BOTH sides here rather than trusting the report. Same reproducer, same ITK 5.4.7-24 in an overlay, only samseg changed: samseg 0.5a0-7 RED exit 1, the ITK exception inside KvlRigidRegistration.register() samseg 0.5a0-8 GREEN exit 0, corr(fixed,out) 0.9986 tests/samseg-itk-abi.bats is the same check as a test. - Why a floor is right here when samseg's own `InsightToolkit5 >= 5.4.7-13` was useless: that one tried to guard an ABI, and a layout change at an unchanged soname satisfies any floor. This one says "releases before -8 are known broken", which is a statement about builds, and the ABI constraint is enforced one hop down by samseg's `itk(abi) = 5.4-legacy` equality. simnibs links no ITK, so depending on the abi token from here would be wrong in kind. - Gate checked before adding it, since a floor nothing satisfies makes the package uninstallable: python3-samseg 0.5a0-8 is published on all six chroots and simnibs 4.6.0-15 is on all six. rpm ordering confirmed -- 0.5a0-7.fc44 is refused, 0.5a0-8.fc44/.fc45/.fc46 all satisfy. * Tue Oct 06 2026 Morgan Hough - 4.6.0-15 - Patch2: name the missing binary. path2bin() only CONSTRUCTS SIMNIBSDIR/external/bin/linux/ and never checks it, with no $PATH fallback, so a missing external tool is completely silent until something tries to execute it -- and in charm that is always after the expensive work. It cost ten minutes of meshing for mmg3d_O3 in -13, and on the DGX Spark it cost a full surface reconstruction before dying on CAT_Surf2Sphere with a bare FileNotFoundError against a directory that exists, is empty, and is owned by no package. Now it raises where the path is built, names the program, and for CAT_* adds that these come from CAT12, are needed only for spherical registration, and that the cortical surfaces themselves are unaffected -- what is lost is the fsaverage mapping, not the surfaces. - Checked every caller before making path2bin raise: none guards it with os.path.exists or try/except, and the only one that enumerates (cli/postinstall_simnibs.py) iterates exactly ["meshfix", "mmg3d_O3"], both of which this package provides. So the new exception cannot fire on a working install. - Still NOT provided: CAT_Surf2Sphere and CAT_WarpSurf. Packaging CAT12 is a separate question with its own licence, and is Morgan's call. - Measured on aarch64 by neurospark, and corrected by them at source after I first wrote it down wrong twice over. The surface ESTIMATION runs on CPU and writes lh/rh central, pial, white and sigma; the --surfaces invocation as a whole then exits 1 at "Generating spherical registrations" for want of CAT_Surf2Sphere, so the stage does NOT complete -- only the surface files are produced. Peak for that invocation alone is ~34 GiB (35,625,776 KiB from /usr/bin/time -v; docker stats 34.19 GiB), and because it died 58 s in, the full stage peak is at least that and is unmeasured beyond it. My earlier "21-24 GB" was the RSS at the instant the kernel killed the process here: a floor, not a peak. "35.6 GB" was then a unit slip for 34 GiB. - Worth sending upstream: this is a two-line improvement that turns every missing-external-binary failure in SimNIBS from a late, anonymous FileNotFoundError into an immediate, named one. * Sun Oct 04 2026 Morgan Hough - 4.6.0-14 - Patch1: pass -rn 0 at all four mmg3d call sites. With -13 charm finally reached the meshing stage and then died there, 17 seconds in, with "*** buffer overflow detected ***" followed by mmg's own "potential lack of memory" -- on a machine with 22 GB free. The memory message is a red herring from mmg's generic handler. gdb puts the abort inside SCOTCH: __fortify_fail <- __chk_fail <- _SCOTCHbgraphBipartGg, reached through seven levels of bgraphBipartMl2 from mmg's renumbering. The bug is in scotch 7.0, not in mmg and not in SimNIBS. Renumbering is a cache-locality optimisation, so -rn 0 is a safe bypass: measured on the same 3.9M-tetrahedron mesh, default aborts at 17 s and -rn 0 completes in 5 m 22 s, writing 5,524,943 tetrahedra. Drop Patch1 once Fedora's scotch carries the fix; see docs/upstream/scotch-bgraphbipartgg-buffer-overflow.md. - %%check now counts mmg3d call sites and asserts the patch reached all four. %%autosetup reports a non-matching hunk as "ignored" and does not fail the build -- release 11 shipped green with its only patch silently skipped -- so the apply is verified by its effect, not by its exit status. * Sat Oct 03 2026 Morgan Hough - 4.6.0-13 - Third thing blocking charm, and the last in the meshing path: it shells out to mmg3d_O3 and meshfix, which %%prep correctly deletes along with the rest of upstream's bundled prebuilt binaries -- and nothing put anything back. simnibs resolves them by CONSTRUCTING a path, SIMNIBSDIR/external/bin/linux/, with no $PATH fallback, so the run died with FileNotFoundError after ten minutes of meshing and 100,204 relabelled tetrahedra. - Fedora's mmg3d ships /usr/bin/mmg3d_O3 under exactly the name simnibs expects and meshfix is in this repo, so both are symlinked into that directory and are hard Requires now. %%check fails the build if either symlink does not resolve to an executable. - NOT provided: CAT_Surf2Sphere and CAT_WarpSurf, also bundled upstream and also deleted. They come from CAT12, nothing in Fedora ships them, and they belong to the surface-reconstruction path rather than to meshing. * Sat Oct 03 2026 Morgan Hough - 4.6.0-12 - Fix -11, which failed to build: %%autosetup had no -p1, so rpm ran patch at strip level 0 and reported "No file to patch. Skipping patch. 1 out of 1 hunk ignored" -- and carried on, because an ignored hunk is not an error to %%autosetup. The package would have built and shipped WITHOUT the fix had the hunk count been zero. This package had never carried a patch before, so the missing -p1 had never mattered. * Sat Oct 03 2026 Morgan Hough - 4.6.0-11 - charm can now build a head mesh. With the atlas restored in -9, charm got through registration, segmentation and surfaces and then died in meshing: "OSError: invalid mesh format", after four minutes of work and with no head model produced. - The mesh was never the problem. CGAL wrote a perfectly good 236 MB MEDIT file; simnibs' own read_medit() refused to read it, because CGAL emits "# CGAL::Mesh_complex_3_in_triangulation_3" between the Dimension and Vertices keywords and the reader requires the third line to be exactly "Vertices". MEDIT permits comment lines. - Patch0 skips comments and blank lines in that header. Verified against the file CGAL actually produced: 760,971 nodes, 7,014,996 elements (4,724,266 tetrahedra and 2,290,730 triangles), tissue tags 1-10. - Found by running charm on a real subject (WAND sub-08033, T1+T2). Nothing short of that would have found it: it needs the atlas present, four minutes of meshing, and a CGAL recent enough to write the comment. * Sat Oct 03 2026 Morgan Hough - 4.6.0-10 - CORRECTION to the -9 entry, which stated that "any pip or wheel install of SimNIBS 4.6.0 has the same crippled atlas". That is wrong. Upstream's released wheel is complete: reading the central directory of simnibs-4.6.0-cp311-cp311-linux_x86_64.whl shows all 14 atlas files at the same paths, byte sizes matching the repository. Anyone using that wheel or the official installer has a working charm. - The defect is specific to building from a source TARBALL. The build uses setuptools-scm, whose file finder enumerates git-tracked files -- which is how a wheel built from a checkout gets the atlas, and MANIFEST.in says so itself ("Excluding top level folders (because scm includes them automatically)"). A tarball has no .git, that finder returns nothing, and MANIFEST.in alone decides, where the graft names a directory that does not exist. Distributions build from tarballs; upstream does not. - No package content changes in this release. The atlas fix from -9 is unchanged and verified: simnibs-data carries all 14 files at the exact upstream sizes. * Sat Oct 03 2026 Morgan Hough - 4.6.0-9 - charm could not build a head model at all. Running it on a real T1/T2 for the first time -- WAND sub-08033 -- died in the first stage: "Could not create IO object for reading file .../charm_atlas_mni_v1-1/ template.nii -- The file doesn't exist". Both charm atlases were installed with only their three small text files; the template volume and the three atlas_*.gz, 229 MB across the two, were missing. - Cause is upstream's MANIFEST.in: "graft simnibs/segmentation/atlases/ charm_atlas_mni" names a directory that does not exist, because the atlases are charm_atlas_mni_v1-0 and _v1-1. The three files that did ship were caught incidentally by "global-include *.txt *.ini"; template.nii is not a .txt and atlas_level1.txt.gz is not either. So any pip or wheel install of SimNIBS 4.6.0 has the same crippled atlas. Reported upstream. - The files are present in the GitHub tarball this package builds from, so %%install now copies them in, and they go in the -data subpackage. - %%check asserts both template.nii exist and are over 40 MB. This is the kind of defect that import checks cannot see: 27 BATS tests, a clean install and `charm --help` all passed for months with the atlas gutted. * Mon Sep 28 2026 Morgan Hough - 4.6.0-8 - Require python3-brainnet >= 0.2 and stop stripping brainnet from pyproject.toml. This is the last link: `charm --help` now RUNS. It has been broken since the package existed -- first on torch (fixed in -7), then on ITK legacy symbols in samseg (fixed by samseg 0.5a0-6), and finally on ModuleNotFoundError: No module named 'brainnet' at simnibs/segmentation/brain_surface.py line 13. Verified in a clean fedora-44-x86_64 chroot with python3-simnibs, simnibs-data, python3-brainnet, python3-brainnet-data and python3-brainsynth installed: `charm --help` exits 0 and prints its full option list. - %%prep now ASSERTS that pyproject.toml still declares brainnet>=0.2, instead of carrying a comment saying the sed was dropped. mkl and tbb stay stripped (conda-only names for system libraries) and petsc4py stays stripped from the build deps only; neither is the same case. - With this, simnibs/mesh_tools/meshing.py and simnibs/optimization/opt_struct.py are importable for the first time, so meshing and optimisation are usable and not only the pre-built head models. * Sat Sep 26 2026 Morgan Hough - 4.6.0-7 - Require python3-torch. segmentation/brain_surface.py imports it, and both mesh_tools/meshing.py and optimization/opt_struct.py import that, so without torch `charm --help` died with ModuleNotFoundError and head model creation from a subject's own MRI was impossible. Upstream does not declare torch in pyproject.toml at all -- the same omission as python-mumps. Found by running upstream's own shipped test suite against the package. - Recommend python3-mne for the EEG forward modelling paths. - tests/simnibs.bats: execute the entry points instead of only locating them. charm was on PATH and broken, which the old presence check could not see. * Sat Sep 26 2026 Morgan Hough - 4.6.0-6 - Make `import simnibs` actually work. Two runtime dependencies were missing: python3-cortech (was only Recommends in -5) and python3-mumps (never declared -- upstream omits it from pyproject.toml with the note that it "only works automatically via conda", but fem.py imports it at module scope). Both are packaged now, and both are hard Requires. Verified by importing simnibs, sim_struct and run_simnibs as an unprivileged user in a clean root. - Stop stripping cortech from pyproject.toml; it is packaged, so the wheel metadata should say so. * Sat Sep 26 2026 Morgan Hough - 4.6.0-5 - python3-simnibs now requires simnibs-data. Nothing pulled it in before, so `dnf install python3-simnibs` gave a working import and no coil models, no head templates and no electrode caps -- every simulation failed at the point of use, with nothing to say why. 143 MB of resources the package cannot work without. - Stop stripping the gmsh dependency and require python3-gmsh: Fedora has shipped gmsh 4.15 with Python bindings all along, so the meshing and mesh visualisation paths were being removed for no reason. - Recommend simnibs-gui (how most people drive it) and python3-cortech (cortical layer placement), and keep fsl as a Suggests since it is nonfree. * Thu Jun 11 2026 Morgan Hough - 4.6.0-4 - Refresh rebuild against the Python 3.15 rebuilds of its dependency chain (python-charm-gems, python-samseg, python-surfa, python-pygpc, python-fmm3dpy) so rawhide resolves consistently. No spec/source changes. * Sat May 23 2026 Morgan Hough - 4.6.0-3 - CGAL 6 (rawhide/F45): port _mesh_volumes.cpp create_labeled_image_mesh_domain to the named-parameter form (matches existing _cgal_intersect.cpp patches) * Sat May 23 2026 Morgan Hough - 4.6.0-2 - Drop upstream-installed top-level tools/ package (Python 3.14 site-packages bleed; was triggering "Installed (but unpackaged) file(s) found" on F44) - Fix bogus changelog weekday: Apr 23 2026 is Thursday, not Wednesday * Thu Apr 23 2026 Morgan Hough - 4.6.0-1 - Update to 4.6.0 - Remove cat_c_utils patches (files removed upstream) - Relax fmm3dpy version pin (was ==1.0.4, now >=1.0.0) - Remove new unpackaged deps (brainnet, cortech, gmsh) from pyproject.toml * Wed Mar 11 2026 Morgan Hough - 4.5.0-4 - Fix C99 complex I macro clash with CAT C utilities (undef I) - Fix FINFINITY macro trailing semicolons - Fix distutils newer_group removal for Python 3.12+ - Add CFLAGS for GCC 15 C compilation compatibility - Work around CGAL 6.0.3 const-correctness bug in Add_features_in_domain * Wed Mar 11 2026 Morgan Hough - 4.5.0-3 - Patch setup.py for non-conda system build - Use system CGAL/eigen3/gmp/mpfr paths instead of CONDA_PREFIX - Fix C++ standard to gnu++17 for GCC 15 / CGAL 5.x - Set SETUPTOOLS_SCM_PRETEND_VERSION for non-git tarball builds - Remove petsc4py from build deps (not yet available) * Tue Mar 10 2026 Morgan Hough - 4.5.0-2 - Fix package names: cgal-devel to CGAL-devel, setuptools-scm to setuptools_scm - Add charm_gems and petsc4py runtime Requires - Remove tools subpackage (extensions are in python3-simnibs) - Remove mkl/tbb conda-only deps from pyproject.toml * Wed Feb 25 2026 Morgan Hough - 4.5.0-1 - Initial package for SimNIBS 4.5.0