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