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