1d8606c27SBarry Smith! 2d8606c27SBarry Smith! 3d8606c27SBarry Smith! This example demonstrates basic use of the SNES Fortran interface. 4d8606c27SBarry Smith! 5d8606c27SBarry Smith! 677d968b7SBarry Smith module ex12fmodule 7d8606c27SBarry Smith#include <petsc/finclude/petscsnes.h> 8d8606c27SBarry Smith use petscsnes 9d8606c27SBarry Smith type User 10d8606c27SBarry Smith DM da 11d8606c27SBarry Smith Vec F 12d8606c27SBarry Smith Vec xl 13d8606c27SBarry Smith MPI_Comm comm 14d8606c27SBarry Smith PetscInt N 15d8606c27SBarry Smith end type User 16d8606c27SBarry Smith save 17d8606c27SBarry Smith type monctx 18d8606c27SBarry Smith PetscInt :: its,lag 19d8606c27SBarry Smith end type monctx 20d8606c27SBarry Smith end module 21d8606c27SBarry Smith 22d8606c27SBarry Smith! --------------------------------------------------------------------- 23d8606c27SBarry Smith! Subroutine FormMonitor 24d8606c27SBarry Smith! This function lets up keep track of the SNES progress at each step 25d8606c27SBarry Smith! In this routine, we determine when the Jacobian is rebuilt with the parameter 'jag' 26d8606c27SBarry Smith! 27d8606c27SBarry Smith! Input Parameters: 28d8606c27SBarry Smith! snes - SNES nonlinear solver context 29d8606c27SBarry Smith! its - current nonlinear iteration, starting from a call of SNESSolve() 30d8606c27SBarry Smith! norm - 2-norm of current residual (may be approximate) 31d8606c27SBarry Smith! snesm - monctx designed module (included in Snesmmod) 32d8606c27SBarry Smith! --------------------------------------------------------------------- 33d8606c27SBarry Smith subroutine FormMonitor(snes,its,norm,snesm,ierr) 3477d968b7SBarry Smith use ex12fmodule 35d8606c27SBarry Smith implicit none 36d8606c27SBarry Smith 37d8606c27SBarry Smith SNES :: snes 38d8606c27SBarry Smith PetscInt :: its,one,mone 39d8606c27SBarry Smith PetscScalar :: norm 40d8606c27SBarry Smith type(monctx) :: snesm 41d8606c27SBarry Smith PetscErrorCode :: ierr 42d8606c27SBarry Smith 43d8606c27SBarry Smith! write(6,*) ' ' 44d8606c27SBarry Smith! write(6,*) ' its ',its,snesm%its,'lag', 45d8606c27SBarry Smith! & snesm%lag 46d8606c27SBarry Smith! call flush(6) 47d8606c27SBarry Smith if (mod(snesm%its,snesm%lag).eq.0) then 48d8606c27SBarry Smith one = 1 49d8606c27SBarry Smith PetscCall(SNESSetLagJacobian(snes,one,ierr)) ! build jacobian 50d8606c27SBarry Smith else 51d8606c27SBarry Smith mone = -1 52d8606c27SBarry Smith PetscCall(SNESSetLagJacobian(snes,mone,ierr)) ! do NOT build jacobian 53d8606c27SBarry Smith endif 54d8606c27SBarry Smith snesm%its = snesm%its + 1 55d8606c27SBarry Smith end subroutine FormMonitor 56d8606c27SBarry Smith 57d8606c27SBarry Smith! Note: Any user-defined Fortran routines (such as FormJacobian) 58d8606c27SBarry Smith! MUST be declared as external. 59d8606c27SBarry Smith! 6042ce371bSBarry Smith 61d8606c27SBarry Smith program main 6277d968b7SBarry Smith use ex12fmodule 63d8606c27SBarry Smith implicit none 64d8606c27SBarry Smith type(User) ctx 65d8606c27SBarry Smith PetscMPIInt rank,size 66d8606c27SBarry Smith PetscErrorCode ierr 67d8606c27SBarry Smith PetscInt N,start,end,nn,i 68d8606c27SBarry Smith PetscInt ii,its,i1,i0,i3 69d8606c27SBarry Smith PetscBool flg 70d8606c27SBarry Smith SNES snes 71d8606c27SBarry Smith Mat J 72d8606c27SBarry Smith Vec x,r,u 73d8606c27SBarry Smith PetscScalar xp,FF,UU,h 74d8606c27SBarry Smith character*(10) matrixname 75d8606c27SBarry Smith external FormJacobian,FormFunction 76d8606c27SBarry Smith external formmonitor 77d8606c27SBarry Smith type(monctx) :: snesm 78d8606c27SBarry Smith 79d8606c27SBarry Smith PetscCallA(PetscInitialize(ierr)) 80d8606c27SBarry Smith i1 = 1 81d8606c27SBarry Smith i0 = 0 82d8606c27SBarry Smith i3 = 3 83d8606c27SBarry Smith N = 10 84d8606c27SBarry Smith PetscCallA(PetscOptionsGetInt(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,'-n',N,flg,ierr)) 85d8606c27SBarry Smith h = 1.0/real(N-1) 86d8606c27SBarry Smith ctx%N = N 87d8606c27SBarry Smith ctx%comm = PETSC_COMM_WORLD 88d8606c27SBarry Smith 89d8606c27SBarry Smith PetscCallMPIA(MPI_Comm_rank(PETSC_COMM_WORLD,rank,ierr)) 90d8606c27SBarry Smith PetscCallMPIA(MPI_Comm_size(PETSC_COMM_WORLD,size,ierr)) 91d8606c27SBarry Smith 92d8606c27SBarry Smith! Set up data structures 93d8606c27SBarry Smith PetscCallA(DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,N,i1,i1,PETSC_NULL_INTEGER,ctx%da,ierr)) 94d8606c27SBarry Smith PetscCallA(DMSetFromOptions(ctx%da,ierr)) 95d8606c27SBarry Smith PetscCallA(DMSetUp(ctx%da,ierr)) 96d8606c27SBarry Smith PetscCallA(DMCreateGlobalVector(ctx%da,x,ierr)) 97d8606c27SBarry Smith PetscCallA(DMCreateLocalVector(ctx%da,ctx%xl,ierr)) 98d8606c27SBarry Smith 99d8606c27SBarry Smith PetscCallA(PetscObjectSetName(x,'Approximate Solution',ierr)) 100d8606c27SBarry Smith PetscCallA(VecDuplicate(x,r,ierr)) 101d8606c27SBarry Smith PetscCallA(VecDuplicate(x,ctx%F,ierr)) 102d8606c27SBarry Smith PetscCallA(VecDuplicate(x,U,ierr)) 103d8606c27SBarry Smith PetscCallA(PetscObjectSetName(U,'Exact Solution',ierr)) 104d8606c27SBarry Smith 105d8606c27SBarry Smith PetscCallA(MatCreateAIJ(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,N,N,i3,PETSC_NULL_INTEGER,i0,PETSC_NULL_INTEGER,J,ierr)) 106d8606c27SBarry Smith PetscCallA(MatSetOption(J,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_FALSE,ierr)) 107d8606c27SBarry Smith PetscCallA(MatGetType(J,matrixname,ierr)) 108d8606c27SBarry Smith 109*dd8e379bSPierre Jolivet! Store right-hand side of PDE and exact solution 110d8606c27SBarry Smith PetscCallA(VecGetOwnershipRange(x,start,end,ierr)) 111d8606c27SBarry Smith xp = h*start 112d8606c27SBarry Smith nn = end - start 113d8606c27SBarry Smith ii = start 114d8606c27SBarry Smith do 10, i=0,nn-1 115d8606c27SBarry Smith FF = 6.0*xp + (xp+1.e-12)**6.e0 116d8606c27SBarry Smith UU = xp*xp*xp 117d8606c27SBarry Smith PetscCallA(VecSetValues(ctx%F,i1,ii,FF,INSERT_VALUES,ierr)) 118d8606c27SBarry Smith PetscCallA(VecSetValues(U,i1,ii,UU,INSERT_VALUES,ierr)) 119d8606c27SBarry Smith xp = xp + h 120d8606c27SBarry Smith ii = ii + 1 121d8606c27SBarry Smith 10 continue 122d8606c27SBarry Smith PetscCallA(VecAssemblyBegin(ctx%F,ierr)) 123d8606c27SBarry Smith PetscCallA(VecAssemblyEnd(ctx%F,ierr)) 124d8606c27SBarry Smith PetscCallA(VecAssemblyBegin(U,ierr)) 125d8606c27SBarry Smith PetscCallA(VecAssemblyEnd(U,ierr)) 126d8606c27SBarry Smith 127d8606c27SBarry Smith! Create nonlinear solver 128d8606c27SBarry Smith PetscCallA(SNESCreate(PETSC_COMM_WORLD,snes,ierr)) 129d8606c27SBarry Smith 130d8606c27SBarry Smith! Set various routines and options 131d8606c27SBarry Smith PetscCallA(SNESSetFunction(snes,r,FormFunction,ctx,ierr)) 132d8606c27SBarry Smith PetscCallA(SNESSetJacobian(snes,J,J,FormJacobian,ctx,ierr)) 133d8606c27SBarry Smith 134d8606c27SBarry Smith snesm%its = 0 135d8606c27SBarry Smith PetscCallA(SNESGetLagJacobian(snes,snesm%lag,ierr)) 136d8606c27SBarry Smith PetscCallA(SNESMonitorSet(snes,FormMonitor,snesm,PETSC_NULL_FUNCTION,ierr)) 137d8606c27SBarry Smith PetscCallA(SNESSetFromOptions(snes,ierr)) 138d8606c27SBarry Smith 139d8606c27SBarry Smith! Solve nonlinear system 140d8606c27SBarry Smith PetscCallA(FormInitialGuess(snes,x,ierr)) 141d8606c27SBarry Smith PetscCallA(SNESSolve(snes,PETSC_NULL_VEC,x,ierr)) 142d8606c27SBarry Smith PetscCallA(SNESGetIterationNumber(snes,its,ierr)) 143d8606c27SBarry Smith 144d8606c27SBarry Smith! Free work space. All PETSc objects should be destroyed when they 145d8606c27SBarry Smith! are no longer needed. 146d8606c27SBarry Smith PetscCallA(VecDestroy(x,ierr)) 147d8606c27SBarry Smith PetscCallA(VecDestroy(ctx%xl,ierr)) 148d8606c27SBarry Smith PetscCallA(VecDestroy(r,ierr)) 149d8606c27SBarry Smith PetscCallA(VecDestroy(U,ierr)) 150d8606c27SBarry Smith PetscCallA(VecDestroy(ctx%F,ierr)) 151d8606c27SBarry Smith PetscCallA(MatDestroy(J,ierr)) 152d8606c27SBarry Smith PetscCallA(SNESDestroy(snes,ierr)) 153d8606c27SBarry Smith PetscCallA(DMDestroy(ctx%da,ierr)) 154d8606c27SBarry Smith PetscCallA(PetscFinalize(ierr)) 155d8606c27SBarry Smith end 156d8606c27SBarry Smith 157d8606c27SBarry Smith! -------------------- Evaluate Function F(x) --------------------- 158d8606c27SBarry Smith 159d8606c27SBarry Smith subroutine FormFunction(snes,x,f,ctx,ierr) 16077d968b7SBarry Smith use ex12fmodule 161d8606c27SBarry Smith implicit none 162d8606c27SBarry Smith SNES snes 163d8606c27SBarry Smith Vec x,f 164d8606c27SBarry Smith type(User) ctx 165d8606c27SBarry Smith PetscMPIInt rank,size,zero 166d8606c27SBarry Smith PetscInt i,s,n 167d8606c27SBarry Smith PetscErrorCode ierr 16842ce371bSBarry Smith PetscScalar h,d 16942ce371bSBarry Smith PetscScalar,pointer :: vf2(:),vxx(:),vff(:) 170d8606c27SBarry Smith 171d8606c27SBarry Smith zero = 0 172d8606c27SBarry Smith PetscCallMPI(MPI_Comm_rank(ctx%comm,rank,ierr)) 173d8606c27SBarry Smith PetscCallMPI(MPI_Comm_size(ctx%comm,size,ierr)) 174d8606c27SBarry Smith h = 1.0/(real(ctx%N) - 1.0) 175d8606c27SBarry Smith PetscCall(DMGlobalToLocalBegin(ctx%da,x,INSERT_VALUES,ctx%xl,ierr)) 176d8606c27SBarry Smith PetscCall(DMGlobalToLocalEnd(ctx%da,x,INSERT_VALUES,ctx%xl,ierr)) 177d8606c27SBarry Smith 178d8606c27SBarry Smith PetscCall(VecGetLocalSize(ctx%xl,n,ierr)) 179d8606c27SBarry Smith if (n .gt. 1000) then 180d8606c27SBarry Smith print*, 'Local work array not big enough' 181d8606c27SBarry Smith call MPI_Abort(PETSC_COMM_WORLD,zero,ierr) 182d8606c27SBarry Smith endif 183d8606c27SBarry Smith 18442ce371bSBarry Smith PetscCall(VecGetArrayReadF90(ctx%xl,vxx,ierr)) 18542ce371bSBarry Smith PetscCall(VecGetArrayF90(f,vff,ierr)) 18642ce371bSBarry Smith PetscCall(VecGetArrayF90(ctx%F,vF2,ierr)) 187d8606c27SBarry Smith 188d8606c27SBarry Smith d = h*h 189d8606c27SBarry Smith 190d8606c27SBarry Smith! 191d8606c27SBarry Smith! Note that the array vxx() was obtained from a ghosted local vector 192d8606c27SBarry Smith! ctx%xl while the array vff() was obtained from the non-ghosted parallel 193d8606c27SBarry Smith! vector F. This is why there is a need for shift variable s. Since vff() 194d8606c27SBarry Smith! does not have locations for the ghost variables we need to index in it 195d8606c27SBarry Smith! slightly different then indexing into vxx(). For example on processor 196d8606c27SBarry Smith! 1 (the second processor) 197d8606c27SBarry Smith! 198d8606c27SBarry Smith! xx(1) xx(2) xx(3) ..... 199d8606c27SBarry Smith! ^^^^^^^ ^^^^^ ^^^^^ 200d8606c27SBarry Smith! ghost value 1st local value 2nd local value 201d8606c27SBarry Smith! 202d8606c27SBarry Smith! ff(1) ff(2) 203d8606c27SBarry Smith! ^^^^^^^ ^^^^^^^ 204d8606c27SBarry Smith! 1st local value 2nd local value 205d8606c27SBarry Smith! 206d8606c27SBarry Smith if (rank .eq. 0) then 207d8606c27SBarry Smith s = 0 20842ce371bSBarry Smith vff(1) = vxx(1) 209d8606c27SBarry Smith else 210d8606c27SBarry Smith s = 1 211d8606c27SBarry Smith endif 212d8606c27SBarry Smith 213d8606c27SBarry Smith do 10 i=1,n-2 21442ce371bSBarry Smith vff(i-s+1) = d*(vxx(i) - 2.0*vxx(i+1) + vxx(i+2)) + vxx(i+1)*vxx(i+1) - vF2(i-s+1) 215d8606c27SBarry Smith 10 continue 216d8606c27SBarry Smith 217d8606c27SBarry Smith if (rank .eq. size-1) then 21842ce371bSBarry Smith vff(n-s) = vxx(n) - 1.0 219d8606c27SBarry Smith endif 220d8606c27SBarry Smith 22142ce371bSBarry Smith PetscCall(VecRestoreArrayF90(f,vff,ierr)) 22242ce371bSBarry Smith PetscCall(VecRestoreArrayReadF90(ctx%xl,vxx,ierr)) 22342ce371bSBarry Smith PetscCall(VecRestoreArrayF90(ctx%F,vF2,ierr)) 224d8606c27SBarry Smith return 225d8606c27SBarry Smith end 226d8606c27SBarry Smith 227d8606c27SBarry Smith! -------------------- Form initial approximation ----------------- 228d8606c27SBarry Smith 229d8606c27SBarry Smith subroutine FormInitialGuess(snes,x,ierr) 23077d968b7SBarry Smith use ex12fmodule 231d8606c27SBarry Smith implicit none 232d8606c27SBarry Smith 233d8606c27SBarry Smith PetscErrorCode ierr 234d8606c27SBarry Smith Vec x 235d8606c27SBarry Smith SNES snes 236d8606c27SBarry Smith PetscScalar five 237d8606c27SBarry Smith 238d8606c27SBarry Smith five = .5 239d8606c27SBarry Smith PetscCall(VecSet(x,five,ierr)) 240d8606c27SBarry Smith return 241d8606c27SBarry Smith end 242d8606c27SBarry Smith 243d8606c27SBarry Smith! -------------------- Evaluate Jacobian -------------------- 244d8606c27SBarry Smith 245d8606c27SBarry Smith subroutine FormJacobian(snes,x,jac,B,ctx,ierr) 24677d968b7SBarry Smith use ex12fmodule 247d8606c27SBarry Smith implicit none 248d8606c27SBarry Smith 249d8606c27SBarry Smith SNES snes 250d8606c27SBarry Smith Vec x 251d8606c27SBarry Smith Mat jac,B 252d8606c27SBarry Smith type(User) ctx 253d8606c27SBarry Smith PetscInt ii,istart,iend 254d8606c27SBarry Smith PetscInt i,j,n,end,start,i1 255d8606c27SBarry Smith PetscErrorCode ierr 256d8606c27SBarry Smith PetscMPIInt rank,size 25742ce371bSBarry Smith PetscScalar d,A,h 25842ce371bSBarry Smith PetscScalar,pointer :: vxx(:) 259d8606c27SBarry Smith 260d8606c27SBarry Smith i1 = 1 261d8606c27SBarry Smith h = 1.0/(real(ctx%N) - 1.0) 262d8606c27SBarry Smith d = h*h 263d8606c27SBarry Smith PetscCallMPI(MPI_Comm_rank(ctx%comm,rank,ierr)) 264d8606c27SBarry Smith PetscCallMPI(MPI_Comm_size(ctx%comm,size,ierr)) 265d8606c27SBarry Smith 26642ce371bSBarry Smith PetscCall(VecGetArrayReadF90(x,vxx,ierr)) 267d8606c27SBarry Smith PetscCall(VecGetOwnershipRange(x,start,end,ierr)) 268d8606c27SBarry Smith n = end - start 269d8606c27SBarry Smith 270d8606c27SBarry Smith if (rank .eq. 0) then 271d8606c27SBarry Smith A = 1.0 272d8606c27SBarry Smith PetscCall(MatSetValues(jac,i1,start,i1,start,A,INSERT_VALUES,ierr)) 273d8606c27SBarry Smith istart = 1 274d8606c27SBarry Smith else 275d8606c27SBarry Smith istart = 0 276d8606c27SBarry Smith endif 277d8606c27SBarry Smith if (rank .eq. size-1) then 278d8606c27SBarry Smith i = INT(ctx%N-1) 279d8606c27SBarry Smith A = 1.0 280d8606c27SBarry Smith PetscCall(MatSetValues(jac,i1,i,i1,i,A,INSERT_VALUES,ierr)) 281d8606c27SBarry Smith iend = n-1 282d8606c27SBarry Smith else 283d8606c27SBarry Smith iend = n 284d8606c27SBarry Smith endif 285d8606c27SBarry Smith do 10 i=istart,iend-1 286d8606c27SBarry Smith ii = i + start 287d8606c27SBarry Smith j = start + i - 1 288d8606c27SBarry Smith PetscCall(MatSetValues(jac,i1,ii,i1,j,d,INSERT_VALUES,ierr)) 289d8606c27SBarry Smith j = start + i + 1 290d8606c27SBarry Smith PetscCall(MatSetValues(jac,i1,ii,i1,j,d,INSERT_VALUES,ierr)) 29142ce371bSBarry Smith A = -2.0*d + 2.0*vxx(i+1) 292d8606c27SBarry Smith PetscCall(MatSetValues(jac,i1,ii,i1,ii,A,INSERT_VALUES,ierr)) 293d8606c27SBarry Smith 10 continue 29442ce371bSBarry Smith PetscCall(VecRestoreArrayReadF90(x,vxx,ierr)) 295d8606c27SBarry Smith PetscCall(MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY,ierr)) 296d8606c27SBarry Smith PetscCall(MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY,ierr)) 297d8606c27SBarry Smith return 298d8606c27SBarry Smith end 299d8606c27SBarry Smith 300d8606c27SBarry Smith!/*TEST 301d8606c27SBarry Smith! 302d8606c27SBarry Smith! test: 303d8606c27SBarry Smith! nsize: 2 304d8606c27SBarry Smith! args: -ksp_gmres_cgs_refinement_type refine_always -n 10 -snes_monitor_short 305d8606c27SBarry Smith! output_file: output/ex12_1.out 306d8606c27SBarry Smith! 307d8606c27SBarry Smith!TEST*/ 308