Repository navigation
Follow-ups to the reviews of #399: lmax checks, hartree-fock++ hessian coverage, compiler cleanups - #450
Merged
Conversation
…stent lmax_exceeded - compute1()/compute2() only asserted that the shells do not exceed the max_l of the Engine, hence a Release build overran the stack and scratch buffers sized for max_l; throw Engine::lmax_exceeded instead. - lmax_exceeded thrown by initialize() reported the max AM + 1 as the limit, the one thrown by compute2() the max AM; report the max AM in both, and include the task and the limits in what(). - rkb_operators: the "folded" paragraph applies to the operators with one folded electron; opop_coulomb_opop already contains the -1 of i², as its prefactor column says. - tests for the per-center checks of compute2(), the max_l check, the limit reported by initialize(), and the core evaluator rebuilt by set(BraKet).
…t do it; test the hessian in CI again - the validator accepted "2-body forces/hessian skipped" whenever it saw it; it now reads the max AM of the ERI kernels for each derivative order from the features file (new LIBINT_ERI_MAX_AM_DERIVS) and accepts a skip only if that is below the AM of the basis. - the CI lane with LIBINT2_MAX_AM="2;2;1" generated 2nd-derivative ERIs up to p only, so hartree-fock++ skipped its hessian, which then was not tested in any lane; generate them up to d (LIBINT2_ERI_MAX_AM="2;2;2"). - api_basic_compile_test: the 2-center derivative checks also need the 2-center (2eri<d>) kernels.
- rkb_fold_make_children: lead the symbolic sum with a +1 term, so that the cross x cross components of opop_coulomb_opop no longer multiply by -1.0 (which was also missing from the flop count). - descriptors of the RKB and σ·p 1-body operators: check the component index (both bounds) in all builds. - build_libint: PairSwap::coupled requires p1p2_swappable, check at compile time instead of asserting in the predicates; stale comments (translational invariance is handled by DerivGaussV2), unused includes, a leftover flush. - master_ints_list: SMultipole_1_1_int was outside the LIBINT_SUPPORT_ONEBODYINTS guard of the list. - comments: the reason for the DerivGaussV2TI label, "quaternions".
The C and Fortran tests compute the primitive data with differently ordered arithmetic; with 2nd-derivative ERIs over d shells (now generated in the CI lane with LIBINT2_ERI_MAX_AM="2;2;2") 2 of ~1400 elements, small differences of large terms, differed by 5e-12 relative to themselves (3e-15 in absolute terms). Measure the difference relative to the largest element of the shell set instead.
…ll AM The per-shell asserts against max_l ran before the new all-builds check, so Debug builds aborted instead of throwing. Replace them with the throw and drop the now-redundant check that followed the canonicalization.
evaleev
force-pushed
the
fix/rkb-review-followups
branch
from
October 26, 2026 11:00
4bfc309 to
d36ed43
Compare
…tor) initialize() resized primdata_ only when given max_nprim, so set(BraKet) and set(Operator) kept the size for the old braket rank; e.g. switching from a 3-center to a 4-center braket overran primdata_ (caught by the new set(BraKet) test, crashing CI). The Engine now records max_nprim_, which initialize() uses, and max_nprim() returns it instead of a value derived from the size of the last computed ShellPair.
intrinsic_deriv_order() dispatches on the runtime operator, and compute2 called it in the loop over primitives; the operator and the derivative order are template parameters of compute2, hence use a constexpr.
RecurrenceRelation::is_alias() (false by default) declares that the target
is identical, element by element and in the same layout, to the only child.
handle_trivial_nodes() then makes the vertex refer to the child, provided
the child has no other parent and is not a target, so no code is generated
for the RR; update_func_names() and ExtractRR skip referring vertices, so
neither is the RR's function included or generated.
CR_11_Coulombσp_11 (one derivative integral with unit coefficient per
component) is an alias: the 19 3coulomb_op prereq kernels of the RKB test
configuration accumulate the derivative integrals directly instead of
copying them first, and CR_Coulombop_{0,1,2} are no longer generated.
test9 checks the children of direct differentiation and of translational invariance, that the generated code is shared by the spectators but not by different shells or directions, builds shell sets that call both kinds of DerivGaussV2 functions, and that CR_11_Coulombσp_11 is an alias. The test driver returned 0 even if a test threw, hence could never fail.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-ups to the reviews of #399 (the nonblocking items that were still open when it merged).
Engine
compute1()/compute2()check the shells against the Engine'smax_lin all builds and throwEngine::lmax_exceeded. Before, this was only a Debug assert, so a Release build overran the stack/scratch sized formax_l; this is also the case on master before Relativistic 2e 3- and 4-center integrals #399.lmax_exceeded::lmax_limit()is the max AM wherever it is thrown;initialize()used to report max AM + 1.what()now names the task and both values.rkb_operatorsdocs: the "folded" paragraph applies to the operators with one folded electron;opop_coulomb_opopalready contains the −1 of i².compute2()(live wheneverLIBINT2_ERI3_MAX_AM>LIBINT2_MAX_AM, as in CI);max_lcheck;initialize();set(BraKet).set(BraKet)/set(Operator)resize the primitive data for the rank of the new braket. Before,initialize()resized it only when givenmax_nprim, so e.g. switching an Engine from 3 to 4 centers overran the buffer (found by the newset(BraKet)test under ASan).max_nprim()returns the value the Engine was sized for; it used to be derived from the size of the last computed shell pair.compute2()evaluates the total derivative order (der+ the operator's intrinsic order) at compile time instead of callingintrinsic_deriv_order()per primitive.hartree-fock++ / CI
LIBINT_ERI_MAX_AM_DERIVS), and the validator accepts a skip only if the kernels cannot handle the d shells of the basis.LIBINT2_MAX_AM="2;2;1"generated 2nd-derivative ERIs up to p only. hartree-fock++ therefore skipped its Hessian, which was tested in no lane. The lane now generates them up to d (LIBINT2_ERI_MAX_AM="2;2;2").api_basic_compile_test: the 2-center derivative checks also need the2eri<d>kernels.Compiler
PairSwap::coupled⇒p1p2_swappableis astatic_assertinstead of asserts in the shell-set predicates.SMultipole_1_1_intwas outside theLIBINT_SUPPORT_ONEBODYINTSguard.RecurrenceRelation::is_alias(): an RR whose target is identical to its only child.handle_trivial_nodes()makes such a vertex refer to its child (when the child has no other parent and is not a target), and no code is generated or included for the RR.CR_11_Coulombσp_11is one, so thecoulomb_opkernels accumulate the derivative integrals directly instead of copying them first. In the configuration below, 193coulomb_opkernels change,CR_Coulombop_{0,1,2}are no longer generated, and every other generated file is unchanged.DerivGaussV2test (children of direct differentiation and of translational invariance, code shared by spectators but not by shells or directions, code-generating builds of both paths,CR_11_Coulombσp_11is an alias). The test driver now exits nonzero if a test throws; it used to return 0 regardless.Verified locally (macOS, Apple clang, gfortran 14) with the configuration of the modified CI lane (
MAX_AM=2;2;1,ERI_MAX_AM=2;2;2,ENABLE_ERI=2,ERI3_MAX_AM=3;2, RKB on,RKB_ERI3_MAX_AM=3, ERI2 on, Fortran, Release):check-libint2compilerpasses 2/2 andcheckpasses 17/17: 47 unit test cases, 134,570,582 assertions.MAX_AM2).check-libint2compilerandcheckpass again.This PR was agent-generated and human-reviewed.