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: }