Actual source code: snesj.c
2: #include src/snes/snesimpl.h
6: /*@C
7: SNESDefaultComputeJacobian - Computes the Jacobian using finite differences.
9: Collective on SNES
11: Input Parameters:
12: + x1 - compute Jacobian at this point
13: - ctx - application's function context, as set with SNESSetFunction()
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
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)
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.
32: An alternative routine that uses coloring to explot matrix sparsity is
33: SNESDefaultComputeJacobianColor().
35: Level: intermediate
37: .keywords: SNES, finite differences, Jacobian
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;
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;
54: PetscOptionsGetReal(snes->prefix,"-snes_test_err",&epsilon,0);
55: eval_fct = SNESComputeFunction;
57: PetscObjectGetComm((PetscObject)x1,&comm);
58: MatAssembled(*B,&assembled);
59: if (assembled) {
60: MatZeroEntries(*B);
61: }
62: if (!snes->nvwork) {
63: VecDuplicateVecs(x1,3,&snes->vwork);
64: snes->nvwork = 3;
65: PetscLogObjectParents(snes,3,snes->vwork);
66: }
67: j1a = snes->vwork[0]; j2a = snes->vwork[1]; x2 = snes->vwork[2];
69: VecGetSize(x1,&N);
70: VecGetOwnershipRange(x1,&start,&end);
71: (*eval_fct)(snes,x1,j1a);
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: VecCopy(x1,x2);
79: if (i>= start && i<end) {
80: VecGetArray(x1,&xx);
81: dx = xx[i-start];
82: VecRestoreArray(x1,&xx);
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: VecSetValues(x2,1,&i,&dx,ADD_VALUES);
93: } else {
94: wscale = 0.0;
95: }
96: (*eval_fct)(snes,x2,j2a);
97: VecAXPY(&mone,j1a,j2a);
98: /* Communicate scale to all processors */
99: MPI_Allreduce(&wscale,&scale,1,MPIU_SCALAR,PetscSum_Op,comm);
100: VecScale(&scale,j2a);
101: VecNorm(j2a,NORM_INFINITY,&amax); amax *= 1.e-14;
102: VecGetArray(j2a,&y);
103: for (j=start; j<end; j++) {
104: if (PetscAbsScalar(y[j-start]) > amax) {
105: MatSetValues(*B,1,&j,1,&i,y+j-start,INSERT_VALUES);
106: }
107: }
108: VecRestoreArray(j2a,&y);
109: }
110: MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);
111: MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);
112: *flag = DIFFERENT_NONZERO_PATTERN;
113: return(0);
114: }