xref: /petsc/src/snes/interface/snesj.c (revision 8d359177c33ddf5f82763e570f2db1a8881cb79a)
111320018SBarry Smith 
2b45d2f2cSJed Brown #include <petsc-private/snesimpl.h>    /*I  "petscsnes.h"  I*/
311320018SBarry Smith 
44a2ae208SSatish Balay #undef __FUNCT__
5*8d359177SBarry Smith #define __FUNCT__ "SNESComputeJacobianDefault"
64b828684SBarry Smith /*@C
7*8d359177SBarry Smith    SNESComputeJacobianDefault - Computes the Jacobian using finite differences.
811320018SBarry Smith 
9fee21e36SBarry Smith    Collective on SNES
10fee21e36SBarry Smith 
11c7afd0dbSLois Curfman McInnes    Input Parameters:
12c7afd0dbSLois Curfman McInnes +  x1 - compute Jacobian at this point
13c7afd0dbSLois Curfman McInnes -  ctx - application's function context, as set with SNESSetFunction()
14c7afd0dbSLois Curfman McInnes 
15c7afd0dbSLois Curfman McInnes    Output Parameters:
16c7afd0dbSLois Curfman McInnes +  J - Jacobian matrix (not altered in this routine)
17c7afd0dbSLois Curfman McInnes .  B - newly computed Jacobian matrix to use with preconditioner (generally the same as J)
18c7afd0dbSLois Curfman McInnes -  flag - flag indicating whether the matrix sparsity structure has changed
19c7afd0dbSLois Curfman McInnes 
20ad960d00SLois Curfman McInnes    Options Database Key:
21*8d359177SBarry Smith +  -snes_fd - Activates SNESComputeJacobianDefault()
2279f36460SBarry Smith .  -snes_test_err - Square root of function error tolerance, default square root of machine
2377d8c4bbSBarry Smith                     epsilon (1.e-8 in double, 3.e-4 in single)
243ec795f1SBarry Smith -  -mat_fd_type - Either wp or ds (see MATMFFD_WP or MATMFFD_DS)
25ad960d00SLois Curfman McInnes 
265f3c43d9SLois Curfman McInnes    Notes:
275f3c43d9SLois Curfman McInnes    This routine is slow and expensive, and is not currently optimized
285f3c43d9SLois Curfman McInnes    to take advantage of sparsity in the problem.  Although
29*8d359177SBarry Smith    SNESComputeJacobianDefault() is not recommended for general use
305f3c43d9SLois Curfman McInnes    in large-scale applications, It can be useful in checking the
315f3c43d9SLois Curfman McInnes    correctness of a user-provided Jacobian.
3211320018SBarry Smith 
3379f36460SBarry Smith    An alternative routine that uses coloring to exploit matrix sparsity is
34*8d359177SBarry Smith    SNESComputeJacobianDefaultColor().
35b4fc646aSLois Curfman McInnes 
3636851e7fSLois Curfman McInnes    Level: intermediate
3736851e7fSLois Curfman McInnes 
385f3c43d9SLois Curfman McInnes .keywords: SNES, finite differences, Jacobian
395f3c43d9SLois Curfman McInnes 
40*8d359177SBarry Smith .seealso: SNESSetJacobian(), SNESComputeJacobianDefaultColor(), MatCreateSNESMF()
4111320018SBarry Smith @*/
42*8d359177SBarry Smith PetscErrorCode  SNESComputeJacobianDefault(SNES snes,Vec x1,Mat *J,Mat *B,MatStructure *flag,void *ctx)
4311320018SBarry Smith {
4488c956adSLois Curfman McInnes   Vec            j1a,j2a,x2;
456849ba73SBarry Smith   PetscErrorCode ierr;
4686c88abdSHong Zhang   PetscInt       i,N,start,end,j,value,root;
4786c88abdSHong Zhang   PetscScalar    dx,*y,*xx,wscale;
4877d8c4bbSBarry Smith   PetscReal      amax,epsilon = PETSC_SQRT_MACHINE_EPSILON;
4979f36460SBarry Smith   PetscReal      dx_min = 1.e-16,dx_par = 1.e-1,unorm;
50bbb6d6a8SBarry Smith   MPI_Comm       comm;
516849ba73SBarry Smith   PetscErrorCode (*eval_fct)(SNES,Vec,Vec)=0;
52ace3abfcSBarry Smith   PetscBool      assembled,use_wp = PETSC_TRUE,flg;
5379f36460SBarry Smith   const char     *list[2] = {"ds","wp"};
5486c88abdSHong Zhang   PetscMPIInt    size;
5586c88abdSHong Zhang   const PetscInt *ranges;
560521c3abSLois Curfman McInnes 
573a40ed3dSBarry Smith   PetscFunctionBegin;
587adad957SLisandro Dalcin   ierr     = PetscOptionsGetReal(((PetscObject)snes)->prefix,"-snes_test_err",&epsilon,0);CHKERRQ(ierr);
594b27c08aSLois Curfman McInnes   eval_fct = SNESComputeFunction;
6023242f5aSBarry Smith 
612d0c0e3bSBarry Smith   ierr = PetscObjectGetComm((PetscObject)x1,&comm);CHKERRQ(ierr);
6286c88abdSHong Zhang   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
630b9b6f31SBarry Smith   ierr = MatAssembled(*B,&assembled);CHKERRQ(ierr);
640b9b6f31SBarry Smith   if (assembled) {
652d0c0e3bSBarry Smith     ierr = MatZeroEntries(*B);CHKERRQ(ierr);
660b9b6f31SBarry Smith   }
67aa79bc6dSLois Curfman McInnes   if (!snes->nvwork) {
68aa79bc6dSLois Curfman McInnes     snes->nvwork = 3;
69f5af7f23SKarl Rupp 
7085385478SLisandro Dalcin     ierr = VecDuplicateVecs(x1,snes->nvwork,&snes->vwork);CHKERRQ(ierr);
7185385478SLisandro Dalcin     ierr = PetscLogObjectParents(snes,snes->nvwork,snes->vwork);CHKERRQ(ierr);
72aa79bc6dSLois Curfman McInnes   }
7388c956adSLois Curfman McInnes   j1a = snes->vwork[0]; j2a = snes->vwork[1]; x2 = snes->vwork[2];
7423242f5aSBarry Smith 
7578b31e54SBarry Smith   ierr = VecGetSize(x1,&N);CHKERRQ(ierr);
7678b31e54SBarry Smith   ierr = VecGetOwnershipRange(x1,&start,&end);CHKERRQ(ierr);
77a86fb38aSBarry Smith   ierr = (*eval_fct)(snes,x1,j1a);CHKERRQ(ierr);
78c005e166SLois Curfman McInnes 
79*8d359177SBarry Smith   ierr = PetscOptionsEList("-mat_fd_type","Algorithm to compute difference parameter","SNESComputeJacobianDefault",list,2,"wp",&value,&flg);CHKERRQ(ierr);
80f5af7f23SKarl Rupp   if (flg && !value) use_wp = PETSC_FALSE;
81f5af7f23SKarl Rupp 
8279f36460SBarry Smith   if (use_wp) {
8379f36460SBarry Smith     ierr = VecNorm(x1,NORM_2,&unorm);CHKERRQ(ierr);
8479f36460SBarry Smith   }
85c005e166SLois Curfman McInnes   /* Compute Jacobian approximation, 1 column at a time.
8688c956adSLois Curfman McInnes       x1 = current iterate, j1a = F(x1)
8788c956adSLois Curfman McInnes       x2 = perturbed iterate, j2a = F(x2)
88c005e166SLois Curfman McInnes    */
8939e2f89bSBarry Smith   for (i=0; i<N; i++) {
9078b31e54SBarry Smith     ierr = VecCopy(x1,x2);CHKERRQ(ierr);
9123242f5aSBarry Smith     if (i>= start && i<end) {
922e8a6d31SBarry Smith       ierr = VecGetArray(x1,&xx);CHKERRQ(ierr);
93f5af7f23SKarl Rupp       if (use_wp) dx = 1.0 + unorm;
94f5af7f23SKarl Rupp       else        dx = xx[i-start];
952e8a6d31SBarry Smith       ierr = VecRestoreArray(x1,&xx);CHKERRQ(ierr);
966bd79f97SJed Brown       if (PetscAbsScalar(dx) < dx_min) dx = (PetscRealPart(dx) < 0. ? -1. : 1.) * dx_par;
9739e2f89bSBarry Smith       dx    *= epsilon;
9874f6f00dSLois Curfman McInnes       wscale = 1.0/dx;
992e8a6d31SBarry Smith       ierr   = VecSetValues(x2,1,&i,&dx,ADD_VALUES);CHKERRQ(ierr);
1006c783aadSBarry Smith     } else {
101bbb6d6a8SBarry Smith       wscale = 0.0;
102bbb6d6a8SBarry Smith     }
103275089ecSBarry Smith     ierr = VecAssemblyBegin(x2);CHKERRQ(ierr);
104275089ecSBarry Smith     ierr = VecAssemblyEnd(x2);CHKERRQ(ierr);
105a86fb38aSBarry Smith     ierr = (*eval_fct)(snes,x2,j2a);CHKERRQ(ierr);
10679f36460SBarry Smith     ierr = VecAXPY(j2a,-1.0,j1a);CHKERRQ(ierr);
10786c88abdSHong Zhang     /* Communicate scale=1/dx_i to all processors */
10886c88abdSHong Zhang     ierr = VecGetOwnershipRanges(x1,&ranges);CHKERRQ(ierr);
10986c88abdSHong Zhang     root = size;
11086c88abdSHong Zhang     for (j=size-1; j>-1; j--) {
11186c88abdSHong Zhang       root--;
11286c88abdSHong Zhang       if (i>=ranges[j]) break;
11386c88abdSHong Zhang     }
11486c88abdSHong Zhang     ierr = MPI_Bcast(&wscale,1,MPIU_SCALAR,root,comm);CHKERRQ(ierr);
11586c88abdSHong Zhang 
11686c88abdSHong Zhang     ierr = VecScale(j2a,wscale);CHKERRQ(ierr);
1172e8a6d31SBarry Smith     ierr = VecNorm(j2a,NORM_INFINITY,&amax);CHKERRQ(ierr); amax *= 1.e-14;
118d142edc7SBarry Smith     ierr = VecGetArray(j2a,&y);CHKERRQ(ierr);
11923242f5aSBarry Smith     for (j=start; j<end; j++) {
120f6e735bbSHong Zhang       if (PetscAbsScalar(y[j-start]) > amax || j == i) {
121b4fc646aSLois Curfman McInnes         ierr = MatSetValues(*B,1,&j,1,&i,y+j-start,INSERT_VALUES);CHKERRQ(ierr);
12223242f5aSBarry Smith       }
12323242f5aSBarry Smith     }
1242e8a6d31SBarry Smith     ierr = VecRestoreArray(j2a,&y);CHKERRQ(ierr);
12523242f5aSBarry Smith   }
126b4fc646aSLois Curfman McInnes   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
127b4fc646aSLois Curfman McInnes   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
128f588057bSBarry Smith   if (*B != *J) {
129f588057bSBarry Smith     ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
130f588057bSBarry Smith     ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
131f588057bSBarry Smith   }
132595b82d2SBarry Smith   *flag =  DIFFERENT_NONZERO_PATTERN;
1333a40ed3dSBarry Smith   PetscFunctionReturn(0);
13411320018SBarry Smith }
13511320018SBarry Smith 
136bd45824fSLois Curfman McInnes 
137