xref: /petsc/src/snes/interface/snesj.c (revision e6e75211d226c622f451867f53ce5d558649ff4f)
1 
2 #include <petsc/private/snesimpl.h>    /*I  "petscsnes.h"  I*/
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "SNESComputeJacobianDefault"
6 /*@C
7    SNESComputeJacobianDefault - 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 
19    Options Database Key:
20 +  -snes_fd - Activates SNESComputeJacobianDefault()
21 .  -snes_test_err - Square root of function error tolerance, default square root of machine
22                     epsilon (1.e-8 in double, 3.e-4 in single)
23 -  -mat_fd_type - Either wp or ds (see MATMFFD_WP or MATMFFD_DS)
24 
25    Notes:
26    This routine is slow and expensive, and is not currently optimized
27    to take advantage of sparsity in the problem.  Although
28    SNESComputeJacobianDefault() is not recommended for general use
29    in large-scale applications, It can be useful in checking the
30    correctness of a user-provided Jacobian.
31 
32    An alternative routine that uses coloring to exploit matrix sparsity is
33    SNESComputeJacobianDefaultColor().
34 
35    Level: intermediate
36 
37 .keywords: SNES, finite differences, Jacobian
38 
39 .seealso: SNESSetJacobian(), SNESComputeJacobianDefaultColor(), MatCreateSNESMF()
40 @*/
41 PetscErrorCode  SNESComputeJacobianDefault(SNES snes,Vec x1,Mat J,Mat B,void *ctx)
42 {
43   Vec               j1a,j2a,x2;
44   PetscErrorCode    ierr;
45   PetscInt          i,N,start,end,j,value,root;
46   PetscScalar       dx,*y,wscale;
47   const PetscScalar *xx;
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 = PetscOptionsBegin(PetscObjectComm((PetscObject)snes),((PetscObject)snes)->prefix,"Differencing options","SNES");CHKERRQ(ierr);
80   ierr = PetscOptionsEList("-mat_fd_type","Algorithm to compute difference parameter","SNESComputeJacobianDefault",list,2,"wp",&value,&flg);CHKERRQ(ierr);
81   ierr = PetscOptionsEnd();CHKERRQ(ierr);
82   if (flg && !value) use_wp = PETSC_FALSE;
83 
84   if (use_wp) {
85     ierr = VecNorm(x1,NORM_2,&unorm);CHKERRQ(ierr);
86   }
87   /* Compute Jacobian approximation, 1 column at a time.
88       x1 = current iterate, j1a = F(x1)
89       x2 = perturbed iterate, j2a = F(x2)
90    */
91   for (i=0; i<N; i++) {
92     ierr = VecCopy(x1,x2);CHKERRQ(ierr);
93     if (i>= start && i<end) {
94       ierr = VecGetArrayRead(x1,&xx);CHKERRQ(ierr);
95       if (use_wp) dx = PetscSqrtReal(1.0 + unorm);
96       else        dx = xx[i-start];
97       ierr = VecRestoreArrayRead(x1,&xx);CHKERRQ(ierr);
98       if (PetscAbsScalar(dx) < dx_min) dx = (PetscRealPart(dx) < 0. ? -1. : 1.) * dx_par;
99       dx    *= epsilon;
100       wscale = 1.0/dx;
101       ierr   = VecSetValues(x2,1,&i,&dx,ADD_VALUES);CHKERRQ(ierr);
102     } else {
103       wscale = 0.0;
104     }
105     ierr = VecAssemblyBegin(x2);CHKERRQ(ierr);
106     ierr = VecAssemblyEnd(x2);CHKERRQ(ierr);
107     ierr = (*eval_fct)(snes,x2,j2a);CHKERRQ(ierr);
108     ierr = VecAXPY(j2a,-1.0,j1a);CHKERRQ(ierr);
109     /* Communicate scale=1/dx_i to all processors */
110     ierr = VecGetOwnershipRanges(x1,&ranges);CHKERRQ(ierr);
111     root = size;
112     for (j=size-1; j>-1; j--) {
113       root--;
114       if (i>=ranges[j]) break;
115     }
116     ierr = MPI_Bcast(&wscale,1,MPIU_SCALAR,root,comm);CHKERRQ(ierr);
117 
118     ierr = VecScale(j2a,wscale);CHKERRQ(ierr);
119     ierr = VecNorm(j2a,NORM_INFINITY,&amax);CHKERRQ(ierr); amax *= 1.e-14;
120     ierr = VecGetArray(j2a,&y);CHKERRQ(ierr);
121     for (j=start; j<end; j++) {
122       if (PetscAbsScalar(y[j-start]) > amax || j == i) {
123         ierr = MatSetValues(B,1,&j,1,&i,y+j-start,INSERT_VALUES);CHKERRQ(ierr);
124       }
125     }
126     ierr = VecRestoreArray(j2a,&y);CHKERRQ(ierr);
127   }
128   ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
129   ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
130   if (B != J) {
131     ierr = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
132     ierr = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
133   }
134   PetscFunctionReturn(0);
135 }
136 
137 
138