Skip to content

Migrate off GSL onto fortnum - #28

Closed
krystophny wants to merge 1 commit into
mainfrom
drop-gsl-fortnum
Closed

Migrate off GSL onto fortnum#28
krystophny wants to merge 1 commit into
mainfrom
drop-gsl-fortnum

Conversation

@krystophny

Copy link
Copy Markdown
Member

Migrate MEPHIT off GSL onto fortnum, the single numerical core. Consumers depend
on fortnum directly (not the libneo math-kit). This supersedes the
libneo-routed PR #26.

What changed

Fortran (src/mephit_pert.f90)

  • Drop the bind(C) interface to gsl_sf_bessel_In_array and call
    fortnum_special bessel_in_array in kilca_vacuum_fourier.
  • fortnum fills I_n(0:nmax), so the order |pol_mode|-1 (which is -1 when
    pol_mode = 0) is recovered via I_{-n}(x) = I_n(x). Call-site values are
    unchanged.

C

  • hyper1F1.c: gsl_integration_qag (rule GSL_INTEG_GAUSS21) becomes
    fortnum_integrate_qag(..., key=21, ..., ctx=&qp), threading the quadrature
    parameters through the C ABI context pointer; gsl_sum_levin_u_* becomes
    fortnum_levin_u_accel. Adds #include <float.h> for DBL_EPSILON,
    formerly pulled in transitively by the GSL headers.
  • mephit_fem.c: gsl_integration_glfixed_* becomes
    fortnum_gauss_legendre_ab(order, 0.0, 1.0, ...).
  • mephit_util.c / mephit_run.c: remove the GSL error-handler plumbing
    (gsl_errno_msg, gsl_set_error_handler); fortnum reports status via return
    codes.

Build

  • Drop find_package(GSL) and the FGSL pickup from CMakeLists.txt /
    cmake/SetupCODE.cmake.
  • Fetch fortnum with FetchContent from git@github.com:lazy-fortran/fortnum.git
    (GIT_TAG main), guarded by if(NOT TARGET fortnum) so a transitive pull
    through libneo does not redeclare the target. Link the fortnum target; add
    ${fortnum_SOURCE_DIR}/include to the C/C++ include path for fortnum.h.

FFTW (src/fftw3.f90) and the netlib zeroin / d1mach routines are not GSL
and are untouched. GSL is fully removed: no find_package(GSL), no GSL::gsl,
no gsl/* includes, no gsl_ symbols in libmephit.so.

This migration required forwarding an opaque user context through fortnum's
callback-driven C ABI (the header documented it as forwarded but the wrappers
hardcoded NULL). Fixed upstream in fortnum
(lazy-fortran/fortnum@dc277b5) and verified there before consuming it here.

Verification

GSL fully removed from the source and the linked library:

$ rg -n -i 'gsl' src/ CMakeLists.txt cmake/SetupCODE.cmake | grep -vi fgsl
CMakeLists.txt:102:### fortnum: numerical core replacing the former GSL routines. ...
$ ldd lib/libmephit.so | rg -i gsl        # no match
$ nm -D lib/libmephit.so | rg -i gsl      # no match

Full CMake configure (fortnum fetched over SSH, no GSL):

$ cmake -S . -B build -G Ninja
...
-- === Dependency Detection Complete ===
-- Performing Test FORTNUM_HAVE_HEAP_TRAMPOLINES - Success
-- Configuring done (13.8s)
-- Generating done (0.1s)
-- Build files have been written to: build

Full build (library + all executables), green:

$ cmake --build build -j$(nproc)
...
[86/91] Linking Fortran static library lib/libneo.a
[88/91] Linking CXX shared library lib/libmephit.so
[89/91] Linking Fortran executable bin/mephit_test.x
[90/91] Linking C executable bin/mephit_run.x
[91/91] Linking Fortran executable bin/mephit_post.x
$ ls bin/
mephit_post.x  mephit_run.x  mephit_test.x
$ nm -D lib/libmephit.so | rg 'fortnum_integrate_qag|fortnum_gauss_legendre_ab|fortnum_levin_u_accel'
0000000000115940 T fortnum_gauss_legendre_ab
0000000000115680 T fortnum_integrate_qag
0000000000115740 T fortnum_levin_u_accel
$ ./bin/mephit_test.x
ERROR STOP expected path to config file as first parameter   # loads, then exits on missing arg

Numerical equivalence of the migrated routines:

1F1(1;b;z) via the fortnum QAG path vs an independent Kummer-series reference
(b = 2 + 0.5i, z = 0.3 - 0.2i):

quad 1F1(1;b;z) = 1.11595703944 + -0.151544119902i      # fortnum_integrate_qag
series 1F1(1;b;z) = 1.11595703944 + -0.151544119902i    # independent reference

Bessel index logic in kilca_vacuum_fourier vs scipy iv, including the
pol_mode = 0 case that needs I_{-1} = I_1:

pol_mode=0  I_{m-1,m,m+1}=  0.797329314979  1.469277797944  0.797329314979
pol_mode=1  I_{m-1,m,m+1}=  1.469277797944  0.797329314979  0.242617313361
pol_mode=2  I_{m-1,m,m+1}=  0.797329314979  0.242617313361  0.050814504638
# scipy.special.iv reference, x = 1.3:
pol_mode= 0 I_{m-1,m,m+1}= 0.7973293149792691 1.469277797944251 0.7973293149792691
pol_mode= 1 I_{m-1,m,m+1}= 1.469277797944251 0.7973293149792691 0.2426173133607603
pol_mode= 2 I_{m-1,m,m+1}= 0.7973293149792691 0.2426173133607603 0.05081450463846809

5-point Gauss-Legendre on [0,1] from fortnum_gauss_legendre_ab integrates
1, x, x^2 exactly (matching the former GSL glfixed rule):

int 1 = 1.000000000000 (exp 1)
int x = 0.500000000000 (exp 0.5)
int x^2 = 0.333333333333 (exp 0.333333333333)

Upstream fortnum test suite after the ctx-ABI fix, including the C smoke test:

$ ctest --output-on-failure
100% tests passed, 0 tests failed out of 67
Total Test time (real) =   0.42 sec

Supersedes #26.

Replace every GSL numerical routine with the fortnum core. Consumers now
depend on fortnum directly rather than on the GSL/FGSL stack.

Fortran (src/mephit_pert.f90): drop the bind(C) interface to
gsl_sf_bessel_In_array and call fortnum_special bessel_in_array in
kilca_vacuum_fourier. fortnum fills I_n(0:nmax), so the order |pol_mode|-1
needed for the radial Bessel sum (which is -1 when pol_mode = 0) is recovered
through the symmetry I_{-n}(x) = I_n(x). Call-site results are unchanged.

C: hyper1F1.c uses fortnum_integrate_qag (key 21, the former GSL_INTEG_GAUSS21)
for the 1F1 quadrature, threading the quad_params through the C ABI context
pointer, and fortnum_levin_u_accel for the Kummer-series acceleration. The
quadrature integrand now relies on float.h for DBL_EPSILON, formerly pulled in
transitively by the GSL headers. mephit_fem.c builds the unit-interval
Gauss-Legendre rule with fortnum_gauss_legendre_ab. The GSL error-handler
plumbing (gsl_errno_msg, gsl_set_error_handler) is removed from mephit_util and
mephit_run; fortnum routines report status through return codes.

Build: drop find_package(GSL) and the FGSL pickup, fetch fortnum via
FetchContent (git@github.com:lazy-fortran/fortnum.git, GIT_TAG main) guarded by
NOT TARGET fortnum so a transitive pull through libneo does not redeclare the
target, link the fortnum target, and add its include directory for the C/C++
sources. FFTW and the netlib zeroin/d1mach routines are untouched; they were
never GSL.

Supersedes #26.
@krystophny krystophny mentioned this pull request Jun 14, 2026
@krystophny

Copy link
Copy Markdown
Member Author

This monolithic migration is superseded by an atomic, stacked re-cut off main, with the FFTW migration added. One PR per dependency or concern, each individually reviewable; merged in order they compose to the full migration:

The stack tip builds clean: libmephit.so plus all three executables link, with zero GSL, FFTW, AMOS, and SLATEC symbols in the library and no GSL or FFTW dynamic dependency in the binaries. fortnum's own suite (68 tests) passes at tag a7faa3c. PRs 1 to 3 are drafts because their tips do not link the executables standalone (the empty FFTW_LIBRARIES link, also broken on main, is fixed in PR 4). Leaving this PR open for a human to close.

@krystophny

Copy link
Copy Markdown
Member Author

Split into atomic per-aspect PRs #29-#33 (bessel, 1F1, C-quadrature, FFTW, plumbing). Closing in favor of the atomic stack.

@krystophny krystophny closed this Jun 14, 2026
@krystophny
krystophny deleted the drop-gsl-fortnum branch August 20, 2026 06:47
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.

1 participant