Actual source code: snesj.c
petsc-3.3-p7 2013-05-11
2: #include <petsc-private/snesimpl.h> /*I "petscsnes.h" I*/
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)
24: - -mat_fd_type - Either wp or ds (see MATMFFD_WP or MATMFFD_DS)
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.
33: An alternative routine that uses coloring to exploit matrix sparsity is
34: SNESDefaultComputeJacobianColor().
36: Level: intermediate
38: .keywords: SNES, finite differences, Jacobian
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;
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;
58: PetscOptionsGetReal(((PetscObject)snes)->prefix,"-snes_test_err",&epsilon,0);
59: eval_fct = SNESComputeFunction;
61: PetscObjectGetComm((PetscObject)x1,&comm);
62: MPI_Comm_size(comm,&size);
63: MatAssembled(*B,&assembled);
64: if (assembled) {
65: MatZeroEntries(*B);
66: }
67: if (!snes->nvwork) {
68: snes->nvwork = 3;
69: VecDuplicateVecs(x1,snes->nvwork,&snes->vwork);
70: PetscLogObjectParents(snes,snes->nvwork,snes->vwork);
71: }
72: j1a = snes->vwork[0]; j2a = snes->vwork[1]; x2 = snes->vwork[2];
74: VecGetSize(x1,&N);
75: VecGetOwnershipRange(x1,&start,&end);
76: (*eval_fct)(snes,x1,j1a);
78: PetscOptionsEList("-mat_fd_type","Algorithm to compute difference parameter","SNESDefaultComputeJacobian",list,2,"wp",&value,&flg);
79: if (flg && !value) {
80: use_wp = PETSC_FALSE;
81: }
82: if (use_wp) {
83: VecNorm(x1,NORM_2,&unorm);
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: VecCopy(x1,x2);
91: if (i>= start && i<end) {
92: VecGetArray(x1,&xx);
93: if (use_wp) {
94: dx = 1.0 + unorm;
95: } else {
96: dx = xx[i-start];
97: }
98: VecRestoreArray(x1,&xx);
99: if (PetscAbsScalar(dx) < dx_min) dx = (PetscRealPart(dx) < 0. ? -1. : 1.) * dx_par;
100: dx *= epsilon;
101: wscale = 1.0/dx;
102: VecSetValues(x2,1,&i,&dx,ADD_VALUES);
103: } else {
104: wscale = 0.0;
105: }
106: VecAssemblyBegin(x2);
107: VecAssemblyEnd(x2);
108: (*eval_fct)(snes,x2,j2a);
109: VecAXPY(j2a,-1.0,j1a);
110: /* Communicate scale=1/dx_i to all processors */
111: VecGetOwnershipRanges(x1,&ranges);
112: root = size;
113: for (j=size-1; j>-1; j--){
114: root--;
115: if (i>=ranges[j]) break;
116: }
117: MPI_Bcast(&wscale,1,MPIU_SCALAR,root,comm);
119: VecScale(j2a,wscale);
120: VecNorm(j2a,NORM_INFINITY,&amax); amax *= 1.e-14;
121: VecGetArray(j2a,&y);
122: for (j=start; j<end; j++) {
123: if (PetscAbsScalar(y[j-start]) > amax || j == i) {
124: MatSetValues(*B,1,&j,1,&i,y+j-start,INSERT_VALUES);
125: }
126: }
127: VecRestoreArray(j2a,&y);
128: }
129: MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);
130: MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);
131: if (*B != *J) {
132: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
133: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
134: }
135: *flag = DIFFERENT_NONZERO_PATTERN;
136: return(0);
137: }