Repository navigation
Optimization in transient linear FE operator for zero Dirichlet value case - #1345
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1345 +/- ##
==========================================
+ Coverage 89.52% 89.58% +0.05%
==========================================
Files 243 243
Lines 32142 32138 -4
==========================================
+ Hits 28776 28791 +15
+ Misses 3366 3347 -19
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
JordiManyer
left a comment
There was a problem hiding this comment.
Hi @oriolcg thanks for the contribution! From a mathematical point of view, I am ok with the change. I left a comment on some aesthetic changes, please have a look. Thank you!
| for k in 0:get_order(odeop) | ||
| w = ws[k+1] | ||
| iszero(w) && continue | ||
| if is_form_constant(odeop, k) |
There was a problem hiding this comment.
Maybe we can use this function instead of !isnothing(const_form)? Also the axpy_values? I believe we are doing the same here than what you want to do above.
Then, can we create a helper like _has_zero_dirichlet_values(odeopcache.Us[k+1]) that instead of acting on the space itself acts on the operator like is_form_constant(odeop, k)? Under the hood we can do the same thing, but lets try to keep things clean.
There was a problem hiding this comment.
I modified according to the suggestion. We cannot use axpy_entries as this is a mat-vec product. We still need to check the underlying FEspace, so we cannot just rely on the operator alone. I added a wrapper function is_form_constant_and_zero_dirichlet. See latest commit.
|
Alright, all good! Thanks for the contribution @oriolcg ! |
Hi @JordiManyer, I propose an optimization for the case of
LinearODEOperatorwith zero Dirichlet values. See explanation below (AI-generated).A linear transient problem in Gridap is written as
and built with
TransientLinearFEOperator(forms, res, U, V; constant_forms). When a form is declared constant,allocate_odeopcacheassembles its matrixA_konce and stores it inodeopcache.const_forms. For a linear problem with constant forms, every step still performs a full quadrature pass over all cells for every bilinear form, only to obtain avector that equals
Σ_k A_k ∂tᵏu.Since the system matrix is factorised once, this assembly becomes the dominant per-step cost (tested time of 3-4x slower than only doing algebraic operations).
Why Gridap cannot simply use
A_k · ∂tᵏuThe identity
holds only if
∂tᵏuₕis fully determined by its free values, i.e. if the space of the k-th time derivative has zero Dirichlet values.A_konly stores the free × free block; with non-zero Dirichlet values the residual also contains the lifting termA_k^{free,Dir} · ∂tᵏu_D(t), which is not stored.constant_formsonly states that the bilinear form does not depend on time; it says nothing about the boundary data. So the stock code takes the generic, always-correct path.The proposed change
In
Algebra.residual!(r, ::ODEOpFromTFEOp{<:AbstractLinearODE}, …)(
src/ODEs/ODEOpsFromTFEOps.jl), each form is treated separately:with
The forcing
res(t, v)and any form that does not satisfy the condition are assembled exactly as before. The assembly call is also skipped when nothing is left to assemble (num_domains(dc) == 0, asjacobian_add!already does).Because the decision is taken per form, the common cases work as follows:
u = 1on ∂Ω)u_D = g(x)(1 + t))ramp(t)·sin(ωt))(In each case the table gives the path actually taken in practice, as reported by
_has_zero_dirichlet_valueson the evaluated spaces.)Nothing changes for non-constant forms, for quasilinear / semilinear / nonlinear operators, or for the Jacobian.