# FEBio links 12 module .so into a private libdir; debug_package nil keeps the
# first packaging simple (the build is Release with force-include GCC15 fixes).
%global debug_package %{nil}
%global febiolibdir %{_libdir}/febio
Name: febio
Version: 4.12
Release: 5%{?dist}
Summary: Finite element solver for biomechanics and biophysics
License: MIT
URL: https://febio.org/
Source0: https://github.com/febiosoftware/FEBio/archive/refs/tags/v%{version}.tar.gz#/FEBio-%{version}.tar.gz
# Our own %%check model (upstream's source ships none; its TestSuite has no licence).
Source1: febio-check-uniaxial.feb
# Upstream b91fda7 (in v4.13): Logfile::printbox passed 1024 as the size to every
# snprintf into a buffer it had already partly filled, so _FORTIFY_SOURCE aborted
# ("buffer overflow detected") the first time a solver printed a box -- i.e.
# every static/quasi-static model died in FENewtonSolver::Init.
Patch0: febio-logfile-printbox-fortify.patch
# Without MKL the default solver is Skyline, which is symmetric-only, so every
# biphasic/fluid/FSI/solute/multiphasic (and nonsymmetric solid) model failed at
# the first solve: 168 of the 548 TestSuite problems. Default to SuperLU_MT
# (Fedora's SuperLUMT) when it is built in.
Patch1: febio-default-solver-superlu-mt.patch
BuildRequires: gcc-c++
BuildRequires: gcc
BuildRequires: cmake
BuildRequires: ninja-build
BuildRequires: chrpath
BuildRequires: libomp-devel
# Optional-feature libraries, all from Fedora (MKL is proprietary and omitted ->
# FEBio falls back to its built-in Skyline direct solver):
BuildRequires: hypre-devel
BuildRequires: levmar-devel
BuildRequires: fftw-devel
BuildRequires: zlib-ng-compat-devel
# MMG adaptive mesh refinement: the component headers/libs live in the per-engine
# subpackages (mmg-devel alone ships only the umbrella libmmg.h, which #includes
# them). FEBio uses the mmg3d engine; pull in the components it needs.
BuildRequires: mmg-devel
BuildRequires: mmg3d-devel
BuildRequires: mmgs-devel
# Sparse LU for nonsymmetric systems (Patch1 makes it the default solver).
BuildRequires: SuperLUMT-devel
%description
FEBio (Finite Elements for Biomechanics) is a nonlinear finite element solver
developed at the University of Utah (SCI Institute / Musculoskeletal Research
Laboratories) for problems in computational biomechanics and biophysics: large-
deformation solid mechanics, biphasic/multiphasic (poroelastic) tissue, fluid
and FSI, reactive transport, and parameter optimization.
This package provides the `febio4` command-line solver with the HYPRE BoomerAMG
iterative solver, MMG adaptive mesh refinement, FFTW, zlib plot compression, and
levmar parameter optimization. It is built without Intel MKL (proprietary), so the
Pardiso/iterative MKL solvers are unavailable and FEBio uses its built-in Skyline
direct solver by default; the HYPRE iterative solver remains available.
%prep
%autosetup -p1 -n FEBio-%{version}
%build
# -D__OPENMP: Fedora's SuperLUMT is the OpenMP build; its headers pick their lock
# type from this macro.
# GCC 15 no longer transitively includes these; FEBio uses strcpy/uint*/etc.
# without the explicit headers -> force-include. MKL off (proprietary) -> Skyline.
# Static stdlibs off (Fedora policy). Optional libs (incl. MMG, via the mmg3d/mmgs
# component packages) wired to their Fedora system paths.
# SuperLUMT 4.0.2 (F45+) ships one libsuperlu_mt.so; 4.0.1 split it per precision.
slu=%{_libdir}/libsuperlu_mt.so; [ -e "$slu" ] || slu=%{_libdir}/libsuperlumt_d.so
cmake -S . -B cbuild -GNinja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="%{optflags} -include cstring -include cstdint -include cstdlib -D__OPENMP" \
-DUSE_MKL=OFF \
-DUSE_STATIC_STDLIBS=OFF \
-DUSE_ZLIB=ON -DZLIB_LIBRARY_RELEASE=%{_libdir}/libz.so -DZLIB_INCLUDE_DIR=%{_includedir} \
-DUSE_FFTW=ON -DFFTW_LIB=%{_libdir}/libfftw3.so -DFFTW_INC=%{_includedir} \
-DUSE_HYPRE=ON -DHYPRE_LIB=%{_libdir}/libHYPRE.so -DHYPRE_INC=%{_includedir}/hypre \
-DUSE_LEVMAR=ON -DLEVMAR_LIB=%{_libdir}/liblevmar.so -DLEVMAR_INC=%{_includedir} \
-DUSE_MMG=ON -DMMG_LIB=%{_libdir}/libmmg3d.so -DMMGS_LIB=%{_libdir}/libmmgs.so -DMMG_INC=%{_includedir} \
-DUSE_SUPERLU_MT=ON -DSUPERLU_MT_LIB="$slu" -DSUPERLU_MT_INC=%{_includedir}/SuperLUMT
cmake --build cbuild %{?_smp_mflags}
%install
# FEBio has no install rules. Co-locate febio4 + its module libs in a private dir
# with $ORIGIN RPATH, and expose febio4 on PATH via a symlink.
install -d %{buildroot}%{febiolibdir}
install -m 0755 cbuild/bin/febio4 %{buildroot}%{febiolibdir}/febio4
install -m 0755 cbuild/lib/*.so %{buildroot}%{febiolibdir}/
# Drop the build-dir RPATH leak; point everything at its own directory.
for f in %{buildroot}%{febiolibdir}/febio4 %{buildroot}%{febiolibdir}/*.so; do
chrpath -r '$ORIGIN' "$f"
done
install -d %{buildroot}%{_bindir}
ln -s ../%{_lib}/febio/febio4 %{buildroot}%{_bindir}/febio4
# febio4 reads febio.xml from its own directory. Ship one that loads every plugin
# package's .so from %%{_libdir}/febio/plugins (febio-chem, febio-heat, ...). It sets
# no default_linear_solver, so Patch1's SuperLU_MT default stands. The folder must
# exist: import_folder throws on a missing directory.
install -d %{buildroot}%{febiolibdir}/plugins %{buildroot}%{_sysconfdir}/febio
cat > %{buildroot}%{_sysconfdir}/febio/febio.xml <<'EOF'
%{febiolibdir}/plugins
EOF
ln -s %{_sysconfdir}/febio/febio.xml %{buildroot}%{febiolibdir}/febio.xml
# --- febio-devel SDK ---------------------------------------------------------
# Install the module headers (namespaced under %%{_includedir}/febio, included as
# etc.) plus a CMake config exposing one imported target per module,
# so FEBio Studio and FEBio plugins can find_package(FEBio).
for mod in FECore NumCore FEBioLib FEBioMech FEBioMix FEBioFluid FEBioRVE \
FEBioPlot FEBioXML FEAMR FEBioOpt FEImgLib; do
find "$mod" -name '*.h' -o -name '*.hpp' | while read -r h; do
install -D -m 0644 "$h" "%{buildroot}%{_includedir}/febio/$h"
done
done
install -d %{buildroot}%{_libdir}/cmake/FEBio
cat > %{buildroot}%{_libdir}/cmake/FEBio/FEBioConfig.cmake <<'EOF'
# Fedora febio-devel: FEBio SDK config exposing one imported target per module.
# (Replaces upstream's in-tree/build-dir config with explicit installed paths.)
set(FEBIO_INCLUDE_DIR "%{_includedir}/febio")
set(_febio_map
FECore:fecore FEBioMech:febiomech FEBioMix:febiomix FEBioFluid:febiofluid
FEBioRVE:febiorve FEBioPlot:febioplot FEBioXML:febioxml FEBioLib:febiolib
FEAMR:feamr FEBioOpt:febioopt FEImgLib:feimglib NumCore:numcore)
foreach(pair IN LISTS _febio_map)
string(REPLACE ":" ";" _parts ${pair})
list(GET _parts 0 _tgt)
list(GET _parts 1 _lib)
if(NOT TARGET FEBio::${_tgt})
add_library(FEBio::${_tgt} SHARED IMPORTED)
set_target_properties(FEBio::${_tgt} PROPERTIES
IMPORTED_LOCATION "%{febiolibdir}/lib${_lib}.so"
INTERFACE_INCLUDE_DIRECTORIES "${FEBIO_INCLUDE_DIR}")
endif()
endforeach()
set(FEBio_FOUND TRUE)
EOF
%package devel
Summary: FEBio SDK: headers and CMake config for FEBio plugins and FEBio Studio
Requires: %{name}%{?_isa} = %{version}-%{release}
%description devel
Development files (module headers and a CMake package configuration exposing the
FEBio:: imported targets) for building FEBio plugins or applications that
link the FEBio libraries, such as FEBio Studio.
%check
# Solve a one-element uniaxial stretch with the just-built solver and compare to
# the small-strain answer: corner contracts by v*eps = 3e-5, axial 1e-4. This is
# what would have caught the printbox abort above.
# The second run assembles it as non-symmetric, which Skyline could not solve.
# -noconfig: the build tree has a CMake-written febio.xml forcing skyline; the
# installed package has none, so this is what users run.
mkdir -p check
cp -p %{SOURCE1} check/sym.feb
sed 's|symmetric<|non-symmetric<|' %{SOURCE1} > check/nonsym.feb
grep -q 'non-symmetric' check/nonsym.feb
for m in sym nonsym; do
rm -f check/corner.txt
(cd check && OMP_NUM_THREADS=1 ../cbuild/bin/febio4 -noconfig -i $m.feb -silent)
grep -q 'N O R M A L T E R M I N A T I O N' check/$m.log
tail -n 1 check/corner.txt | awk -v m=$m '
function a(x) { return x < 0 ? -x : x }
{ print m, "corner u =", $2, $3, $4
exit !(a($2 + 3e-5) < 3e-7 && a($3 + 3e-5) < 3e-7 && a($4 - 1e-4) < 1e-9) }'
done
grep -q 'superlu_mt' check/nonsym.log
# The shipped config, pointed at an empty plugin folder, must load and keep SuperLU_MT.
mkdir -p check/plugins
sed 's|%{febiolibdir}/plugins|'"$PWD"'/check/plugins|' %{buildroot}%{_sysconfdir}/febio/febio.xml > check/febio.xml
(cd check && OMP_NUM_THREADS=1 ../cbuild/bin/febio4 -config febio.xml -i sym.feb -silent)
grep -q 'superlu_mt' check/sym.log
%files
%license LICENSE
%doc README.md
%dir %{febiolibdir}
%{febiolibdir}/febio4
%{febiolibdir}/*.so
%dir %{febiolibdir}/plugins
%{febiolibdir}/febio.xml
%dir %{_sysconfdir}/febio
%config(noreplace) %{_sysconfdir}/febio/febio.xml
%{_bindir}/febio4
%files devel
%{_includedir}/febio/
%{_libdir}/cmake/FEBio/
%changelog
* Fri Oct 09 2026 Morgan Hough - 4.12-5
- Ship /etc/febio/febio.xml (linked from %%{_libdir}/febio) importing every
plugin in %%{_libdir}/febio/plugins, for the febio-chem/heat/erd/warp packages.
* Fri Oct 09 2026 Morgan Hough - 4.12-4
- Build the SuperLU_MT solver (Fedora SuperLUMT) and make it the default:
Skyline is symmetric-only, so biphasic, fluid, FSI, solute and multiphasic
models all failed at the first solve.
- %%check also solves the model with a non-symmetric stiffness matrix.
* Fri Oct 09 2026 Morgan Hough - 4.12-3
- Backport upstream b91fda7: febio4 aborted with "buffer overflow detected"
(_FORTIFY_SOURCE, Logfile::printbox) on every static model.
- Add %%check: solve a one-element uniaxial model and check it against the
small-strain answer.
* Sun Jun 21 2026 Morgan Hough - 4.12-2
- Add febio-devel SDK subpackage (module headers + FEBioConfig.cmake with the
FEBio:: imported targets), required to build FEBio Studio and plugins.
* Sun Jun 21 2026 Morgan Hough - 4.12-1
- Initial package: FEBio 4.12 finite element solver (febio4). Built with system
HYPRE/levmar/FFTW/zlib and MMG adaptive mesh refinement (via the mmg3d-devel +
mmgs-devel component packages); MKL omitted (proprietary -> Skyline solver).
GCC15 force-include fixes; module libs in a private %%{_libdir}/febio with
$ORIGIN RPATH. FEBio Studio (GUI) not included.