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> 7c5e229c2SMartin Diehlmodule ex12fmodule 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 Smithend 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 Smithsubroutine 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) 474820e4eaSBarry Smith if (mod(snesm%its, snesm%lag) == 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 end if 54d8606c27SBarry Smith snesm%its = snesm%its + 1 55d8606c27SBarry Smithend 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 Smithprogram 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 935d83a8b1SBarry Smith PetscCallA(DMDACreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, N, i1, i1, PETSC_NULL_INTEGER_ARRAY, 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 1055d83a8b1SBarry Smith PetscCallA(MatCreateAIJ(PETSC_COMM_WORLD, PETSC_DECIDE, PETSC_DECIDE, N, N, i3, PETSC_NULL_INTEGER_ARRAY, i0, PETSC_NULL_INTEGER_ARRAY, J, ierr)) 106d8606c27SBarry Smith PetscCallA(MatSetOption(J, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE, ierr)) 107d8606c27SBarry Smith PetscCallA(MatGetType(J, matrixname, ierr)) 108d8606c27SBarry Smith 109dd8e379bSPierre 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 114*ceeae6b5SMartin Diehl do i = 0, nn - 1 115d8606c27SBarry Smith FF = 6.0*xp + (xp + 1.e-12)**6.e0 116d8606c27SBarry Smith UU = xp*xp*xp 1175d83a8b1SBarry Smith PetscCallA(VecSetValues(ctx%F, i1, [ii], [FF], INSERT_VALUES, ierr)) 1185d83a8b1SBarry Smith PetscCallA(VecSetValues(U, i1, [ii], [UU], INSERT_VALUES, ierr)) 119d8606c27SBarry Smith xp = xp + h 120d8606c27SBarry Smith ii = ii + 1 121*ceeae6b5SMartin Diehl end do 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 Smithend 156d8606c27SBarry Smith 157d8606c27SBarry Smith! -------------------- Evaluate Function F(x) --------------------- 158d8606c27SBarry Smith 159d8606c27SBarry Smithsubroutine 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)) 1794820e4eaSBarry Smith if (n > 1000) then 180d8606c27SBarry Smith print *, 'Local work array not big enough' 181d8606c27SBarry Smith call MPI_Abort(PETSC_COMM_WORLD, zero, ierr) 182d8606c27SBarry Smith end if 183d8606c27SBarry Smith 184ce78bad3SBarry Smith PetscCall(VecGetArrayRead(ctx%xl, vxx, ierr)) 185ce78bad3SBarry Smith PetscCall(VecGetArray(f, vff, ierr)) 186ce78bad3SBarry Smith PetscCall(VecGetArray(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! 2064820e4eaSBarry Smith if (rank == 0) then 207d8606c27SBarry Smith s = 0 20842ce371bSBarry Smith vff(1) = vxx(1) 209d8606c27SBarry Smith else 210d8606c27SBarry Smith s = 1 211d8606c27SBarry Smith end if 212d8606c27SBarry Smith 213*ceeae6b5SMartin Diehl do 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) 215*ceeae6b5SMartin Diehl end do 216d8606c27SBarry Smith 2174820e4eaSBarry Smith if (rank == size - 1) then 21842ce371bSBarry Smith vff(n - s) = vxx(n) - 1.0 219d8606c27SBarry Smith end if 220d8606c27SBarry Smith 221ce78bad3SBarry Smith PetscCall(VecRestoreArray(f, vff, ierr)) 222ce78bad3SBarry Smith PetscCall(VecRestoreArrayRead(ctx%xl, vxx, ierr)) 223ce78bad3SBarry Smith PetscCall(VecRestoreArray(ctx%F, vF2, ierr)) 224d8606c27SBarry Smithend 225d8606c27SBarry Smith 226d8606c27SBarry Smith! -------------------- Form initial approximation ----------------- 227d8606c27SBarry Smith 228d8606c27SBarry Smithsubroutine FormInitialGuess(snes, x, ierr) 22977d968b7SBarry Smith use ex12fmodule 230d8606c27SBarry Smith implicit none 231d8606c27SBarry Smith 232d8606c27SBarry Smith PetscErrorCode ierr 233d8606c27SBarry Smith Vec x 234d8606c27SBarry Smith SNES snes 235d8606c27SBarry Smith PetscScalar five 236d8606c27SBarry Smith 237d8606c27SBarry Smith five = .5 238d8606c27SBarry Smith PetscCall(VecSet(x, five, ierr)) 239d8606c27SBarry Smithend 240d8606c27SBarry Smith 241d8606c27SBarry Smith! -------------------- Evaluate Jacobian -------------------- 242d8606c27SBarry Smith 243d8606c27SBarry Smithsubroutine FormJacobian(snes, x, jac, B, ctx, ierr) 24477d968b7SBarry Smith use ex12fmodule 245d8606c27SBarry Smith implicit none 246d8606c27SBarry Smith 247d8606c27SBarry Smith SNES snes 248d8606c27SBarry Smith Vec x 249d8606c27SBarry Smith Mat jac, B 250d8606c27SBarry Smith type(User) ctx 251d8606c27SBarry Smith PetscInt ii, istart, iend 252d8606c27SBarry Smith PetscInt i, j, n, end, start, i1 253d8606c27SBarry Smith PetscErrorCode ierr 254d8606c27SBarry Smith PetscMPIInt rank, size 25542ce371bSBarry Smith PetscScalar d, A, h 25642ce371bSBarry Smith PetscScalar, pointer :: vxx(:) 257d8606c27SBarry Smith 258d8606c27SBarry Smith i1 = 1 259d8606c27SBarry Smith h = 1.0/(real(ctx%N) - 1.0) 260d8606c27SBarry Smith d = h*h 261d8606c27SBarry Smith PetscCallMPI(MPI_Comm_rank(ctx%comm, rank, ierr)) 262d8606c27SBarry Smith PetscCallMPI(MPI_Comm_size(ctx%comm, size, ierr)) 263d8606c27SBarry Smith 264ce78bad3SBarry Smith PetscCall(VecGetArrayRead(x, vxx, ierr)) 265d8606c27SBarry Smith PetscCall(VecGetOwnershipRange(x, start, end, ierr)) 266d8606c27SBarry Smith n = end - start 267d8606c27SBarry Smith 2684820e4eaSBarry Smith if (rank == 0) then 269d8606c27SBarry Smith A = 1.0 2705d83a8b1SBarry Smith PetscCall(MatSetValues(jac, i1, [start], i1, [start], [A], INSERT_VALUES, ierr)) 271d8606c27SBarry Smith istart = 1 272d8606c27SBarry Smith else 273d8606c27SBarry Smith istart = 0 274d8606c27SBarry Smith end if 2754820e4eaSBarry Smith if (rank == size - 1) then 276d8606c27SBarry Smith i = INT(ctx%N - 1) 277d8606c27SBarry Smith A = 1.0 2785d83a8b1SBarry Smith PetscCall(MatSetValues(jac, i1, [i], i1, [i], [A], INSERT_VALUES, ierr)) 279d8606c27SBarry Smith iend = n - 1 280d8606c27SBarry Smith else 281d8606c27SBarry Smith iend = n 282d8606c27SBarry Smith end if 283*ceeae6b5SMartin Diehl do i = istart, iend - 1 284d8606c27SBarry Smith ii = i + start 285d8606c27SBarry Smith j = start + i - 1 2865d83a8b1SBarry Smith PetscCall(MatSetValues(jac, i1, [ii], i1, [j], [d], INSERT_VALUES, ierr)) 287d8606c27SBarry Smith j = start + i + 1 2885d83a8b1SBarry Smith PetscCall(MatSetValues(jac, i1, [ii], i1, [j], [d], INSERT_VALUES, ierr)) 28942ce371bSBarry Smith A = -2.0*d + 2.0*vxx(i + 1) 2905d83a8b1SBarry Smith PetscCall(MatSetValues(jac, i1, [ii], i1, [ii], [A], INSERT_VALUES, ierr)) 291*ceeae6b5SMartin Diehl end do 292ce78bad3SBarry Smith PetscCall(VecRestoreArrayRead(x, vxx, ierr)) 293d8606c27SBarry Smith PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY, ierr)) 294d8606c27SBarry Smith PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY, ierr)) 295d8606c27SBarry Smithend 296d8606c27SBarry Smith 297d8606c27SBarry Smith!/*TEST 298d8606c27SBarry Smith! 299d8606c27SBarry Smith! test: 300d8606c27SBarry Smith! nsize: 2 301d8606c27SBarry Smith! args: -ksp_gmres_cgs_refinement_type refine_always -n 10 -snes_monitor_short 302d8606c27SBarry Smith! output_file: output/ex12_1.out 303d8606c27SBarry Smith! 304d8606c27SBarry Smith!TEST*/ 305