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