xref: /petsc/src/snes/interface/snesj2.c (revision 0df40c3555541438f50e9ac13eaa6989b426b66a)
1 
2 #include <petsc/private/snesimpl.h>    /*I  "petscsnes.h"  I*/
3 #include <petscdm.h>                   /*I  "petscdm.h"    I*/
4 
5 /*
6    MatFDColoringSetFunction() takes a function with four arguments, we want to use SNESComputeFunction()
7    since it logs function computation information.
8 */
9 static PetscErrorCode SNESComputeFunctionCtx(SNES snes,Vec x,Vec f,void *ctx)
10 {
11   return SNESComputeFunction(snes,x,f);
12 }
13 static PetscErrorCode SNESComputeMFFunctionCtx(SNES snes,Vec x,Vec f,void *ctx)
14 {
15   return SNESComputeMFFunction(snes,x,f);
16 }
17 
18 /*@C
19     SNESComputeJacobianDefaultColor - Computes the Jacobian using
20     finite differences and coloring to exploit matrix sparsity.
21 
22     Collective on SNES
23 
24     Input Parameters:
25 +   snes - nonlinear solver object
26 .   x1 - location at which to evaluate Jacobian
27 -   ctx - MatFDColoring context or NULL
28 
29     Output Parameters:
30 +   J - Jacobian matrix (not altered in this routine)
31 -   B - newly computed Jacobian matrix to use with preconditioner (generally the same as J)
32 
33     Level: intermediate
34 
35    Options Database Key:
36 +  -snes_fd_color_use_mat - use a matrix coloring from the explicit matrix nonzero pattern instead of from the DM providing the matrix
37 .  -snes_fd_color - Activates SNESComputeJacobianDefaultColor() in SNESSetFromOptions()
38 .  -mat_fd_coloring_err <err> - Sets <err> (square root of relative error in the function)
39 .  -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude
40 .  -mat_fd_type - Either wp or ds (see MATMFFD_WP or MATMFFD_DS)
41 .  -snes_mf_operator - Use matrix free application of Jacobian
42 -  -snes_mf - Use matrix free Jacobian with no explicit Jacobian represenation
43 
44     Notes:
45         If the coloring is not provided through the context, this will first try to get the
46         coloring from the DM.  If the DM type has no coloring routine, then it will try to
47         get the coloring from the matrix.  This requires that the matrix have nonzero entries
48         precomputed.
49 
50        SNES supports three approaches for computing (approximate) Jacobians: user provided via SNESSetJacobian(), matrix free via SNESSetUseMatrixFree(),
51        and computing explictly with finite differences and coloring using MatFDColoring. It is also possible to use automatic differentiation
52        and the MatFDColoring object, see src/ts/tutorials/autodiff/ex16adj_tl.cxx
53 
54 
55 .seealso: SNESSetJacobian(), SNESTestJacobian(), SNESComputeJacobianDefault(), SNESSetUseMatrixFree(),
56           MatFDColoringCreate(), MatFDColoringSetFunction()
57 
58 @*/
59 PetscErrorCode  SNESComputeJacobianDefaultColor(SNES snes,Vec x1,Mat J,Mat B,void *ctx)
60 {
61   MatFDColoring  color = (MatFDColoring)ctx;
62   PetscErrorCode ierr;
63   DM             dm;
64   MatColoring    mc;
65   ISColoring     iscoloring;
66   PetscBool      hascolor;
67   PetscBool      solvec,matcolor = PETSC_FALSE;
68   DMSNES         dms;
69 
70   PetscFunctionBegin;
71   if (color) PetscValidHeaderSpecific(color,MAT_FDCOLORING_CLASSID,6);
72   if (!color) {ierr  = PetscObjectQuery((PetscObject)B,"SNESMatFDColoring",(PetscObject*)&color);CHKERRQ(ierr);}
73 
74   if (!color) {
75     ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
76     ierr = DMHasColoring(dm,&hascolor);CHKERRQ(ierr);
77     matcolor = PETSC_FALSE;
78     ierr = PetscOptionsGetBool(((PetscObject)snes)->options,((PetscObject)snes)->prefix,"-snes_fd_color_use_mat",&matcolor,NULL);CHKERRQ(ierr);
79     if (hascolor && !matcolor) {
80       ierr = DMCreateColoring(dm,IS_COLORING_GLOBAL,&iscoloring);CHKERRQ(ierr);
81     } else {
82       ierr = MatColoringCreate(B,&mc);CHKERRQ(ierr);
83       ierr = MatColoringSetDistance(mc,2);CHKERRQ(ierr);
84       ierr = MatColoringSetType(mc,MATCOLORINGSL);CHKERRQ(ierr);
85       ierr = MatColoringSetFromOptions(mc);CHKERRQ(ierr);
86       ierr = MatColoringApply(mc,&iscoloring);CHKERRQ(ierr);
87       ierr = MatColoringDestroy(&mc);CHKERRQ(ierr);
88     }
89     ierr = MatFDColoringCreate(B,iscoloring,&color);CHKERRQ(ierr);
90     ierr = DMGetDMSNES(dm,&dms);CHKERRQ(ierr);
91     if (dms->ops->computemffunction) {
92       ierr = MatFDColoringSetFunction(color,(PetscErrorCode (*)(void))SNESComputeMFFunctionCtx,NULL);CHKERRQ(ierr);
93     } else {
94       ierr = MatFDColoringSetFunction(color,(PetscErrorCode (*)(void))SNESComputeFunctionCtx,NULL);CHKERRQ(ierr);
95     }
96     ierr = MatFDColoringSetFromOptions(color);CHKERRQ(ierr);
97     ierr = MatFDColoringSetUp(B,iscoloring,color);CHKERRQ(ierr);
98     ierr = ISColoringDestroy(&iscoloring);CHKERRQ(ierr);
99     ierr = PetscObjectCompose((PetscObject)B,"SNESMatFDColoring",(PetscObject)color);CHKERRQ(ierr);
100     ierr = PetscObjectDereference((PetscObject)color);CHKERRQ(ierr);
101   }
102 
103   /* F is only usable if there is no RHS on the SNES and the full solution corresponds to x1 */
104   ierr = VecEqual(x1,snes->vec_sol,&solvec);CHKERRQ(ierr);
105   if (!snes->vec_rhs && solvec) {
106     Vec F;
107     ierr = SNESGetFunction(snes,&F,NULL,NULL);CHKERRQ(ierr);
108     ierr = MatFDColoringSetF(color,F);CHKERRQ(ierr);
109   }
110   ierr = MatFDColoringApply(B,color,x1,snes);CHKERRQ(ierr);
111   if (J != B) {
112     ierr = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
113     ierr = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
114   }
115   PetscFunctionReturn(0);
116 }
117