Repository navigation
Description
Summary
Tracking issue for the driver refactor in HyperFEM (src/ComputationalModels/Drivers.jl, src/Solvers/, ext/HyperFEMKernelsExt.jl). It is the driver-side companion of the scalable linear-solver block (#21) and appears in the master plan (#22).
Goal: drivers with concrete types and no allocations per load step or Newton iteration, one incremental loop shared by all models, and a backend contract that HyperFEMKernels and the solver block plug into, without changing the user interface (constructors, solve!, PostProcessor, Adv_Mater scripts).
Stages are named R0–R5 so they do not clash with the stages (S0–S5) and decisions (D1–D5) of #21.
Relation with the solver block (#21)
- R0 is measured inside S0: one baseline for drivers and solvers.
- S0′ also takes the allocation fixes of the efficiency review: line searches without
x + α*dx(trial vector in the cache),x .+= α .* dx,IterativeSolverwithouteval(Meta.parse(...))persolve!, views inInjectivity_Preserving_LS. - R4 (single Newton) goes after S1 and before S3. It is designed with what S1 (PETSc Krylov + AMG, lagged AMG) and S3 (matrix-free Jacobian inside Newton) need, and it is the evolution of
Newton_RaphsonSolverafter S0′, so S0′ is not lost. It follows whatever Scalable linear solvers: plan, decisions and traceability #21 decides in D5 (curvature criterion).
S0 (incl. R0) ─► S0′ ─┬─► R1 ─► R2 ─► R3
└─► S1 ─────────────► R4a ─► R4 ─► S3 ─► S4 ─► S5
(S2 after S1, independent of R*)
R5 MPI: postponed
Stages
- R0 — Driver baseline (inside S0,
benchmark/drivers/in HyperFEMKernels)- Time and bytes per Newton iteration (residual, Jacobian, factorization, rest), per load step and per
solve!; driver allocations outside assembly and the linear solve. StaticMechanicalDirichlet(withProjectDirichlet), EM plate P1 and Q2 box, hMRE, with:gridapand:kernel.
- Time and bytes per Newton iteration (residual, Jacobian, factorization, rest), per load step and per
- R1 — Typed caches, backend as a type (HyperFEM,
drivers-typed-caches, fromkernel-backend)AlgebraicBackend/GridapBackend/KernelBackend(the latter in the extension);backend = :gridap | :kernelstill accepted; theValhooks stay one cycle as a bridge.- Typed
NonlinearStepCache;cachesas aNamedTuple(sopost.comp_model.caches[3]keeps working). - Remove dead code (
post_solve!, brokenget_measure/get_assemblersofStaticLinearModel). StaggeredModelreturnsall(flags);kargsolveacceptsNamedTuples.- No
Vector{Float64}in signatures; noGC.gc()in the dynamic driver. - Clear errors for custom/distributed assemblers with
:kernel(open item of [Kernel backend]: HyperFEMKernels integration — phases, status and path to main HyperFEM.jl#258). - Bit-identical.
- R2 — Single incremental loop (HyperFEM,
drivers-single-loop)LoadStepping,TimeStepping,step!(m, Λ, ∆Λ; load)with today's order of operations, used by the static, dynamic (Midpoint) and staggered models.DynamicNonlinearModelgetsbackend(open item of HyperFEM.jl#258); optional hookson_bisection,presolver;post.state.- Bit-identical on all simulation tests with both backends.
- R3 — Dirichlet projection and
StaticLinearModel(HyperFEM,drivers-dirichlet-linear)dirichlet_projection!assembles into the Newton cache instead of a newAffineFEOperatorper step.StaticLinearModel:numerical_setup!only ifKwas reassembled; one inner constructor; shared_solve_linear!.- Bit-identical, or rounding accepted and documented.
- R4a — Newton ↔ linear-solver interface (
docs/design/newton-linear-solver.md, after S1)- Cache that accepts a matrix-free Jacobian (needed by S3); preconditioner refresh with
x(numerical_setup!(ns, A, x), lagged AMG from S1); optional inexact tolerance (Eisenstat–Walker), off by default; one-passresidual_and_jacobian!with fallback. - Checkpoint (Jesús).
- Cache that accepts a matrix-free Jacobian (needed by S3); preconditioner refresh with
- R4 — Single Newton (HyperFEM,
drivers-newton)HyperFEM.NewtonSolveras the evolution ofNewton_RaphsonSolver(line search,ctol, linear-solver convergence check from S0′);Newton_RaphsonSolverdeprecated; GridapSolvers'NewtonSolverstill accepted.- Convergence through
converged(nls, cache)instead of readingnls.log.residuals;Injectivity_Preserving_LSoverblockswith a global reduction ofα. - Bit-identical with LU; zero-allocation test per iteration (skipped with
--check-bounds=yes).
- R5 — MPI: postponed. Meanwhile R1–R4 keep the serial code MPI-ready: no
Vector{Float64}, no scalar indexing, global reductions for control-flow decisions, output from the main rank only.
Decisions (@jmartfrut, 2026-10-24)
- Single Newton
HyperFEM.NewtonSolver;Newton_RaphsonSolverdeprecated. - Dirichlet-projection operator stored untyped in the cache;
ProjectDirichletstays asolve!kwarg. StaggeredModelreturnsall(flags).- If the projection on the cache is not bit-identical, rounding is accepted and documented.
- MPI postponed.
- Backend as a type:
AlgebraicBackend/GridapBackend/KernelBackend.
User-visible changes
Only two: the convergence flag of StaggeredModel (today it is wrong) and a depwarn for Newton_RaphsonSolver. Everything else is optional and additive.
Rules
- One branch per stage, from
kernel-backend, merged back into it; stacked if the previous PR is under review. - Validation: HyperFEM
Pkg.test()with both backends; bit-identical on the simulation tests and the Adv_Mater scripts (dev/run_sims.jl,compare_sims.jl,advmater_compare.jl); Julia 1.10 only for the:gridappath (HyperFEMKernels and GridapPETSc require 1.12). - A HyperFEM stage that needs something new from HyperFEMKernels is merged after the corresponding HyperFEMKernels PR (HyperFEM CI clones HyperFEMKernels
main). - Each stage: dated entry in
ESTADO.md, PR text indocs/PR_<branch>.md, checkbox ticked here with a short comment. PRs reference this issue and the stage (R1, …).
Activity
[-]Plan: driver refactor (HyperFEM) + iterative solver block (tracking)[/-][+]Driver refactor in HyperFEM (tracking, companion of #21)[/+]jmartfrut commentedon Oct 29, 2026
Update after unifying this plan with the solver block (#21), 2026-10-29. Full detail in the project document
design/solvers.md, section "Unified stage structure".NewtonRaphson(notHyperFEM.NewtonSolver);Newton_RaphsonSolverdeprecated for one release. GridapSolvers is dropped from HyperFEM (own tolerances and convergence log); itsNewtonSolverkeeps working for one release through a weak-dependency extension with a deprecation warning. The Newton takes two strategies:linesearch(FullStepLS,BacktrackingLS,InjectivityLS) andtangent(ConsistentTangent,HybridTangent); the operator exposes optionalenergy,max_stepandjacobian!(…, :projected)hooks implemented by the drivers.x, optional Eisenstat–Walker, one-passresidual_and_jacobian!. The matrix-free-ready cache and thelinear_convergedhook are already in S0′.benchmark/drivers/), as planned.maxbisecas consecutive bisections. The Dirichlet reset after a bisection (§6, point 3) is a bug fix and goes in S0′ with its own test. R2's acceptance test: the full piston (15d) against Horák's curve, local only (HYPERFEM_TEST_LONG=1).:lazy/:compiled(HyperFEM #263); the types becomeLazyBackend/CompiledBackend, and they absorb S0′'s operator hooks without changing their signature.jmartfrut commentedon Nov 6, 2026
Closing this tracking issue: the driver refactor is complete.
What landed
backend = :gridap | :kernel), so the assembly engine can be swapped without touching the drivers' public API. The default stays:gridap.HyperFEMKernelsExtextension (weak dependency). HyperFEM does not depend on HyperFEMKernels at load time.CompiledBackend(; jacobian = :matrixfree), and energy / injectivity-step evaluation is dispatched on the backend.Validation
test/SolversTests/).PRs
Notes
[compat]bumped in #__).Companion of #21.