xref: /petsc/src/snes/tests/ex12f.F90 (revision 4820e4ea99a084ae862a8c395f732bc7c0e1a6d0)
1d8606c27SBarry Smith!
2d8606c27SBarry Smith!
3d8606c27SBarry Smith!  This example demonstrates basic use of the SNES Fortran interface.
4d8606c27SBarry Smith!
5d8606c27SBarry Smith!
677d968b7SBarry Smithmodule ex12fmodule
7d8606c27SBarry Smith#include <petsc/finclude/petscsnes.h>
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)
47*4820e4eaSBarry 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
114d8606c27SBarry Smith  do 10, 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
121d8606c27SBarry Smith10  continue
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 Smith  end
156d8606c27SBarry Smith
157d8606c27SBarry Smith! --------------------  Evaluate Function F(x) ---------------------
158d8606c27SBarry Smith
159d8606c27SBarry Smith  subroutine 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))
179*4820e4eaSBarry 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!
206*4820e4eaSBarry 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
213d8606c27SBarry Smith    do 10 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)
215d8606c27SBarry Smith10    continue
216d8606c27SBarry Smith
217*4820e4eaSBarry 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 Smith    end
225d8606c27SBarry Smith
226d8606c27SBarry Smith! --------------------  Form initial approximation -----------------
227d8606c27SBarry Smith
228d8606c27SBarry Smith    subroutine 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 Smith    end
240d8606c27SBarry Smith
241d8606c27SBarry Smith! --------------------  Evaluate Jacobian --------------------
242d8606c27SBarry Smith
243d8606c27SBarry Smith    subroutine 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
268*4820e4eaSBarry 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
275*4820e4eaSBarry 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
283d8606c27SBarry Smith      do 10 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))
291d8606c27SBarry Smith10      continue
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 Smith      end
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