xref: /petsc/src/snes/interface/snesj.c (revision be1d678a52e6eff2808b2fa31ae986cdbf03c9fe)
1 
2 #include "src/snes/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 
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    SNESDefaultComputeJacobian() 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 explot matrix sparsity is
33    SNESDefaultComputeJacobianColor().
34 
35    Level: intermediate
36 
37 .keywords: SNES, finite differences, Jacobian
38 
39 .seealso: SNESSetJacobian(), SNESDefaultComputeJacobianColor()
40 @*/
41 PetscErrorCode SNESDefaultComputeJacobian(SNES snes,Vec x1,Mat *J,Mat *B,MatStructure *flag,void *ctx)
42 {
43   Vec            j1a,j2a,x2;
44   PetscErrorCode ierr;
45   PetscInt       i,N,start,end,j;
46   PetscScalar    dx,mone = -1.0,*y,scale,*xx,wscale;
47   PetscReal      amax,epsilon = PETSC_SQRT_MACHINE_EPSILON;
48   PetscReal      dx_min = 1.e-16,dx_par = 1.e-1;
49   MPI_Comm       comm;
50   PetscErrorCode (*eval_fct)(SNES,Vec,Vec)=0;
51   PetscTruth     assembled;
52 
53   PetscFunctionBegin;
54   ierr = PetscOptionsGetReal(snes->prefix,"-snes_test_err",&epsilon,0);CHKERRQ(ierr);
55   eval_fct = SNESComputeFunction;
56 
57   ierr = PetscObjectGetComm((PetscObject)x1,&comm);CHKERRQ(ierr);
58   ierr = MatAssembled(*B,&assembled);CHKERRQ(ierr);
59   if (assembled) {
60     ierr = MatZeroEntries(*B);CHKERRQ(ierr);
61   }
62   if (!snes->nvwork) {
63     ierr = VecDuplicateVecs(x1,3,&snes->vwork);CHKERRQ(ierr);
64     snes->nvwork = 3;
65     ierr = PetscLogObjectParents(snes,3,snes->vwork);CHKERRQ(ierr);
66   }
67   j1a = snes->vwork[0]; j2a = snes->vwork[1]; x2 = snes->vwork[2];
68 
69   ierr = VecGetSize(x1,&N);CHKERRQ(ierr);
70   ierr = VecGetOwnershipRange(x1,&start,&end);CHKERRQ(ierr);
71   ierr = (*eval_fct)(snes,x1,j1a);CHKERRQ(ierr);
72 
73   /* Compute Jacobian approximation, 1 column at a time.
74       x1 = current iterate, j1a = F(x1)
75       x2 = perturbed iterate, j2a = F(x2)
76    */
77   for (i=0; i<N; i++) {
78     ierr = VecCopy(x1,x2);CHKERRQ(ierr);
79     if (i>= start && i<end) {
80       ierr = VecGetArray(x1,&xx);CHKERRQ(ierr);
81       dx = xx[i-start];
82       ierr = VecRestoreArray(x1,&xx);CHKERRQ(ierr);
83 #if !defined(PETSC_USE_COMPLEX)
84       if (dx < dx_min && dx >= 0.0) dx = dx_par;
85       else if (dx < 0.0 && dx > -dx_min) dx = -dx_par;
86 #else
87       if (PetscAbsScalar(dx) < dx_min && PetscRealPart(dx) >= 0.0) dx = dx_par;
88       else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < dx_min) dx = -dx_par;
89 #endif
90       dx *= epsilon;
91       wscale = 1.0/dx;
92       ierr = VecSetValues(x2,1,&i,&dx,ADD_VALUES);CHKERRQ(ierr);
93     } else {
94       wscale = 0.0;
95     }
96     ierr = (*eval_fct)(snes,x2,j2a);CHKERRQ(ierr);
97     ierr = VecAXPY(&mone,j1a,j2a);CHKERRQ(ierr);
98     /* Communicate scale to all processors */
99     ierr = MPI_Allreduce(&wscale,&scale,1,MPIU_SCALAR,PetscSum_Op,comm);CHKERRQ(ierr);
100     ierr = VecScale(&scale,j2a);CHKERRQ(ierr);
101     ierr = VecNorm(j2a,NORM_INFINITY,&amax);CHKERRQ(ierr); amax *= 1.e-14;
102     ierr = VecGetArray(j2a,&y);CHKERRQ(ierr);
103     for (j=start; j<end; j++) {
104       if (PetscAbsScalar(y[j-start]) > amax) {
105         ierr = MatSetValues(*B,1,&j,1,&i,y+j-start,INSERT_VALUES);CHKERRQ(ierr);
106       }
107     }
108     ierr = VecRestoreArray(j2a,&y);CHKERRQ(ierr);
109   }
110   ierr  = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
111   ierr  = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
112   *flag =  DIFFERENT_NONZERO_PATTERN;
113   PetscFunctionReturn(0);
114 }
115 
116 
117