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> 7*e7a95102SMartin Diehlmodule ex12f_mod 8d8606c27SBarry Smith use petscsnes 9*e7a95102SMartin Diehl implicit none 10d8606c27SBarry Smith type User 11d8606c27SBarry Smith DM da 12d8606c27SBarry Smith Vec F 13d8606c27SBarry Smith Vec xl 14d8606c27SBarry Smith MPI_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 20*e7a95102SMartin Diehl 21*e7a95102SMartin Diehlcontains 22*e7a95102SMartin Diehl! -------------------- Evaluate Function F(x) --------------------- 23*e7a95102SMartin Diehl 24*e7a95102SMartin Diehl subroutine FormFunction(snes, x, f, ctx, ierr) 25*e7a95102SMartin Diehl SNES snes 26*e7a95102SMartin Diehl Vec x, f 27*e7a95102SMartin Diehl type(User) ctx 28*e7a95102SMartin Diehl PetscMPIInt rank, size, zero 29*e7a95102SMartin Diehl PetscInt i, s, n 30*e7a95102SMartin Diehl PetscErrorCode ierr 31*e7a95102SMartin Diehl PetscScalar h, d 32*e7a95102SMartin Diehl PetscScalar, pointer :: vf2(:), vxx(:), vff(:) 33*e7a95102SMartin Diehl 34*e7a95102SMartin Diehl zero = 0 35*e7a95102SMartin Diehl PetscCallMPI(MPI_Comm_rank(ctx%comm, rank, ierr)) 36*e7a95102SMartin Diehl PetscCallMPI(MPI_Comm_size(ctx%comm, size, ierr)) 37*e7a95102SMartin Diehl h = 1.0/(real(ctx%N) - 1.0) 38*e7a95102SMartin Diehl PetscCall(DMGlobalToLocalBegin(ctx%da, x, INSERT_VALUES, ctx%xl, ierr)) 39*e7a95102SMartin Diehl PetscCall(DMGlobalToLocalEnd(ctx%da, x, INSERT_VALUES, ctx%xl, ierr)) 40*e7a95102SMartin Diehl 41*e7a95102SMartin Diehl PetscCall(VecGetLocalSize(ctx%xl, n, ierr)) 42*e7a95102SMartin Diehl if (n > 1000) then 43*e7a95102SMartin Diehl print *, 'Local work array not big enough' 44*e7a95102SMartin Diehl call MPI_Abort(PETSC_COMM_WORLD, zero, ierr) 45*e7a95102SMartin Diehl end if 46*e7a95102SMartin Diehl 47*e7a95102SMartin Diehl PetscCall(VecGetArrayRead(ctx%xl, vxx, ierr)) 48*e7a95102SMartin Diehl PetscCall(VecGetArray(f, vff, ierr)) 49*e7a95102SMartin Diehl PetscCall(VecGetArray(ctx%F, vF2, ierr)) 50*e7a95102SMartin Diehl 51*e7a95102SMartin Diehl d = h*h 52*e7a95102SMartin Diehl 53*e7a95102SMartin Diehl! 54*e7a95102SMartin Diehl! Note that the array vxx() was obtained from a ghosted local vector 55*e7a95102SMartin Diehl! ctx%xl while the array vff() was obtained from the non-ghosted parallel 56*e7a95102SMartin Diehl! vector F. This is why there is a need for shift variable s. Since vff() 57*e7a95102SMartin Diehl! does not have locations for the ghost variables we need to index in it 58*e7a95102SMartin Diehl! slightly different then indexing into vxx(). For example on processor 59*e7a95102SMartin Diehl! 1 (the second processor) 60*e7a95102SMartin Diehl! 61*e7a95102SMartin Diehl! xx(1) xx(2) xx(3) ..... 62*e7a95102SMartin Diehl! ^^^^^^^ ^^^^^ ^^^^^ 63*e7a95102SMartin Diehl! ghost value 1st local value 2nd local value 64*e7a95102SMartin Diehl! 65*e7a95102SMartin Diehl! ff(1) ff(2) 66*e7a95102SMartin Diehl! ^^^^^^^ ^^^^^^^ 67*e7a95102SMartin Diehl! 1st local value 2nd local value 68*e7a95102SMartin Diehl! 69*e7a95102SMartin Diehl if (rank == 0) then 70*e7a95102SMartin Diehl s = 0 71*e7a95102SMartin Diehl vff(1) = vxx(1) 72*e7a95102SMartin Diehl else 73*e7a95102SMartin Diehl s = 1 74*e7a95102SMartin Diehl end if 75*e7a95102SMartin Diehl 76*e7a95102SMartin Diehl do i = 1, n - 2 77*e7a95102SMartin 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) 78*e7a95102SMartin Diehl end do 79*e7a95102SMartin Diehl 80*e7a95102SMartin Diehl if (rank == size - 1) then 81*e7a95102SMartin Diehl vff(n - s) = vxx(n) - 1.0 82*e7a95102SMartin Diehl end if 83*e7a95102SMartin Diehl 84*e7a95102SMartin Diehl PetscCall(VecRestoreArray(f, vff, ierr)) 85*e7a95102SMartin Diehl PetscCall(VecRestoreArrayRead(ctx%xl, vxx, ierr)) 86*e7a95102SMartin Diehl PetscCall(VecRestoreArray(ctx%F, vF2, ierr)) 87*e7a95102SMartin 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 122*e7a95102SMartin Diehl! -------------------- Form initial approximation ----------------- 123*e7a95102SMartin Diehl 124*e7a95102SMartin Diehl subroutine FormInitialGuess(snes, x, ierr) 125*e7a95102SMartin Diehl 126*e7a95102SMartin Diehl PetscErrorCode ierr 127*e7a95102SMartin Diehl Vec x 128*e7a95102SMartin Diehl SNES snes 129*e7a95102SMartin Diehl PetscScalar five 130*e7a95102SMartin Diehl 131*e7a95102SMartin Diehl five = .5 132*e7a95102SMartin Diehl PetscCall(VecSet(x, five, ierr)) 133*e7a95102SMartin Diehl end 134*e7a95102SMartin Diehl 135*e7a95102SMartin Diehl! -------------------- Evaluate Jacobian -------------------- 136*e7a95102SMartin Diehl 137*e7a95102SMartin Diehl subroutine FormJacobian(snes, x, jac, B, ctx, ierr) 138*e7a95102SMartin Diehl 139*e7a95102SMartin Diehl SNES snes 140*e7a95102SMartin Diehl Vec x 141*e7a95102SMartin Diehl Mat jac, B 142*e7a95102SMartin Diehl type(User) ctx 143*e7a95102SMartin Diehl PetscInt ii, istart, iend 144*e7a95102SMartin Diehl PetscInt i, j, n, end, start, i1 145*e7a95102SMartin Diehl PetscErrorCode ierr 146*e7a95102SMartin Diehl PetscMPIInt rank, size 147*e7a95102SMartin Diehl PetscScalar d, A, h 148*e7a95102SMartin Diehl PetscScalar, pointer :: vxx(:) 149*e7a95102SMartin Diehl 150*e7a95102SMartin Diehl i1 = 1 151*e7a95102SMartin Diehl h = 1.0/(real(ctx%N) - 1.0) 152*e7a95102SMartin Diehl d = h*h 153*e7a95102SMartin Diehl PetscCallMPI(MPI_Comm_rank(ctx%comm, rank, ierr)) 154*e7a95102SMartin Diehl PetscCallMPI(MPI_Comm_size(ctx%comm, size, ierr)) 155*e7a95102SMartin Diehl 156*e7a95102SMartin Diehl PetscCall(VecGetArrayRead(x, vxx, ierr)) 157*e7a95102SMartin Diehl PetscCall(VecGetOwnershipRange(x, start, end, ierr)) 158*e7a95102SMartin Diehl n = end - start 159*e7a95102SMartin Diehl 160*e7a95102SMartin Diehl if (rank == 0) then 161*e7a95102SMartin Diehl A = 1.0 162*e7a95102SMartin Diehl PetscCall(MatSetValues(jac, i1, [start], i1, [start], [A], INSERT_VALUES, ierr)) 163*e7a95102SMartin Diehl istart = 1 164*e7a95102SMartin Diehl else 165*e7a95102SMartin Diehl istart = 0 166*e7a95102SMartin Diehl end if 167*e7a95102SMartin Diehl if (rank == size - 1) then 168*e7a95102SMartin Diehl i = INT(ctx%N - 1) 169*e7a95102SMartin Diehl A = 1.0 170*e7a95102SMartin Diehl PetscCall(MatSetValues(jac, i1, [i], i1, [i], [A], INSERT_VALUES, ierr)) 171*e7a95102SMartin Diehl iend = n - 1 172*e7a95102SMartin Diehl else 173*e7a95102SMartin Diehl iend = n 174*e7a95102SMartin Diehl end if 175*e7a95102SMartin Diehl do i = istart, iend - 1 176*e7a95102SMartin Diehl ii = i + start 177*e7a95102SMartin Diehl j = start + i - 1 178*e7a95102SMartin Diehl PetscCall(MatSetValues(jac, i1, [ii], i1, [j], [d], INSERT_VALUES, ierr)) 179*e7a95102SMartin Diehl j = start + i + 1 180*e7a95102SMartin Diehl PetscCall(MatSetValues(jac, i1, [ii], i1, [j], [d], INSERT_VALUES, ierr)) 181*e7a95102SMartin Diehl A = -2.0*d + 2.0*vxx(i + 1) 182*e7a95102SMartin Diehl PetscCall(MatSetValues(jac, i1, [ii], i1, [ii], [A], INSERT_VALUES, ierr)) 183*e7a95102SMartin Diehl end do 184*e7a95102SMartin Diehl PetscCall(VecRestoreArrayRead(x, vxx, ierr)) 185*e7a95102SMartin Diehl PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY, ierr)) 186*e7a95102SMartin Diehl PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY, ierr)) 187*e7a95102SMartin Diehl end 188*e7a95102SMartin Diehl 189*e7a95102SMartin Diehlend module 19042ce371bSBarry Smith 191d8606c27SBarry Smithprogram main 192*e7a95102SMartin Diehl use ex12f_mod 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