-
-
Notifications
You must be signed in to change notification settings - Fork 194
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
SNES solver interface for standard, block and nest systems #3648
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: Michal Habera <[email protected]>
…function for extracting Jacobians
…of `solve`. Let the user do this with the Problem-class function replace solution. Also expose the petsc objects in the solver through properties
If you want to use the lowest level API the users can call the appropriate |
The others wanted a low level API. We can of course remove the mid-layer, ie not expose |
The low level API can for instance be used to set your own |
Seems like a good suggestion to break this out further.
My view is that SNESSolver will end up being re-born as NonlinearProblem (in the same way LinearProblem wraps KSP), but that's another discussion to be had. So then in terms of using petsc4py SNES, there will be the Edit: @michalhabera There is an "example" of using SNES directly at https://github.com/FEniCS/dolfinx/pull/3648/files#diff-f9b6597717f57bdb47379a64d265490d51aa09a0320d4d47511b09fba2371b1bR304 |
) | ||
x, converged_reason, _ = solver.solve() | ||
assert converged_reason > 0 | ||
solver.copy_vec_to_function(x, U) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we can agree that SNESSolver
should be NonlinearProblem
then this call should go inside solve and also solve should do any necessary ghost updates, in the same way that LinearProblem
works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do that in this PR so that we can review this important set of changes as a whole.
I've seen the tests and "how" to use the API. But my question was more about "why" to use it, in the tests all could be neatly done with the high level SNESSolver. |
This was a request of Jack. As he stated, he wants to work directly with the |
Three (edit) points here:
|
snes.setJacobian(partial(J_nest, u, jacobian, preconditioner, bcs), A, P) | ||
else: | ||
raise ValueError(f"Unsupported SNES type {assembly_type}") | ||
return snes, x |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thinking behind returning x
is that users must not under any circumstances use the data behind u
to call SNES solve
. This may be signposting that might not be necessary for users of the lower-level interface. On the other hand, easy mistake to make.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A first pass of comments.
I would prefer to see this built up in stages, perhaps by starting with bottom-up functionality that simplifies the test examples. An example to start could be a single function copies data from DOLFINx Function
s in/out of blocked PETSc data structures, and get that as simple as possible. This could be merged aheads of a SNES interface.
u: typing.Union[Function | list[Function]], | ||
du: typing.Optional[typing.Union[ufl.Argument, list[ufl.Argument]]] = None, | ||
) -> typing.Union[ufl.Form, list[list[ufl.Form]]]: | ||
"""Compute the Jacobian :math:`J = \\frac{\\partial F}{\\partial u}[\\delta u]`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not clear from the docs what is 'computed'. It should say something like it computes the derivative of a UFL form to generate a UFL form for the Jacobian.
Need to document the arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to review and edit all of the documentation in due course. Many issues, also with consistency with respect to LinearProblem
.
a: typing.Union[list[list[fem.Form]], fem.Form], | ||
L: typing.Union[list[fem.Form], fem.Form], | ||
P: typing.Union[list[list[fem.Form]], list[fem.Form], fem.Form, None], | ||
assembly_type: fem.petsc.AssemblyType, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think assembly_type
should be a PETSc Mat/Vec type. This would allow the caller to not only specify 'nest`, but also other PETSc matrix types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already discussed this, it was also my preference, but @jorgensd told me it's not possible to discern between nest and block types. I do see MATNEST
and MATBLOCK
though: https://petsc.org/release/manualpages/Mat/MatType/ - would these work @jorgensd ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use createBlockMat
(https://petsc.org/release/manualpages/Mat/MatCreateBlockMat/).
We use createMat
and attach an index set to it based on the concatenated index maps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to discern between block and nest types. If the forms are a list, then it's block or nest. Nest is used if the user asks for nest, otherwise MATAIJ
or whatever else they want.
The interface should probably have options for the vector and the matrix (matrices for nest), since they can differ. Even for a single matrix or a matrix in a nest there are options, e.g. block CSR. See
dolfinx/python/dolfinx/fem/petsc.py
Line 174 in 192222e
def create_matrix(a: Form, mat_type=None) -> PETSc.Mat: |
MatType
. The other "create_matrix functions should have that option too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you want:
- Send in two arguments, "MatType" and "VecType" to the
SNESSolver
-constructor. - If the user sends in any mat-type but nest, check if the residual is a list or not.
2a. If it is a list use assemble_block and corresponding methods
2b. OTherwise use assemble etc.
What should happen if:
- A user sends in snes as argument, but a single form (non-blocked).
- The user sends in a non-matching argument to MatType and VecType.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Focusing on the matrix, the user should do one of the following:
- Send in
None
for the matrix type. In this case the default PETSc matrix type will be used. If the forms are blocked, the assembly will be blocked; or - Send in
MATNEST
as the matrix type. In this case each block will have the default matrix type; or - Send in a list-of-lists with the matrix type for each block in a
MATNEST
matrix.
The C++ interfaces for creating the matrices support these options. The code should handle a PETSc prefix to support setting of matrix types from the command line.
return self._copy_vec_to_function | ||
|
||
|
||
def F_standard( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The F_foo
function names looks weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What should we call them then?
Just calling them weird isn't very helpful.
Co-authored-by: Garth N. Wells <[email protected]>
I find this an unreasonable request. |
There are concerns on the design. It will be easier, and faster, to get the design right by building it up in steps, bottom up. |
My impression is that we should first tackle the comment made by @garth-wells https://github.com/FEniCS/dolfinx/pull/3648/files#r1973997836 in a separate PR. This can then be refactored to use #3659 which should remove many of the if statements regarding assigning functions to vectors and vice-versa. We can then think about if there are any smart ways to deal with Mat and Vec types in the SNES solver setup. |
A "functional" approach to the snes problem interface.
This reduced the code to:
create_snes_solver
, that returns the the user aSNESObject
and a vector to solve intox
dolfinx.fem.Function|list[dolfinx.fem.Function
(u
) to the PETSc vector used for solving (x
)The tests now show examples of:
SNESSolver
, the highest level interfacecreate_snes_solver
, the mid-level interfacedolfinx.nls.petsc
anddolfinx.fem.petsc
to interact with your own snes solver instance.