Implement the 13 integrals missing relative to libcint 6.1.3 - #24
Implement the 13 integrals missing relative to libcint 6.1.3#24susilehtola wants to merge 2 commits into
Conversation
The file has been present in the source tree and its integrals (int1e_ipipipnuc, int1e_ipipiprinv, int1e_ipipnucip, int1e_ipiprinvip) are declared in include/cint_funcs.h, but it was never listed in CMakeLists.txt, so the symbols were missing from the built library. libcint compiles the same file. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTc5De7stABc2q58NHV22E
qcint 6.1.3 lacked 13 integrals that libcint 6.1.3 exports. Five of
them (int1e_r{2,4}_origi_ip2, int3c1e_ip1_r{2,4,6}_origk) are required
by PySCF >= 2.13 for nuclear gradients with GTH pseudopotentials, so
PySCF built against qcint failed with undefined symbols
(pyscf/gto/pp_int.py, pyscf/pbc/gto/pseudo/pp_int.py).
Generated with scripts/gen-code.cl (which reproduces all previously
committed autocode byte-for-byte):
* src/autocode/deriv4.c (new): int1e_ipiprinvipip, int1e_ipipiprinvip,
int1e_ipipipiprinv. The declarations were already present in
scripts/auto_intor.cl but the file had never been generated.
* src/autocode/lresc.c (new): int1e_iprinvr, int1e_iprinviprip,
int1e_rinvipiprip, int1e_ipiprinvrip; declarations added to
scripts/auto_intor.cl following libcint.
* src/autocode/int3c1e.c: second derivatives int3c1e_ipip1,
int3c1e_ip1ip2, int3c1e_ipvip1, int3c1e_ipip2.
* src/cint1e_a.c: int1e_r2_origi_ip2, int1e_r4_origi_ip2.
* src/cint3c1e_a.c: int3c1e_ip1_r2_origk, int3c1e_ip1_r4_origk,
int3c1e_ip1_r6_origk.
Ported by hand to the SIMD framework:
* src/g4c1e.c, src/cint4c1e.c (new): int4c1e, enabled with the same
WITH_4C1E cmake option as libcint. CINTg4c1e_ovlp vectorizes the
libcint algorithm with one primitive quartet per SIMD lane, reusing
the existing CINTg0_{lj,kj,il,lj}_4d expansion routines; the
primitive loop follows CINT3c1e_loop_nopt extended to four shells.
include/cint_funcs.h is updated to declare the same set of integrals
as libcint (this also adds the previously undeclared
int1e_grids_ipip, which was already implemented).
All new integrals were validated numerically against libcint 6.1.3
over every shell tuple of a mixed s/p/d/f contracted/primitive test
basis, in both _sph and _cart forms; agreement is at machine
precision. int3c1e_ip1_r6_origk was additionally validated against
finite differences of int3c1e_r6_origk because libcint's own
implementation of that integral has a bug in its y component (it
reads the uninitialized work array g76).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TTc5De7stABc2q58NHV22E
|
CI note: qcint's workflow downloads the test scripts from libcint master at run time ( Also note that pyscf cannot serve as a numerical reference for |
As I reported in October 2025 in pyscf/pyscf#3021, some PySCF tests failed with missing symbols. This turned out to be due to a mismatch in qcint and libcint: the former was missing some integral classes. This PR implements those missing integral types.
AI summary
qcint 6.1.3 does not export 13 integrals that libcint 6.1.3 provides. Five of them —
int1e_r{2,4}_origi_ip2andint3c1e_ip1_r{2,4,6}_origk— are required by PySCF >= 2.13 for nuclear gradients with GTH pseudopotentials, so PySCF built against qcint aborts with undefined-symbolAttributeErrors inpyscf.gto.pp_int/pyscf.pbc.gto.pseudo.pp_int. This was found while enabling the PySCF test suite in Fedora, where qcint provides libcint on x86-64; 10 tests fail.Generated code (via
scripts/gen-code.cl, which reproduces all previously committed autocode byte-for-byte):src/autocode/deriv4.c(new):int1e_ipiprinvipip,int1e_ipipiprinvip,int1e_ipipipiprinv— already declared inauto_intor.cl, but the file had never been generated;src/autocode/lresc.c(new):int1e_iprinvr,int1e_iprinviprip,int1e_rinvipiprip,int1e_ipiprinvrip;src/autocode/int3c1e.c:int3c1e_ipip1,int3c1e_ip1ip2,int3c1e_ipvip1,int3c1e_ipip2;src/cint1e_a.c/src/cint3c1e_a.c: the five PySCF-critical integrals listed above.Hand-ported to the SIMD framework:
int4c1e(src/g4c1e.c+src/cint4c1e.c, behind the sameWITH_4C1Eoption as libcint).CINTg4c1e_ovlpvectorizes libcint's algorithm with one primitive quartet per SIMD lane, reusing the existingCINTg0_{lj,kj,il,ik}_4dexpansion routines; the primitive loop followsCINT3c1e_loop_noptextended to four shells.A separate first commit adds
src/autocode/deriv3.ctoCMakeLists.txt: the file was in the tree and its integrals declared incint_funcs.h, but it was never compiled, soint1e_ipipipnuc,int1e_ipipiprinv,int1e_ipipnucip, andint1e_ipiprinvipwere also absent from the built library.include/cint_funcs.his updated to declare the same integral set as libcint.Validation. Every new integral was compared against libcint 6.1.3 over all shell tuples of a mixed s/p/d/f contracted/primitive basis, in both
_sphand_cartforms: agreement is at machine precision (<= 3e-13;int4c1eat 1e-13). A smoke test of 17 pre-existing integrals shows no regressions.int3c1e_ip1_r6_origkwas additionally validated against finite differences ofint3c1e_r6_origk, because libcint's own hand-written version of that integral has a bug in its y component (an uninitializedg76read; fix submitted separately as sunqm/libcint#132).🤖 Generated with Claude Code
https://claude.ai/code/session_01TTc5De7stABc2q58NHV22E