# Upstream's newest tag is release-1.12.10; master has one commit past it and is # what the ACES tree builds from, so package the tip as bicpl, minc-tools and # EBTKS already do here. configure.in still says 1.12.0. %global commit 0fdb7b069afec6983d5aa0be1f9156266cef393b %global shortcommit %(c=%{commit}; echo ${c:0:7}) %global date 20121217 Name: N3 Version: 1.12.10 Release: 1.%{date}git%{shortcommit}%{?dist} Summary: Non-parametric non-uniform intensity normalization (nu_correct) # COPYING: the classic MNI/BIC permissive notice, John Sled 1996. No advertising # clause, no field-of-use limit. docs/civet-licensing.md (tier 1). License: HPND URL: https://github.com/aces/N3 Source0: %{url}/archive/%{commit}/%{name}-%{shortcommit}.tar.gz # m4/ is a git submodule (BIC-MNI/mni-acmacros), absent from the archive # tarball; configure.in needs its macros. Same arrangement as bicpl and EBTKS. Source1: https://github.com/BIC-MNI/mni-acmacros/archive/master.tar.gz#/mni-acmacros.tar.gz # Maps the pre-VIO_ volume_io spellings this code uses onto current libminc. Source2: mni-volume-io-compat.h # std::isfinite instead of a probe that cannot succeed, and ::array to # disambiguate from std::array. See docs/upstream/n3-cxx11-compat.md Patch0: N3-cxx11-compat.patch BuildRequires: autoconf BuildRequires: automake BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: libtool BuildRequires: make BuildRequires: perl-interpreter # testing/do_test is itself an MNI::Startup script, and the drivers it runs # parse their options with Getopt::Tabular. BuildRequires: perl-MNI BuildRequires: perl(Getopt::Tabular) BuildRequires: EBTKS-devel # src/Splines/TBSpline.cc calls dsysv_ directly, declaring its own prototype. # Upstream got it from the CLAPACK subset bundled inside EBTKS; we dropped that # (dead code there, and it no longer compiles), so link Fedora's LAPACK. BuildRequires: lapack-devel BuildRequires: libminc-devel BuildRequires: netcdf-devel BuildRequires: zlib-devel # The user-facing tools are Perl scripts driving the compiled programs; they # use MNI::Startup, MNI::Spawn and friends, and run MINC command line tools. Requires: perl-MNI Requires: perl(Getopt::Tabular) Requires: minc-tools %description N3 (Non-parametric Non-uniform intensity Normalization) corrects the smooth intensity inhomogeneity field of MRI volumes without needing a tissue model. It is the correction step used throughout the MNI/BIC pipelines, notably CIVET, and is best known through its nu_correct driver. This package provides nu_correct, nu_estimate, nu_evaluate, sharpen_volume, spline_smooth, evaluate_field, volume_hist, volume_stats and the supporting tools, plus the two brain masks N3 ships as model data. %prep %autosetup -p1 -n %{name}-%{commit} # Supply the mni-acmacros submodule that the tarball cannot carry. mkdir -p m4 tar -xf %{SOURCE1} --strip-components=1 -C m4 test -f m4/smr_WITH_BUILD_PATH.m4 %build autoreconf -ifv -I m4 # Fedora's libminc names its volume_io library libminc_io, not libvolume_io2, # and puts the headers in a subdirectory. Same two adjustments bicpl makes. sed -i 's/volume_io2/minc_io/g' configure grep -q 'minc_io' configure # N3 uses the old volume_io names (Volume, Real, ...) that libminc 2.x renamed # with a VIO_ prefix -- 52 uses of Volume and 51 of Real across src/. Force the # compatibility header into every translation unit, including configure's own # probes, which is why this is set before %%configure rather than in AM_CPPFLAGS. cp %{SOURCE2} compat_minc.h # 1996-era C++, as with EBTKS: needs the old implicit conversions tolerated. export CXXFLAGS="%{optflags} -std=gnu++17 -fpermissive -I%{_includedir}/libminc \ -include $(pwd)/compat_minc.h" # -DMNI_COMPAT_AXIS_MACROS for C only: src/ExtractTag/extracttag.c uses the bare # X/Y/Z axis constants, while the C++ sources use X and Y as matrix variables. # The two cannot coexist in one flag set, and only the C file needs the macros. # # The MNI configure probes are written in pre-C99 style -- mni_REQUIRE_LIB(z) # compiles `int f = compress2;`, assigning a function pointer to an int, and # others call undeclared functions. GCC 14+ makes both hard errors, so the # probes fail to compile and configure reports the libraries as missing rather # than as unusable. Demote them for the probes; bicpl does the same. export CFLAGS="%{optflags} -std=gnu17 -I%{_includedir}/libminc \ -Wno-error=implicit-function-declaration -Wno-error=implicit-int \ -Wno-error=incompatible-pointer-types -Wno-error=int-conversion \ -include $(pwd)/compat_minc.h -DMNI_COMPAT_AXIS_MACROS" %configure \ --with-minc2 \ --with-build-path=%{_prefix} \ LIBS="-lminc_io -lminc2 -lnetcdf -lhdf5 -llapack -lblas -lz -lm" %make_build %install %make_install find %{buildroot} -name '*.la' -delete %check # testing/do_test registers the tools with MNI::Spawn against ONE directory -- # the parent of testing/, i.e. the top build directory. The compiled programs # are there, but the Perl drivers are built in src/NUcorrect, so extending PATH # does not help: the search path is explicit. They are also generated with sed # and stay mode 644 until `make install` runs them through INSTALL_SCRIPT. # Link them where the test looks, executable. for f in src/NUcorrect/*; do test -f "$f" || continue case "$f" in *.in|*.c) continue;; esac chmod +x "$f" ln -sf "$f" . done test -x field2imp && test -x nu_correct # The drivers find their model data at $FindBin::Bin/../share/N3, i.e. relative # to the program, which resolves to %%{_datadir}/N3 once installed. In the build # tree that directory does not exist, so nu_estimate_np_and_em cannot read the # average brain mask, silently proceeds without it under -auto_mask, and the # corrected volume then differs from the reference (0.256% RMS, 2.45% peak -- # not a rounding difference, a different computation). Stage the data where the # scripts will look. They append .gz themselves, so ship it as-is. mkdir -p ../share/N3 cp model_data/N3/*.mnc.gz ../share/N3/ # do_test exits 1 even on a clean run -- the status is left over from the last # command it spawns, not from any test -- so automake reports FAIL regardless. # Judge it by what it actually reports instead of by its exit code, and print # the log either way: automake only writes it to a file, so a COPR build would # otherwise say "FAIL: do_test" with no indication of why. make check || : cat testing/do_test.log # Upstream's own criteria (do_test.in): no fatal error, and warnings/errors/ # fails within the tolerances it prints. Plus the numerical check, which is the # point of the suite: the corrected volume must match the reference. grep -q 'All of the tests were completed without suffering a fatal error' testing/do_test.log ! grep -q 'potential problems' testing/do_test.log # The numerical comparison against the 2012 reference volume does not reproduce # exactly here: 0.254% RMS, 7.04% peak. Everything testable has been ruled out # (FP contraction, our EBTKS patches, the model data, master vs the release tag) # -- see docs/upstream/n3-reference-mismatch.md, which is a question for # upstream. do_test itself prints these numbers and ignores them. Bound them so # a gross regression still fails the build, and print what was measured. grep -E 'RMS difference|Maximum difference' testing/do_test.log %{__awk} '/RMS difference:/ { gsub(/[()%]/, "", $NF) if ($NF+0 > 1.0) { print "RMS difference " $NF "% exceeds the 1% bound"; exit 1 } print "RMS difference " $NF "% is within the documented 1% bound" }' testing/do_test.log %files %license COPYING %doc AUTHORS ChangeLog NEWS README %{_bindir}/correct_field %{_bindir}/evaluate_field %{_bindir}/extracttag %{_bindir}/field2imp %{_bindir}/imp2field %{_bindir}/make_template %{_bindir}/nu_correct %{_bindir}/nu_estimate %{_bindir}/nu_estimate_np_and_em %{_bindir}/nu_evaluate %{_bindir}/resample_labels %{_bindir}/sharpen_hist %{_bindir}/sharpen_volume %{_bindir}/spline_smooth %{_bindir}/volume_hist %{_bindir}/volume_stats %{_datadir}/N3/ %changelog * Thu Sep 24 2026 Morgan Hough - 1.12.10-1.20121217git0fdb7b0 - Initial package, from the tip of upstream master. CIVET/MNI tier 1 (docs/civet-licensing.md); needs EBTKS and perl-MNI, both packaged here.