-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adjoints of FEOperators #337
Comments
I went ahead and started the implementation of I'm not sure if this is the most correct/efficient way of defining the adjoints. Could you take a look and let me know what do you think, @santiagobadia @fverdugo ? |
I would follow a quite different approach, which I think opens the door to more optimizations. From the user perspective: a(u,v) = a(u,v) = ∫( ∇(v)⋅∇(u) )*dΩ # Some bi-linear form
l(v) = ∫( v*f )*dΩ + ∫( v*(n_Γ⋅∇u) )*dΓ # Some linear form (external loads)
ld(u) = ∫( abs2(u-u_target) )*dΩ +# Some linear form (objective function)
op_opd = AffineFEOperatorWithAdjoint(a,l,ld,U,V;selfadjoint=true) # Better name?
uh, udh = solve(op_opd) # Forward and adjoint solutions.
# If `selfadjoint=true` one can reuse the numerical setup of the solver.
In the non-linear case, the idea is the same res(u,v) = # the residual as now
jac(u,du,v) = # the jacobian as now
ld(u) = ∫( abs2(u-u_target) )*dΩ +# Some linear form (objective function)
op_opd = FEOperatorWithAdjoint(res,jac,ld,U,V;selfadjoint=true)
uh, udh = solve(op_opd)
|
BTW, you can always implement these geters if you want to consider forward and adjoint problems separately (at the cost of loosing the optimizations that take place when they are solved together) op = get_forward(op_opd)
opd = get_adjoint(op_opd) # This will be always an AffineFEOperator
# or by using iteration
op, opd = op_opd |
Transposing lazily or assembling the transpose from the bilinear form / jacobian will depend on the linear solver used for the adjoint. If the linear solver allows to use a lazy transpose efficiently, this would be the best option. Since it depends on the linear solver, at some point we need to do dispatch with it. |
@fverdugo are you thinking on two |
For serial |
@fverdugo @oriolcg We want to create adjoints of
FEOperator
s. In this sense, I propose a method likewhere
op
is aFEOperator
,uh
is the solution. We have discussed to include there theRHS
, but it would be misleading, it has nothing to do with the adjoint. Instead, I would return aAffineFEOperator
with zero right hand side and create a method that takesadj_op
and therhs
separately.The internal implementation of this adj_op can be:
If
op
is aAffineFEOperator
, we can consider as the most general method, to take the corresponding sparse matrix and perform a lazyJulia
transpose. However, I think that this is probably not what we want for some particular implementation of the matrix (e.g., when using PETSc arrays, etc). In those cases, more concrete versions of the transpose, e.g., non-lazy versions, will be needed.If
op
is aFEOperatorFromTerms
, to define the transpose of this operator that does exactly the same as theFEOperatorFromTerms
but tranposes the local element matrix before its assembly. Since it is a minor change in the implementation ofFEOperatorFromTerms
, I would probably use a trait to implement this.The text was updated successfully, but these errors were encountered: