xref: /petsc/src/snes/interface/snesj2.c (revision 78e7fe0e06848ca8fe60c2c13067b329c49db3a6)
191627157SBarry Smith 
2af0996ceSBarry Smith #include <petsc/private/snesimpl.h> /*I  "petscsnes.h"  I*/
31e25c274SJed Brown #include <petscdm.h>                /*I  "petscdm.h"    I*/
491627157SBarry Smith 
562cd874fSBarry Smith /*
662cd874fSBarry Smith    MatFDColoringSetFunction() takes a function with four arguments, we want to use SNESComputeFunction()
762cd874fSBarry Smith    since it logs function computation information.
862cd874fSBarry Smith */
9d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESComputeFunctionCtx(SNES snes, Vec x, Vec f, void *ctx)
10d71ae5a4SJacob Faibussowitsch {
1162cd874fSBarry Smith   return SNESComputeFunction(snes, x, f);
1262cd874fSBarry Smith }
13d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESComputeMFFunctionCtx(SNES snes, Vec x, Vec f, void *ctx)
14d71ae5a4SJacob Faibussowitsch {
150df40c35SBarry Smith   return SNESComputeMFFunction(snes, x, f);
160df40c35SBarry Smith }
1762cd874fSBarry Smith 
1891627157SBarry Smith /*@C
198d359177SBarry Smith     SNESComputeJacobianDefaultColor - Computes the Jacobian using
20b4fc646aSLois Curfman McInnes     finite differences and coloring to exploit matrix sparsity.
2191627157SBarry Smith 
22f6dfbefdSBarry Smith     Collective on snes
23fee21e36SBarry Smith 
24c7afd0dbSLois Curfman McInnes     Input Parameters:
25c7afd0dbSLois Curfman McInnes +   snes - nonlinear solver object
26c7afd0dbSLois Curfman McInnes .   x1 - location at which to evaluate Jacobian
277fb41025SPeter Brune -   ctx - MatFDColoring context or NULL
28c7afd0dbSLois Curfman McInnes 
29c7afd0dbSLois Curfman McInnes     Output Parameters:
30c7afd0dbSLois Curfman McInnes +   J - Jacobian matrix (not altered in this routine)
3156744491SBarry Smith -   B - newly computed Jacobian matrix to use with preconditioner (generally the same as J)
32c7afd0dbSLois Curfman McInnes 
3336851e7fSLois Curfman McInnes     Level: intermediate
3436851e7fSLois Curfman McInnes 
35f6dfbefdSBarry Smith    Options Database Keys:
365620d6dcSBarry Smith +  -snes_fd_color_use_mat - use a matrix coloring from the explicit matrix nonzero pattern instead of from the DM providing the matrix
37f6dfbefdSBarry Smith .  -snes_fd_color - Activates `SNESComputeJacobianDefaultColor()` in `SNESSetFromOptions()`
385620d6dcSBarry Smith .  -mat_fd_coloring_err <err> - Sets <err> (square root of relative error in the function)
395620d6dcSBarry Smith .  -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude
40f6dfbefdSBarry Smith .  -mat_fd_type - Either wp or ds (see `MATMFFD_WP` or `MATMFFD_DS`)
41ec5066bdSBarry Smith .  -snes_mf_operator - Use matrix free application of Jacobian
42a5b23f4aSJose E. Roman -  -snes_mf - Use matrix free Jacobian with no explicit Jacobian representation
435620d6dcSBarry Smith 
4495452b02SPatrick Sanan     Notes:
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 
55f6dfbefdSBarry Smith .seealso: `SNES`, `SNESSetJacobian()`, `SNESTestJacobian()`, `SNESComputeJacobianDefault()`, `SNESSetUseMatrixFree()`,
56db781477SPatrick Sanan           `MatFDColoringCreate()`, `MatFDColoringSetFunction()`
5791627157SBarry Smith @*/
58d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESComputeJacobianDefaultColor(SNES snes, Vec x1, Mat J, Mat B, void *ctx)
59d71ae5a4SJacob Faibussowitsch {
607fb41025SPeter Brune   MatFDColoring color = (MatFDColoring)ctx;
614e269d77SPeter Brune   DM            dm;
62335efc43SPeter Brune   MatColoring   mc;
634e269d77SPeter Brune   ISColoring    iscoloring;
64b0ae01b7SPeter Brune   PetscBool     hascolor;
65aa2f1b4eSJed Brown   PetscBool     solvec, matcolor = PETSC_FALSE;
660df40c35SBarry Smith   DMSNES        dms;
67dff777c9SBarry Smith 
683a40ed3dSBarry Smith   PetscFunctionBegin;
69064a246eSJacob Faibussowitsch   if (color) PetscValidHeaderSpecific(color, MAT_FDCOLORING_CLASSID, 5);
709566063dSJacob Faibussowitsch   if (!color) PetscCall(PetscObjectQuery((PetscObject)B, "SNESMatFDColoring", (PetscObject *)&color));
7162cd874fSBarry Smith 
724e269d77SPeter Brune   if (!color) {
739566063dSJacob Faibussowitsch     PetscCall(SNESGetDM(snes, &dm));
749566063dSJacob Faibussowitsch     PetscCall(DMHasColoring(dm, &hascolor));
75924833adSPeter Brune     matcolor = PETSC_FALSE;
769566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_fd_color_use_mat", &matcolor, NULL));
77c3138ed3SPeter Brune     if (hascolor && !matcolor) {
789566063dSJacob Faibussowitsch       PetscCall(DMCreateColoring(dm, IS_COLORING_GLOBAL, &iscoloring));
79b0ae01b7SPeter Brune     } else {
809566063dSJacob Faibussowitsch       PetscCall(MatColoringCreate(B, &mc));
819566063dSJacob Faibussowitsch       PetscCall(MatColoringSetDistance(mc, 2));
829566063dSJacob Faibussowitsch       PetscCall(MatColoringSetType(mc, MATCOLORINGSL));
839566063dSJacob Faibussowitsch       PetscCall(MatColoringSetFromOptions(mc));
849566063dSJacob Faibussowitsch       PetscCall(MatColoringApply(mc, &iscoloring));
859566063dSJacob Faibussowitsch       PetscCall(MatColoringDestroy(&mc));
860df40c35SBarry Smith     }
879566063dSJacob Faibussowitsch     PetscCall(MatFDColoringCreate(B, iscoloring, &color));
889566063dSJacob Faibussowitsch     PetscCall(DMGetDMSNES(dm, &dms));
890df40c35SBarry Smith     if (dms->ops->computemffunction) {
909566063dSJacob Faibussowitsch       PetscCall(MatFDColoringSetFunction(color, (PetscErrorCode(*)(void))SNESComputeMFFunctionCtx, NULL));
910df40c35SBarry Smith     } else {
929566063dSJacob Faibussowitsch       PetscCall(MatFDColoringSetFunction(color, (PetscErrorCode(*)(void))SNESComputeFunctionCtx, NULL));
930df40c35SBarry Smith     }
949566063dSJacob Faibussowitsch     PetscCall(MatFDColoringSetFromOptions(color));
959566063dSJacob Faibussowitsch     PetscCall(MatFDColoringSetUp(B, iscoloring, color));
969566063dSJacob Faibussowitsch     PetscCall(ISColoringDestroy(&iscoloring));
979566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)B, "SNESMatFDColoring", (PetscObject)color));
989566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)color));
994a9d489dSBarry Smith   }
10095862db2SPeter Brune 
101c89319d2SPeter Brune   /* F is only usable if there is no RHS on the SNES and the full solution corresponds to x1 */
1029566063dSJacob Faibussowitsch   PetscCall(VecEqual(x1, snes->vec_sol, &solvec));
103c89319d2SPeter Brune   if (!snes->vec_rhs && solvec) {
10462cd874fSBarry Smith     Vec F;
1059566063dSJacob Faibussowitsch     PetscCall(SNESGetFunction(snes, &F, NULL, NULL));
1069566063dSJacob Faibussowitsch     PetscCall(MatFDColoringSetF(color, F));
10795862db2SPeter Brune   }
1089566063dSJacob Faibussowitsch   PetscCall(MatFDColoringApply(B, color, x1, snes));
10994ab13aaSBarry Smith   if (J != B) {
1109566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
1119566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
112194405b3SBarry Smith   }
1133a40ed3dSBarry Smith   PetscFunctionReturn(0);
11491627157SBarry Smith }
115*78e7fe0eSHong Zhang 
116*78e7fe0eSHong Zhang /*@C
117*78e7fe0eSHong Zhang   SNESPruneJacobianColor - Remove nondiagonal zeros in the Jacobian matrix and update the MFFD coloring.
118*78e7fe0eSHong Zhang 
119*78e7fe0eSHong Zhang   Collective on SNES
120*78e7fe0eSHong Zhang 
121*78e7fe0eSHong Zhang   Input Parameters:
122*78e7fe0eSHong Zhang + snes - the SNES context
123*78e7fe0eSHong Zhang . J - Jacobian matrix (not altered in this routine)
124*78e7fe0eSHong Zhang - B - newly computed Jacobian matrix to use with preconditioner (generally the same as J)
125*78e7fe0eSHong Zhang 
126*78e7fe0eSHong Zhang   Level: intermediate
127*78e7fe0eSHong Zhang 
128*78e7fe0eSHong Zhang   Notes:
129*78e7fe0eSHong Zhang   This function improves the MFFD coloring when the Jacobian matrix is overallocated or contains
130*78e7fe0eSHong Zhang   many constant zeros entries, which is typically the case when the matrix is generated by a DM
131*78e7fe0eSHong Zhang   and multiple fields are involved.
132*78e7fe0eSHong Zhang 
133*78e7fe0eSHong Zhang   Users need to make sure that the Jacobian matrix is properly filled to reflect the sparsity
134*78e7fe0eSHong Zhang   structure. For MFFD coloring, the values of nonzero entries are not important. So one can
135*78e7fe0eSHong Zhang   usually call SNESComputeJacobian() with randomized input vectors to generate a dummy Jacobian.
136*78e7fe0eSHong Zhang   SNESComputeJacobian() should be called before SNESSolve() but after SNESSetUp().
137*78e7fe0eSHong Zhang 
138*78e7fe0eSHong Zhang .seealso: `SNESComputeJacobianDefaultColor()`, `MatEliminateZeros()`, `MatFDColoringCreate()`, `MatFDColoringSetFunction()`
139*78e7fe0eSHong Zhang @*/
140*78e7fe0eSHong Zhang PetscErrorCode SNESPruneJacobianColor(SNES snes, Mat J, Mat B)
141*78e7fe0eSHong Zhang {
142*78e7fe0eSHong Zhang   DM            dm;
143*78e7fe0eSHong Zhang   DMSNES        dms;
144*78e7fe0eSHong Zhang   MatColoring   mc;
145*78e7fe0eSHong Zhang   ISColoring    iscoloring;
146*78e7fe0eSHong Zhang   MatFDColoring matfdcoloring;
147*78e7fe0eSHong Zhang 
148*78e7fe0eSHong Zhang   PetscFunctionBegin;
149*78e7fe0eSHong Zhang   /* Generate new coloring after eliminating zeros in the matrix */
150*78e7fe0eSHong Zhang   PetscCall(MatEliminateZeros(B));
151*78e7fe0eSHong Zhang   PetscCall(MatColoringCreate(B, &mc));
152*78e7fe0eSHong Zhang   PetscCall(MatColoringSetDistance(mc, 2));
153*78e7fe0eSHong Zhang   PetscCall(MatColoringSetType(mc, MATCOLORINGSL));
154*78e7fe0eSHong Zhang   PetscCall(MatColoringSetFromOptions(mc));
155*78e7fe0eSHong Zhang   PetscCall(MatColoringApply(mc, &iscoloring));
156*78e7fe0eSHong Zhang   PetscCall(MatColoringDestroy(&mc));
157*78e7fe0eSHong Zhang   /* Replace the old coloring with the new one */
158*78e7fe0eSHong Zhang   PetscCall(MatFDColoringCreate(B, iscoloring, &matfdcoloring));
159*78e7fe0eSHong Zhang   PetscCall(SNESGetDM(snes, &dm));
160*78e7fe0eSHong Zhang   PetscCall(DMGetDMSNES(dm, &dms));
161*78e7fe0eSHong Zhang   // Comment out the following branch to bypass the coverage test. You can uncomment it when needed.
162*78e7fe0eSHong Zhang   //if (dms->ops->computemffunction) {
163*78e7fe0eSHong Zhang   //  PetscCall(MatFDColoringSetFunction(matfdcoloring, (PetscErrorCode(*)(void))SNESComputeMFFunctionCtx, NULL));
164*78e7fe0eSHong Zhang   //} else {
165*78e7fe0eSHong Zhang   PetscCall(MatFDColoringSetFunction(matfdcoloring, (PetscErrorCode(*)(void))SNESComputeFunctionCtx, NULL));
166*78e7fe0eSHong Zhang   //}
167*78e7fe0eSHong Zhang   PetscCall(MatFDColoringSetFromOptions(matfdcoloring));
168*78e7fe0eSHong Zhang   PetscCall(MatFDColoringSetUp(B, iscoloring, matfdcoloring));
169*78e7fe0eSHong Zhang   PetscCall(PetscObjectCompose((PetscObject)B, "SNESMatFDColoring", (PetscObject)matfdcoloring));
170*78e7fe0eSHong Zhang   PetscCall(PetscObjectDereference((PetscObject)matfdcoloring));
171*78e7fe0eSHong Zhang   PetscCall(ISColoringDestroy(&iscoloring));
172*78e7fe0eSHong Zhang   PetscFunctionReturn(0);
173*78e7fe0eSHong Zhang }
174