111320018SBarry Smith 2b45d2f2cSJed Brown #include <petsc-private/snesimpl.h> /*I "petscsnes.h" I*/ 311320018SBarry Smith 44a2ae208SSatish Balay #undef __FUNCT__ 58d359177SBarry Smith #define __FUNCT__ "SNESComputeJacobianDefault" 64b828684SBarry Smith /*@C 78d359177SBarry 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) 17d1e9a80fSBarry Smith - B - newly computed Jacobian matrix to use with preconditioner (generally the same as J) 18c7afd0dbSLois Curfman McInnes 19ad960d00SLois Curfman McInnes Options Database Key: 208d359177SBarry Smith + -snes_fd - Activates SNESComputeJacobianDefault() 2179f36460SBarry Smith . -snes_test_err - Square root of function error tolerance, default square root of machine 2277d8c4bbSBarry Smith epsilon (1.e-8 in double, 3.e-4 in single) 233ec795f1SBarry Smith - -mat_fd_type - Either wp or ds (see MATMFFD_WP or MATMFFD_DS) 24ad960d00SLois Curfman McInnes 255f3c43d9SLois Curfman McInnes Notes: 265f3c43d9SLois Curfman McInnes This routine is slow and expensive, and is not currently optimized 275f3c43d9SLois Curfman McInnes to take advantage of sparsity in the problem. Although 288d359177SBarry Smith SNESComputeJacobianDefault() is not recommended for general use 295f3c43d9SLois Curfman McInnes in large-scale applications, It can be useful in checking the 305f3c43d9SLois Curfman McInnes correctness of a user-provided Jacobian. 3111320018SBarry Smith 3279f36460SBarry Smith An alternative routine that uses coloring to exploit matrix sparsity is 338d359177SBarry Smith SNESComputeJacobianDefaultColor(). 34b4fc646aSLois Curfman McInnes 3536851e7fSLois Curfman McInnes Level: intermediate 3636851e7fSLois Curfman McInnes 375f3c43d9SLois Curfman McInnes .keywords: SNES, finite differences, Jacobian 385f3c43d9SLois Curfman McInnes 398d359177SBarry Smith .seealso: SNESSetJacobian(), SNESComputeJacobianDefaultColor(), MatCreateSNESMF() 4011320018SBarry Smith @*/ 41d1e9a80fSBarry Smith PetscErrorCode SNESComputeJacobianDefault(SNES snes,Vec x1,Mat J,Mat B,void *ctx) 4211320018SBarry Smith { 4388c956adSLois Curfman McInnes Vec j1a,j2a,x2; 446849ba73SBarry Smith PetscErrorCode ierr; 4586c88abdSHong Zhang PetscInt i,N,start,end,j,value,root; 4686c88abdSHong Zhang PetscScalar dx,*y,*xx,wscale; 4777d8c4bbSBarry Smith PetscReal amax,epsilon = PETSC_SQRT_MACHINE_EPSILON; 4879f36460SBarry Smith PetscReal dx_min = 1.e-16,dx_par = 1.e-1,unorm; 49bbb6d6a8SBarry Smith MPI_Comm comm; 506849ba73SBarry Smith PetscErrorCode (*eval_fct)(SNES,Vec,Vec)=0; 51ace3abfcSBarry Smith PetscBool assembled,use_wp = PETSC_TRUE,flg; 5279f36460SBarry Smith const char *list[2] = {"ds","wp"}; 5386c88abdSHong Zhang PetscMPIInt size; 5486c88abdSHong Zhang const PetscInt *ranges; 550521c3abSLois Curfman McInnes 563a40ed3dSBarry Smith PetscFunctionBegin; 577adad957SLisandro Dalcin ierr = PetscOptionsGetReal(((PetscObject)snes)->prefix,"-snes_test_err",&epsilon,0);CHKERRQ(ierr); 584b27c08aSLois Curfman McInnes eval_fct = SNESComputeFunction; 5923242f5aSBarry Smith 602d0c0e3bSBarry Smith ierr = PetscObjectGetComm((PetscObject)x1,&comm);CHKERRQ(ierr); 6186c88abdSHong Zhang ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 6294ab13aaSBarry Smith ierr = MatAssembled(B,&assembled);CHKERRQ(ierr); 630b9b6f31SBarry Smith if (assembled) { 6494ab13aaSBarry Smith ierr = MatZeroEntries(B);CHKERRQ(ierr); 650b9b6f31SBarry Smith } 66aa79bc6dSLois Curfman McInnes if (!snes->nvwork) { 67aa79bc6dSLois Curfman McInnes snes->nvwork = 3; 68f5af7f23SKarl Rupp 6985385478SLisandro Dalcin ierr = VecDuplicateVecs(x1,snes->nvwork,&snes->vwork);CHKERRQ(ierr); 7085385478SLisandro Dalcin ierr = PetscLogObjectParents(snes,snes->nvwork,snes->vwork);CHKERRQ(ierr); 71aa79bc6dSLois Curfman McInnes } 7288c956adSLois Curfman McInnes j1a = snes->vwork[0]; j2a = snes->vwork[1]; x2 = snes->vwork[2]; 7323242f5aSBarry Smith 7478b31e54SBarry Smith ierr = VecGetSize(x1,&N);CHKERRQ(ierr); 7578b31e54SBarry Smith ierr = VecGetOwnershipRange(x1,&start,&end);CHKERRQ(ierr); 76a86fb38aSBarry Smith ierr = (*eval_fct)(snes,x1,j1a);CHKERRQ(ierr); 77c005e166SLois Curfman McInnes 78*e55864a3SBarry Smith ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)snes),((PetscObject)snes)->prefix,"Differencing options","SNES"); 798d359177SBarry Smith ierr = PetscOptionsEList("-mat_fd_type","Algorithm to compute difference parameter","SNESComputeJacobianDefault",list,2,"wp",&value,&flg);CHKERRQ(ierr); 80*e55864a3SBarry Smith ierr = PetscOptionsEnd(); 81f5af7f23SKarl Rupp if (flg && !value) use_wp = PETSC_FALSE; 82f5af7f23SKarl Rupp 8379f36460SBarry Smith if (use_wp) { 8479f36460SBarry Smith ierr = VecNorm(x1,NORM_2,&unorm);CHKERRQ(ierr); 8579f36460SBarry Smith } 86c005e166SLois Curfman McInnes /* Compute Jacobian approximation, 1 column at a time. 8788c956adSLois Curfman McInnes x1 = current iterate, j1a = F(x1) 8888c956adSLois Curfman McInnes x2 = perturbed iterate, j2a = F(x2) 89c005e166SLois Curfman McInnes */ 9039e2f89bSBarry Smith for (i=0; i<N; i++) { 9178b31e54SBarry Smith ierr = VecCopy(x1,x2);CHKERRQ(ierr); 9223242f5aSBarry Smith if (i>= start && i<end) { 932e8a6d31SBarry Smith ierr = VecGetArray(x1,&xx);CHKERRQ(ierr); 94f5af7f23SKarl Rupp if (use_wp) dx = 1.0 + unorm; 95f5af7f23SKarl Rupp else dx = xx[i-start]; 962e8a6d31SBarry Smith ierr = VecRestoreArray(x1,&xx);CHKERRQ(ierr); 976bd79f97SJed Brown if (PetscAbsScalar(dx) < dx_min) dx = (PetscRealPart(dx) < 0. ? -1. : 1.) * dx_par; 9839e2f89bSBarry Smith dx *= epsilon; 9974f6f00dSLois Curfman McInnes wscale = 1.0/dx; 1002e8a6d31SBarry Smith ierr = VecSetValues(x2,1,&i,&dx,ADD_VALUES);CHKERRQ(ierr); 1016c783aadSBarry Smith } else { 102bbb6d6a8SBarry Smith wscale = 0.0; 103bbb6d6a8SBarry Smith } 104275089ecSBarry Smith ierr = VecAssemblyBegin(x2);CHKERRQ(ierr); 105275089ecSBarry Smith ierr = VecAssemblyEnd(x2);CHKERRQ(ierr); 106a86fb38aSBarry Smith ierr = (*eval_fct)(snes,x2,j2a);CHKERRQ(ierr); 10779f36460SBarry Smith ierr = VecAXPY(j2a,-1.0,j1a);CHKERRQ(ierr); 10886c88abdSHong Zhang /* Communicate scale=1/dx_i to all processors */ 10986c88abdSHong Zhang ierr = VecGetOwnershipRanges(x1,&ranges);CHKERRQ(ierr); 11086c88abdSHong Zhang root = size; 11186c88abdSHong Zhang for (j=size-1; j>-1; j--) { 11286c88abdSHong Zhang root--; 11386c88abdSHong Zhang if (i>=ranges[j]) break; 11486c88abdSHong Zhang } 11586c88abdSHong Zhang ierr = MPI_Bcast(&wscale,1,MPIU_SCALAR,root,comm);CHKERRQ(ierr); 11686c88abdSHong Zhang 11786c88abdSHong Zhang ierr = VecScale(j2a,wscale);CHKERRQ(ierr); 1182e8a6d31SBarry Smith ierr = VecNorm(j2a,NORM_INFINITY,&amax);CHKERRQ(ierr); amax *= 1.e-14; 119d142edc7SBarry Smith ierr = VecGetArray(j2a,&y);CHKERRQ(ierr); 12023242f5aSBarry Smith for (j=start; j<end; j++) { 121f6e735bbSHong Zhang if (PetscAbsScalar(y[j-start]) > amax || j == i) { 12294ab13aaSBarry Smith ierr = MatSetValues(B,1,&j,1,&i,y+j-start,INSERT_VALUES);CHKERRQ(ierr); 12323242f5aSBarry Smith } 12423242f5aSBarry Smith } 1252e8a6d31SBarry Smith ierr = VecRestoreArray(j2a,&y);CHKERRQ(ierr); 12623242f5aSBarry Smith } 12794ab13aaSBarry Smith ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 12894ab13aaSBarry Smith ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 12994ab13aaSBarry Smith if (B != J) { 13094ab13aaSBarry Smith ierr = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 13194ab13aaSBarry Smith ierr = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 132f588057bSBarry Smith } 1333a40ed3dSBarry Smith PetscFunctionReturn(0); 13411320018SBarry Smith } 13511320018SBarry Smith 136bd45824fSLois Curfman McInnes 137