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