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