Actual source code: snesj.c
2: #include <petsc/private/snesimpl.h>
3: #include <petscdm.h>
5: /*@C
6: SNESComputeJacobianDefault - Computes the Jacobian using finite differences.
8: Collective on SNES
10: Input Parameters:
11: + snes - the SNES context
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)
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)
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.
32: An alternative routine that uses coloring to exploit matrix sparsity is
33: SNESComputeJacobianDefaultColor().
35: This routine ignores the maximum number of function evaluations set with SNESSetTolerances() and the function
36: evaluations it performs are not counted in what is returned by of SNESGetNumberFunctionEvals().
38: Level: intermediate
40: .seealso: SNESSetJacobian(), SNESComputeJacobianDefaultColor(), MatCreateSNESMF()
41: @*/
42: PetscErrorCode SNESComputeJacobianDefault(SNES snes,Vec x1,Mat J,Mat B,void *ctx)
43: {
44: Vec j1a,j2a,x2;
45: PetscErrorCode ierr;
46: PetscInt i,N,start,end,j,value,root,max_funcs = snes->max_funcs;
47: PetscScalar dx,*y,wscale;
48: const PetscScalar *xx;
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: PetscBool assembled,use_wp = PETSC_TRUE,flg;
53: const char *list[2] = {"ds","wp"};
54: PetscMPIInt size;
55: const PetscInt *ranges;
56: DM dm;
57: DMSNES dms;
59: snes->max_funcs = PETSC_MAX_INT;
60: /* Since this Jacobian will possibly have "extra" nonzero locations just turn off errors for these locations */
61: MatSetOption(B,MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);
62: PetscOptionsGetReal(((PetscObject)snes)->options,((PetscObject)snes)->prefix,"-snes_test_err",&epsilon,NULL);
64: PetscObjectGetComm((PetscObject)x1,&comm);
65: MPI_Comm_size(comm,&size);
66: MatAssembled(B,&assembled);
67: if (assembled) {
68: MatZeroEntries(B);
69: }
70: if (!snes->nvwork) {
71: if (snes->dm) {
72: DMGetGlobalVector(snes->dm,&j1a);
73: DMGetGlobalVector(snes->dm,&j2a);
74: DMGetGlobalVector(snes->dm,&x2);
75: } else {
76: snes->nvwork = 3;
77: VecDuplicateVecs(x1,snes->nvwork,&snes->vwork);
78: PetscLogObjectParents(snes,snes->nvwork,snes->vwork);
79: j1a = snes->vwork[0]; j2a = snes->vwork[1]; x2 = snes->vwork[2];
80: }
81: }
83: VecGetSize(x1,&N);
84: VecGetOwnershipRange(x1,&start,&end);
85: SNESGetDM(snes,&dm);
86: DMGetDMSNES(dm,&dms);
87: if (dms->ops->computemffunction) {
88: SNESComputeMFFunction(snes,x1,j1a);
89: } else {
90: SNESComputeFunction(snes,x1,j1a);
91: }
93: PetscOptionsBegin(PetscObjectComm((PetscObject)snes),((PetscObject)snes)->prefix,"Differencing options","SNES");
94: PetscOptionsEList("-mat_fd_type","Algorithm to compute difference parameter","SNESComputeJacobianDefault",list,2,"wp",&value,&flg);
95: PetscOptionsEnd();
96: if (flg && !value) use_wp = PETSC_FALSE;
98: if (use_wp) {
99: VecNorm(x1,NORM_2,&unorm);
100: }
101: /* Compute Jacobian approximation, 1 column at a time.
102: x1 = current iterate, j1a = F(x1)
103: x2 = perturbed iterate, j2a = F(x2)
104: */
105: for (i=0; i<N; i++) {
106: VecCopy(x1,x2);
107: if (i>= start && i<end) {
108: VecGetArrayRead(x1,&xx);
109: if (use_wp) dx = PetscSqrtReal(1.0 + unorm);
110: else dx = xx[i-start];
111: VecRestoreArrayRead(x1,&xx);
112: if (PetscAbsScalar(dx) < dx_min) dx = (PetscRealPart(dx) < 0. ? -1. : 1.) * dx_par;
113: dx *= epsilon;
114: wscale = 1.0/dx;
115: VecSetValues(x2,1,&i,&dx,ADD_VALUES);
116: } else {
117: wscale = 0.0;
118: }
119: VecAssemblyBegin(x2);
120: VecAssemblyEnd(x2);
121: if (dms->ops->computemffunction) {
122: SNESComputeMFFunction(snes,x2,j2a);
123: } else {
124: SNESComputeFunction(snes,x2,j2a);
125: }
126: VecAXPY(j2a,-1.0,j1a);
127: /* Communicate scale=1/dx_i to all processors */
128: VecGetOwnershipRanges(x1,&ranges);
129: root = size;
130: for (j=size-1; j>-1; j--) {
131: root--;
132: if (i>=ranges[j]) break;
133: }
134: MPI_Bcast(&wscale,1,MPIU_SCALAR,root,comm);
135: VecScale(j2a,wscale);
136: VecNorm(j2a,NORM_INFINITY,&amax); amax *= 1.e-14;
137: VecGetArray(j2a,&y);
138: for (j=start; j<end; j++) {
139: if (PetscAbsScalar(y[j-start]) > amax || j == i) {
140: MatSetValues(B,1,&j,1,&i,y+j-start,INSERT_VALUES);
141: }
142: }
143: VecRestoreArray(j2a,&y);
144: }
145: if (snes->dm) {
146: DMRestoreGlobalVector(snes->dm,&j1a);
147: DMRestoreGlobalVector(snes->dm,&j2a);
148: DMRestoreGlobalVector(snes->dm,&x2);
149: }
150: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
151: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
152: if (B != J) {
153: MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);
154: MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);
155: }
156: snes->max_funcs = max_funcs;
157: snes->nfuncs -= N;
158: return 0;
159: }