xref: /petsc/src/snes/interface/snesj.c (revision 047240e14af00aad1ef65e96f6fface8924f7f7e)
1 
2 #include <petsc-private/snesimpl.h>    /*I  "petscsnes.h"  I*/
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "SNESDefaultComputeJacobian"
6 /*@C
7    SNESDefaultComputeJacobian - Computes the Jacobian using finite differences.
8 
9    Collective on SNES
10 
11    Input Parameters:
12 +  x1 - compute Jacobian at this point
13 -  ctx - application's function context, as set with SNESSetFunction()
14 
15    Output Parameters:
16 +  J - Jacobian matrix (not altered in this routine)
17 .  B - newly computed Jacobian matrix to use with preconditioner (generally the same as J)
18 -  flag - flag indicating whether the matrix sparsity structure has changed
19 
20    Options Database Key:
21 +  -snes_fd - Activates SNESDefaultComputeJacobian()
22 .  -snes_test_err - Square root of function error tolerance, default square root of machine
23                     epsilon (1.e-8 in double, 3.e-4 in single)
24 -  -mat_fd_type - Either wp or ds (see MATMFFD_WP or MATMFFD_DS)
25 
26    Notes:
27    This routine is slow and expensive, and is not currently optimized
28    to take advantage of sparsity in the problem.  Although
29    SNESDefaultComputeJacobian() is not recommended for general use
30    in large-scale applications, It can be useful in checking the
31    correctness of a user-provided Jacobian.
32 
33    An alternative routine that uses coloring to exploit matrix sparsity is
34    SNESDefaultComputeJacobianColor().
35 
36    Level: intermediate
37 
38 .keywords: SNES, finite differences, Jacobian
39 
40 .seealso: SNESSetJacobian(), SNESDefaultComputeJacobianColor(), MatCreateSNESMF()
41 @*/
42 PetscErrorCode  SNESDefaultComputeJacobian(SNES snes,Vec x1,Mat *J,Mat *B,MatStructure *flag,void *ctx)
43 {
44   Vec            j1a,j2a,x2;
45   PetscErrorCode ierr;
46   PetscInt       i,N,start,end,j,value,root;
47   PetscScalar    dx,*y,*xx,wscale;
48   PetscReal      amax,epsilon = PETSC_SQRT_MACHINE_EPSILON;
49   PetscReal      dx_min = 1.e-16,dx_par = 1.e-1,unorm;
50   MPI_Comm       comm;
51   PetscErrorCode (*eval_fct)(SNES,Vec,Vec)=0;
52   PetscBool      assembled,use_wp = PETSC_TRUE,flg;
53   const char     *list[2] = {"ds","wp"};
54   PetscMPIInt    size;
55   const PetscInt *ranges;
56 
57   PetscFunctionBegin;
58   ierr     = PetscOptionsGetReal(((PetscObject)snes)->prefix,"-snes_test_err",&epsilon,0);CHKERRQ(ierr);
59   eval_fct = SNESComputeFunction;
60 
61   ierr = PetscObjectGetComm((PetscObject)x1,&comm);CHKERRQ(ierr);
62   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
63   ierr = MatAssembled(*B,&assembled);CHKERRQ(ierr);
64   if (assembled) {
65     ierr = MatZeroEntries(*B);CHKERRQ(ierr);
66   }
67   if (!snes->nvwork) {
68     snes->nvwork = 3;
69 
70     ierr = VecDuplicateVecs(x1,snes->nvwork,&snes->vwork);CHKERRQ(ierr);
71     ierr = PetscLogObjectParents(snes,snes->nvwork,snes->vwork);CHKERRQ(ierr);
72   }
73   j1a = snes->vwork[0]; j2a = snes->vwork[1]; x2 = snes->vwork[2];
74 
75   ierr = VecGetSize(x1,&N);CHKERRQ(ierr);
76   ierr = VecGetOwnershipRange(x1,&start,&end);CHKERRQ(ierr);
77   ierr = (*eval_fct)(snes,x1,j1a);CHKERRQ(ierr);
78 
79   ierr = PetscOptionsEList("-mat_fd_type","Algorithm to compute difference parameter","SNESDefaultComputeJacobian",list,2,"wp",&value,&flg);CHKERRQ(ierr);
80   if (flg && !value) use_wp = PETSC_FALSE;
81 
82   if (use_wp) {
83     ierr = VecNorm(x1,NORM_2,&unorm);CHKERRQ(ierr);
84   }
85   /* Compute Jacobian approximation, 1 column at a time.
86       x1 = current iterate, j1a = F(x1)
87       x2 = perturbed iterate, j2a = F(x2)
88    */
89   for (i=0; i<N; i++) {
90     ierr = VecCopy(x1,x2);CHKERRQ(ierr);
91     if (i>= start && i<end) {
92       ierr = VecGetArray(x1,&xx);CHKERRQ(ierr);
93       if (use_wp) dx = 1.0 + unorm;
94       else        dx = xx[i-start];
95       ierr = VecRestoreArray(x1,&xx);CHKERRQ(ierr);
96       if (PetscAbsScalar(dx) < dx_min) dx = (PetscRealPart(dx) < 0. ? -1. : 1.) * dx_par;
97       dx    *= epsilon;
98       wscale = 1.0/dx;
99       ierr   = VecSetValues(x2,1,&i,&dx,ADD_VALUES);CHKERRQ(ierr);
100     } else {
101       wscale = 0.0;
102     }
103     ierr = VecAssemblyBegin(x2);CHKERRQ(ierr);
104     ierr = VecAssemblyEnd(x2);CHKERRQ(ierr);
105     ierr = (*eval_fct)(snes,x2,j2a);CHKERRQ(ierr);
106     ierr = VecAXPY(j2a,-1.0,j1a);CHKERRQ(ierr);
107     /* Communicate scale=1/dx_i to all processors */
108     ierr = VecGetOwnershipRanges(x1,&ranges);CHKERRQ(ierr);
109     root = size;
110     for (j=size-1; j>-1; j--) {
111       root--;
112       if (i>=ranges[j]) break;
113     }
114     ierr = MPI_Bcast(&wscale,1,MPIU_SCALAR,root,comm);CHKERRQ(ierr);
115 
116     ierr = VecScale(j2a,wscale);CHKERRQ(ierr);
117     ierr = VecNorm(j2a,NORM_INFINITY,&amax);CHKERRQ(ierr); amax *= 1.e-14;
118     ierr = VecGetArray(j2a,&y);CHKERRQ(ierr);
119     for (j=start; j<end; j++) {
120       if (PetscAbsScalar(y[j-start]) > amax || j == i) {
121         ierr = MatSetValues(*B,1,&j,1,&i,y+j-start,INSERT_VALUES);CHKERRQ(ierr);
122       }
123     }
124     ierr = VecRestoreArray(j2a,&y);CHKERRQ(ierr);
125   }
126   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
127   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
128   if (*B != *J) {
129     ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
130     ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
131   }
132   *flag =  DIFFERENT_NONZERO_PATTERN;
133   PetscFunctionReturn(0);
134 }
135 
136 
137