xref: /petsc/src/snes/interface/snesj2.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
1af0996ceSBarry Smith #include <petsc/private/snesimpl.h> /*I  "petscsnes.h"  I*/
21e25c274SJed Brown #include <petscdm.h>                /*I  "petscdm.h"    I*/
391627157SBarry Smith 
462cd874fSBarry Smith /*
562cd874fSBarry Smith    MatFDColoringSetFunction() takes a function with four arguments, we want to use SNESComputeFunction()
662cd874fSBarry Smith    since it logs function computation information.
762cd874fSBarry Smith */
SNESComputeFunctionCtx(void * snes,Vec x,Vec f,PetscCtx ctx)8*2a8381b2SBarry Smith static PetscErrorCode SNESComputeFunctionCtx(void *snes, Vec x, Vec f, PetscCtx ctx)
9d71ae5a4SJacob Faibussowitsch {
10810441c8SPierre Jolivet   return SNESComputeFunction((SNES)snes, x, f);
1162cd874fSBarry Smith }
SNESComputeMFFunctionCtx(void * snes,Vec x,Vec f,PetscCtx ctx)12*2a8381b2SBarry Smith static PetscErrorCode SNESComputeMFFunctionCtx(void *snes, Vec x, Vec f, PetscCtx ctx)
13d71ae5a4SJacob Faibussowitsch {
14810441c8SPierre Jolivet   return SNESComputeMFFunction((SNES)snes, x, f);
150df40c35SBarry Smith }
1662cd874fSBarry Smith 
175d83a8b1SBarry Smith /*@
188d359177SBarry Smith   SNESComputeJacobianDefaultColor - Computes the Jacobian using
19b4fc646aSLois Curfman McInnes   finite differences and coloring to exploit matrix sparsity.
2091627157SBarry Smith 
21c3339decSBarry Smith   Collective
22fee21e36SBarry Smith 
23c7afd0dbSLois Curfman McInnes   Input Parameters:
24c7afd0dbSLois Curfman McInnes + snes - nonlinear solver object
25c7afd0dbSLois Curfman McInnes . x1   - location at which to evaluate Jacobian
26dc4c0fb0SBarry Smith - ctx  - `MatFDColoring` context or `NULL`
27c7afd0dbSLois Curfman McInnes 
28c7afd0dbSLois Curfman McInnes   Output Parameters:
29c7afd0dbSLois Curfman McInnes + J - Jacobian matrix (not altered in this routine)
30dc4c0fb0SBarry Smith - B - newly computed Jacobian matrix to use with preconditioner (generally the same as `J`)
31c7afd0dbSLois Curfman McInnes 
32f6dfbefdSBarry Smith   Options Database Keys:
33dc4c0fb0SBarry Smith + -snes_fd_color_use_mat       - use a matrix coloring from the explicit matrix nonzero pattern instead of from the `DM` providing the matrix
34f6dfbefdSBarry Smith . -snes_fd_color               - Activates `SNESComputeJacobianDefaultColor()` in `SNESSetFromOptions()`
355620d6dcSBarry Smith . -mat_fd_coloring_err <err>   - Sets <err> (square root of relative error in the function)
365620d6dcSBarry Smith . -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude
37f6dfbefdSBarry Smith . -mat_fd_type                 - Either wp or ds (see `MATMFFD_WP` or `MATMFFD_DS`)
3801c1178eSBarry Smith . -snes_mf_operator            - Use matrix-free application of Jacobian
3901c1178eSBarry Smith - -snes_mf                     - Use matrix-free Jacobian with no explicit Jacobian representation
405620d6dcSBarry Smith 
4195452b02SPatrick Sanan   Notes:
42420bcc1bSBarry Smith 
43420bcc1bSBarry Smith   Level: intermediate
44420bcc1bSBarry Smith 
4595452b02SPatrick Sanan   If the coloring is not provided through the context, this will first try to get the
46f6dfbefdSBarry Smith   coloring from the `DM`.  If the `DM` has no coloring routine, then it will try to
47f6dfbefdSBarry Smith   get the coloring from the matrix.  This requires that the matrix have its nonzero locations already provided.
48b0ae01b7SPeter Brune 
49f6dfbefdSBarry Smith   `SNES` supports three approaches for computing (approximate) Jacobians: user provided via `SNESSetJacobian()`, matrix-free via `SNESSetUseMatrixFree()`,
50f6dfbefdSBarry Smith   and computing explicitly with finite differences and coloring using `MatFDColoring`. It is also possible to use automatic differentiation
51f6dfbefdSBarry Smith   and the `MatFDColoring` object, see src/ts/tutorials/autodiff/ex16adj_tl.cxx
52ec5066bdSBarry Smith 
53f6dfbefdSBarry Smith   This function can be provided to `SNESSetJacobian()` along with an appropriate sparse matrix to hold the Jacobian
54f6dfbefdSBarry Smith 
55420bcc1bSBarry Smith   Developer Note:
56420bcc1bSBarry Smith   The function has a poorly chosen name since it does not mention the use of finite differences
57420bcc1bSBarry Smith 
58420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESSetJacobian()`, `SNESTestJacobian()`, `SNESComputeJacobianDefault()`, `SNESSetUseMatrixFree()`,
59db781477SPatrick Sanan           `MatFDColoringCreate()`, `MatFDColoringSetFunction()`
6091627157SBarry Smith @*/
SNESComputeJacobianDefaultColor(SNES snes,Vec x1,Mat J,Mat B,PetscCtx ctx)61*2a8381b2SBarry Smith PetscErrorCode SNESComputeJacobianDefaultColor(SNES snes, Vec x1, Mat J, Mat B, PetscCtx ctx)
62d71ae5a4SJacob Faibussowitsch {
637fb41025SPeter Brune   MatFDColoring color = (MatFDColoring)ctx;
644e269d77SPeter Brune   DM            dm;
65335efc43SPeter Brune   MatColoring   mc;
664e269d77SPeter Brune   ISColoring    iscoloring;
67b0ae01b7SPeter Brune   PetscBool     hascolor;
68aa2f1b4eSJed Brown   PetscBool     solvec, matcolor = PETSC_FALSE;
690df40c35SBarry Smith   DMSNES        dms;
70dff777c9SBarry Smith 
713a40ed3dSBarry Smith   PetscFunctionBegin;
72064a246eSJacob Faibussowitsch   if (color) PetscValidHeaderSpecific(color, MAT_FDCOLORING_CLASSID, 5);
739566063dSJacob Faibussowitsch   if (!color) PetscCall(PetscObjectQuery((PetscObject)B, "SNESMatFDColoring", (PetscObject *)&color));
7462cd874fSBarry Smith 
754e269d77SPeter Brune   if (!color) {
769566063dSJacob Faibussowitsch     PetscCall(SNESGetDM(snes, &dm));
779566063dSJacob Faibussowitsch     PetscCall(DMHasColoring(dm, &hascolor));
78924833adSPeter Brune     matcolor = PETSC_FALSE;
799566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_fd_color_use_mat", &matcolor, NULL));
80c3138ed3SPeter Brune     if (hascolor && !matcolor) {
819566063dSJacob Faibussowitsch       PetscCall(DMCreateColoring(dm, IS_COLORING_GLOBAL, &iscoloring));
82b0ae01b7SPeter Brune     } else {
839566063dSJacob Faibussowitsch       PetscCall(MatColoringCreate(B, &mc));
849566063dSJacob Faibussowitsch       PetscCall(MatColoringSetDistance(mc, 2));
859566063dSJacob Faibussowitsch       PetscCall(MatColoringSetType(mc, MATCOLORINGSL));
869566063dSJacob Faibussowitsch       PetscCall(MatColoringSetFromOptions(mc));
879566063dSJacob Faibussowitsch       PetscCall(MatColoringApply(mc, &iscoloring));
889566063dSJacob Faibussowitsch       PetscCall(MatColoringDestroy(&mc));
890df40c35SBarry Smith     }
909566063dSJacob Faibussowitsch     PetscCall(MatFDColoringCreate(B, iscoloring, &color));
919566063dSJacob Faibussowitsch     PetscCall(DMGetDMSNES(dm, &dms));
920df40c35SBarry Smith     if (dms->ops->computemffunction) {
932ba42892SBarry Smith       PetscCall(MatFDColoringSetFunction(color, (MatFDColoringFn *)SNESComputeMFFunctionCtx, NULL));
940df40c35SBarry Smith     } else {
952ba42892SBarry Smith       PetscCall(MatFDColoringSetFunction(color, (MatFDColoringFn *)SNESComputeFunctionCtx, NULL));
960df40c35SBarry Smith     }
979566063dSJacob Faibussowitsch     PetscCall(MatFDColoringSetFromOptions(color));
989566063dSJacob Faibussowitsch     PetscCall(MatFDColoringSetUp(B, iscoloring, color));
999566063dSJacob Faibussowitsch     PetscCall(ISColoringDestroy(&iscoloring));
1009566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)B, "SNESMatFDColoring", (PetscObject)color));
1019566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)color));
1024a9d489dSBarry Smith   }
10395862db2SPeter Brune 
104c89319d2SPeter Brune   /* F is only usable if there is no RHS on the SNES and the full solution corresponds to x1 */
1059566063dSJacob Faibussowitsch   PetscCall(VecEqual(x1, snes->vec_sol, &solvec));
106c89319d2SPeter Brune   if (!snes->vec_rhs && solvec) {
10762cd874fSBarry Smith     Vec F;
1089566063dSJacob Faibussowitsch     PetscCall(SNESGetFunction(snes, &F, NULL, NULL));
1099566063dSJacob Faibussowitsch     PetscCall(MatFDColoringSetF(color, F));
11095862db2SPeter Brune   }
1119566063dSJacob Faibussowitsch   PetscCall(MatFDColoringApply(B, color, x1, snes));
11294ab13aaSBarry Smith   if (J != B) {
1139566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
1149566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
115194405b3SBarry Smith   }
1163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11791627157SBarry Smith }
11878e7fe0eSHong Zhang 
1195d83a8b1SBarry Smith /*@
120420bcc1bSBarry Smith   SNESPruneJacobianColor - Remove nondiagonal zeros in the Jacobian matrix and update the `MatMFFD` coloring information based on the new nonzero structure
12178e7fe0eSHong Zhang 
122dc4c0fb0SBarry Smith   Collective
12378e7fe0eSHong Zhang 
12478e7fe0eSHong Zhang   Input Parameters:
125dc4c0fb0SBarry Smith + snes - the `SNES` context
12678e7fe0eSHong Zhang . J    - Jacobian matrix (not altered in this routine)
127dc4c0fb0SBarry Smith - B    - newly computed Jacobian matrix to use with preconditioner (generally the same as `J`)
12878e7fe0eSHong Zhang 
12978e7fe0eSHong Zhang   Level: intermediate
13078e7fe0eSHong Zhang 
13178e7fe0eSHong Zhang   Notes:
1327b2dc123SHong Zhang   This function improves the `MatMFFD` coloring performance when the Jacobian matrix is overallocated or contains
133dc4c0fb0SBarry Smith   many constant zeros entries, which is typically the case when the matrix is generated by a `DM`
13478e7fe0eSHong Zhang   and multiple fields are involved.
13578e7fe0eSHong Zhang 
13678e7fe0eSHong Zhang   Users need to make sure that the Jacobian matrix is properly filled to reflect the sparsity
1377b2dc123SHong Zhang   structure. For `MatMFFD` coloring, the values of nonzero entries are not important. So one can
1387b2dc123SHong Zhang   usually call `SNESComputeJacobian()` with randomized input vectors to generate a dummy Jacobian.
1397b2dc123SHong Zhang   `SNESComputeJacobian()` should be called before `SNESSolve()` but after `SNESSetUp()`.
14078e7fe0eSHong Zhang 
141420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESComputeJacobianDefaultColor()`, `MatEliminateZeros()`, `MatFDColoringCreate()`, `MatFDColoringSetFunction()`
14278e7fe0eSHong Zhang @*/
SNESPruneJacobianColor(SNES snes,Mat J,Mat B)14378e7fe0eSHong Zhang PetscErrorCode SNESPruneJacobianColor(SNES snes, Mat J, Mat B)
14478e7fe0eSHong Zhang {
14578e7fe0eSHong Zhang   DM            dm;
14678e7fe0eSHong Zhang   DMSNES        dms;
14778e7fe0eSHong Zhang   MatColoring   mc;
14878e7fe0eSHong Zhang   ISColoring    iscoloring;
14978e7fe0eSHong Zhang   MatFDColoring matfdcoloring;
15078e7fe0eSHong Zhang 
15178e7fe0eSHong Zhang   PetscFunctionBegin;
15278e7fe0eSHong Zhang   /* Generate new coloring after eliminating zeros in the matrix */
15358c11ad4SPierre Jolivet   PetscCall(MatEliminateZeros(B, PETSC_TRUE));
15478e7fe0eSHong Zhang   PetscCall(MatColoringCreate(B, &mc));
15578e7fe0eSHong Zhang   PetscCall(MatColoringSetDistance(mc, 2));
15678e7fe0eSHong Zhang   PetscCall(MatColoringSetType(mc, MATCOLORINGSL));
15778e7fe0eSHong Zhang   PetscCall(MatColoringSetFromOptions(mc));
15878e7fe0eSHong Zhang   PetscCall(MatColoringApply(mc, &iscoloring));
15978e7fe0eSHong Zhang   PetscCall(MatColoringDestroy(&mc));
16078e7fe0eSHong Zhang   /* Replace the old coloring with the new one */
16178e7fe0eSHong Zhang   PetscCall(MatFDColoringCreate(B, iscoloring, &matfdcoloring));
16278e7fe0eSHong Zhang   PetscCall(SNESGetDM(snes, &dm));
16378e7fe0eSHong Zhang   PetscCall(DMGetDMSNES(dm, &dms));
16478e7fe0eSHong Zhang   // Comment out the following branch to bypass the coverage test. You can uncomment it when needed.
16578e7fe0eSHong Zhang   //if (dms->ops->computemffunction) {
1662ba42892SBarry Smith   //  PetscCall(MatFDColoringSetFunction(matfdcoloring, (MatFDColoringFn *)SNESComputeMFFunctionCtx, NULL));
16778e7fe0eSHong Zhang   //} else {
1682ba42892SBarry Smith   PetscCall(MatFDColoringSetFunction(matfdcoloring, (MatFDColoringFn *)SNESComputeFunctionCtx, NULL));
16978e7fe0eSHong Zhang   //}
17078e7fe0eSHong Zhang   PetscCall(MatFDColoringSetFromOptions(matfdcoloring));
17178e7fe0eSHong Zhang   PetscCall(MatFDColoringSetUp(B, iscoloring, matfdcoloring));
17278e7fe0eSHong Zhang   PetscCall(PetscObjectCompose((PetscObject)B, "SNESMatFDColoring", (PetscObject)matfdcoloring));
17378e7fe0eSHong Zhang   PetscCall(PetscObjectDereference((PetscObject)matfdcoloring));
17478e7fe0eSHong Zhang   PetscCall(ISColoringDestroy(&iscoloring));
1753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17678e7fe0eSHong Zhang }
177