xref: /petsc/src/snes/tests/ex12f.F90 (revision 77d968b72e8e27b79bcc994c018975de390644ed)
1d8606c27SBarry Smith!
2d8606c27SBarry Smith!
3d8606c27SBarry Smith!  This example demonstrates basic use of the SNES Fortran interface.
4d8606c27SBarry Smith!
5d8606c27SBarry Smith!
6*77d968b7SBarry Smith        module 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 Smith      end module
21d8606c27SBarry Smith
22d8606c27SBarry Smith! ---------------------------------------------------------------------
23d8606c27SBarry Smith! ---------------------------------------------------------------------
24d8606c27SBarry Smith!  Subroutine FormMonitor
25d8606c27SBarry Smith!  This function lets up keep track of the SNES progress at each step
26d8606c27SBarry Smith!  In this routine, we determine when the Jacobian is rebuilt with the parameter 'jag'
27d8606c27SBarry Smith!
28d8606c27SBarry Smith!  Input Parameters:
29d8606c27SBarry Smith!    snes    - SNES nonlinear solver context
30d8606c27SBarry Smith!    its     - current nonlinear iteration, starting from a call of SNESSolve()
31d8606c27SBarry Smith!    norm    - 2-norm of current residual (may be approximate)
32d8606c27SBarry Smith!    snesm - monctx designed module (included in Snesmmod)
33d8606c27SBarry Smith! ---------------------------------------------------------------------
34d8606c27SBarry Smith      subroutine FormMonitor(snes,its,norm,snesm,ierr)
35*77d968b7SBarry Smith      use ex12fmodule
36d8606c27SBarry Smith      implicit none
37d8606c27SBarry Smith
38d8606c27SBarry Smith      SNES ::           snes
39d8606c27SBarry Smith      PetscInt ::       its,one,mone
40d8606c27SBarry Smith      PetscScalar ::    norm
41d8606c27SBarry Smith      type(monctx) ::   snesm
42d8606c27SBarry Smith      PetscErrorCode :: ierr
43d8606c27SBarry Smith
44d8606c27SBarry Smith!      write(6,*) ' '
45d8606c27SBarry Smith!      write(6,*) '    its ',its,snesm%its,'lag',
46d8606c27SBarry Smith!     &            snesm%lag
47d8606c27SBarry Smith!      call flush(6)
48d8606c27SBarry Smith      if (mod(snesm%its,snesm%lag).eq.0) then
49d8606c27SBarry Smith        one = 1
50d8606c27SBarry Smith        PetscCall(SNESSetLagJacobian(snes,one,ierr))  ! build jacobian
51d8606c27SBarry Smith      else
52d8606c27SBarry Smith        mone = -1
53d8606c27SBarry Smith        PetscCall(SNESSetLagJacobian(snes,mone,ierr)) ! do NOT build jacobian
54d8606c27SBarry Smith      endif
55d8606c27SBarry Smith      snesm%its = snesm%its + 1
56d8606c27SBarry Smith      end subroutine FormMonitor
57d8606c27SBarry Smith
58d8606c27SBarry Smith!  Note: Any user-defined Fortran routines (such as FormJacobian)
59d8606c27SBarry Smith!  MUST be declared as external.
60d8606c27SBarry Smith!
61d8606c27SBarry Smith!
62d8606c27SBarry Smith! Macros to make setting/getting  values into vector clearer.
63d8606c27SBarry Smith! The element xx(ib) is the ibth element in the vector indicated by ctx%F
64d8606c27SBarry Smith#define xx(ib)  vxx(ixx + (ib))
65d8606c27SBarry Smith#define ff(ib)  vff(iff + (ib))
66d8606c27SBarry Smith#define F2(ib)  vF2(iF2 + (ib))
67d8606c27SBarry Smith      program main
68*77d968b7SBarry Smith      use ex12fmodule
69d8606c27SBarry Smith      implicit none
70d8606c27SBarry Smith      type(User) ctx
71d8606c27SBarry Smith      PetscMPIInt rank,size
72d8606c27SBarry Smith      PetscErrorCode ierr
73d8606c27SBarry Smith      PetscInt N,start,end,nn,i
74d8606c27SBarry Smith      PetscInt ii,its,i1,i0,i3
75d8606c27SBarry Smith      PetscBool  flg
76d8606c27SBarry Smith      SNES             snes
77d8606c27SBarry Smith      Mat              J
78d8606c27SBarry Smith      Vec              x,r,u
79d8606c27SBarry Smith      PetscScalar      xp,FF,UU,h
80d8606c27SBarry Smith      character*(10)   matrixname
81d8606c27SBarry Smith      external         FormJacobian,FormFunction
82d8606c27SBarry Smith      external         formmonitor
83d8606c27SBarry Smith      type(monctx) :: snesm
84d8606c27SBarry Smith
85d8606c27SBarry Smith      PetscCallA(PetscInitialize(ierr))
86d8606c27SBarry Smith      i1 = 1
87d8606c27SBarry Smith      i0 = 0
88d8606c27SBarry Smith      i3 = 3
89d8606c27SBarry Smith      N  = 10
90d8606c27SBarry Smith      PetscCallA(PetscOptionsGetInt(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,'-n',N,flg,ierr))
91d8606c27SBarry Smith      h = 1.0/real(N-1)
92d8606c27SBarry Smith      ctx%N = N
93d8606c27SBarry Smith      ctx%comm = PETSC_COMM_WORLD
94d8606c27SBarry Smith
95d8606c27SBarry Smith      PetscCallMPIA(MPI_Comm_rank(PETSC_COMM_WORLD,rank,ierr))
96d8606c27SBarry Smith      PetscCallMPIA(MPI_Comm_size(PETSC_COMM_WORLD,size,ierr))
97d8606c27SBarry Smith
98d8606c27SBarry Smith! Set up data structures
99d8606c27SBarry Smith      PetscCallA(DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,N,i1,i1,PETSC_NULL_INTEGER,ctx%da,ierr))
100d8606c27SBarry Smith      PetscCallA(DMSetFromOptions(ctx%da,ierr))
101d8606c27SBarry Smith      PetscCallA(DMSetUp(ctx%da,ierr))
102d8606c27SBarry Smith      PetscCallA(DMCreateGlobalVector(ctx%da,x,ierr))
103d8606c27SBarry Smith      PetscCallA(DMCreateLocalVector(ctx%da,ctx%xl,ierr))
104d8606c27SBarry Smith
105d8606c27SBarry Smith      PetscCallA(PetscObjectSetName(x,'Approximate Solution',ierr))
106d8606c27SBarry Smith      PetscCallA(VecDuplicate(x,r,ierr))
107d8606c27SBarry Smith      PetscCallA(VecDuplicate(x,ctx%F,ierr))
108d8606c27SBarry Smith      PetscCallA(VecDuplicate(x,U,ierr))
109d8606c27SBarry Smith      PetscCallA(PetscObjectSetName(U,'Exact Solution',ierr))
110d8606c27SBarry Smith
111d8606c27SBarry Smith      PetscCallA(MatCreateAIJ(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,N,N,i3,PETSC_NULL_INTEGER,i0,PETSC_NULL_INTEGER,J,ierr))
112d8606c27SBarry Smith      PetscCallA(MatSetOption(J,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_FALSE,ierr))
113d8606c27SBarry Smith      PetscCallA(MatGetType(J,matrixname,ierr))
114d8606c27SBarry Smith
115d8606c27SBarry Smith! Store right-hand-side of PDE and exact solution
116d8606c27SBarry Smith      PetscCallA(VecGetOwnershipRange(x,start,end,ierr))
117d8606c27SBarry Smith      xp = h*start
118d8606c27SBarry Smith      nn = end - start
119d8606c27SBarry Smith      ii = start
120d8606c27SBarry Smith      do 10, i=0,nn-1
121d8606c27SBarry Smith        FF = 6.0*xp + (xp+1.e-12)**6.e0
122d8606c27SBarry Smith        UU = xp*xp*xp
123d8606c27SBarry Smith        PetscCallA(VecSetValues(ctx%F,i1,ii,FF,INSERT_VALUES,ierr))
124d8606c27SBarry Smith        PetscCallA(VecSetValues(U,i1,ii,UU,INSERT_VALUES,ierr))
125d8606c27SBarry Smith        xp = xp + h
126d8606c27SBarry Smith        ii = ii + 1
127d8606c27SBarry Smith 10   continue
128d8606c27SBarry Smith      PetscCallA(VecAssemblyBegin(ctx%F,ierr))
129d8606c27SBarry Smith      PetscCallA(VecAssemblyEnd(ctx%F,ierr))
130d8606c27SBarry Smith      PetscCallA(VecAssemblyBegin(U,ierr))
131d8606c27SBarry Smith      PetscCallA(VecAssemblyEnd(U,ierr))
132d8606c27SBarry Smith
133d8606c27SBarry Smith! Create nonlinear solver
134d8606c27SBarry Smith      PetscCallA(SNESCreate(PETSC_COMM_WORLD,snes,ierr))
135d8606c27SBarry Smith
136d8606c27SBarry Smith! Set various routines and options
137d8606c27SBarry Smith      PetscCallA(SNESSetFunction(snes,r,FormFunction,ctx,ierr))
138d8606c27SBarry Smith      PetscCallA(SNESSetJacobian(snes,J,J,FormJacobian,ctx,ierr))
139d8606c27SBarry Smith
140d8606c27SBarry Smith      snesm%its = 0
141d8606c27SBarry Smith      PetscCallA(SNESGetLagJacobian(snes,snesm%lag,ierr))
142d8606c27SBarry Smith      PetscCallA(SNESMonitorSet(snes,FormMonitor,snesm,PETSC_NULL_FUNCTION,ierr))
143d8606c27SBarry Smith      PetscCallA(SNESSetFromOptions(snes,ierr))
144d8606c27SBarry Smith
145d8606c27SBarry Smith! Solve nonlinear system
146d8606c27SBarry Smith      PetscCallA(FormInitialGuess(snes,x,ierr))
147d8606c27SBarry Smith      PetscCallA(SNESSolve(snes,PETSC_NULL_VEC,x,ierr))
148d8606c27SBarry Smith      PetscCallA(SNESGetIterationNumber(snes,its,ierr))
149d8606c27SBarry Smith
150d8606c27SBarry Smith!  Free work space.  All PETSc objects should be destroyed when they
151d8606c27SBarry Smith!  are no longer needed.
152d8606c27SBarry Smith      PetscCallA(VecDestroy(x,ierr))
153d8606c27SBarry Smith      PetscCallA(VecDestroy(ctx%xl,ierr))
154d8606c27SBarry Smith      PetscCallA(VecDestroy(r,ierr))
155d8606c27SBarry Smith      PetscCallA(VecDestroy(U,ierr))
156d8606c27SBarry Smith      PetscCallA(VecDestroy(ctx%F,ierr))
157d8606c27SBarry Smith      PetscCallA(MatDestroy(J,ierr))
158d8606c27SBarry Smith      PetscCallA(SNESDestroy(snes,ierr))
159d8606c27SBarry Smith      PetscCallA(DMDestroy(ctx%da,ierr))
160d8606c27SBarry Smith      PetscCallA(PetscFinalize(ierr))
161d8606c27SBarry Smith      end
162d8606c27SBarry Smith
163d8606c27SBarry Smith! --------------------  Evaluate Function F(x) ---------------------
164d8606c27SBarry Smith
165d8606c27SBarry Smith      subroutine FormFunction(snes,x,f,ctx,ierr)
166*77d968b7SBarry Smith      use ex12fmodule
167d8606c27SBarry Smith      implicit none
168d8606c27SBarry Smith      SNES             snes
169d8606c27SBarry Smith      Vec              x,f
170d8606c27SBarry Smith      type(User) ctx
171d8606c27SBarry Smith      PetscMPIInt  rank,size,zero
172d8606c27SBarry Smith      PetscInt i,s,n
173d8606c27SBarry Smith      PetscErrorCode ierr
174d8606c27SBarry Smith      PetscOffset      ixx,iff,iF2
175d8606c27SBarry Smith      PetscScalar      h,d,vf2(2),vxx(2),vff(2)
176d8606c27SBarry Smith
177d8606c27SBarry Smith      zero = 0
178d8606c27SBarry Smith      PetscCallMPI(MPI_Comm_rank(ctx%comm,rank,ierr))
179d8606c27SBarry Smith      PetscCallMPI(MPI_Comm_size(ctx%comm,size,ierr))
180d8606c27SBarry Smith      h     = 1.0/(real(ctx%N) - 1.0)
181d8606c27SBarry Smith      PetscCall(DMGlobalToLocalBegin(ctx%da,x,INSERT_VALUES,ctx%xl,ierr))
182d8606c27SBarry Smith      PetscCall(DMGlobalToLocalEnd(ctx%da,x,INSERT_VALUES,ctx%xl,ierr))
183d8606c27SBarry Smith
184d8606c27SBarry Smith      PetscCall(VecGetLocalSize(ctx%xl,n,ierr))
185d8606c27SBarry Smith      if (n .gt. 1000) then
186d8606c27SBarry Smith        print*, 'Local work array not big enough'
187d8606c27SBarry Smith        call MPI_Abort(PETSC_COMM_WORLD,zero,ierr)
188d8606c27SBarry Smith      endif
189d8606c27SBarry Smith
190d8606c27SBarry Smith!
191d8606c27SBarry Smith! This sets the index ixx so that vxx(ixx+1) is the first local
192d8606c27SBarry Smith! element in the vector indicated by ctx%xl.
193d8606c27SBarry Smith!
194d8606c27SBarry Smith      PetscCall(VecGetArrayRead(ctx%xl,vxx,ixx,ierr))
195d8606c27SBarry Smith      PetscCall(VecGetArray(f,vff,iff,ierr))
196d8606c27SBarry Smith      PetscCall(VecGetArray(ctx%F,vF2,iF2,ierr))
197d8606c27SBarry Smith
198d8606c27SBarry Smith      d = h*h
199d8606c27SBarry Smith
200d8606c27SBarry Smith!
201d8606c27SBarry Smith!  Note that the array vxx() was obtained from a ghosted local vector
202d8606c27SBarry Smith!  ctx%xl while the array vff() was obtained from the non-ghosted parallel
203d8606c27SBarry Smith!  vector F. This is why there is a need for shift variable s. Since vff()
204d8606c27SBarry Smith!  does not have locations for the ghost variables we need to index in it
205d8606c27SBarry Smith!  slightly different then indexing into vxx(). For example on processor
206d8606c27SBarry Smith!  1 (the second processor)
207d8606c27SBarry Smith!
208d8606c27SBarry Smith!        xx(1)        xx(2)             xx(3)             .....
209d8606c27SBarry Smith!      ^^^^^^^        ^^^^^             ^^^^^
210d8606c27SBarry Smith!      ghost value   1st local value   2nd local value
211d8606c27SBarry Smith!
212d8606c27SBarry Smith!                      ff(1)             ff(2)
213d8606c27SBarry Smith!                     ^^^^^^^           ^^^^^^^
214d8606c27SBarry Smith!                    1st local value   2nd local value
215d8606c27SBarry Smith!
216d8606c27SBarry Smith       if (rank .eq. 0) then
217d8606c27SBarry Smith        s = 0
218d8606c27SBarry Smith        ff(1) = xx(1)
219d8606c27SBarry Smith      else
220d8606c27SBarry Smith        s = 1
221d8606c27SBarry Smith      endif
222d8606c27SBarry Smith
223d8606c27SBarry Smith      do 10 i=1,n-2
224d8606c27SBarry Smith       ff(i-s+1) = d*(xx(i) - 2.0*xx(i+1) + xx(i+2)) + xx(i+1)*xx(i+1) - F2(i-s+1)
225d8606c27SBarry Smith 10   continue
226d8606c27SBarry Smith
227d8606c27SBarry Smith      if (rank .eq. size-1) then
228d8606c27SBarry Smith        ff(n-s) = xx(n) - 1.0
229d8606c27SBarry Smith      endif
230d8606c27SBarry Smith
231d8606c27SBarry Smith      PetscCall(VecRestoreArray(f,vff,iff,ierr))
232d8606c27SBarry Smith      PetscCall(VecRestoreArrayRead(ctx%xl,vxx,ixx,ierr))
233d8606c27SBarry Smith      PetscCall(VecRestoreArray(ctx%F,vF2,iF2,ierr))
234d8606c27SBarry Smith      return
235d8606c27SBarry Smith      end
236d8606c27SBarry Smith
237d8606c27SBarry Smith! --------------------  Form initial approximation -----------------
238d8606c27SBarry Smith
239d8606c27SBarry Smith      subroutine FormInitialGuess(snes,x,ierr)
240*77d968b7SBarry Smith      use ex12fmodule
241d8606c27SBarry Smith      implicit none
242d8606c27SBarry Smith
243d8606c27SBarry Smith      PetscErrorCode   ierr
244d8606c27SBarry Smith      Vec              x
245d8606c27SBarry Smith      SNES             snes
246d8606c27SBarry Smith      PetscScalar      five
247d8606c27SBarry Smith
248d8606c27SBarry Smith      five = .5
249d8606c27SBarry Smith      PetscCall(VecSet(x,five,ierr))
250d8606c27SBarry Smith      return
251d8606c27SBarry Smith      end
252d8606c27SBarry Smith
253d8606c27SBarry Smith! --------------------  Evaluate Jacobian --------------------
254d8606c27SBarry Smith
255d8606c27SBarry Smith      subroutine FormJacobian(snes,x,jac,B,ctx,ierr)
256*77d968b7SBarry Smith      use ex12fmodule
257d8606c27SBarry Smith      implicit none
258d8606c27SBarry Smith
259d8606c27SBarry Smith      SNES             snes
260d8606c27SBarry Smith      Vec              x
261d8606c27SBarry Smith      Mat              jac,B
262d8606c27SBarry Smith      type(User) ctx
263d8606c27SBarry Smith      PetscInt  ii,istart,iend
264d8606c27SBarry Smith      PetscInt  i,j,n,end,start,i1
265d8606c27SBarry Smith      PetscErrorCode ierr
266d8606c27SBarry Smith      PetscMPIInt rank,size
267d8606c27SBarry Smith      PetscOffset      ixx
268d8606c27SBarry Smith      PetscScalar      d,A,h,vxx(2)
269d8606c27SBarry Smith
270d8606c27SBarry Smith      i1 = 1
271d8606c27SBarry Smith      h = 1.0/(real(ctx%N) - 1.0)
272d8606c27SBarry Smith      d = h*h
273d8606c27SBarry Smith      PetscCallMPI(MPI_Comm_rank(ctx%comm,rank,ierr))
274d8606c27SBarry Smith      PetscCallMPI(MPI_Comm_size(ctx%comm,size,ierr))
275d8606c27SBarry Smith
276d8606c27SBarry Smith      PetscCall(VecGetArrayRead(x,vxx,ixx,ierr))
277d8606c27SBarry Smith      PetscCall(VecGetOwnershipRange(x,start,end,ierr))
278d8606c27SBarry Smith      n = end - start
279d8606c27SBarry Smith
280d8606c27SBarry Smith      if (rank .eq. 0) then
281d8606c27SBarry Smith        A = 1.0
282d8606c27SBarry Smith        PetscCall(MatSetValues(jac,i1,start,i1,start,A,INSERT_VALUES,ierr))
283d8606c27SBarry Smith        istart = 1
284d8606c27SBarry Smith      else
285d8606c27SBarry Smith        istart = 0
286d8606c27SBarry Smith      endif
287d8606c27SBarry Smith      if (rank .eq. size-1) then
288d8606c27SBarry Smith        i = INT(ctx%N-1)
289d8606c27SBarry Smith        A = 1.0
290d8606c27SBarry Smith        PetscCall(MatSetValues(jac,i1,i,i1,i,A,INSERT_VALUES,ierr))
291d8606c27SBarry Smith        iend = n-1
292d8606c27SBarry Smith      else
293d8606c27SBarry Smith        iend = n
294d8606c27SBarry Smith      endif
295d8606c27SBarry Smith      do 10 i=istart,iend-1
296d8606c27SBarry Smith        ii = i + start
297d8606c27SBarry Smith        j = start + i - 1
298d8606c27SBarry Smith        PetscCall(MatSetValues(jac,i1,ii,i1,j,d,INSERT_VALUES,ierr))
299d8606c27SBarry Smith        j = start + i + 1
300d8606c27SBarry Smith        PetscCall(MatSetValues(jac,i1,ii,i1,j,d,INSERT_VALUES,ierr))
301d8606c27SBarry Smith        A = -2.0*d + 2.0*xx(i+1)
302d8606c27SBarry Smith        PetscCall(MatSetValues(jac,i1,ii,i1,ii,A,INSERT_VALUES,ierr))
303d8606c27SBarry Smith 10   continue
304d8606c27SBarry Smith      PetscCall(VecRestoreArrayRead(x,vxx,ixx,ierr))
305d8606c27SBarry Smith      PetscCall(MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY,ierr))
306d8606c27SBarry Smith      PetscCall(MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY,ierr))
307d8606c27SBarry Smith      return
308d8606c27SBarry Smith      end
309d8606c27SBarry Smith
310d8606c27SBarry Smith!/*TEST
311d8606c27SBarry Smith!
312d8606c27SBarry Smith!   test:
313d8606c27SBarry Smith!      nsize: 2
314d8606c27SBarry Smith!      args: -ksp_gmres_cgs_refinement_type refine_always -n 10 -snes_monitor_short
315d8606c27SBarry Smith!      output_file: output/ex12_1.out
316d8606c27SBarry Smith!
317d8606c27SBarry Smith!TEST*/
318