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