# SLEPc tracks PETSc release-for-release (SLEPc 3.N needs PETSc 3.N), so like # python-petsc4py the version follows whatever PETSc each Fedora release ships: # f43 petsc 3.23.6 -> slepc 3.23.3 # f44 petsc 3.24.6 -> slepc 3.24.3 # f45 petsc 3.25.x -> slepc 3.25.2 # f46 petsc 3.26.0 -> slepc 3.26.0 # Only the Open MPI flavour for now: it is the one fenics-dolfinx builds against. %global ver_f43 3.23.3 %global ver_f44 3.24.3 %global ver_f45 3.25.2 %global ver_f46 3.26.0 %if 0%{?fedora} >= 46 %global srcnum 3 %global petsc_series 3.26 %elif 0%{?fedora} == 45 %global srcnum 2 %global petsc_series 3.25 %elif 0%{?fedora} == 43 %global srcnum 0 %global petsc_series 3.23 %else %global srcnum 1 %global petsc_series 3.24 %endif # SLEPc's configure (and slepc4py's) want a PETSc prefix laid out as # $PETSC_DIR/include + $PETSC_DIR/lib/petsc/conf; Fedora's Open MPI PETSc keeps # headers in %%{_includedir}/openmpi-%%{_arch}/petsc. Present that shape with a # symlink farm (the same approach as python-petsc4py). %global petscroot %{_builddir}/petscroot-openmpi Name: slepc %if 0%{?fedora} >= 46 Version: %{ver_f46} %elif 0%{?fedora} == 45 Version: %{ver_f45} %elif 0%{?fedora} == 43 Version: %{ver_f43} %else Version: %{ver_f44} %endif Release: 1%{?dist} Summary: Scalable Library for Eigenvalue Problem Computations License: BSD-2-Clause URL: https://slepc.upv.es/ # All four are listed so the SRPM (built before %%{fedora} is known) carries # each; %%prep unpacks the one for this release. Source0: https://slepc.upv.es/download/distrib/slepc-%{ver_f43}.tar.gz Source1: https://slepc.upv.es/download/distrib/slepc-%{ver_f44}.tar.gz Source2: https://slepc.upv.es/download/distrib/slepc-%{ver_f45}.tar.gz Source3: https://slepc.upv.es/download/distrib/slepc-%{ver_f46}.tar.gz BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: make BuildRequires: python3-devel BuildRequires: openmpi-devel BuildRequires: petsc-openmpi-devel >= %{petsc_series} BuildRequires: petsc-openmpi-devel < %{petsc_series}.999 BuildRequires: python3-petsc-openmpi BuildRequires: python3-mpi4py-openmpi BuildRequires: python3-numpy BuildRequires: python3-Cython BuildRequires: python3-setuptools BuildRequires: python3-pip BuildRequires: python3-wheel %global _description %{expand: SLEPc is a library for the solution of large scale sparse eigenvalue problems on parallel computers, built on PETSc. It provides eigensolvers (EPS), singular value (SVD), polynomial (PEP) and nonlinear (NEP) eigensolvers, and matrix functions (MFN), with Krylov-Schur, Davidson, LOBPCG and other methods.} %description %_description %package openmpi Summary: SLEPc built against Open MPI Requires: petsc-openmpi%{?_isa} %description openmpi %_description This package contains the Open MPI build. %package openmpi-devel Summary: Development files for SLEPc (Open MPI) Requires: %{name}-openmpi%{?_isa} = %{version}-%{release} Requires: petsc-openmpi-devel%{?_isa} %description openmpi-devel Headers, pkg-config file, makefile fragments and library link for SLEPc built against Open MPI. %package -n python3-slepc-openmpi Summary: Python bindings for SLEPc (slepc4py, Open MPI) Requires: %{name}-openmpi%{?_isa} = %{version}-%{release} Requires: python3-petsc-openmpi%{?_isa} Provides: slepc4py-openmpi = %{version}-%{release} %description -n python3-slepc-openmpi slepc4py, the Python bindings for SLEPc, built against Open MPI. Installed in the Open MPI Python path, alongside python3-petsc-openmpi's petsc4py. %prep %setup -q -c -T tar -xzf %{_sourcedir}/slepc-%{version}.tar.gz --strip-components=1 test -f include/slepcversion.h grep -q "SLEPC_VERSION_MINOR *$(echo %{version} | cut -d. -f2)" include/slepcversion.h %build %{_openmpi_load} rm -rf %{petscroot}; mkdir -p %{petscroot} ln -s %{_includedir}/openmpi-%{_arch}/petsc %{petscroot}/include ln -s ${MPI_LIB} %{petscroot}/lib export PETSC_DIR=%{petscroot} PETSC_ARCH= SLEPC_DIR=$PWD ./configure --prefix=%{_builddir}/stage make SLEPC_DIR=$PWD PETSC_DIR=%{petscroot} PETSC_ARCH= MAKE_NP=%{_smp_build_ncpus} make SLEPC_DIR=$PWD PETSC_DIR=%{petscroot} PETSC_ARCH= install %{_openmpi_unload} %install %{_openmpi_load} # Staged prefix -> Fedora MPI layout: libraries and makefile fragments under # ${MPI_LIB}, headers under ${MPI_INCLUDE}/slepc. st=%{_builddir}/stage mkdir -p %{buildroot}${MPI_LIB} %{buildroot}${MPI_INCLUDE}/slepc cp -a $st/lib/libslepc.so* %{buildroot}${MPI_LIB}/ cp -a $st/include/. %{buildroot}${MPI_INCLUDE}/slepc/ mkdir -p %{buildroot}${MPI_LIB}/slepc %{buildroot}${MPI_LIB}/pkgconfig cp -a $st/lib/slepc/conf %{buildroot}${MPI_LIB}/slepc/ sed -e "s|^includedir=.*|includedir=${MPI_INCLUDE}/slepc|" \ -e "s|^libdir=.*|libdir=${MPI_LIB}|" \ -e "s|^prefix=.*|prefix=${MPI_HOME}|" \ $st/lib/pkgconfig/slepc.pc > %{buildroot}${MPI_LIB}/pkgconfig/slepc.pc # The installed slepcvariables point at the staging prefix; repoint them. sed -i -e "s|$st/include|${MPI_INCLUDE}/slepc|g" -e "s|$st/lib|${MPI_LIB}|g" -e "s|$st|${MPI_HOME}|g" \ %{buildroot}${MPI_LIB}/slepc/conf/* ! grep -rl "%{_builddir}" %{buildroot}${MPI_LIB}/slepc %{buildroot}${MPI_LIB}/pkgconfig # slepc4py, against the staged SLEPc and Fedora's Open MPI petsc4py pushd src/binding/slepc4py export PETSC_DIR=%{petscroot} PETSC_ARCH= SLEPC_DIR=$st export LDFLAGS="%{build_ldflags} -Wl,-rpath,${MPI_LIB}" %{python3} -m pip install --no-deps --no-build-isolation --no-index \ --root %{buildroot} --prefix %{_prefix} -v . popd # Fedora MPI guidelines: MPI-flavoured Python modules live under # %%{python3_sitearch}/openmpi (as petsc4py and mpi4py do). mkdir -p %{buildroot}%{python3_sitearch}/openmpi mv %{buildroot}%{python3_sitearch}/slepc4py %{buildroot}%{python3_sitearch}/slepc4py-*.dist-info \ %{buildroot}%{python3_sitearch}/openmpi/ # The extension must find the installed libslepc, not the staging copy. for so in $(find %{buildroot}%{python3_sitearch}/openmpi/slepc4py -name '*.so'); do ! readelf -d "$so" | grep -E 'R(UN)?PATH' | grep -q "%{_builddir}" done %{_openmpi_unload} %check %{_openmpi_load} export LD_LIBRARY_PATH=%{buildroot}${MPI_LIB}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} export OMPI_MCA_rmaps_base_oversubscribe=1 export PRTE_MCA_rmaps_default_mapping_policy=:oversubscribe # 1-D Dirichlet Laplacian, n = 100: the smallest eigenvalues are known exactly, # 2 - 2 cos(k pi / (n + 1)). Solve in C (2 ranks) and in Python (2 ranks). cat > eps.c <<'C' #include #include int main(int argc, char **argv) { Mat A; EPS eps; PetscInt n = 100, Istart, Iend, i, nconv; PetscScalar kr; PetscCall(SlepcInitialize(&argc, &argv, NULL, NULL)); PetscCall(MatCreate(PETSC_COMM_WORLD, &A)); PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, n, n)); PetscCall(MatSetFromOptions(A)); PetscCall(MatGetOwnershipRange(A, &Istart, &Iend)); for (i = Istart; i < Iend; i++) { if (i > 0) PetscCall(MatSetValue(A, i, i - 1, -1.0, INSERT_VALUES)); if (i < n - 1) PetscCall(MatSetValue(A, i, i + 1, -1.0, INSERT_VALUES)); PetscCall(MatSetValue(A, i, i, 2.0, INSERT_VALUES)); } PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); PetscCall(EPSCreate(PETSC_COMM_WORLD, &eps)); PetscCall(EPSSetOperators(eps, A, NULL)); PetscCall(EPSSetProblemType(eps, EPS_HEP)); PetscCall(EPSSetWhichEigenpairs(eps, EPS_SMALLEST_REAL)); PetscCall(EPSSetDimensions(eps, 3, PETSC_DEFAULT, PETSC_DEFAULT)); PetscCall(EPSSetTolerances(eps, 1e-10, 1000)); PetscCall(EPSSolve(eps)); PetscCall(EPSGetConverged(eps, &nconv)); PetscCheck(nconv >= 3, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "only %d converged", (int)nconv); for (i = 0; i < 3; i++) { double exact = 2.0 - 2.0 * cos((i + 1) * M_PI / (n + 1)); PetscCall(EPSGetEigenvalue(eps, i, &kr, NULL)); PetscCheck(fabs(PetscRealPart(kr) - exact) < 1e-8, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "eigenvalue %d: %g != %g", (int)i, (double)PetscRealPart(kr), exact); } PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SLEPc C check OK: %d converged\n", (int)nconv)); PetscCall(EPSDestroy(&eps)); PetscCall(MatDestroy(&A)); PetscCall(SlepcFinalize()); return 0; } C mpicc -o eps eps.c -I%{buildroot}${MPI_INCLUDE}/slepc -I${MPI_INCLUDE}/petsc \ -L%{buildroot}${MPI_LIB} -lslepc -L${MPI_LIB} -lpetsc -lm mpiexec -n 2 ./eps cat > eps.py <<'PY' import math, sys import slepc4py; slepc4py.init(sys.argv) from petsc4py import PETSc from slepc4py import SLEPc n = 100 A = PETSc.Mat().createAIJ([n, n], nnz=3) s, e = A.getOwnershipRange() for i in range(s, e): if i > 0: A[i, i - 1] = -1.0 if i < n - 1: A[i, i + 1] = -1.0 A[i, i] = 2.0 A.assemble() E = SLEPc.EPS().create() E.setOperators(A); E.setProblemType(SLEPc.EPS.ProblemType.HEP) E.setWhichEigenpairs(SLEPc.EPS.Which.SMALLEST_REAL); E.setDimensions(3) E.setTolerances(1e-10, 1000); E.solve() assert E.getConverged() >= 3, E.getConverged() for k in range(3): exact = 2 - 2 * math.cos((k + 1) * math.pi / (n + 1)) assert abs(E.getEigenvalue(k).real - exact) < 1e-8, (k, E.getEigenvalue(k), exact) PETSc.Sys.Print("slepc4py", slepc4py.__version__, "check OK") PY PYTHONPATH=%{buildroot}%{python3_sitearch}/openmpi:${PYTHONPATH} mpiexec -n 2 %{python3} eps.py %{_openmpi_unload} %files openmpi %license LICENSE.md %doc README.md %{_libdir}/openmpi/lib/libslepc.so.* %files openmpi-devel %{_libdir}/openmpi/lib/libslepc.so %{_includedir}/openmpi-%{_arch}/slepc/ %{_libdir}/openmpi/lib/slepc/ %{_libdir}/openmpi/lib/pkgconfig/slepc.pc %files -n python3-slepc-openmpi %license src/binding/slepc4py/LICENSE.rst %{python3_sitearch}/openmpi/slepc4py/ %{python3_sitearch}/openmpi/slepc4py-*.dist-info/ %changelog * Sun Oct 25 2026 Morgan Hough - 3.24.3-1 - New package: SLEPc and slepc4py (Open MPI), version matched to each Fedora release's PETSc. For DOLFINx eigenproblems (DOLFINX_ENABLE_SLEPC) and MFEM. %%check solves a 1-D Laplacian eigenproblem with known eigenvalues in C and in Python on 2 MPI ranks.