xref: /petsc/src/snes/tests/ex12f.F90 (revision 749c190bad46ba447444c173d8c7a4080c70750e)
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