Skip to content

Migrate off GSL onto the fortnum numerical core#139

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

Migrate off GSL onto the fortnum numerical core#139
krystophny wants to merge 1 commit into
mainfrom
drop-gsl-fortnum

Conversation

@krystophny

Copy link
Copy Markdown
Member

Supersedes #135.

Addresses #134. KAMEL is MIT-licensed but linked GSL (GPL-2.0+). This PR removes GSL entirely and routes every numerical call through the fortnum library (fetched from lazy-fortran/fortnum), the single numerical core for the group. Where #135 reimplemented the GSL routines in-tree and pulled Bessel from libneo, this PR depends on fortnum directly. No shipped binary links GSL.

What moved

KIM (Fortran)

  • gsl_sf_bessel_In -> fortnum bessel_in in FLR2_asymptotics.f90 (negative orders via I_{-n}=I_n, handled inside bessel_in).
  • gsl_sf_erf -> the Fortran 2008 erf intrinsic (integrands.f90, integrands_adaptive.f90, numerics_utils.f90).
  • gsl_mod.f90 deleted (the gsl_sf_erfc/gsl_sf_dawson bindings were dead). KIM_lib links the Fortran fortnum target; find_package(GSL) and the GSL link/include are gone.

KiLCA / QL-Balance (C/C++), via the fortnum C ABI (fortnum.h)

  • gsl_odeiv rk8pd evolve loops -> fortnum_ode_integrate_dop (calc_back.cpp, incompressible.cpp, compressible_flow.cpp). The historical rhs_* callbacks forward through small fortnum_ode_rhs adapters; the returned mesh is replayed exactly as the evolve loop stored each accepted step.
  • gsl_integration_qag -> fortnum_integrate_qag (four_transf.cpp, calc_I_array_drift.cpp); gsl_integration_qagi -> fortnum_integrate_qagiu with inf=2 (vel_integral.cpp).
  • gsl_root_fsolver brent -> fortnum_root_brent (calc_mode.cpp).
  • gsl_multiroot_fdfsolver hybridsj -> fortnum_multiroot_hybrid (calc_eigmode.cpp); eval_det is reexpressed on the fortnum_vector_fn ABI and the finite-difference Jacobian moves into the solver. The dead qng-based calc_circle_integral_gkq and the gsl_multiroot print helpers are removed.
  • gsl_deriv_central -> fortnum_deriv_central (incompressible.cpp, compressible_flow.cpp).
  • gsl_heapsort_index -> fortnum_argsort via a sort_index_doubles helper in shared.cpp (calc_cond.cpp, sysmat_profs.cpp, adaptive_grid.cpp).
  • KiLCA hyper1F1 quadrature path -> fortnum_hyperg_1f1_a1; the GSL-only Levin variant (marked "do not use" upstream) is removed.
  • Public interfaces (rhs_*, jac_*, the Afunc/Bfunc helpers) are preserved so callers compile unchanged; only the GSL internals are replaced.

Build

  • cmake/FetchFortnum.cmake fetches fortnum via FetchContent from git@github.com:lazy-fortran/fortnum.git (GIT_TAG main), guarded by if(NOT TARGET fortnum) so a transitive pull (e.g. through libneo) does not double-declare the target. The Fortran fortnum target backs the Fortran sources; ${fortnum_SOURCE_DIR}/include is on the C/C++ include path for fortnum.h.
  • cmake/FetchGSL.cmake deleted and include(FetchGSL) removed; gsl/gslcblas dropped from the KiLCA, KIM, and QL-Balance link lists and include paths.
  • KIM_exe and the KIM KiLCA-dependent tests link the freshly built kilca_lib target instead of a hardcoded stale prebuilt archive under build/.
  • GSL removed from the setup scripts, the standalone KiLCA build helpers, and the dependency lists in the READMEs.

This depends on the fortnum C ABI forwarding a user void* ctx to the callbacks (fortnum_integrate_*, fortnum_root_brent, fortnum_deriv_central, fortnum_multiroot_hybrid, fortnum_ode_*); that small ABI addition is committed on fortnum main (dc277b5).

Verification

Linux x86_64, gfortran/gcc 16.1.1, CMake 4.3.3, Ninja, fortnum main. All dependencies (LAPACK, SuiteSparse, SUNDIALS, NetCDF, HDF5, fortnum) resolved; no GSL fetched or built.

Before (origin/main): cmake/FetchGSL.cmake fetches and builds GSL 2.4; KiLCA/KIM/QL-Balance link gsl/gslcblas.

After (this branch): full build succeeds, no GSL symbol in any shipped binary.

$ cmake --build build -j  (forced recompile of all migrated sources)
[16/28] Linking CXX static library install/lib/libKiLCA_Lib_..._Release_64bit.a
[22/28] Linking CXX executable install/bin/KiLCA_Normal_..._Release_64bit
[23/28] Linking CXX executable install/bin/KIM.x
[28/28] Linking CXX executable install/bin/ql-balance.x
EXIT=0

$ for b in KIM.x KiLCA_Normal_... KiLCA_EigParam_... ql-balance.x post_processor_64bit fouriermodes.x; do nm install/bin/$b | grep -ic gsl_; done
KIM.x                       gsl=0
KiLCA_Normal_...            gsl=0
KiLCA_EigParam_...          gsl=0
ql-balance.x                gsl=0
post_processor_64bit        gsl=0
fouriermodes.x              gsl=0

ctest (18/18 pass), including the KiLCA-math tests that now run through fortnum:

$ ctest
 1/18 test_rk4_integrator ............. Passed
 ...
10/18 test_integration_methods ....... Passed
11/18 test_quadpack_qagi ............. Passed
12/18 test_root_finding .............. Passed
15/18 test_ampere_matrices ........... Passed
17/18 test_rhs_balance ............... Passed
18/18 test_kim_adapter ............... Passed

100% tests passed, 0 tests failed out of 18

fortnum's own suite (67/67) passes against the C-ABI ctx change, including a new context-forwarding check in the C smoke test:

integrate_qag(ctx scale*x)   got=1.5 want=1.5 abs_err=0 PASS
ALL CAPI SMOKE CHECKS PASSED
100% tests passed, 0 tests failed out of 67

Remaining

  • The bundled AMOS complex Bessel (zbesj/zbesi/zbesk in hmedium.f90, calc_D_array_*.f90, bessel.f90, plus the KiLCA/math/bessel/amos tree) is not GSL and is untouched here. Migrating it to fortnum bessel_j_complex/bessel_i_complex/bessel_k_complex and deleting the bundled AMOS is a separate follow-up; it does not affect the GSL removal.
  • KIM's own dispersion sources (fun_input.f90, wkb_dispersion.f90) call zbesi from the bundled SLATEC (not GSL); also untouched.

Remove the GSL dependency from KAMEL (KIM, KiLCA, QL-Balance) and route
every numerical call through fortnum, fetched from lazy-fortran/fortnum.
No shipped binary links GSL; every install/bin and tests/*.x executable
has zero gsl_ symbols.

KIM (Fortran):
- gsl_sf_bessel_In -> fortnum bessel_in in FLR2_asymptotics.f90 (negative
  orders handled by bessel_in via I_{-n}=I_n).
- gsl_sf_erf -> the Fortran 2008 erf intrinsic (integrands.f90,
  integrands_adaptive.f90, numerics_utils.f90); the aliased import is
  dropped so the intrinsic resolves.
- gsl_mod.f90 deleted (the gsl_sf_erfc / gsl_sf_dawson bindings were dead).
- KIM_lib links the Fortran fortnum target; find_package(GSL) and the GSL
  link/include are removed.

KiLCA / QL-Balance (C/C++), via the fortnum C ABI (fortnum.h):
- gsl_odeiv rk8pd evolve loops -> fortnum_ode_integrate_dop in
  calc_back.cpp, incompressible.cpp, compressible_flow.cpp. The historical
  rhs_* callbacks are forwarded through small fortnum_ode_rhs adapters; the
  returned mesh is replayed exactly as the evolve loop stored each step.
- gsl_integration_qag -> fortnum_integrate_qag (four_transf.cpp,
  calc_I_array_drift.cpp); gsl_integration_qagi -> fortnum_integrate_qagiu
  with inf=2 (vel_integral.cpp).
- gsl_root_fsolver brent -> fortnum_root_brent (calc_mode.cpp).
- gsl_multiroot_fdfsolver hybridsj -> fortnum_multiroot_hybrid
  (calc_eigmode.cpp); eval_det is reexpressed on the fortnum_vector_fn ABI
  and the finite-difference Jacobian moves into the solver. The dead
  qng-based calc_circle_integral_gkq and the gsl_multiroot print helpers
  are removed.
- gsl_deriv_central -> fortnum_deriv_central (incompressible.cpp,
  compressible_flow.cpp).
- gsl_heapsort_index -> fortnum_argsort via a sort_index_doubles helper in
  shared.cpp (calc_cond.cpp, sysmat_profs.cpp, adaptive_grid.cpp).
- KiLCA hyper1F1 quadrature path -> fortnum_hyperg_1f1_a1; the GSL-only
  Levin variant (marked "do not use" upstream) is removed.
- Public interfaces (rhs_*, jac_*, Afunc/Bfunc helpers) are preserved so
  callers compile unchanged; only the GSL internals are replaced.

Build:
- cmake/FetchFortnum.cmake fetches fortnum via FetchContent from
  git@github.com:lazy-fortran/fortnum.git (GIT_TAG main), guarded by
  if(NOT TARGET fortnum) so a transitive pull does not double-declare it.
  The Fortran fortnum target backs the Fortran sources;
  ${fortnum_SOURCE_DIR}/include is on the C/C++ include path for fortnum.h.
- cmake/FetchGSL.cmake deleted and include(FetchGSL) removed; gsl/gslcblas
  dropped from the KiLCA, KIM, and QL-Balance link lists and include paths.
- KIM_exe and the KIM KiLCA-dependent tests link the freshly built
  kilca_lib target instead of a hardcoded stale prebuilt archive.
- GSL removed from setup scripts, the standalone KiLCA build helpers, and
  the dependency lists in the READMEs.

The bundled AMOS complex Bessel (zbesj/zbesi/zbesk in hmedium.f90,
calc_D_array_*.f90, bessel.f90) is unaffected: it is not GSL and stays in
place pending a separate migration to fortnum bessel_*_complex.
@krystophny krystophny mentioned this pull request Jun 14, 2026
@krystophny

krystophny commented Jun 14, 2026

Copy link
Copy Markdown
Member Author

Superseded by a stack of eight atomic PRs that re-cut this migration off origin/main and also complete the AMOS/SLATEC removal this PR left as follow-up. Each is individually reviewable; merged in order they compose to the full migration. A human should close this PR.

Verification (stack tip, all eight applied): full CMake/Ninja build green, ctest 18/18, and nm over every shipped binary shows 0 AMOS implementation symbols and no GSL symbols from KAMEL code. The only residual GSL is two gsl_sf_gamma* symbols pulled transitively from libneo, not from KAMEL.

@krystophny

Copy link
Copy Markdown
Member Author

Split into atomic per-aspect PRs #140-#147 (KIM specials, KIM QUADPACK, KiLCA quadrature, ODE, roots/util, complex Bessel AMOS/SLATEC removal, 1F1, plumbing). Closing in favor of the atomic stack.

@krystophny krystophny closed this Jun 14, 2026
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