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